From 209b4a1b023d9df158f9de5b55b00b33679b7a08 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 1 Oct 2018 18:46:16 -0700 Subject: [PATCH] Fix surround sound channel mapping on ALSA --- app/streaming/audio/audio.cpp | 18 ++++++---- .../audio/renderers/portaudiorenderer.cpp | 36 +++++++++++++++++++ .../audio/renderers/portaudiorenderer.h | 2 ++ app/streaming/audio/renderers/renderer.h | 2 ++ app/streaming/audio/renderers/sdl.h | 2 ++ app/streaming/audio/renderers/sdlaud.cpp | 5 +++ 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/app/streaming/audio/audio.cpp b/app/streaming/audio/audio.cpp index 60c21bb0..976af3f3 100644 --- a/app/streaming/audio/audio.cpp +++ b/app/streaming/audio/audio.cpp @@ -59,23 +59,27 @@ int Session::arInit(int /* audioConfiguration */, SDL_memcpy(&s_ActiveSession->m_AudioConfig, opusConfig, sizeof(*opusConfig)); + s_ActiveSession->m_AudioRenderer = s_ActiveSession->createAudioRenderer(); + if (s_ActiveSession->m_AudioRenderer == nullptr) { + return -1; + } + + // Allow the audio renderer to adjust the channel mapping to fit its + // preferred channel order + s_ActiveSession->m_AudioRenderer->adjustOpusChannelMapping(&s_ActiveSession->m_AudioConfig); + s_ActiveSession->m_OpusDecoder = opus_multistream_decoder_create(opusConfig->sampleRate, opusConfig->channelCount, opusConfig->streams, opusConfig->coupledStreams, - opusConfig->mapping, + s_ActiveSession->m_AudioConfig.mapping, &error); if (s_ActiveSession->m_OpusDecoder == NULL) { + delete s_ActiveSession->m_AudioRenderer; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create decoder: %d", error); - return -1; - } - - s_ActiveSession->m_AudioRenderer = s_ActiveSession->createAudioRenderer(); - if (s_ActiveSession->m_AudioRenderer == nullptr) { - opus_multistream_decoder_destroy(s_ActiveSession->m_OpusDecoder); return -2; } diff --git a/app/streaming/audio/renderers/portaudiorenderer.cpp b/app/streaming/audio/renderers/portaudiorenderer.cpp index 3504808c..baf2a827 100644 --- a/app/streaming/audio/renderers/portaudiorenderer.cpp +++ b/app/streaming/audio/renderers/portaudiorenderer.cpp @@ -194,6 +194,42 @@ int PortAudioRenderer::detectAudioConfiguration() const } } +void PortAudioRenderer::adjustOpusChannelMapping(OPUS_MULTISTREAM_CONFIGURATION* opusConfig) const +{ + const OPUS_MULTISTREAM_CONFIGURATION origConfig = *opusConfig; + + const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice()); + if (deviceInfo == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Pa_GetDeviceInfo() failed"); + return; + } + + const PaHostApiInfo* hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); + if (hostApiInfo == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Pa_GetHostApiInfo() failed"); + return; + } + + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "PortAudio host API: %s", + hostApiInfo->name); + + if (hostApiInfo->type == paALSA) { + // The default mapping array has is: FL-FR-C-LFE-RL-RR + // ALSA expects: FL-FR-RL-RR-C-LFE + opusConfig->mapping[0] = origConfig.mapping[0]; + opusConfig->mapping[1] = origConfig.mapping[1]; + if (opusConfig->channelCount == 6) { + opusConfig->mapping[2] = origConfig.mapping[4]; + opusConfig->mapping[3] = origConfig.mapping[5]; + opusConfig->mapping[4] = origConfig.mapping[2]; + opusConfig->mapping[5] = origConfig.mapping[3]; + } + } +} + int PortAudioRenderer::paStreamCallback(const void*, void* output, unsigned long frameCount, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void* userData) { auto me = reinterpret_cast(userData); diff --git a/app/streaming/audio/renderers/portaudiorenderer.h b/app/streaming/audio/renderers/portaudiorenderer.h index d1a08b2e..85ffb475 100644 --- a/app/streaming/audio/renderers/portaudiorenderer.h +++ b/app/streaming/audio/renderers/portaudiorenderer.h @@ -24,6 +24,8 @@ public: virtual int detectAudioConfiguration() const; + virtual void adjustOpusChannelMapping(OPUS_MULTISTREAM_CONFIGURATION* opusConfig) const; + static int paStreamCallback(const void *input, void *output, unsigned long frameCount, diff --git a/app/streaming/audio/renderers/renderer.h b/app/streaming/audio/renderers/renderer.h index e67687e2..eaead051 100644 --- a/app/streaming/audio/renderers/renderer.h +++ b/app/streaming/audio/renderers/renderer.h @@ -10,6 +10,8 @@ class IAudioRenderer public: virtual ~IAudioRenderer() {} + virtual void adjustOpusChannelMapping(OPUS_MULTISTREAM_CONFIGURATION* opusConfig) const = 0; + virtual bool prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* opusConfig) = 0; virtual void submitAudio(short* audioBuffer, int audioSize) = 0; diff --git a/app/streaming/audio/renderers/sdl.h b/app/streaming/audio/renderers/sdl.h index 1d22e9ff..accc5508 100644 --- a/app/streaming/audio/renderers/sdl.h +++ b/app/streaming/audio/renderers/sdl.h @@ -23,6 +23,8 @@ public: virtual int detectAudioConfiguration() const; + virtual void adjustOpusChannelMapping(OPUS_MULTISTREAM_CONFIGURATION* opusConfig) const; + private: SDL_AudioDeviceID m_AudioDevice; Uint32 m_ChannelCount; diff --git a/app/streaming/audio/renderers/sdlaud.cpp b/app/streaming/audio/renderers/sdlaud.cpp index dc888c80..85d15e87 100644 --- a/app/streaming/audio/renderers/sdlaud.cpp +++ b/app/streaming/audio/renderers/sdlaud.cpp @@ -51,6 +51,11 @@ int SdlAudioRenderer::detectAudioConfiguration() const } } +void SdlAudioRenderer::adjustOpusChannelMapping(OPUS_MULTISTREAM_CONFIGURATION*) const +{ + // The default mapping is fine for SDL +} + bool SdlAudioRenderer::testAudio(int audioConfiguration) const { SDL_AudioSpec want, have;