Introduced helper method AudioStream::renderAndUpdateState

This method is now used in majority of audio drivers that simplifies
rendering loops or the callbacks yet ensures that all drivers invoke
the related operations in the right order.
This commit is contained in:
sergm
2020-12-19 20:33:29 +02:00
parent 27f7032cca
commit e1e398b435
9 changed files with 17 additions and 23 deletions

View File

@@ -59,8 +59,7 @@ void *AlsaAudioStream::processingThread(void *userData) {
framesInAudioBuffer = (quint32)delayp;
}
}
audioStream.updateTimeInfo(nanosNow, framesInAudioBuffer);
audioStream.synthRoute.render(audioStream.buffer, audioStream.bufferSize);
audioStream.renderAndUpdateState(audioStream.buffer, audioStream.bufferSize, nanosNow, framesInAudioBuffer);
error = snd_pcm_writei(audioStream.stream, audioStream.buffer, audioStream.bufferSize);
if (error < 0) {
qDebug() << "snd_pcm_writei failed:" << snd_strerror(error) << "-> recovering...";
@@ -75,7 +74,6 @@ void *AlsaAudioStream::processingThread(void *userData) {
// isErrorOccured = true;
// break;
}
audioStream.framesRendered(audioStream.bufferSize);
}
if (isErrorOccured) {
snd_pcm_close(audioStream.stream);

View File

@@ -82,6 +82,13 @@ quint64 AudioStream::computeMIDITimestamp(uint relativeFrameTime) const {
return getRenderedFramesCount() + relativeFrameTime;
}
// Only called from the rendering thread.
void AudioStream::renderAndUpdateState(MT32Emu::Bit16s *buffer, const quint32 frameCount, const MasterClockNanos measuredNanos, const quint32 framesInAudioBuffer) {
updateTimeInfo(measuredNanos, framesInAudioBuffer);
synthRoute.render(buffer, frameCount);
framesRendered(frameCount);
}
// Only called from the rendering thread.
void AudioStream::updateTimeInfo(const MasterClockNanos measuredNanos, const quint32 framesInAudioBuffer) {
const TimeInfo &timeInfo = timeInfos[getSnapshotReadIx(timeInfoChangeCount)];

View File

@@ -40,6 +40,7 @@ protected:
} timeInfos[2];
QAtomicInt timeInfoChangeCount;
void renderAndUpdateState(MT32Emu::Bit16s *buffer, const quint32 frameCount, const MasterClockNanos measuredNanos, const quint32 framesInAudioBuffer);
void updateTimeInfo(const MasterClockNanos measuredNanos, const quint32 framesInAudioBuffer);
bool isAutoLatencyMode() const;
void framesRendered(quint32 frameCount);

View File

@@ -93,11 +93,9 @@ void CoreAudioStream::renderOutputBuffer(void *userData, AudioQueueRef queue, Au
qDebug() << "CoreAudio: AudioQueueGetCurrentTime() returns invalid sample time";
}
}
stream->updateTimeInfo(nanosNow, framesInAudioBuffer);
uint frameCount = buffer->mAudioDataByteSize >> 2;
stream->synthRoute.render((MT32Emu::Bit16s *)buffer->mAudioData, frameCount);
stream->framesRendered(frameCount);
stream->renderAndUpdateState((MT32Emu::Bit16s *)buffer->mAudioData, frameCount, nanosNow, framesInAudioBuffer);
OSStatus res = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
if (res) qDebug() << "CoreAudio: AudioQueueEnqueueBuffer() failed with error code:" << res;

View File

@@ -64,8 +64,7 @@ void *OSSAudioStream::processingThread(void *userData) {
} else {
framesInAudioBuffer = 0;
}
audioStream.updateTimeInfo(nanosNow, framesInAudioBuffer);
audioStream.synthRoute.render(audioStream.buffer, audioStream.bufferSize);
audioStream.renderAndUpdateState(audioStream.buffer, audioStream.bufferSize, nanosNow, framesInAudioBuffer);
error = write(audioStream.stream, audioStream.buffer, FRAME_SIZE * audioStream.bufferSize);
if (error != int(FRAME_SIZE * audioStream.bufferSize)) {
if (error == -1) {
@@ -76,7 +75,6 @@ void *OSSAudioStream::processingThread(void *userData) {
isErrorOccured = true;
break;
}
audioStream.framesRendered(audioStream.bufferSize);
}
if (isErrorOccured) {
close(audioStream.stream);

View File

@@ -134,10 +134,8 @@ int PortAudioStream::paCallback(const void *inputBuffer, void *outputBuffer, uns
} else {
framesInAudioBuffer = 0;
}
stream->updateTimeInfo(nanosNow, framesInAudioBuffer);
stream->renderAndUpdateState((Bit16s *)outputBuffer, quint32(frameCount), nanosNow, framesInAudioBuffer);
stream->synthRoute.render((Bit16s *)outputBuffer, frameCount);
stream->framesRendered(quint32(frameCount));
return paContinue;
}

View File

@@ -151,8 +151,7 @@ void *PulseAudioStream::processingThread(void *userData) {
} else {
framesInAudioBuffer = 0;
}
audioStream.updateTimeInfo(nanosNow, framesInAudioBuffer);
audioStream.synthRoute.render(audioStream.buffer, audioStream.bufferSize);
audioStream.renderAndUpdateState(audioStream.buffer, audioStream.bufferSize, nanosNow, framesInAudioBuffer);
if (_pa_simple_write(audioStream.stream, audioStream.buffer, audioStream.bufferSize * FRAME_SIZE, &error) < 0) {
qDebug() << "pa_simple_write() failed:" << _pa_strerror(error);
_pa_simple_free(audioStream.stream);
@@ -162,7 +161,6 @@ void *PulseAudioStream::processingThread(void *userData) {
audioStream.processingThreadID = 0;
return NULL;
}
audioStream.framesRendered(audioStream.bufferSize);
}
audioStream.stopProcessing = false;
audioStream.processingThreadID = 0;
@@ -209,7 +207,7 @@ bool PulseAudioStream::start() {
while (initFrames > 0) {
if (_pa_simple_write(stream, buffer, FRAME_SIZE * bufferSize, &error) < 0) {
qDebug() << "pa_simple_write() failed:" << _pa_strerror(error);
_pa_simple_free(stream);
_pa_simple_free(stream);
stream = NULL;
return false;
}
@@ -240,7 +238,7 @@ void PulseAudioStream::close() {
if (_pa_simple_drain(stream, &error) < 0) {
qDebug() << "pa_simple_drain() failed:" << _pa_strerror(error);
}
_pa_simple_free(stream);
_pa_simple_free(stream);
stream = NULL;
}
return;

View File

@@ -51,10 +51,8 @@ public:
} else {
framesInAudioBuffer = 0;
}
stream.updateTimeInfo(nanosNow, framesInAudioBuffer);
uint framesToRender = uint(len >> 2);
stream.synthRoute.render((Bit16s *)data, framesToRender);
stream.framesRendered(framesToRender);
stream.renderAndUpdateState((Bit16s *)data, framesToRender, nanosNow, framesInAudioBuffer);
return len;
}

View File

@@ -150,9 +150,7 @@ void WinMMAudioProcessor::run() {
}
}
DWORD framesInAudioBuffer = playCursor < renderPos ? renderPos - playCursor : (renderPos + stream.audioLatencyFrames) - playCursor;
stream.updateTimeInfo(nanosNow, framesInAudioBuffer);
stream.synthRoute.render(buf, frameCount);
stream.framesRendered(frameCount);
stream.renderAndUpdateState(buf, frameCount, nanosNow, framesInAudioBuffer);
if (!stream.ringBufferMode && waveOutWrite(stream.hWaveOut, waveHdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {
qDebug() << "WinMMAudioDriver: waveOutWrite failed, thread stopped";
stream.stopProcessing = true;