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