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 
7 #include "AudioConfig.h"
8 
9 namespace mozilla {
10 
11 typedef AudioConfig::ChannelLayout ChannelLayout;
12 
13 /**
14  * AudioConfig::ChannelLayout
15  */
16 
17 /*
18  SMPTE channel layout (also known as wave order)
19  DUAL-MONO      L   R
20  DUAL-MONO-LFE  L   R   LFE
21  MONO           M
22  MONO-LFE       M   LFE
23  STEREO         L   R
24  STEREO-LFE     L   R   LFE
25  3F             L   R   C
26  3F-LFE         L   R   C    LFE
27  2F1            L   R   S
28  2F1-LFE        L   R   LFE  S
29  3F1            L   R   C    S
30  3F1-LFE        L   R   C    LFE S
31  2F2            L   R   LS   RS
32  2F2-LFE        L   R   LFE  LS   RS
33  3F2            L   R   C    LS   RS
34  3F2-LFE        L   R   C    LFE  LS   RS
35  3F3R-LFE       L   R   C    LFE  BC   LS   RS
36  3F4-LFE        L   R   C    LFE  Rls  Rrs  LS   RS
37 */
38 
UpdateChannelMap()39 void AudioConfig::ChannelLayout::UpdateChannelMap() {
40   mValid = mChannels.Length() <= MAX_CHANNELS;
41   mChannelMap = UNKNOWN_MAP;
42   if (mValid) {
43     mChannelMap = Map();
44     mValid = mChannelMap > 0;
45   }
46 }
47 
Map() const48 auto AudioConfig::ChannelLayout::Map() const -> ChannelMap {
49   if (mChannelMap != UNKNOWN_MAP) {
50     return mChannelMap;
51   }
52   if (mChannels.Length() > MAX_CHANNELS) {
53     return UNKNOWN_MAP;
54   }
55   ChannelMap map = UNKNOWN_MAP;
56   for (size_t i = 0; i < mChannels.Length(); i++) {
57     if (uint32_t(mChannels[i]) > sizeof(ChannelMap) * 8) {
58       return UNKNOWN_MAP;
59     }
60     ChannelMap mask = 1 << mChannels[i];
61     if (mChannels[i] == CHANNEL_INVALID || (mChannelMap & mask)) {
62       // Invalid configuration.
63       return UNKNOWN_MAP;
64     }
65     map |= mask;
66   }
67   return map;
68 }
69 
70 const AudioConfig::Channel*
DefaultLayoutForChannels(uint32_t aChannels) const71 AudioConfig::ChannelLayout::DefaultLayoutForChannels(uint32_t aChannels) const {
72   switch (aChannels) {
73     case 1:  // MONO
74     {
75       static const Channel config[] = {CHANNEL_FRONT_CENTER};
76       return config;
77     }
78     case 2:  // STEREO
79     {
80       static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT};
81       return config;
82     }
83     case 3:  // 3F
84     {
85       static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
86                                        CHANNEL_FRONT_CENTER};
87       return config;
88     }
89     case 4:  // QUAD
90     {
91       static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
92                                        CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
93       return config;
94     }
95     case 5:  // 3F2
96     {
97       static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
98                                        CHANNEL_FRONT_CENTER, CHANNEL_SIDE_LEFT,
99                                        CHANNEL_SIDE_RIGHT};
100       return config;
101     }
102     case 6:  // 3F2-LFE
103     {
104       static const Channel config[] = {
105           CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
106           CHANNEL_LFE,        CHANNEL_SIDE_LEFT,   CHANNEL_SIDE_RIGHT};
107       return config;
108     }
109     case 7:  // 3F3R-LFE
110     {
111       static const Channel config[] = {
112           CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
113           CHANNEL_LFE,        CHANNEL_BACK_CENTER, CHANNEL_SIDE_LEFT,
114           CHANNEL_SIDE_RIGHT};
115       return config;
116     }
117     case 8:  // 3F4-LFE
118     {
119       static const Channel config[] = {
120           CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
121           CHANNEL_LFE,        CHANNEL_BACK_LEFT,   CHANNEL_BACK_RIGHT,
122           CHANNEL_SIDE_LEFT,  CHANNEL_SIDE_RIGHT};
123       return config;
124     }
125     default:
126       return nullptr;
127   }
128 }
129 
130 /* static */ AudioConfig::ChannelLayout
SMPTEDefault(const ChannelLayout & aChannelLayout)131 AudioConfig::ChannelLayout::SMPTEDefault(const ChannelLayout& aChannelLayout) {
132   if (!aChannelLayout.IsValid()) {
133     return aChannelLayout;
134   }
135   return SMPTEDefault(aChannelLayout.Map());
136 }
137 
138 /* static */
SMPTEDefault(ChannelMap aMap)139 ChannelLayout AudioConfig::ChannelLayout::SMPTEDefault(ChannelMap aMap) {
140   // First handle the most common cases.
141   switch (aMap) {
142     case LMONO_MAP:
143       return ChannelLayout{CHANNEL_FRONT_CENTER};
144     case LSTEREO_MAP:
145       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT};
146     case L3F_MAP:
147       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
148                            CHANNEL_FRONT_CENTER};
149     case L3F_LFE_MAP:
150       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
151                            CHANNEL_FRONT_CENTER, CHANNEL_LFE};
152     case L2F1_MAP:
153       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
154                            CHANNEL_BACK_CENTER};
155     case L2F1_LFE_MAP:
156       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_LFE,
157                            CHANNEL_BACK_CENTER};
158     case L3F1_MAP:
159       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
160                            CHANNEL_FRONT_CENTER, CHANNEL_BACK_CENTER};
161     case L3F1_LFE_MAP:
162       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
163                            CHANNEL_FRONT_CENTER, CHANNEL_LFE,
164                            CHANNEL_BACK_CENTER};
165     case L2F2_MAP:
166       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
167                            CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
168     case L2F2_LFE_MAP:
169       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_LFE,
170                            CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
171     case LQUAD_MAP:
172       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
173                            CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
174     case LQUAD_LFE_MAP:
175       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_LFE,
176                            CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
177     case L3F2_MAP:
178       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
179                            CHANNEL_FRONT_CENTER, CHANNEL_SIDE_LEFT,
180                            CHANNEL_SIDE_RIGHT};
181     case L3F2_LFE_MAP:
182       return ChannelLayout{CHANNEL_FRONT_LEFT,   CHANNEL_FRONT_RIGHT,
183                            CHANNEL_FRONT_CENTER, CHANNEL_LFE,
184                            CHANNEL_SIDE_LEFT,    CHANNEL_SIDE_RIGHT};
185     case L3F2_BACK_MAP:
186       return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
187                            CHANNEL_FRONT_CENTER, CHANNEL_BACK_LEFT,
188                            CHANNEL_BACK_RIGHT};
189     case L3F2_BACK_LFE_MAP:
190       return ChannelLayout{CHANNEL_FRONT_LEFT,   CHANNEL_FRONT_RIGHT,
191                            CHANNEL_FRONT_CENTER, CHANNEL_LFE,
192                            CHANNEL_BACK_LEFT,    CHANNEL_BACK_RIGHT};
193     case L3F3R_LFE_MAP:
194       return ChannelLayout{CHANNEL_FRONT_LEFT,   CHANNEL_FRONT_RIGHT,
195                            CHANNEL_FRONT_CENTER, CHANNEL_LFE,
196                            CHANNEL_BACK_CENTER,  CHANNEL_SIDE_LEFT,
197                            CHANNEL_SIDE_RIGHT};
198     case L3F4_LFE_MAP:
199       return ChannelLayout{CHANNEL_FRONT_LEFT,   CHANNEL_FRONT_RIGHT,
200                            CHANNEL_FRONT_CENTER, CHANNEL_LFE,
201                            CHANNEL_BACK_LEFT,    CHANNEL_BACK_RIGHT,
202                            CHANNEL_SIDE_LEFT,    CHANNEL_SIDE_RIGHT};
203     default:
204       break;
205   }
206 
207   static_assert(MAX_CHANNELS <= sizeof(ChannelMap) * 8,
208                 "Must be able to fit channels on bit mask");
209   AutoTArray<Channel, MAX_CHANNELS> layout;
210   uint32_t channels = 0;
211 
212   uint32_t i = 0;
213   while (aMap) {
214     if (aMap & 1) {
215       channels++;
216       if (channels > MAX_CHANNELS) {
217         return ChannelLayout();
218       }
219       layout.AppendElement(static_cast<Channel>(i));
220     }
221     aMap >>= 1;
222     i++;
223   }
224   return ChannelLayout(channels, layout.Elements());
225 }
226 
MappingTable(const ChannelLayout & aOther,nsTArray<uint8_t> * aMap) const227 bool AudioConfig::ChannelLayout::MappingTable(const ChannelLayout& aOther,
228                                               nsTArray<uint8_t>* aMap) const {
229   if (!IsValid() || !aOther.IsValid() || Map() != aOther.Map()) {
230     if (aMap) {
231       aMap->SetLength(0);
232     }
233     return false;
234   }
235   if (!aMap) {
236     return true;
237   }
238   aMap->SetLength(Count());
239   for (uint32_t i = 0; i < Count(); i++) {
240     for (uint32_t j = 0; j < Count(); j++) {
241       if (aOther[j] == mChannels[i]) {
242         (*aMap)[j] = i;
243         break;
244       }
245     }
246   }
247   return true;
248 }
249 
250 /**
251  * AudioConfig::ChannelConfig
252  */
253 
FormatToString(AudioConfig::SampleFormat aFormat)254 /* static */ const char* AudioConfig::FormatToString(
255     AudioConfig::SampleFormat aFormat) {
256   switch (aFormat) {
257     case FORMAT_U8:
258       return "unsigned 8 bit";
259     case FORMAT_S16:
260       return "signed 16 bit";
261     case FORMAT_S24:
262       return "signed 24 bit MSB";
263     case FORMAT_S24LSB:
264       return "signed 24 bit LSB";
265     case FORMAT_S32:
266       return "signed 32 bit";
267     case FORMAT_FLT:
268       return "32 bit floating point";
269     case FORMAT_NONE:
270       return "none";
271     default:
272       return "unknown";
273   }
274 }
275 /* static */
SampleSize(AudioConfig::SampleFormat aFormat)276 uint32_t AudioConfig::SampleSize(AudioConfig::SampleFormat aFormat) {
277   switch (aFormat) {
278     case FORMAT_U8:
279       return 1;
280     case FORMAT_S16:
281       return 2;
282     case FORMAT_S24:
283       [[fallthrough]];
284     case FORMAT_S24LSB:
285       [[fallthrough]];
286     case FORMAT_S32:
287       [[fallthrough]];
288     case FORMAT_FLT:
289       return 4;
290     case FORMAT_NONE:
291     default:
292       return 0;
293   }
294 }
295 
296 /* static */
FormatToBits(AudioConfig::SampleFormat aFormat)297 uint32_t AudioConfig::FormatToBits(AudioConfig::SampleFormat aFormat) {
298   switch (aFormat) {
299     case FORMAT_U8:
300       return 8;
301     case FORMAT_S16:
302       return 16;
303     case FORMAT_S24LSB:
304       [[fallthrough]];
305     case FORMAT_S24:
306       return 24;
307     case FORMAT_S32:
308       [[fallthrough]];
309     case FORMAT_FLT:
310       return 32;
311     case FORMAT_NONE:
312       [[fallthrough]];
313     default:
314       return 0;
315   }
316 }
317 
AudioConfig(const ChannelLayout & aChannelLayout,uint32_t aRate,AudioConfig::SampleFormat aFormat,bool aInterleaved)318 AudioConfig::AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
319                          AudioConfig::SampleFormat aFormat, bool aInterleaved)
320     : mChannelLayout(aChannelLayout),
321       mChannels(aChannelLayout.Count()),
322       mRate(aRate),
323       mFormat(aFormat),
324       mInterleaved(aInterleaved) {}
325 
AudioConfig(const ChannelLayout & aChannelLayout,uint32_t aChannels,uint32_t aRate,AudioConfig::SampleFormat aFormat,bool aInterleaved)326 AudioConfig::AudioConfig(const ChannelLayout& aChannelLayout,
327                          uint32_t aChannels, uint32_t aRate,
328                          AudioConfig::SampleFormat aFormat, bool aInterleaved)
329     : mChannelLayout(aChannelLayout),
330       mChannels(aChannels),
331       mRate(aRate),
332       mFormat(aFormat),
333       mInterleaved(aInterleaved) {}
334 
AudioConfig(uint32_t aChannels,uint32_t aRate,AudioConfig::SampleFormat aFormat,bool aInterleaved)335 AudioConfig::AudioConfig(uint32_t aChannels, uint32_t aRate,
336                          AudioConfig::SampleFormat aFormat, bool aInterleaved)
337     : mChannelLayout(aChannels),
338       mChannels(aChannels),
339       mRate(aRate),
340       mFormat(aFormat),
341       mInterleaved(aInterleaved) {}
342 
343 }  // namespace mozilla
344