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