1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #if !defined(AudioLayout_h)
7 #  define AudioLayout_h
8 
9 #  include <cstdint>
10 #  include <initializer_list>
11 #  include "mozilla/MathAlgorithms.h"
12 #  include "nsTArray.h"
13 
14 namespace mozilla {
15 
16 class AudioConfig {
17  public:
18   // Channel definition is conveniently defined to be in the same order as
19   // WAVEFORMAT && SMPTE, even though this is unused for now.
20   enum Channel {
21     CHANNEL_INVALID = -1,
22     CHANNEL_FRONT_LEFT = 0,
23     CHANNEL_FRONT_RIGHT,
24     CHANNEL_FRONT_CENTER,
25     CHANNEL_LFE,
26     CHANNEL_BACK_LEFT,
27     CHANNEL_BACK_RIGHT,
28     CHANNEL_FRONT_LEFT_OF_CENTER,
29     CHANNEL_FRONT_RIGHT_OF_CENTER,
30     CHANNEL_BACK_CENTER,
31     CHANNEL_SIDE_LEFT,
32     CHANNEL_SIDE_RIGHT,
33     // From WAVEFORMAT definition.
34     CHANNEL_TOP_CENTER,
35     CHANNEL_TOP_FRONT_LEFT,
36     CHANNEL_TOP_FRONT_CENTER,
37     CHANNEL_TOP_FRONT_RIGHT,
38     CHANNEL_TOP_BACK_LEFT,
39     CHANNEL_TOP_BACK_CENTER,
40     CHANNEL_TOP_BACK_RIGHT
41   };
42 
43   class ChannelLayout {
44    public:
45     // The maximum number of channels a channel map can represent.
46     static constexpr uint32_t MAX_CHANNELS = 32;
47 
48     typedef uint32_t ChannelMap;
49 
ChannelLayout()50     ChannelLayout() : mChannelMap(UNKNOWN_MAP), mValid(false) {}
ChannelLayout(uint32_t aChannels)51     explicit ChannelLayout(uint32_t aChannels)
52         : ChannelLayout(aChannels, DefaultLayoutForChannels(aChannels)) {}
ChannelLayout(uint32_t aChannels,const Channel * aConfig)53     ChannelLayout(uint32_t aChannels, const Channel* aConfig)
54         : ChannelLayout() {
55       if (aChannels == 0 || !aConfig) {
56         return;
57       }
58       mChannels.AppendElements(aConfig, aChannels);
59       UpdateChannelMap();
60     }
ChannelLayout(std::initializer_list<Channel> aChannelList)61     explicit ChannelLayout(std::initializer_list<Channel> aChannelList)
62         : ChannelLayout(aChannelList.size(), aChannelList.begin()) {}
63     bool operator==(const ChannelLayout& aOther) const {
64       return mChannels == aOther.mChannels;
65     }
66     bool operator!=(const ChannelLayout& aOther) const {
67       return mChannels != aOther.mChannels;
68     }
69     const Channel& operator[](uint32_t aIndex) const {
70       MOZ_ASSERT(mChannels.Length() > aIndex);
71       return mChannels[aIndex];
72     }
Count()73     uint32_t Count() const { return mChannels.Length(); }
74     ChannelMap Map() const;
75 
76     // Calculate the mapping table from the current layout to aOther such that
77     // one can easily go from one layout to the other by doing:
78     // out[channel] = in[map[channel]].
79     // Returns true if the reordering is possible or false otherwise.
80     // If true, then aMap, if set, will be updated to contain the mapping table
81     // allowing conversion from the current layout to aOther.
82     // If aMap is empty, then MappingTable can be used to simply determine if
83     // the current layout can be easily reordered to aOther.
84     bool MappingTable(const ChannelLayout& aOther,
85                       nsTArray<uint8_t>* aMap = nullptr) const;
IsValid()86     bool IsValid() const { return mValid; }
HasChannel(Channel aChannel)87     bool HasChannel(Channel aChannel) const {
88       return mChannelMap & (1 << aChannel);
89     }
90     // Return the number of channels found in this ChannelMap.
Channels(ChannelMap aMap)91     static uint32_t Channels(ChannelMap aMap) {
92       static_assert(sizeof(ChannelMap) == sizeof(uint32_t),
93                     "Must adjust ChannelMap type");
94       return CountPopulation32(aMap);
95     }
96 
97     static ChannelLayout SMPTEDefault(const ChannelLayout& aChannelLayout);
98     static ChannelLayout SMPTEDefault(ChannelMap aMap);
99 
100     static constexpr ChannelMap UNKNOWN_MAP = 0;
101 
102     // Common channel layout definitions.
103     static constexpr ChannelMap LMONO_MAP = 1 << CHANNEL_FRONT_CENTER;
104     static constexpr ChannelMap LMONO_LFE_MAP =
105         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE;
106     static constexpr ChannelMap LSTEREO_MAP =
107         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT;
108     static constexpr ChannelMap LSTEREO_LFE_MAP =
109         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE;
110     static constexpr ChannelMap L3F_MAP = 1 << CHANNEL_FRONT_LEFT |
111                                           1 << CHANNEL_FRONT_RIGHT |
112                                           1 << CHANNEL_FRONT_CENTER;
113     static constexpr ChannelMap L3F_LFE_MAP =
114         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
115         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE;
116     static constexpr ChannelMap L2F1_MAP = 1 << CHANNEL_FRONT_LEFT |
117                                            1 << CHANNEL_FRONT_RIGHT |
118                                            1 << CHANNEL_BACK_CENTER;
119     static constexpr ChannelMap L2F1_LFE_MAP =
120         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE |
121         1 << CHANNEL_BACK_CENTER;
122     static constexpr ChannelMap L3F1_MAP =
123         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
124         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_BACK_CENTER;
125     static constexpr ChannelMap LSURROUND_MAP = L3F1_MAP;
126     static constexpr ChannelMap L3F1_LFE_MAP =
127         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
128         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_BACK_CENTER;
129     static constexpr ChannelMap L2F2_MAP =
130         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
131         1 << CHANNEL_SIDE_LEFT | 1 << CHANNEL_SIDE_RIGHT;
132     static constexpr ChannelMap L2F2_LFE_MAP =
133         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE |
134         1 << CHANNEL_SIDE_LEFT | 1 << CHANNEL_SIDE_RIGHT;
135     static constexpr ChannelMap LQUAD_MAP =
136         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
137         1 << CHANNEL_BACK_LEFT | 1 << CHANNEL_BACK_RIGHT;
138     static constexpr ChannelMap LQUAD_LFE_MAP =
139         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT | 1 << CHANNEL_LFE |
140         1 << CHANNEL_BACK_LEFT | 1 << CHANNEL_BACK_RIGHT;
141     static constexpr ChannelMap L3F2_MAP =
142         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
143         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_SIDE_LEFT |
144         1 << CHANNEL_SIDE_RIGHT;
145     static constexpr ChannelMap L3F2_LFE_MAP =
146         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
147         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_SIDE_LEFT |
148         1 << CHANNEL_SIDE_RIGHT;
149     // 3F2_LFE Alias
150     static constexpr ChannelMap L5POINT1_SURROUND_MAP = L3F2_LFE_MAP;
151     static constexpr ChannelMap L3F2_BACK_MAP =
152         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
153         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_BACK_LEFT |
154         1 << CHANNEL_BACK_RIGHT;
155     static constexpr ChannelMap L3F2_BACK_LFE_MAP =
156         L3F2_BACK_MAP | 1 << CHANNEL_LFE;
157     static constexpr ChannelMap L3F3R_LFE_MAP =
158         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
159         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE |
160         1 << CHANNEL_BACK_CENTER | 1 << CHANNEL_SIDE_LEFT |
161         1 << CHANNEL_SIDE_RIGHT;
162     static ChannelLayout L3F4_LFE;
163     static constexpr ChannelMap L3F4_LFE_MAP =
164         1 << CHANNEL_FRONT_LEFT | 1 << CHANNEL_FRONT_RIGHT |
165         1 << CHANNEL_FRONT_CENTER | 1 << CHANNEL_LFE | 1 << CHANNEL_BACK_LEFT |
166         1 << CHANNEL_BACK_RIGHT | 1 << CHANNEL_SIDE_LEFT |
167         1 << CHANNEL_SIDE_RIGHT;
168     // 3F4_LFE Alias
169     static ChannelLayout L7POINT1_SURROUND;
170     static constexpr ChannelMap L7POINT1_SURROUND_MAP = L3F4_LFE_MAP;
171 
172    private:
173     void UpdateChannelMap();
174     const Channel* DefaultLayoutForChannels(uint32_t aChannels) const;
175     CopyableAutoTArray<Channel, MAX_CHANNELS> mChannels;
176     ChannelMap mChannelMap;
177     bool mValid;
178   };
179 
180   enum SampleFormat {
181     FORMAT_NONE = 0,
182     FORMAT_U8,
183     FORMAT_S16,
184     FORMAT_S24LSB,
185     FORMAT_S24,
186     FORMAT_S32,
187     FORMAT_FLT,
188 #  if defined(MOZ_SAMPLE_TYPE_FLOAT32)
189     FORMAT_DEFAULT = FORMAT_FLT
190 #  elif defined(MOZ_SAMPLE_TYPE_S16)
191     FORMAT_DEFAULT = FORMAT_S16
192 #  else
193 #    error "Not supported audio type"
194 #  endif
195   };
196 
197   AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
198               AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
199               bool aInterleaved = true);
200   AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aChannels,
201               uint32_t aRate,
202               AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
203               bool aInterleaved = true);
204   // Will create a channel configuration from default SMPTE ordering.
205   AudioConfig(uint32_t aChannels, uint32_t aRate,
206               AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
207               bool aInterleaved = true);
208 
Layout()209   const ChannelLayout& Layout() const { return mChannelLayout; }
Channels()210   uint32_t Channels() const {
211     if (!mChannelLayout.IsValid()) {
212       return mChannels;
213     }
214     return mChannelLayout.Count();
215   }
Rate()216   uint32_t Rate() const { return mRate; }
Format()217   SampleFormat Format() const { return mFormat; }
Interleaved()218   bool Interleaved() const { return mInterleaved; }
219   bool operator==(const AudioConfig& aOther) const {
220     return mChannelLayout == aOther.mChannelLayout && mRate == aOther.mRate &&
221            mFormat == aOther.mFormat && mInterleaved == aOther.mInterleaved;
222   }
223   bool operator!=(const AudioConfig& aOther) const {
224     return !(*this == aOther);
225   }
226 
IsValid()227   bool IsValid() const {
228     return mChannelLayout.IsValid() && Format() != FORMAT_NONE && Rate() > 0;
229   }
230 
231   static const char* FormatToString(SampleFormat aFormat);
232   static uint32_t SampleSize(SampleFormat aFormat);
233   static uint32_t FormatToBits(SampleFormat aFormat);
234 
235  private:
236   // Channels configuration.
237   ChannelLayout mChannelLayout;
238 
239   // Channel count.
240   uint32_t mChannels;
241 
242   // Sample rate.
243   uint32_t mRate;
244 
245   // Sample format.
246   SampleFormat mFormat;
247 
248   bool mInterleaved;
249 };
250 
251 }  // namespace mozilla
252 
253 #endif  // AudioLayout_h
254