diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 04747d503378..298a9cf58066 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -167,6 +167,19 @@ void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer, } } +uint32_t DecideAudioPlaybackChannels(const AudioInfo& info) +{ + if (MediaPrefs::MonoAudio()) { + return 1; + } + + if (MediaPrefs::AudioSinkForceStereo()) { + return 2; + } + + return info.mChannels; +} + bool IsVideoContentType(const nsCString& aContentType) { diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index 80a4e3428152..14cbf56a6311 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -158,6 +158,10 @@ ScaleDisplayByAspectRatio(gfx::IntSize& aDisplay, float aAspectRatio); void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer, uint32_t aFrames); +// Decide the number of playback channels according to the +// given AudioInfo and the prefs that are being set. +uint32_t DecideAudioPlaybackChannels(const AudioInfo& info); + bool IsVideoContentType(const nsCString& aContentType); // Returns true if it's safe to use aPicture as the picture to be diff --git a/dom/media/mediasink/AudioSink.cpp b/dom/media/mediasink/AudioSink.cpp index dd687100ce5f..2ebd4ed787b0 100644 --- a/dom/media/mediasink/AudioSink.cpp +++ b/dom/media/mediasink/AudioSink.cpp @@ -64,12 +64,7 @@ AudioSink::AudioSink(AbstractThread* aThread, } MOZ_DIAGNOSTIC_ASSERT(mOutputRate, "output rate can't be 0."); - bool monoAudioEnabled = MediaPrefs::MonoAudio(); - - mOutputChannels = - monoAudioEnabled - ? 1 - : (MediaPrefs::AudioSinkForceStereo() ? 2 : mInfo.mChannels); + mOutputChannels = DecideAudioPlaybackChannels(mInfo); } AudioSink::~AudioSink() diff --git a/dom/media/platforms/agnostic/OpusDecoder.cpp b/dom/media/platforms/agnostic/OpusDecoder.cpp index db420240487b..6489539e03db 100644 --- a/dom/media/platforms/agnostic/OpusDecoder.cpp +++ b/dom/media/platforms/agnostic/OpusDecoder.cpp @@ -95,6 +95,17 @@ OpusDataDecoder::Init() mOpusParser->mCoupledStreams, mMappingTable.Elements(), &r); + + // Opus has a special feature for stereo coding where it represent wide + // stereo channels by 180-degree out of phase. This improves quality, but + // needs to be disabled when the output is downmixed to mono. Playback number + // of channels are set in AudioSink, using the same method + // `DecideAudioPlaybackChannels()`, and triggers downmix if needed. + if (mOpusDecoder && mOpusParser->mChannels == 2 && + DecideAudioPlaybackChannels(mInfo) == 1) { + opus_multistream_decoder_ctl(mOpusDecoder, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + } + mSkip = mOpusParser->mPreSkip; mPaddingDiscarded = false;