summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Andrews <athenian200@outlook.com>2021-08-24 16:07:22 -0500
committerJeremy Andrews <athenian200@outlook.com>2021-08-24 16:07:22 -0500
commit89c3761e5c995efbd5d6039f938773c5259e947d (patch)
tree8eeb25f606609001ff30ee287ad74c8356a90c17
parent893fc903790e1ca5bba598113c49d94a165e333b (diff)
downloaduxp-89c3761e5c995efbd5d6039f938773c5259e947d.tar.gz
Issue #1806 - Part 5: Add multichannel audio capability.
I'm positive this works on Windows at the very least. Cubeb added proper channel map support at some point, and this allows us to take advantage of that. Ref: BZ 1431221, BZ 1432779
-rw-r--r--dom/base/nsDOMWindowUtils.cpp7
-rw-r--r--dom/interfaces/base/nsIDOMWindowUtils.idl5
-rw-r--r--dom/media/AccurateSeekTask.cpp3
-rw-r--r--dom/media/AudioConverter.cpp2
-rw-r--r--dom/media/AudioStream.cpp3
-rw-r--r--dom/media/AudioStream.h5
-rw-r--r--dom/media/CubebUtils.h3
-rw-r--r--dom/media/MediaData.cpp3
-rw-r--r--dom/media/MediaData.h144
-rw-r--r--dom/media/MediaInfo.cpp194
-rw-r--r--dom/media/MediaInfo.h7
-rw-r--r--dom/media/MediaPrefs.h6
-rw-r--r--dom/media/mediasink/DecodedAudioDataSink.cpp22
-rw-r--r--dom/media/platforms/agnostic/VorbisDecoder.cpp59
-rw-r--r--dom/media/platforms/apple/AppleATDecoder.cpp28
-rw-r--r--dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp5
-rw-r--r--dom/media/platforms/wmf/WMFAudioMFTManager.cpp13
-rw-r--r--dom/media/platforms/wmf/WMFAudioMFTManager.h1
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;