1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Implement the playMono16Sound API sanely

This API used to start *A NEW THREAD* for every sound played!!

Now we simply have a dedicated source and buffer to play those sounds, we use a timer to cleanup the buffer 50ms after the sound is done playing (if a new sound hasn't started in the meantime)
This commit is contained in:
tux3 2016-01-22 00:10:54 +01:00
parent f57bf331d6
commit 6425448196
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
2 changed files with 51 additions and 65 deletions

View File

@ -51,52 +51,6 @@
} while (0)
#endif
/**
@class AudioPlayer
@brief Non-blocking audio player.
The audio data is played from start to finish (no streaming).
*/
class AudioPlayer : public QThread
{
public:
AudioPlayer(ALuint source, const QByteArray& data)
: mSource(source)
{
alGenBuffers(1, &mBuffer);
alBufferData(mBuffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100);
alSourcei(mSource, AL_BUFFER, mBuffer);
connect(this, &AudioPlayer::finished, this, &AudioPlayer::deleteLater);
}
private:
void run() override final
{
alSourceRewind(mSource);
alSourcePlay(mSource);
QMutexLocker locker(&playLock);
ALint state = AL_PLAYING;
while (state == AL_PLAYING) {
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
waitPlaying.wait(&playLock, 2000);
}
alSourceStop(mSource);
alDeleteBuffers(1, &mBuffer);
}
public:
QMutex playLock;
QWaitCondition waitPlaying;
private:
ALuint mBuffer;
ALuint mSource;
};
/**
Returns the singleton instance.
*/
@ -114,6 +68,7 @@ Audio::Audio()
, alOutDev(nullptr)
, alOutContext(nullptr)
, alMainSource(0)
, alMainBuffer(0)
, outputInitialized(false)
{
audioThread->setObjectName("qTox Audio");
@ -129,6 +84,8 @@ Audio::Audio()
captureTimer.setInterval(AUDIO_FRAME_DURATION/2);
captureTimer.setSingleShot(false);
captureTimer.start();
connect(&playMono16Timer, &QTimer::timeout, this, &Audio::playMono16SoundCleanup);
playMono16Timer.setSingleShot(true);
if (!audioThread->isRunning())
audioThread->start();
@ -360,6 +317,16 @@ bool Audio::initOutput(QString outDevDescr)
return true;
}
/**
Play a 44100Hz mono 16bit PCM sound from a file
*/
void Audio::playMono16Sound(const QString& path)
{
QFile sndFile(path);
sndFile.open(QIODevice::ReadOnly);
playMono16Sound(QByteArray(sndFile.readAll()));
}
/**
Play a 44100Hz mono 16bit PCM sound
*/
@ -370,27 +337,23 @@ void Audio::playMono16Sound(const QByteArray& data)
if (!autoInitOutput())
return;
AudioPlayer *player = new AudioPlayer(alMainSource, data);
connect(player, &AudioPlayer::finished, [=]() {
QMutexLocker locker(&audioLock);
if (!alMainBuffer)
alGenBuffers(1, &alMainBuffer);
if (outSources.isEmpty())
cleanupOutput();
else
qDebug("Audio output not closed -> there are pending subscriptions.");
});
ALint state;
alGetSourcei(alMainSource, AL_SOURCE_STATE, &state);
if (state == AL_PLAYING)
{
alSourceStop(alMainSource);
alSourcei(alMainSource, AL_BUFFER, AL_NONE);
}
player->start();
}
alBufferData(alMainBuffer, AL_FORMAT_MONO16, data.constData(), data.size(), 44100);
alSourcei(alMainSource, AL_BUFFER, static_cast<ALint>(alMainBuffer));
alSourcePlay(alMainSource);
/**
Play a 44100Hz mono 16bit PCM sound from a file
*/
void Audio::playMono16Sound(const QString& path)
{
QFile sndFile(path);
sndFile.open(QIODevice::ReadOnly);
playMono16Sound(QByteArray(sndFile.readAll()));
int durationMs = data.size() * 1000 / 2 / 44100;
playMono16Timer.start(durationMs + 50);
}
/**
@ -479,6 +442,12 @@ void Audio::cleanupOutput()
alSourceStop(alMainSource);
alDeleteSources(1, &alMainSource);
if (alMainBuffer)
{
alDeleteBuffers(1, &alMainBuffer);
alMainBuffer = 0;
}
if (!alcMakeContextCurrent(nullptr))
qWarning("Failed to clear audio context.");
@ -493,6 +462,20 @@ void Audio::cleanupOutput()
}
}
void Audio::playMono16SoundCleanup()
{
QMutexLocker locker(&audioLock);
ALint state;
alGetSourcei(alMainSource, AL_SOURCE_STATE, &state);
if (state == AL_STOPPED)
{
alSourcei(alMainSource, AL_BUFFER, AL_NONE);
alDeleteBuffers(1, &alMainBuffer);
alMainBuffer = 0;
}
}
void Audio::doCapture()
{
QMutexLocker lock(&audioLock);

View File

@ -105,6 +105,8 @@ private:
bool initOutput(QString outDevDescr);
void cleanupInput();
void cleanupOutput();
/// Called after a mono16 sound stopped playing
void playMono16SoundCleanup();
/// Called on the captureTimer events to capture audio
void doCapture();
#if defined(QTOX_FILTER_AUDIO) && defined(ALC_LOOPBACK_CAPTURE_SAMPLES)
@ -118,11 +120,12 @@ private:
ALCdevice* alInDev;
ALfloat inGain;
quint32 inSubscriptions;
QTimer captureTimer;
QTimer captureTimer, playMono16Timer;
ALCdevice* alOutDev;
ALCcontext* alOutContext;
ALuint alMainSource;
ALuint alMainBuffer;
bool outputInitialized;
QList<ALuint> outSources;