From c88651939a37e875bc9362161570b3aaae96ef5a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 23 Jun 2019 13:14:55 -0700 Subject: [PATCH] Re-add latency bounding on the SDL audio renderer --- app/streaming/audio/renderers/sdl.h | 2 ++ app/streaming/audio/renderers/sdlaud.cpp | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/streaming/audio/renderers/sdl.h b/app/streaming/audio/renderers/sdl.h index 53716fa7..63410a06 100644 --- a/app/streaming/audio/renderers/sdl.h +++ b/app/streaming/audio/renderers/sdl.h @@ -21,4 +21,6 @@ public: private: SDL_AudioDeviceID m_AudioDevice; void* m_AudioBuffer; + int m_FrameDurationMs; + int m_FrameSize; }; diff --git a/app/streaming/audio/renderers/sdlaud.cpp b/app/streaming/audio/renderers/sdlaud.cpp index 84d3e096..aa43dd2a 100644 --- a/app/streaming/audio/renderers/sdlaud.cpp +++ b/app/streaming/audio/renderers/sdlaud.cpp @@ -33,6 +33,9 @@ bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* // Specifying non-Po2 seems to work for our supported platforms. want.samples = opusConfig->samplesPerFrame; + m_FrameSize = opusConfig->samplesPerFrame * sizeof(short) * opusConfig->channelCount; + m_FrameDurationMs = opusConfig->samplesPerFrame / 48; + m_AudioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); if (m_AudioDevice == 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, @@ -41,7 +44,7 @@ bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* return false; } - m_AudioBuffer = malloc(opusConfig->samplesPerFrame * sizeof(short) * opusConfig->channelCount); + m_AudioBuffer = malloc(m_FrameSize); if (m_AudioBuffer == nullptr) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to allocate audio buffer"); @@ -92,6 +95,18 @@ bool SdlAudioRenderer::submitAudio(int bytesWritten) return true; } + // Don't queue if there's already more than 30 ms of audio data waiting + // in Moonlight's audio queue. + if (LiGetPendingAudioFrames() * m_FrameDurationMs > 30) { + return true; + } + + // Provide backpressure on the queue to ensure too many frames don't build up + // in SDL's audio queue. + while (SDL_GetQueuedAudioSize(m_AudioDevice) / m_FrameSize > 10) { + SDL_Delay(1); + } + if (SDL_QueueAudio(m_AudioDevice, m_AudioBuffer, bytesWritten) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to queue audio sample: %s", @@ -103,5 +118,6 @@ bool SdlAudioRenderer::submitAudio(int bytesWritten) int SdlAudioRenderer::getCapabilities() { - return CAPABILITY_DIRECT_SUBMIT; + // Direct submit can't be used because we use LiGetPendingAudioFrames() + return 0; }