Bug 1431221 - P5. Split AudioConfig.{h,cpp} from MediaInfo. r=padenot
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 23 Jan 2018 21:06:07 +0100
changeset 463316 2c8f7cf1be79187d387df610324ccc4e59282cab
parent 463315 cd673186a4efc4bf1f6823a1f91123bbd4573613
child 463317 f2450584957a77f912301a1d691b46aead77c427
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1431221
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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',