Bug 1431221 - P5. Split AudioConfig.{h,cpp} from MediaInfo. r=padenot draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 23 Jan 2018 21:06:07 +0100
changeset 771687 d464bd1a8cccda9786a438aac7ea464989c53a34
parent 771686 42aee60aa8d99c751a59487a70120a515c1a5d74
child 771688 441a36597cfe66581dd4d68ca2554345ab1338c0
push id103752
push userbmo:jyavenard@mozilla.com
push dateFri, 23 Mar 2018 17:52:32 +0000
reviewerspadenot
bugs1431221
milestone61.0a1
Bug 1431221 - P5. Split AudioConfig.{h,cpp} from MediaInfo. r=padenot MozReview-Commit-ID: EzaC19HS2B8
dom/media/AudioConfig.cpp
dom/media/AudioConfig.h
dom/media/CubebUtils.cpp
dom/media/MediaData.h
dom/media/MediaInfo.cpp
dom/media/MediaInfo.h
dom/media/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/media/AudioConfig.cpp
@@ -0,0 +1,349 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AudioConfig.h"
+
+namespace mozilla {
+
+typedef AudioConfig::ChannelLayout ChannelLayout;
+
+/**
+ * AudioConfig::ChannelLayout
+ */
+
+/*
+ SMPTE channel layout (also known as wave order)
+ DUAL-MONO      L   R
+ DUAL-MONO-LFE  L   R   LFE
+ MONO           M
+ MONO-LFE       M   LFE
+ STEREO         L   R
+ STEREO-LFE     L   R   LFE
+ 3F             L   R   C
+ 3F-LFE         L   R   C    LFE
+ 2F1            L   R   S
+ 2F1-LFE        L   R   LFE  S
+ 3F1            L   R   C    S
+ 3F1-LFE        L   R   C    LFE S
+ 2F2            L   R   LS   RS
+ 2F2-LFE        L   R   LFE  LS   RS
+ 3F2            L   R   C    LS   RS
+ 3F2-LFE        L   R   C    LFE  LS   RS
+ 3F3R-LFE       L   R   C    LFE  BC   LS   RS
+ 3F4-LFE        L   R   C    LFE  Rls  Rrs  LS   RS
+*/
+
+ChannelLayout ChannelLayout::LMONO{ CHANNEL_FRONT_CENTER };
+ChannelLayout ChannelLayout::LMONO_LFE{ CHANNEL_FRONT_CENTER, CHANNEL_LFE };
+ChannelLayout ChannelLayout::LSTEREO{ CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT };
+ChannelLayout ChannelLayout::LSTEREO_LFE{ CHANNEL_FRONT_LEFT,
+                                          CHANNEL_FRONT_RIGHT,
+                                          CHANNEL_LFE };
+ChannelLayout ChannelLayout::L3F{ CHANNEL_FRONT_LEFT,
+                                  CHANNEL_FRONT_RIGHT,
+                                  CHANNEL_FRONT_CENTER };
+ChannelLayout ChannelLayout::L3F_LFE{ CHANNEL_FRONT_LEFT,
+                                      CHANNEL_FRONT_RIGHT,
+                                      CHANNEL_FRONT_CENTER,
+                                      CHANNEL_LFE };
+ChannelLayout ChannelLayout::L2F1{ CHANNEL_FRONT_LEFT,
+                                   CHANNEL_FRONT_RIGHT,
+                                   CHANNEL_BACK_CENTER };
+ChannelLayout ChannelLayout::L2F1_LFE{ CHANNEL_FRONT_LEFT,
+                                       CHANNEL_FRONT_RIGHT,
+                                       CHANNEL_LFE,
+                                       CHANNEL_BACK_CENTER };
+ChannelLayout ChannelLayout::L3F1{ CHANNEL_FRONT_LEFT,
+                                   CHANNEL_FRONT_RIGHT,
+                                   CHANNEL_FRONT_CENTER,
+                                   CHANNEL_BACK_CENTER };
+ChannelLayout ChannelLayout::LSURROUND = ChannelLayout::L3F1;
+ChannelLayout ChannelLayout::L3F1_LFE{ CHANNEL_FRONT_LEFT,
+                                       CHANNEL_FRONT_RIGHT,
+                                       CHANNEL_FRONT_CENTER,
+                                       CHANNEL_LFE,
+                                       CHANNEL_BACK_CENTER };
+ChannelLayout ChannelLayout::L2F2{ CHANNEL_FRONT_LEFT,
+                                   CHANNEL_FRONT_RIGHT,
+                                   CHANNEL_SIDE_LEFT,
+                                   CHANNEL_SIDE_RIGHT };
+ChannelLayout ChannelLayout::L2F2_LFE{ CHANNEL_FRONT_LEFT,
+                                       CHANNEL_FRONT_RIGHT,
+                                       CHANNEL_LFE,
+                                       CHANNEL_SIDE_LEFT,
+                                       CHANNEL_SIDE_RIGHT };
+ChannelLayout ChannelLayout::LQUAD{ CHANNEL_FRONT_LEFT,
+                                    CHANNEL_FRONT_RIGHT,
+                                    CHANNEL_BACK_LEFT,
+                                    CHANNEL_BACK_RIGHT };
+ChannelLayout ChannelLayout::LQUAD_LFE{ CHANNEL_FRONT_LEFT,
+                                        CHANNEL_FRONT_RIGHT,
+                                        CHANNEL_LFE,
+                                        CHANNEL_BACK_LEFT,
+                                        CHANNEL_BACK_RIGHT };
+ChannelLayout ChannelLayout::L3F2{ CHANNEL_FRONT_LEFT,
+                                   CHANNEL_FRONT_RIGHT,
+                                   CHANNEL_FRONT_CENTER,
+                                   CHANNEL_SIDE_LEFT,
+                                   CHANNEL_SIDE_RIGHT };
+ChannelLayout ChannelLayout::L3F2_LFE{
+  CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
+  CHANNEL_LFE,        CHANNEL_SIDE_LEFT,   CHANNEL_SIDE_RIGHT
+};
+ChannelLayout ChannelLayout::L5POINT1_SURROUND = ChannelLayout::L3F2_LFE;
+
+ChannelLayout ChannelLayout::L3F3R_LFE{
+  CHANNEL_FRONT_LEFT,  CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER, CHANNEL_LFE,
+  CHANNEL_BACK_CENTER, CHANNEL_SIDE_LEFT,   CHANNEL_SIDE_RIGHT
+};
+ChannelLayout ChannelLayout::L3F4_LFE{
+  CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
+  CHANNEL_LFE,        CHANNEL_BACK_LEFT,   CHANNEL_BACK_RIGHT,
+  CHANNEL_SIDE_LEFT,  CHANNEL_SIDE_RIGHT
+};
+ChannelLayout ChannelLayout::L7POINT1_SURROUND = ChannelLayout::L3F4_LFE;
+
+void
+AudioConfig::ChannelLayout::UpdateChannelMap()
+{
+  mValid = mChannels.Length() <= MAX_AUDIO_CHANNELS;
+  mChannelMap = 0;
+  if (mValid) {
+    mChannelMap = Map();
+    mValid = mChannelMap > 0;
+  }
+}
+
+auto
+AudioConfig::ChannelLayout::Map() const -> ChannelMap
+{
+  if (mChannelMap) {
+    return mChannelMap;
+  }
+  ChannelMap map = UNKNOWN_MAP;
+  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)) {
+      // Invalid configuration.
+      return 0;
+    }
+    map |= mask;
+  }
+  return map;
+}
+
+const AudioConfig::Channel*
+AudioConfig::ChannelLayout::DefaultLayoutForChannels(uint32_t aChannels) const
+{
+  switch (aChannels) {
+    case 1: // MONO
+    {
+      static const Channel config[] = { CHANNEL_FRONT_CENTER };
+      return config;
+    }
+    case 2: // STEREO
+    {
+      static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT };
+      return config;
+    }
+    case 3: // 3F
+    {
+      static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER };
+      return config;
+    }
+    case 4: // QUAD
+    {
+      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_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_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_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_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(ChannelMap 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 = 1;
+  while (aMap) {
+    if (aMap & 1) {
+      layout.AppendElement(static_cast<Channel>(i));
+      channels++;
+      if (channels > MAX_AUDIO_CHANNELS) {
+        return ChannelLayout();
+      }
+    }
+    aMap >>= 1;
+  }
+  return ChannelLayout(channels, layout.Elements());
+}
+
+bool
+AudioConfig::ChannelLayout::MappingTable(const ChannelLayout& aOther,
+                                         uint8_t* aMap) const
+{
+  if (!IsValid() || !aOther.IsValid() ||
+      Map() != aOther.Map()) {
+    return false;
+  }
+  if (!aMap) {
+    return true;
+  }
+  for (uint32_t i = 0; i < Count(); i++) {
+    for (uint32_t j = 0; j < Count(); j++) {
+      if (aOther[j] == mChannels[i]) {
+        aMap[j] = i;
+        break;
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * AudioConfig::ChannelConfig
+ */
+
+/* static */ const char*
+AudioConfig::FormatToString(AudioConfig::SampleFormat aFormat)
+{
+  switch (aFormat) {
+    case FORMAT_U8:     return "unsigned 8 bit";
+    case FORMAT_S16:    return "signed 16 bit";
+    case FORMAT_S24:    return "signed 24 bit MSB";
+    case FORMAT_S24LSB: return "signed 24 bit LSB";
+    case FORMAT_S32:    return "signed 32 bit";
+    case FORMAT_FLT:    return "32 bit floating point";
+    case FORMAT_NONE:   return "none";
+    default:            return "unknown";
+  }
+}
+/* static */ uint32_t
+AudioConfig::SampleSize(AudioConfig::SampleFormat aFormat)
+{
+  switch (aFormat) {
+    case FORMAT_U8:     return 1;
+    case FORMAT_S16:    return 2;
+    case FORMAT_S24:    MOZ_FALLTHROUGH;
+    case FORMAT_S24LSB: MOZ_FALLTHROUGH;
+    case FORMAT_S32:    MOZ_FALLTHROUGH;
+    case FORMAT_FLT:    return 4;
+    case FORMAT_NONE:
+    default:            return 0;
+  }
+}
+
+/* static */ uint32_t
+AudioConfig::FormatToBits(AudioConfig::SampleFormat aFormat)
+{
+  switch (aFormat) {
+    case FORMAT_U8:     return 8;
+    case FORMAT_S16:    return 16;
+    case FORMAT_S24LSB: MOZ_FALLTHROUGH;
+    case FORMAT_S24:    return 24;
+    case FORMAT_S32:    MOZ_FALLTHROUGH;
+    case FORMAT_FLT:    return 32;
+    case FORMAT_NONE:   MOZ_FALLTHROUGH;
+    default:            return 0;
+  }
+}
+
+AudioConfig::AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
+                         AudioConfig::SampleFormat aFormat, bool aInterleaved)
+  : mChannelLayout(aChannelLayout)
+  , mChannels(aChannelLayout.Count())
+  , mRate(aRate)
+  , mFormat(aFormat)
+  , mInterleaved(aInterleaved)
+{
+}
+
+AudioConfig::AudioConfig(uint32_t aChannels,
+                         uint32_t aRate,
+                         AudioConfig::SampleFormat aFormat,
+                         bool aInterleaved)
+  : mChannelLayout(aChannels)
+  , mChannels(aChannels)
+  , mRate(aRate)
+  , mFormat(aFormat)
+  , mInterleaved(aInterleaved)
+{
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/AudioConfig.h
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#if !defined(AudioLayout_h)
+#define AudioLayout_h
+
+#include <initializer_list>
+#include <cstdint>
+#include "nsTArray.h"
+
+namespace mozilla {
+
+  // Maximum channel number we can currently handle (7.1)
+#define MAX_AUDIO_CHANNELS 8
+
+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_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
+  {
+  public:
+    typedef uint32_t ChannelMap;
+
+    ChannelLayout() : mChannelMap(0), mValid(false) { }
+    explicit ChannelLayout(uint32_t aChannels)
+      : ChannelLayout(aChannels, DefaultLayoutForChannels(aChannels))
+    {
+    }
+    ChannelLayout(uint32_t aChannels, const Channel* aConfig)
+      : ChannelLayout()
+    {
+      if (aChannels == 0 || !aConfig) {
+        mValid = false;
+        return;
+      }
+      mChannels.AppendElements(aConfig, aChannels);
+      UpdateChannelMap();
+    }
+    explicit ChannelLayout(std::initializer_list<Channel> aChannelList)
+      : ChannelLayout(aChannelList.size(), aChannelList.begin())
+    {
+    }
+    bool operator==(const ChannelLayout& aOther) const
+    {
+      return mChannels == aOther.mChannels;
+    }
+    bool operator!=(const ChannelLayout& aOther) const
+    {
+      return mChannels != aOther.mChannels;
+    }
+    const Channel& operator[](uint32_t aIndex) const
+    {
+      return mChannels[aIndex];
+    }
+    uint32_t Count() const
+    {
+      return mChannels.Length();
+    }
+    ChannelMap 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]].
+    // Returns true if the reordering is possible or false otherwise.
+    // If true, then aMap, if set, will be updated to contain the mapping table
+    // allowing conversion from the current layout to aOther.
+    // If aMap is nullptr, then MappingTable can be used to simply determine if
+    // the current layout can be easily reordered to aOther.
+    // aMap must be an array of size MAX_AUDIO_CHANNELS.
+    bool MappingTable(const ChannelLayout& aOther, uint8_t* aMap = nullptr) const;
+    bool IsValid() const { return mValid; }
+    bool HasChannel(Channel aChannel) const
+    {
+      return mChannelMap & (1 << aChannel);
+    }
+
+    static ChannelLayout SMPTEDefault(
+      const ChannelLayout& aChannelLayout);
+    static ChannelLayout SMPTEDefault(ChannelMap aMap);
+
+    static constexpr ChannelMap UNKNOWN_MAP = 0;
+
+    // Common channel layout definitions.
+    static ChannelLayout LMONO;
+    static constexpr ChannelMap LMONO_MAP = 1 << CHANNEL_FRONT_CENTER;
+    static ChannelLayout LMONO_LFE;
+    static constexpr ChannelMap LMONO_LFE_MAP =
+      1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE;
+    static ChannelLayout LSTEREO;
+    static constexpr ChannelMap LSTEREO_MAP =
+      1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT;
+    static ChannelLayout LSTEREO_LFE;
+    static constexpr ChannelMap LSTEREO_LFE_MAP =
+      1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE;
+    static ChannelLayout L3F;
+    static constexpr ChannelMap L3F_MAP = 1 << CHANNEL_FRONT_LEFT |
+                                        1 << CHANNEL_FRONT_RIGHT |
+                                        1 << CHANNEL_FRONT_CENTER;
+    static ChannelLayout L3F_LFE;
+    static constexpr ChannelMap L3F_LFE_MAP =
+      1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
+      1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE;
+    static ChannelLayout L2F1;
+    static constexpr ChannelMap L2F1_MAP = 1 << CHANNEL_FRONT_LEFT |
+                                         1 << CHANNEL_FRONT_RIGHT |
+                                         1 << CHANNEL_BACK_CENTER;
+    static ChannelLayout L2F1_LFE;
+    static constexpr ChannelMap L2F1_LFE_MAP =
+      1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE |
+      1 << CHANNEL_BACK_CENTER;
+    static ChannelLayout L3F1;
+    static constexpr ChannelMap 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 ChannelMap LSURROUND_MAP = L3F1_MAP;
+    static ChannelLayout L3F1_LFE;
+    static constexpr ChannelMap 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 ChannelMap L2F2_MAP =
+      1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
+      1 << CHANNEL_SIDE_LEFT | 1 << CHANNEL_SIDE_RIGHT;
+    static ChannelLayout L2F2_LFE;
+    static constexpr ChannelMap 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 ChannelMap LQUAD_MAP =
+      1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
+      1 << CHANNEL_BACK_LEFT | 1 << CHANNEL_BACK_RIGHT;
+    static ChannelLayout LQUAD_LFE;
+    static constexpr ChannelMap 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 ChannelMap 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 ChannelMap 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 ChannelMap L5POINT1_SURROUND_MAP = L3F2_LFE_MAP;
+    static ChannelLayout L3F3R_LFE;
+    static constexpr ChannelMap 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 ChannelMap 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 ChannelMap L7POINT1_SURROUND_MAP = L3F4_LFE_MAP;
+
+  private:
+    void UpdateChannelMap();
+    const Channel* DefaultLayoutForChannels(uint32_t aChannels) const;
+    AutoTArray<Channel, MAX_AUDIO_CHANNELS> mChannels;
+    ChannelMap mChannelMap;
+    bool mValid;
+  };
+
+  enum SampleFormat
+  {
+    FORMAT_NONE = 0,
+    FORMAT_U8,
+    FORMAT_S16,
+    FORMAT_S24LSB,
+    FORMAT_S24,
+    FORMAT_S32,
+    FORMAT_FLT,
+#if defined(MOZ_SAMPLE_TYPE_FLOAT32)
+    FORMAT_DEFAULT = FORMAT_FLT
+#elif defined(MOZ_SAMPLE_TYPE_S16)
+    FORMAT_DEFAULT = FORMAT_S16
+#else
+#error "Not supported audio type"
+#endif
+  };
+
+  AudioConfig(const ChannelLayout& aChannelLayout,
+              uint32_t aRate,
+              AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
+              bool aInterleaved = true);
+  // Will create a channel configuration from default SMPTE ordering.
+  AudioConfig(uint32_t aChannels,
+              uint32_t aRate,
+              AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
+              bool aInterleaved = true);
+
+  const ChannelLayout& Layout() const { return mChannelLayout; }
+  uint32_t Channels() const
+  {
+    if (!mChannelLayout.IsValid()) {
+      return mChannels;
+    }
+    return mChannelLayout.Count();
+  }
+  uint32_t Rate() const { return mRate; }
+  SampleFormat Format() const { return mFormat; }
+  bool Interleaved() const { return mInterleaved; }
+  bool operator==(const AudioConfig& aOther) const
+  {
+    return mChannelLayout == aOther.mChannelLayout && mRate == aOther.mRate &&
+           mFormat == aOther.mFormat && mInterleaved == aOther.mInterleaved;
+  }
+  bool operator!=(const AudioConfig& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  bool IsValid() const
+  {
+    return mChannelLayout.IsValid() && Format() != FORMAT_NONE && Rate() > 0;
+  }
+
+  static const char* FormatToString(SampleFormat aFormat);
+  static uint32_t SampleSize(SampleFormat aFormat);
+  static uint32_t FormatToBits(SampleFormat aFormat);
+
+private:
+  // Channels configuration.
+  ChannelLayout mChannelLayout;
+
+  // Channel count.
+  uint32_t mChannels;
+
+  // Sample rate.
+  uint32_t mRate;
+
+  // Sample format.
+  SampleFormat mFormat;
+
+  bool mInterleaved;
+};
+
+} // namespace mozilla
+
+#endif // AudioLayout_h
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -45,18 +45,19 @@
 #define MASK_STEREO_LFE (AudioConfig::ChannelLayout::LSTEREO_LFE_MAP)
 #define MASK_3F         (AudioConfig::ChannelLayout::L3F_MAP)
 #define MASK_3F_LFE     (AudioConfig::ChannelLayout::L3F_LFE_MAP)
 #define MASK_2F1        (AudioConfig::ChannelLayout::L2F1_MAP)
 #define MASK_2F1_LFE    (AudioConfig::ChannelLayout::L2F1_LFE_MAP)
 #define MASK_3F1        (AudioConfig::ChannelLayout::L3F1_MAP)
 #define MASK_3F1_LFE    (AudioConfig::ChannelLayout::L3F1_LFE_MAP)
 #define MASK_2F2        (AudioConfig::ChannelLayout::L2F2_MAP)
+#define MASK_2F2_LFE    (AudioConfig::ChannelLayout::L2F2_LFE_MAP)
 #define MASK_QUAD       (AudioConfig::ChannelLayout::LQUAD_MAP)
-#define MASK_2F2_LFE    (AudioConfig::ChannelLayout::L2F2_LFE_MAP)
+#define MASK_QUAD_LFE   (AudioConfig::ChannelLayout::LQUAD_MAP_LFE)
 #define MASK_3F2        (AudioConfig::ChannelLayout::L3F2_MAP)
 #define MASK_3F2_LFE    (AudioConfig::ChannelLayout::L3F2_LFE_MAP)
 #define MASK_3F3R_LFE   (AudioConfig::ChannelLayout::L3F3R_LFE_MAP)
 #define MASK_3F4_LFE    (AudioConfig::ChannelLayout::L3F4_LFE_MAP)
 
 #if (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)) || defined(XP_MACOSX)
 #define MOZ_CUBEB_REMOTING
 #endif
@@ -178,18 +179,20 @@ const layoutInfo kLayoutInfos[CUBEB_LAYO
   { "stereo",         2, MASK_STEREO },     // CUBEB_LAYOUT_STEREO
   { "stereo lfe",     3, MASK_STEREO_LFE }, // CUBEB_LAYOUT_STEREO_LFE
   { "3f",             3, MASK_3F },         // CUBEB_LAYOUT_3F
   { "3f lfe",         4, MASK_3F_LFE },     // CUBEB_LAYOUT_3F_LFE
   { "2f1",            3, MASK_2F1 },        // CUBEB_LAYOUT_2F1
   { "2f1 lfe",        4, MASK_2F1_LFE },    // CUBEB_LAYOUT_2F1_LFE
   { "3f1",            4, MASK_3F1 },        // CUBEB_LAYOUT_3F1
   { "3f1 lfe",        5, MASK_3F1_LFE },    // CUBEB_LAYOUT_3F1_LFE
-  { "2f2",            4, MASK_2F2_LFE },    // CUBEB_LAYOUT_2F2
+  { "2f2",            4, MASK_2F2 },        // CUBEB_LAYOUT_2F2
   { "2f2 lfe",        5, MASK_2F2_LFE },    // CUBEB_LAYOUT_2F2_LFE
+  { "quad",           4, MASK_QUAD },       // CUBEB_LAYOUT_QUAD
+  { "quad lfe",       5, MASK_QUAD_LFE },   // CUBEB_LAYOUT_QUAD_LFE
   { "3f2",            5, MASK_3F2 },        // CUBEB_LAYOUT_3F2
   { "3f2 lfe",        6, MASK_3F2_LFE },    // CUBEB_LAYOUT_3F2_LFE
   { "3f3r lfe",       7, MASK_3F3R_LFE },   // CUBEB_LAYOUT_3F3R_LFE
   { "3f4 lfe",        8, MASK_3F4_LFE }     // CUBEB_LAYOUT_3F4_LFE
 };
 
 // Prefered samplerate, in Hz (characteristic of the hardware, mixer, platform,
 // and API used).
@@ -650,16 +653,18 @@ cubeb_channel_layout ConvertChannelMapTo
     case MASK_3F: return CUBEB_LAYOUT_3F;
     case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
     case MASK_2F1: return CUBEB_LAYOUT_2F1;
     case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
     case MASK_3F1: return CUBEB_LAYOUT_3F1;
     case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
     case MASK_2F2: return CUBEB_LAYOUT_2F2;
     case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
+    case MASK_QUAD: return CUBEB_LAYOUT_QUAD;
+    case MASK_QUAD_LFE: return CUBEB_LAYOUT_QUAD_LFE;
     case MASK_3F2: return CUBEB_LAYOUT_3F2;
     case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
     case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
     case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
     default:
       NS_ERROR("The channel map is unsupported");
       return CUBEB_LAYOUT_UNDEFINED;
   }
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(MediaData_h)
 #define MediaData_h
 
+#include "AudioConfig.h"
 #include "AudioSampleFormat.h"
 #include "ImageTypes.h"
 #include "SharedBuffer.h"
 #include "TimeUnits.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Span.h"
--- a/dom/media/MediaInfo.cpp
+++ b/dom/media/MediaInfo.cpp
@@ -20,323 +20,9 @@ TrackTypeToStr(TrackInfo::TrackType aTra
     return "Video";
   case TrackInfo::kTextTrack:
     return "Text";
   default:
     return "Unknown";
   }
 }
 
-typedef AudioConfig::ChannelLayout ChannelLayout;
-
-/**
- * AudioConfig::ChannelLayout
- */
-
-/*
- SMPTE channel layout (also known as wave order)
- DUAL-MONO      L   R
- DUAL-MONO-LFE  L   R   LFE
- MONO           M
- MONO-LFE       M   LFE
- STEREO         L   R
- STEREO-LFE     L   R   LFE
- 3F             L   R   C
- 3F-LFE         L   R   C    LFE
- 2F1            L   R   S
- 2F1-LFE        L   R   LFE  S
- 3F1            L   R   C    S
- 3F1-LFE        L   R   C    LFE S
- 2F2            L   R   LS   RS
- 2F2-LFE        L   R   LFE  LS   RS
- 3F2            L   R   C    LS   RS
- 3F2-LFE        L   R   C    LFE  LS   RS
- 3F3R-LFE       L   R   C    LFE  BC   LS   RS
- 3F4-LFE        L   R   C    LFE  Rls  Rrs  LS   RS
-*/
-
-ChannelLayout ChannelLayout::LMONO{ CHANNEL_FRONT_CENTER };
-ChannelLayout ChannelLayout::LMONO_LFE{ CHANNEL_FRONT_CENTER, CHANNEL_LFE };
-ChannelLayout ChannelLayout::LSTEREO{ CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT };
-ChannelLayout ChannelLayout::LSTEREO_LFE{ CHANNEL_FRONT_LEFT,
-                                          CHANNEL_FRONT_RIGHT,
-                                          CHANNEL_LFE };
-ChannelLayout ChannelLayout::L3F{ CHANNEL_FRONT_LEFT,
-                                  CHANNEL_FRONT_RIGHT,
-                                  CHANNEL_FRONT_CENTER };
-ChannelLayout ChannelLayout::L3F_LFE{ CHANNEL_FRONT_LEFT,
-                                      CHANNEL_FRONT_RIGHT,
-                                      CHANNEL_FRONT_CENTER,
-                                      CHANNEL_LFE };
-ChannelLayout ChannelLayout::L2F1{ CHANNEL_FRONT_LEFT,
-                                   CHANNEL_FRONT_RIGHT,
-                                   CHANNEL_BACK_CENTER };
-ChannelLayout ChannelLayout::L2F1_LFE{ CHANNEL_FRONT_LEFT,
-                                       CHANNEL_FRONT_RIGHT,
-                                       CHANNEL_LFE,
-                                       CHANNEL_BACK_CENTER };
-ChannelLayout ChannelLayout::L3F1{ CHANNEL_FRONT_LEFT,
-                                   CHANNEL_FRONT_RIGHT,
-                                   CHANNEL_FRONT_CENTER,
-                                   CHANNEL_BACK_CENTER };
-ChannelLayout ChannelLayout::LSURROUND = ChannelLayout::L3F1;
-ChannelLayout ChannelLayout::L3F1_LFE{ CHANNEL_FRONT_LEFT,
-                                       CHANNEL_FRONT_RIGHT,
-                                       CHANNEL_FRONT_CENTER,
-                                       CHANNEL_LFE,
-                                       CHANNEL_BACK_CENTER };
-ChannelLayout ChannelLayout::L2F2{ CHANNEL_FRONT_LEFT,
-                                   CHANNEL_FRONT_RIGHT,
-                                   CHANNEL_SIDE_LEFT,
-                                   CHANNEL_SIDE_RIGHT };
-ChannelLayout ChannelLayout::L2F2_LFE{ CHANNEL_FRONT_LEFT,
-                                       CHANNEL_FRONT_RIGHT,
-                                       CHANNEL_LFE,
-                                       CHANNEL_SIDE_LEFT,
-                                       CHANNEL_SIDE_RIGHT };
-ChannelLayout ChannelLayout::LQUAD{ CHANNEL_FRONT_LEFT,
-                                    CHANNEL_FRONT_RIGHT,
-                                    CHANNEL_BACK_LEFT,
-                                    CHANNEL_BACK_RIGHT };
-ChannelLayout ChannelLayout::LQUAD_LFE{ CHANNEL_FRONT_LEFT,
-                                        CHANNEL_FRONT_RIGHT,
-                                        CHANNEL_LFE,
-                                        CHANNEL_BACK_LEFT,
-                                        CHANNEL_BACK_RIGHT };
-ChannelLayout ChannelLayout::L3F2{ CHANNEL_FRONT_LEFT,
-                                   CHANNEL_FRONT_RIGHT,
-                                   CHANNEL_FRONT_CENTER,
-                                   CHANNEL_SIDE_LEFT,
-                                   CHANNEL_SIDE_RIGHT };
-ChannelLayout ChannelLayout::L3F2_LFE{
-  CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
-  CHANNEL_LFE,        CHANNEL_SIDE_LEFT,   CHANNEL_SIDE_RIGHT
-};
-ChannelLayout ChannelLayout::L5POINT1_SURROUND = ChannelLayout::L3F2_LFE;
-
-ChannelLayout ChannelLayout::L3F3R_LFE{
-  CHANNEL_FRONT_LEFT,  CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER, CHANNEL_LFE,
-  CHANNEL_BACK_CENTER, CHANNEL_SIDE_LEFT,   CHANNEL_SIDE_RIGHT
-};
-ChannelLayout ChannelLayout::L3F4_LFE{
-  CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
-  CHANNEL_LFE,        CHANNEL_BACK_LEFT,   CHANNEL_BACK_RIGHT,
-  CHANNEL_SIDE_LEFT,  CHANNEL_SIDE_RIGHT
-};
-ChannelLayout ChannelLayout::L7POINT1_SURROUND = ChannelLayout::L3F4_LFE;
-
-void
-AudioConfig::ChannelLayout::UpdateChannelMap()
-{
-  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)) {
-      // Invalid configuration.
-      return 0;
-    }
-    map |= mask;
-  }
-  return map;
-}
-
-/* static */ const AudioConfig::Channel*
-AudioConfig::ChannelLayout::SMPTEDefault(uint32_t aChannels) const
-{
-  switch (aChannels) {
-    case 1: // MONO
-    {
-      static const Channel config[] = { CHANNEL_FRONT_CENTER };
-      return config;
-    }
-    case 2: // STEREO
-    {
-      static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT };
-      return config;
-    }
-    case 3: // 3F
-    {
-      static const Channel config[] = { CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER };
-      return config;
-    }
-    case 4: // 2F2
-    {
-      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_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_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_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_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 */ const AudioConfig::ChannelLayout&
-AudioConfig::ChannelLayout::SMPTEDefault(
-  const ChannelLayout& aChannelLayout)
-{
-  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());
-
-  if (!aChannelLayout.IsValid()) {
-    return aChannelLayout;
-  }
-  const uint32_t map = aChannelLayout.Map();
-  switch (map) {
-    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:
-      // unknown return identical.
-      return aChannelLayout;
-  }
-}
-
-bool
-AudioConfig::ChannelLayout::MappingTable(const ChannelLayout& aOther,
-                                         uint8_t* aMap) const
-{
-  if (!IsValid() || !aOther.IsValid() ||
-      Map() != aOther.Map()) {
-    return false;
-  }
-  if (!aMap) {
-    return true;
-  }
-  for (uint32_t i = 0; i < Count(); i++) {
-    for (uint32_t j = 0; j < Count(); j++) {
-      if (aOther[j] == mChannels[i]) {
-        aMap[j] = i;
-        break;
-      }
-    }
-  }
-  return true;
-}
-
-/**
- * AudioConfig::ChannelConfig
- */
-
-/* static */ const char*
-AudioConfig::FormatToString(AudioConfig::SampleFormat aFormat)
-{
-  switch (aFormat) {
-    case FORMAT_U8:     return "unsigned 8 bit";
-    case FORMAT_S16:    return "signed 16 bit";
-    case FORMAT_S24:    return "signed 24 bit MSB";
-    case FORMAT_S24LSB: return "signed 24 bit LSB";
-    case FORMAT_S32:    return "signed 32 bit";
-    case FORMAT_FLT:    return "32 bit floating point";
-    case FORMAT_NONE:   return "none";
-    default:            return "unknown";
-  }
-}
-/* static */ uint32_t
-AudioConfig::SampleSize(AudioConfig::SampleFormat aFormat)
-{
-  switch (aFormat) {
-    case FORMAT_U8:     return 1;
-    case FORMAT_S16:    return 2;
-    case FORMAT_S24:    MOZ_FALLTHROUGH;
-    case FORMAT_S24LSB: MOZ_FALLTHROUGH;
-    case FORMAT_S32:    MOZ_FALLTHROUGH;
-    case FORMAT_FLT:    return 4;
-    case FORMAT_NONE:
-    default:            return 0;
-  }
-}
-
-/* static */ uint32_t
-AudioConfig::FormatToBits(AudioConfig::SampleFormat aFormat)
-{
-  switch (aFormat) {
-    case FORMAT_U8:     return 8;
-    case FORMAT_S16:    return 16;
-    case FORMAT_S24LSB: MOZ_FALLTHROUGH;
-    case FORMAT_S24:    return 24;
-    case FORMAT_S32:    MOZ_FALLTHROUGH;
-    case FORMAT_FLT:    return 32;
-    case FORMAT_NONE:   MOZ_FALLTHROUGH;
-    default:            return 0;
-  }
-}
-
-AudioConfig::AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
-                         AudioConfig::SampleFormat aFormat, bool aInterleaved)
-  : mChannelLayout(aChannelLayout)
-  , mChannels(aChannelLayout.Count())
-  , mRate(aRate)
-  , mFormat(aFormat)
-  , mInterleaved(aInterleaved)
-{}
-
-AudioConfig::AudioConfig(uint32_t aChannels, uint32_t aRate,
-                         AudioConfig::SampleFormat aFormat, bool aInterleaved)
-  : mChannelLayout(aChannels)
-  , mChannels(aChannels)
-  , mRate(aRate)
-  , mFormat(aFormat)
-  , mInterleaved(aInterleaved)
-{}
-
 } // namespace mozilla
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -6,16 +6,17 @@
 #if !defined(MediaInfo_h)
 #define MediaInfo_h
 
 #include "mozilla/UniquePtr.h"
 #include "mozilla/RefPtr.h"
 #include "nsDataHashtable.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "AudioConfig.h"
 #include "ImageTypes.h"
 #include "MediaData.h"
 #include "TrackID.h" // for TrackID
 #include "TimeUnits.h"
 #include "mozilla/gfx/Point.h" // for gfx::IntSize
 #include "mozilla/gfx/Rect.h"  // for gfx::IntRect
 
 namespace mozilla {
@@ -34,19 +35,16 @@ public:
   {
   }
   nsCString mKey;
   nsCString mValue;
 };
 
 typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
 
-  // Maximum channel number we can currently handle (7.1)
-#define MAX_AUDIO_CHANNELS 8
-
 class TrackInfo
 {
 public:
   enum TrackType
   {
     kUndefinedTrack,
     kAudioTrack,
     kVideoTrack,
@@ -608,273 +606,11 @@ private:
   UniquePtr<TrackInfo> mInfo;
   // A unique ID, guaranteed to change when changing streams.
   uint32_t mStreamSourceID;
 
 public:
   const nsCString& mMimeType;
 };
 
-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_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
-  {
-  public:
-    ChannelLayout() : mChannelMap(0), mValid(false) { }
-    explicit ChannelLayout(uint32_t aChannels)
-      : ChannelLayout(aChannels, SMPTEDefault(aChannels))
-    {
-    }
-    ChannelLayout(uint32_t aChannels, const Channel* aConfig)
-      : ChannelLayout()
-    {
-      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;
-    }
-    bool operator!=(const ChannelLayout& aOther) const
-    {
-      return mChannels != aOther.mChannels;
-    }
-    const Channel& operator[](uint32_t aIndex) const
-    {
-      return mChannels[aIndex];
-    }
-    uint32_t Count() const
-    {
-      return mChannels.Length();
-    }
-    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]].
-    // Returns true if the reordering is possible or false otherwise.
-    // If true, then aMap, if set, will be updated to contain the mapping table
-    // allowing conversion from the current layout to aOther.
-    // If aMap is nullptr, then MappingTable can be used to simply determine if
-    // the current layout can be easily reordered to aOther.
-    // aMap must be an array of size MAX_AUDIO_CHANNELS.
-    bool MappingTable(const ChannelLayout& aOther, uint8_t* aMap = nullptr) const;
-    bool IsValid() const { return mValid; }
-    bool HasChannel(Channel aChannel) const
-    {
-      return mChannelMap & (1 << aChannel);
-    }
-
-    static const ChannelLayout& SMPTEDefault(
-      const ChannelLayout& aChannelLayout);
-
-    // 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;
-    AutoTArray<Channel, MAX_AUDIO_CHANNELS> mChannels;
-    uint32_t mChannelMap;
-    bool mValid;
-  };
-
-  enum SampleFormat
-  {
-    FORMAT_NONE = 0,
-    FORMAT_U8,
-    FORMAT_S16,
-    FORMAT_S24LSB,
-    FORMAT_S24,
-    FORMAT_S32,
-    FORMAT_FLT,
-#if defined(MOZ_SAMPLE_TYPE_FLOAT32)
-    FORMAT_DEFAULT = FORMAT_FLT
-#elif defined(MOZ_SAMPLE_TYPE_S16)
-    FORMAT_DEFAULT = FORMAT_S16
-#else
-#error "Not supported audio type"
-#endif
-  };
-
-  AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
-              AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
-              bool aInterleaved = true);
-  // Will create a channel configuration from default SMPTE ordering.
-  AudioConfig(uint32_t aChannels, uint32_t aRate,
-              AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
-              bool aInterleaved = true);
-
-  const ChannelLayout& Layout() const
-  {
-    return mChannelLayout;
-  }
-  uint32_t Channels() const
-  {
-    if (!mChannelLayout.IsValid()) {
-      return mChannels;
-    }
-    return mChannelLayout.Count();
-  }
-  uint32_t Rate() const
-  {
-    return mRate;
-  }
-  SampleFormat Format() const
-  {
-    return mFormat;
-  }
-  bool Interleaved() const
-  {
-    return mInterleaved;
-  }
-  bool operator==(const AudioConfig& aOther) const
-  {
-    return mChannelLayout == aOther.mChannelLayout && mRate == aOther.mRate &&
-           mFormat == aOther.mFormat && mInterleaved == aOther.mInterleaved;
-  }
-  bool operator!=(const AudioConfig& aOther) const
-  {
-    return !(*this == aOther);
-  }
-
-  bool IsValid() const
-  {
-    return mChannelLayout.IsValid() && Format() != FORMAT_NONE && Rate() > 0;
-  }
-
-  static const char* FormatToString(SampleFormat aFormat);
-  static uint32_t SampleSize(SampleFormat aFormat);
-  static uint32_t FormatToBits(SampleFormat aFormat);
-
-private:
-  // Channels configuration.
-  ChannelLayout mChannelLayout;
-
-  // Channel count.
-  uint32_t mChannels;
-
-  // Sample rate.
-  uint32_t mRate;
-
-  // Sample format.
-  SampleFormat mFormat;
-
-  bool mInterleaved;
-};
-
 } // namespace mozilla
 
 #endif // MediaInfo_h
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -87,16 +87,17 @@ XPIDL_SOURCES += [
 XPIDL_MODULE = 'dom_media'
 
 EXPORTS += [
     'ADTSDecoder.h',
     'ADTSDemuxer.h',
     'AudioBufferUtils.h',
     'AudioChannelFormat.h',
     'AudioCompactor.h',
+    'AudioConfig.h',
     'AudioConverter.h',
     'AudioMixer.h',
     'AudioPacketizer.h',
     'AudioSampleFormat.h',
     'AudioSegment.h',
     'AudioStream.h',
     'AutoplayPolicy.h',
     'BackgroundVideoDecodingPermissionObserver.h',
@@ -203,16 +204,17 @@ EXPORTS.mozilla.dom += [
 ]
 
 UNIFIED_SOURCES += [
     'ADTSDecoder.cpp',
     'ADTSDemuxer.cpp',
     'AudioCaptureStream.cpp',
     'AudioChannelFormat.cpp',
     'AudioCompactor.cpp',
+    'AudioConfig.cpp',
     'AudioConverter.cpp',
     'AudioDeviceInfo.cpp',
     'AudioSegment.cpp',
     'AudioStream.cpp',
     'AudioStreamTrack.cpp',
     'AudioTrack.cpp',
     'AudioTrackList.cpp',
     'AutoplayPolicy.cpp',