diff options
-rw-r--r-- | dom/base/nsDOMWindowUtils.cpp | 7 | ||||
-rw-r--r-- | dom/interfaces/base/nsIDOMWindowUtils.idl | 5 | ||||
-rw-r--r-- | dom/media/AccurateSeekTask.cpp | 3 | ||||
-rw-r--r-- | dom/media/AudioConverter.cpp | 2 | ||||
-rw-r--r-- | dom/media/AudioStream.cpp | 3 | ||||
-rw-r--r-- | dom/media/AudioStream.h | 5 | ||||
-rw-r--r-- | dom/media/CubebUtils.h | 3 | ||||
-rw-r--r-- | dom/media/MediaData.cpp | 3 | ||||
-rw-r--r-- | dom/media/MediaData.h | 144 | ||||
-rw-r--r-- | dom/media/MediaInfo.cpp | 194 | ||||
-rw-r--r-- | dom/media/MediaInfo.h | 7 | ||||
-rw-r--r-- | dom/media/MediaPrefs.h | 6 | ||||
-rw-r--r-- | dom/media/mediasink/DecodedAudioDataSink.cpp | 22 | ||||
-rw-r--r-- | dom/media/platforms/agnostic/VorbisDecoder.cpp | 59 | ||||
-rw-r--r-- | dom/media/platforms/apple/AppleATDecoder.cpp | 28 | ||||
-rw-r--r-- | dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp | 5 | ||||
-rw-r--r-- | dom/media/platforms/wmf/WMFAudioMFTManager.cpp | 13 | ||||
-rw-r--r-- | dom/media/platforms/wmf/WMFAudioMFTManager.h | 1 |
18 files changed, 427 insertions, 83 deletions
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 3606a1b0bc..eb09a6f14f 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2379,13 +2379,6 @@ nsDOMWindowUtils::GetCurrentMaxAudioChannels(uint32_t* aChannels) } NS_IMETHODIMP -nsDOMWindowUtils::GetCurrentPreferredChannelLayout(nsAString& aLayout) -{ - CubebUtils::GetPreferredChannelLayout(aLayout); - return NS_OK; -} - -NS_IMETHODIMP nsDOMWindowUtils::GetCurrentPreferredSampleRate(uint32_t* aRate) { *aRate = CubebUtils::PreferredSampleRate(); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index e563a19985..200bd3caf6 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1432,11 +1432,6 @@ interface nsIDOMWindowUtils : nsISupports { readonly attribute unsigned long currentMaxAudioChannels; /** - * Returns the preferred channel layout of the current audio device. - */ - readonly attribute AString currentPreferredChannelLayout; - - /** * Returns the preferred sample rate of the current audio device. */ readonly attribute unsigned long currentPreferredSampleRate; diff --git a/dom/media/AccurateSeekTask.cpp b/dom/media/AccurateSeekTask.cpp index 30eeb59049..88ac673860 100644 --- a/dom/media/AccurateSeekTask.cpp +++ b/dom/media/AccurateSeekTask.cpp @@ -182,7 +182,8 @@ AccurateSeekTask::DropAudioUpToSeekTarget(MediaData* aSample) frames, Move(audioData), channels, - audio->mRate)); + audio->mRate, + audio->mChannelMap)); MOZ_ASSERT(!mSeekedAudioData, "Should be the 1st sample after seeking"); mSeekedAudioData = data; mDoneAudioSeeking = true; diff --git a/dom/media/AudioConverter.cpp b/dom/media/AudioConverter.cpp index ab9b11543d..a77ea57f4a 100644 --- a/dom/media/AudioConverter.cpp +++ b/dom/media/AudioConverter.cpp @@ -143,7 +143,7 @@ AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const mIn.Format() == AudioConfig::FORMAT_FLT); MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() >= mOut.Channels()); MOZ_DIAGNOSTIC_ASSERT( - mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()), + mIn.Layout() == AudioConfig::ChannelLayout::SMPTEDefault(mIn.Layout()), "Can only downmix input data in SMPTE layout"); MOZ_DIAGNOSTIC_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) || mOut.Layout() == AudioConfig::ChannelLayout(1), diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 77ed512eee..dc1daa2e07 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -317,7 +317,7 @@ int AudioStream::InvokeCubeb(Function aFunction, Args&&... aArgs) } nsresult -AudioStream::Init(uint32_t aNumChannels, uint32_t aRate, +AudioStream::Init(uint32_t aNumChannels, uint32_t aChannelMap, uint32_t aRate, const dom::AudioChannel aAudioChannel) { auto startTime = TimeStamp::Now(); @@ -331,6 +331,7 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate, cubeb_stream_params params; params.rate = aRate; params.channels = mOutChannels; + params.layout = CUBEB_LAYOUT_UNDEFINED; params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value; mAudioClock.Init(aRate); diff --git a/dom/media/AudioStream.h b/dom/media/AudioStream.h index 199314d4b6..e138ab991a 100644 --- a/dom/media/AudioStream.h +++ b/dom/media/AudioStream.h @@ -192,9 +192,10 @@ public: explicit AudioStream(DataSource& aSource); // Initialize the audio stream. aNumChannels is the number of audio - // channels (1 for mono, 2 for stereo, etc) and aRate is the sample rate + // channels (1 for mono, 2 for stereo, etc), aChannelMap is the indicator for + // channel layout(mono, stereo, 5.1 or 7.1 ) and aRate is the sample rate // (22050Hz, 44100Hz, etc). - nsresult Init(uint32_t aNumChannels, uint32_t aRate, + nsresult Init(uint32_t aNumChannels, uint32_t aChannelMap, uint32_t aRate, const dom::AudioChannel aAudioStreamChannel); // Closes the stream. All future use of the stream is an error. diff --git a/dom/media/CubebUtils.h b/dom/media/CubebUtils.h index 2e2e4ba3b5..8449462442 100644 --- a/dom/media/CubebUtils.h +++ b/dom/media/CubebUtils.h @@ -8,6 +8,7 @@ #define CubebUtils_h_ #include "cubeb/cubeb.h" +#include "mozilla/dom/AudioDeviceInfo.h" #include "mozilla/dom/AudioChannelBinding.h" #include "mozilla/Maybe.h" @@ -45,7 +46,7 @@ uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params); bool CubebLatencyPrefSet(); void GetCurrentBackend(nsAString& aBackend); void GetDeviceCollection(nsTArray<RefPtr<AudioDeviceInfo>>& aDeviceInfos, - Side aSide); + Side aSide); } // namespace CubebUtils } // namespace mozilla diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index fb3eff7b51..5b68200eff 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -76,7 +76,8 @@ AudioData::TransferAndUpdateTimestampAndDuration(AudioData* aOther, aOther->mFrames, Move(aOther->mAudioData), aOther->mChannels, - aOther->mRate); + aOther->mRate, + aOther->mChannelMap); return v.forget(); } diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index 909841eb98..dd1d0243e0 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -27,18 +27,29 @@ namespace mozilla { class AudioConfig { public: +// Channel definition is conveniently defined to be in the same order as +// WAVEFORMAT && SMPTE, even though this is unused for now. enum Channel { CHANNEL_INVALID = -1, - CHANNEL_MONO = 0, - CHANNEL_LEFT, - CHANNEL_RIGHT, - CHANNEL_CENTER, - CHANNEL_LS, - CHANNEL_RS, - CHANNEL_RLS, - CHANNEL_RCENTER, - CHANNEL_RRS, + CHANNEL_FRONT_LEFT = 0, + CHANNEL_FRONT_RIGHT, + CHANNEL_FRONT_CENTER, CHANNEL_LFE, + CHANNEL_BACK_LEFT, + CHANNEL_BACK_RIGHT, + CHANNEL_FRONT_LEFT_OF_CENTER, + CHANNEL_FRONT_RIGHT_OF_CENTER, + CHANNEL_BACK_CENTER, + CHANNEL_SIDE_LEFT, + CHANNEL_SIDE_RIGHT, + // From WAVEFORMAT definition. + CHANNEL_TOP_CENTER, + CHANNEL_TOP_FRONT_LEFT, + CHANNEL_TOP_FRONT_CENTER, + CHANNEL_TOP_FRONT_RIGHT, + CHANNEL_TOP_BACK_LEFT, + CHANNEL_TOP_BACK_CENTER, + CHANNEL_TOP_BACK_RIGHT }; class ChannelLayout { @@ -48,18 +59,22 @@ public: , mValid(false) {} explicit ChannelLayout(uint32_t aChannels) - : ChannelLayout(aChannels, SMPTEDefault(aChannels)) + : ChannelLayout(aChannels, DefaultLayoutForChannels(aChannels)) {} ChannelLayout(uint32_t aChannels, const Channel* aConfig) : ChannelLayout() { - if (!aConfig) { + if (aChannels == 0 || !aConfig) { mValid = false; return; } mChannels.AppendElements(aConfig, aChannels); UpdateChannelMap(); } + ChannelLayout(std::initializer_list<Channel> aChannelList) + : ChannelLayout(aChannelList.size(), aChannelList.begin()) + { + } bool operator==(const ChannelLayout& aOther) const { return mChannels == aOther.mChannels; @@ -76,10 +91,8 @@ public: { return mChannels.Length(); } - uint32_t Map() const - { - return mChannelMap; - } + uint32_t Map() const; + // Calculate the mapping table from the current layout to aOther such that // one can easily go from one layout to the other by doing: // out[channel] = in[map[channel]]. @@ -97,9 +110,98 @@ public: { return mChannelMap & (1 << aChannel); } + + static ChannelLayout SMPTEDefault( + const ChannelLayout& aChannelLayout); + static ChannelLayout SMPTEDefault(uint32_t aMap); + + static constexpr uint32_t UNKNOWN_MAP = 0; + + // Common channel layout definitions. + static ChannelLayout LMONO; + static constexpr uint32_t LMONO_MAP = 1 << CHANNEL_FRONT_CENTER; + static ChannelLayout LMONO_LFE; + static constexpr uint32_t LMONO_LFE_MAP = + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE; + static ChannelLayout LSTEREO; + static constexpr uint32_t LSTEREO_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT; + static ChannelLayout LSTEREO_LFE; + static constexpr uint32_t LSTEREO_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE; + static ChannelLayout L3F; + static constexpr uint32_t L3F_MAP = 1 << CHANNEL_FRONT_LEFT | + 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER; + static ChannelLayout L3F_LFE; + static constexpr uint32_t L3F_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE; + static ChannelLayout L2F1; + static constexpr uint32_t L2F1_MAP = 1 << CHANNEL_FRONT_LEFT | + 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_BACK_CENTER; + static ChannelLayout L2F1_LFE; + static constexpr uint32_t L2F1_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE | + 1 << CHANNEL_BACK_CENTER; + static ChannelLayout L3F1; + static constexpr uint32_t L3F1_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_BACK_CENTER; + static ChannelLayout LSURROUND; // Same as 3F1 + static constexpr uint32_t LSURROUND_MAP = L3F1_MAP; + static ChannelLayout L3F1_LFE; + static constexpr uint32_t L3F1_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_BACK_CENTER; + static ChannelLayout L2F2; + static constexpr uint32_t L2F2_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_SIDE_LEFT | 1 << CHANNEL_SIDE_RIGHT; + static ChannelLayout L2F2_LFE; + static constexpr uint32_t L2F2_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE | + 1 << CHANNEL_SIDE_LEFT | 1 << CHANNEL_SIDE_RIGHT; + static ChannelLayout LQUAD; + static constexpr uint32_t LQUAD_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_BACK_LEFT | 1 << CHANNEL_BACK_RIGHT; + static ChannelLayout LQUAD_LFE; + static constexpr uint32_t LQUAD_MAP_LFE = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE | + 1 << CHANNEL_BACK_LEFT | 1 << CHANNEL_BACK_RIGHT; + static ChannelLayout L3F2; + static constexpr uint32_t L3F2_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_SIDE_LEFT | + 1 << CHANNEL_SIDE_RIGHT; + static ChannelLayout L3F2_LFE; + static constexpr uint32_t L3F2_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_SIDE_LEFT | + 1 << CHANNEL_SIDE_RIGHT; + // 3F2_LFE Alias + static ChannelLayout L5POINT1_SURROUND; + static constexpr uint32_t L5POINT1_SURROUND_MAP = L3F2_LFE_MAP; + static ChannelLayout L3F3R_LFE; + static constexpr uint32_t L3F3R_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_BACK_CENTER | + 1 << CHANNEL_SIDE_LEFT | 1 << CHANNEL_SIDE_RIGHT; + static ChannelLayout L3F4_LFE; + static constexpr uint32_t L3F4_LFE_MAP = + 1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | + 1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_BACK_LEFT | + 1 << CHANNEL_BACK_RIGHT | 1 << CHANNEL_SIDE_LEFT | + 1 << CHANNEL_SIDE_RIGHT; + // 3F4_LFE Alias + static ChannelLayout L7POINT1_SURROUND; + static constexpr uint32_t L7POINT1_SURROUND_MAP = L3F4_LFE_MAP; + private: void UpdateChannelMap(); - const Channel* SMPTEDefault(uint32_t aChannels) const; + const Channel* DefaultLayoutForChannels(uint32_t aChannels) const; AutoTArray<Channel, MAX_AUDIO_CHANNELS> mChannels; uint32_t mChannelMap; bool mValid; @@ -189,6 +291,7 @@ private: bool mInterleaved; }; + namespace layers { class Image; class ImageContainer; @@ -542,9 +645,11 @@ public: uint32_t aFrames, AlignedAudioBuffer&& aData, uint32_t aChannels, - uint32_t aRate) + uint32_t aRate, + uint32_t aChannelMap = AudioConfig::ChannelLayout::UNKNOWN_MAP) : MediaData(sType, aOffset, aTime, aDuration, aFrames) , mChannels(aChannels) + , mChannelMap(aChannelMap) , mRate(aRate) , mAudioData(Move(aData)) {} @@ -570,6 +675,11 @@ public: bool IsAudible() const; const uint32_t mChannels; + // The AudioConfig::ChannelLayout map. Channels are ordered as per SMPTE + // definition. A value of UNKNOWN_MAP indicates unknown layout. + // ChannelMap is an unsigned bitmap compatible with Windows' WAVE and FFmpeg + // channel map. + const uint32_t mChannelMap; const uint32_t mRate; // At least one of mAudioBuffer/mAudioData must be non-null. // mChannels channels, each with mFrames frames diff --git a/dom/media/MediaInfo.cpp b/dom/media/MediaInfo.cpp index 568183e688..28b9e77828 100644 --- a/dom/media/MediaInfo.cpp +++ b/dom/media/MediaInfo.cpp @@ -35,69 +35,235 @@ typedef AudioConfig::ChannelLayout ChannelLayout; 3F4-LFE L R C LFE Rls Rrs LS RS */ +ChannelLayout ChannelLayout::LMONO{ AudioConfig::CHANNEL_FRONT_CENTER }; +ChannelLayout ChannelLayout::LMONO_LFE{ AudioConfig::CHANNEL_FRONT_CENTER, AudioConfig::CHANNEL_LFE }; +ChannelLayout ChannelLayout::LSTEREO{ AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_RIGHT }; +ChannelLayout ChannelLayout::LSTEREO_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_LFE }; +ChannelLayout ChannelLayout::L3F{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER }; +ChannelLayout ChannelLayout::L3F_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_LFE }; +ChannelLayout ChannelLayout::L2F1{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_BACK_CENTER }; +ChannelLayout ChannelLayout::L2F1_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_BACK_CENTER }; +ChannelLayout ChannelLayout::L3F1{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_BACK_CENTER }; +ChannelLayout ChannelLayout::LSURROUND = ChannelLayout::L3F1; +ChannelLayout ChannelLayout::L3F1_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_BACK_CENTER }; +ChannelLayout ChannelLayout::L2F2{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT }; +ChannelLayout ChannelLayout::L2F2_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT }; +ChannelLayout ChannelLayout::LQUAD{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT }; +ChannelLayout ChannelLayout::LQUAD_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT }; +ChannelLayout ChannelLayout::L3F2{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT }; +ChannelLayout ChannelLayout::L3F2_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT }; +ChannelLayout ChannelLayout::L5POINT1_SURROUND = ChannelLayout::L3F2_LFE; + +ChannelLayout ChannelLayout::L3F3R_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_BACK_CENTER, + AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT }; +ChannelLayout ChannelLayout::L3F4_LFE{ AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_LFE, + AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT, + AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT }; +ChannelLayout ChannelLayout::L7POINT1_SURROUND = ChannelLayout::L3F4_LFE; + void AudioConfig::ChannelLayout::UpdateChannelMap() { - mChannelMap = 0; mValid = mChannels.Length() <= MAX_AUDIO_CHANNELS; + mChannelMap = 0; + if (mValid) { + mChannelMap = Map(); + mValid = mChannelMap > 0; + } +} + +uint32_t +AudioConfig::ChannelLayout::Map() const +{ + if (mChannelMap) { + return mChannelMap; + } + uint32_t map = 0; for (size_t i = 0; i < mChannels.Length() && i <= MAX_AUDIO_CHANNELS; i++) { uint32_t mask = 1 << mChannels[i]; if (mChannels[i] == CHANNEL_INVALID || (mChannelMap & mask)) { - mValid = false; + // Invalid configuration. + return 0; } - mChannelMap |= mask; + map |= mask; } + return map; } -/* static */ const AudioConfig::Channel* -AudioConfig::ChannelLayout::SMPTEDefault(uint32_t aChannels) const +const AudioConfig::Channel* +AudioConfig::ChannelLayout::DefaultLayoutForChannels(uint32_t aChannels) const { switch (aChannels) { case 1: // MONO { - static const Channel config[] = { CHANNEL_MONO }; + static const Channel config[] = { CHANNEL_FRONT_CENTER }; return config; } case 2: // STEREO { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT }; return config; } case 3: // 3F { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER }; return config; } - case 4: // 2F2 + case 4: // QUAD { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT }; return config; } case 5: // 3F2 { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LS, CHANNEL_RS }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER, CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT }; return config; } case 6: // 3F2-LFE { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER, CHANNEL_LFE, CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT }; return config; } case 7: // 3F3R-LFE { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER, CHANNEL_LS, CHANNEL_RS }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER, CHANNEL_LFE, CHANNEL_BACK_CENTER, CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT }; return config; } case 8: // 3F4-LFE { - static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RLS, CHANNEL_RRS, CHANNEL_LS, CHANNEL_RS }; + static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER, CHANNEL_LFE, CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT, CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT }; return config; } default: return nullptr; } + } +/* static */ AudioConfig::ChannelLayout +AudioConfig::ChannelLayout::SMPTEDefault( + const ChannelLayout& aChannelLayout) +{ + if (!aChannelLayout.IsValid()) { + return aChannelLayout; + } + return SMPTEDefault(aChannelLayout.Map()); +} + +/* static */ ChannelLayout +AudioConfig::ChannelLayout::SMPTEDefault(uint32_t aMap) +{ + MOZ_ASSERT(LMONO_MAP == LMONO.Map()); + MOZ_ASSERT(LMONO_LFE_MAP == LMONO_LFE.Map()); + MOZ_ASSERT(LSTEREO_MAP == LSTEREO.Map()); + MOZ_ASSERT(LSTEREO_LFE_MAP == LSTEREO_LFE.Map()); + MOZ_ASSERT(L3F_MAP == L3F.Map()); + MOZ_ASSERT(L3F_LFE_MAP == L3F_LFE.Map()); + MOZ_ASSERT(L2F1_MAP == L2F1.Map()); + MOZ_ASSERT(L2F1_LFE_MAP == L2F1_LFE.Map()); + MOZ_ASSERT(L3F1_MAP == L3F1.Map()); + MOZ_ASSERT(L3F1_LFE_MAP == L3F1_LFE.Map()); + MOZ_ASSERT(L2F2_MAP == L2F2.Map()); + MOZ_ASSERT(L2F2_LFE_MAP == L2F2_LFE.Map()); + MOZ_ASSERT(LQUAD_MAP == LQUAD.Map()); + MOZ_ASSERT(L3F2_MAP == L3F2.Map()); + MOZ_ASSERT(L3F2_LFE_MAP == L3F2_LFE.Map()); + MOZ_ASSERT(L3F3R_LFE_MAP == L3F3R_LFE.Map()); + MOZ_ASSERT(L3F4_LFE_MAP == L3F4_LFE.Map()); + + // First handle the most common cases. + switch (aMap) { + case LMONO_MAP: return LMONO; + case LMONO_LFE_MAP: return LMONO_LFE; + case LSTEREO_MAP: return LSTEREO; + case LSTEREO_LFE_MAP : return LSTEREO_LFE; + case L3F_MAP: return L3F; + case L3F_LFE_MAP: return L3F_LFE; + case L2F1_MAP: return L2F1; + case L2F1_LFE_MAP: return L2F1_LFE; + case L3F1_MAP: return L3F1; + case L3F1_LFE_MAP: return L3F1_LFE; + case L2F2_MAP: return L2F2; + case L2F2_LFE_MAP: return L2F2_LFE; + case LQUAD_MAP: return LQUAD; + case L3F2_MAP: return L3F2; + case L3F2_LFE_MAP: return L3F2_LFE; + case L3F3R_LFE_MAP: return L3F3R_LFE; + case L3F4_LFE_MAP: return L3F4_LFE; + default: + break; + } + AutoTArray<Channel, MAX_AUDIO_CHANNELS> layout; + uint32_t channels = 0; + + uint32_t i = 0; + while (aMap) { + if (aMap & 1) { + layout.AppendElement(static_cast<Channel>(i)); + channels++; + if (channels > MAX_AUDIO_CHANNELS) { + return ChannelLayout(); + } + } + aMap >>= 1; + i++; + } + return ChannelLayout(channels, layout.Elements()); +} + + bool AudioConfig::ChannelLayout::MappingTable(const ChannelLayout& aOther, uint8_t* aMap) const diff --git a/dom/media/MediaInfo.h b/dom/media/MediaInfo.h index 658c7c3fa7..29dcf2cc97 100644 --- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -314,6 +314,7 @@ public: EmptyString(), EmptyString(), true, 1) , mRate(0) , mChannels(0) + , mChannelMap(AudioConfig::ChannelLayout::UNKNOWN_MAP) , mBitDepth(0) , mProfile(0) , mExtendedProfile(0) @@ -326,6 +327,7 @@ public: : TrackInfo(aOther) , mRate(aOther.mRate) , mChannels(aOther.mChannels) + , mChannelMap(aOther.mChannelMap) , mBitDepth(aOther.mBitDepth) , mProfile(aOther.mProfile) , mExtendedProfile(aOther.mExtendedProfile) @@ -362,6 +364,11 @@ public: // Number of audio channels. uint32_t mChannels; + // The AudioConfig::ChannelLayout map. Channels are ordered as per SMPTE + // definition. A value of UNKNOWN_MAP indicates unknown layout. + // ChannelMap is an unsigned bitmap compatible with Windows' WAVE and FFmpeg + // channel map. + uint32_t mChannelMap; // Bits per sample. uint32_t mBitDepth; diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index c1e66a3cee..84163353a5 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -86,8 +86,12 @@ private: DECL_MEDIA_PREF("accessibility.monoaudio.enable", MonoAudio, bool, false); DECL_MEDIA_PREF("media.resampling.enabled", AudioSinkResampling, bool, false); DECL_MEDIA_PREF("media.resampling.rate", AudioSinkResampleRate, uint32_t, 48000); +#ifdef XP_WIN + // Enable multichannel support on Windows. + DECL_MEDIA_PREF("media.forcestereo.enabled", AudioSinkForceStereo, bool, false); +#else DECL_MEDIA_PREF("media.forcestereo.enabled", AudioSinkForceStereo, bool, true); - +#endif // VideoSink DECL_MEDIA_PREF("media.ruin-av-sync.enabled", RuinAvSync, bool, false); diff --git a/dom/media/mediasink/DecodedAudioDataSink.cpp b/dom/media/mediasink/DecodedAudioDataSink.cpp index e7fcffe4f3..d20eac8acb 100644 --- a/dom/media/mediasink/DecodedAudioDataSink.cpp +++ b/dom/media/mediasink/DecodedAudioDataSink.cpp @@ -195,7 +195,15 @@ nsresult DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams) { mAudioStream = new AudioStream(*this); - nsresult rv = mAudioStream->Init(mOutputChannels, mOutputRate, mChannel); + // When AudioQueue is empty, there is no way to know the channel layout of + // the coming audio data, so we use the predefined channel map instead. + uint32_t channelMap = mConverter + ? mConverter->OutputConfig().Layout().Map() + : AudioConfig::ChannelLayout(mOutputChannels).Map(); + // This layout map is already processed by mConverter with mOutputChannels + // into SMPTE format, so there is no need to worry whether + // MediaPrefs::MonoAudio() or MediaPrefs::AudioSinkForceStereo() is applied. + nsresult rv = mAudioStream->Init(mOutputChannels, channelMap, mOutputRate, mChannel); if (NS_FAILED(rv)) { mAudioStream->Shutdown(); mAudioStream = nullptr; @@ -410,10 +418,18 @@ DecodedAudioDataSink::NotifyAudioNeeded() mFramesParsed = result.value(); } + const AudioConfig::ChannelLayout inputLayout = + data->mChannelMap + ? AudioConfig::ChannelLayout::SMPTEDefault(data->mChannelMap) + : AudioConfig::ChannelLayout(data->mChannels); + const AudioConfig::ChannelLayout outputLayout = + mOutputChannels == data->mChannels + ? inputLayout + : AudioConfig::ChannelLayout(mOutputChannels); mConverter = MakeUnique<AudioConverter>( - AudioConfig(data->mChannels, data->mRate), - AudioConfig(mOutputChannels, mOutputRate)); + AudioConfig(inputLayout, data->mRate), + AudioConfig(outputLayout, mOutputRate)); } // See if there's a gap in the audio. If there is, push silence into the diff --git a/dom/media/platforms/agnostic/VorbisDecoder.cpp b/dom/media/platforms/agnostic/VorbisDecoder.cpp index ed8b90dbd4..f842e64905 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.cpp +++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp @@ -302,47 +302,78 @@ VorbisDataDecoder::VorbisLayout(uint32_t aChannels) switch (aChannels) { case 1: // the stream is monophonic { - static const Channel config[] = { AudioConfig::CHANNEL_MONO }; + static const Channel config[] = { AudioConfig::CHANNEL_FRONT_CENTER }; return config; } case 2: // the stream is stereo. channel order: left, right { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_RIGHT }; + static const Channel config[] = { AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT }; return config; } - case 3: // the stream is a 1d-surround encoding. channel order: left, center, right + case 3: // the stream is a 1d-surround encoding. channel order: left, + // center, right { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT }; + static const Channel config[] = { AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_FRONT_RIGHT }; return config; } - case 4: // the stream is quadraphonic surround. channel order: front left, front right, rear left, rear right + case 4: // the stream is quadraphonic surround. channel order: front left, + // front right, rear left, rear right { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS }; + static const Channel config[] = { AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT }; return config; } - case 5: // the stream is five-channel surround. channel order: front left, center, front right, rear left, rear right + case 5: // the stream is five-channel surround. channel order: front left, + // center, front right, rear left, rear right { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS }; + static const Channel config[] = { AudioConfig::CHANNEL_FRONT_LEFT, + AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_FRONT_RIGHT, + AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT }; return config; } - case 6: // the stream is 5.1 surround. channel order: front left, center, front right, rear left, rear right, LFE + case 6: // the stream is 5.1 surround. channel order: front left, center, + // front right, rear left, rear right, LFE { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS, AudioConfig::CHANNEL_LFE }; + static const Channel config[] = { + AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT, AudioConfig::CHANNEL_LFE + }; return config; } - case 7: // surround. channel order: front left, center, front right, side left, side right, rear center, LFE + case 7: // surround. channel order: front left, center, front right, side + // left, side right, rear center, LFE { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS, AudioConfig::CHANNEL_RCENTER, AudioConfig::CHANNEL_LFE }; + static const Channel config[] = { + AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT, AudioConfig::CHANNEL_BACK_CENTER, + AudioConfig::CHANNEL_LFE + }; return config; } - case 8: // the stream is 7.1 surround. channel order: front left, center, front right, side left, side right, rear left, rear right, LFE + case 8: // the stream is 7.1 surround. channel order: front left, center, + // front right, side left, side right, rear left, rear right, LFE { - static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS, AudioConfig::CHANNEL_RLS, AudioConfig::CHANNEL_RRS, AudioConfig::CHANNEL_LFE }; + static const Channel config[] = { + AudioConfig::CHANNEL_FRONT_LEFT, AudioConfig::CHANNEL_FRONT_CENTER, + AudioConfig::CHANNEL_FRONT_RIGHT, AudioConfig::CHANNEL_SIDE_LEFT, + AudioConfig::CHANNEL_SIDE_RIGHT, AudioConfig::CHANNEL_BACK_LEFT, + AudioConfig::CHANNEL_BACK_RIGHT, AudioConfig::CHANNEL_LFE + }; return config; } default: return nullptr; } + } } // namespace mozilla diff --git a/dom/media/platforms/apple/AppleATDecoder.cpp b/dom/media/platforms/apple/AppleATDecoder.cpp index 65794d82c8..9466a4e8be 100644 --- a/dom/media/platforms/apple/AppleATDecoder.cpp +++ b/dom/media/platforms/apple/AppleATDecoder.cpp @@ -323,8 +323,9 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample) return NS_ERROR_OUT_OF_MEMORY; } if (mChannelLayout && !mAudioConverter) { - AudioConfig in(*mChannelLayout.get(), rate); - AudioConfig out(channels, rate); + AudioConfig in(*mChannelLayout, rate); + AudioConfig out(AudioConfig::ChannelLayout::SMPTEDefault(*mChannelLayout), + rate); if (!in.IsValid() || !out.IsValid()) { return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("Invalid audio config")); @@ -342,7 +343,9 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample) numFrames, data.Forget(), channels, - rate); + rate, + mChannelLayout ? mChannelLayout->Map() + : AudioConfig::ChannelLayout::UNKNOWN_MAP); mCallback->Output(audio); return NS_OK; } @@ -428,26 +431,25 @@ AudioConfig::Channel ConvertChannelLabel(AudioChannelLabel id) { switch (id) { - case kAudioChannelLabel_Mono: - return AudioConfig::CHANNEL_MONO; case kAudioChannelLabel_Left: - return AudioConfig::CHANNEL_LEFT; + return AudioConfig::CHANNEL_FRONT_LEFT; case kAudioChannelLabel_Right: - return AudioConfig::CHANNEL_RIGHT; + return AudioConfig::CHANNEL_FRONT_RIGHT; + case kAudioChannelLabel_Mono: case kAudioChannelLabel_Center: - return AudioConfig::CHANNEL_CENTER; + return AudioConfig::CHANNEL_FRONT_CENTER; case kAudioChannelLabel_LFEScreen: return AudioConfig::CHANNEL_LFE; case kAudioChannelLabel_LeftSurround: - return AudioConfig::CHANNEL_LS; + return AudioConfig::CHANNEL_SIDE_LEFT; case kAudioChannelLabel_RightSurround: - return AudioConfig::CHANNEL_RS; + return AudioConfig::CHANNEL_SIDE_RIGHT; case kAudioChannelLabel_CenterSurround: - return AudioConfig::CHANNEL_RCENTER; + return AudioConfig::CHANNEL_BACK_CENTER; case kAudioChannelLabel_RearSurroundLeft: - return AudioConfig::CHANNEL_RLS; + return AudioConfig::CHANNEL_BACK_LEFT; case kAudioChannelLabel_RearSurroundRight: - return AudioConfig::CHANNEL_RRS; + return AudioConfig::CHANNEL_BACK_RIGHT; default: return AudioConfig::CHANNEL_INVALID; } diff --git a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp index f867ec4942..7e91987251 100644 --- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp @@ -117,6 +117,8 @@ CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames) return audio; } +typedef AudioConfig::ChannelLayout ChannelLayout; + MediaResult FFmpegAudioDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample) { @@ -188,7 +190,8 @@ FFmpegAudioDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample) mFrame->nb_samples, Move(audio), numChannels, - samplingRate); + samplingRate, + mCodecContext->channel_layout); mCallback->Output(data); pts += duration; if (!pts.IsValid()) { diff --git a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp index 3dacdf0aad..cf1ebb1cff 100644 --- a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp @@ -84,6 +84,7 @@ AACAudioSpecificConfigToUserData(uint8_t aAACProfileLevelIndication, WMFAudioMFTManager::WMFAudioMFTManager( const AudioInfo& aConfig) : mAudioChannels(aConfig.mChannels) + , mChannelsMap(AudioConfig::ChannelLayout::UNKNOWN_MAP) , mAudioRate(aConfig.mRate) , mAudioFrameSum(0) , mMustRecaptureAudioPosition(true) @@ -212,6 +213,15 @@ WMFAudioMFTManager::UpdateOutputType() hr = type->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &mAudioChannels); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + uint32_t channelsMap; + hr = type->GetUINT32(MF_MT_AUDIO_CHANNEL_MASK, &channelsMap); + if (SUCCEEDED(hr)) { + mChannelsMap = channelsMap; + } else { + LOG("Unable to retrieve channel layout. Ignoring"); + mChannelsMap = AudioConfig::ChannelLayout::UNKNOWN_MAP; + } + AudioConfig::ChannelLayout layout(mAudioChannels); if (!layout.IsValid()) { return E_FAIL; @@ -338,7 +348,8 @@ WMFAudioMFTManager::Output(int64_t aStreamOffset, numFrames, Move(audioData), mAudioChannels, - mAudioRate); + mAudioRate, + mChannelsMap); #ifdef LOG_SAMPLE_DECODE LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u", diff --git a/dom/media/platforms/wmf/WMFAudioMFTManager.h b/dom/media/platforms/wmf/WMFAudioMFTManager.h index 5bbbc6108a..1f803a0e98 100644 --- a/dom/media/platforms/wmf/WMFAudioMFTManager.h +++ b/dom/media/platforms/wmf/WMFAudioMFTManager.h @@ -47,6 +47,7 @@ private: HRESULT UpdateOutputType(); uint32_t mAudioChannels; + uint32_t mChannelsMap; uint32_t mAudioRate; nsTArray<BYTE> mUserData; |