/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "api/audio/channel_layout.h" #include #include "rtc_base/arraysize.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { static const int kLayoutToChannels[] = { 0, // CHANNEL_LAYOUT_NONE 0, // CHANNEL_LAYOUT_UNSUPPORTED 1, // CHANNEL_LAYOUT_MONO 2, // CHANNEL_LAYOUT_STEREO 3, // CHANNEL_LAYOUT_2_1 3, // CHANNEL_LAYOUT_SURROUND 4, // CHANNEL_LAYOUT_4_0 4, // CHANNEL_LAYOUT_2_2 4, // CHANNEL_LAYOUT_QUAD 5, // CHANNEL_LAYOUT_5_0 6, // CHANNEL_LAYOUT_5_1 5, // CHANNEL_LAYOUT_5_0_BACK 6, // CHANNEL_LAYOUT_5_1_BACK 7, // CHANNEL_LAYOUT_7_0 8, // CHANNEL_LAYOUT_7_1 8, // CHANNEL_LAYOUT_7_1_WIDE 2, // CHANNEL_LAYOUT_STEREO_DOWNMIX 3, // CHANNEL_LAYOUT_2POINT1 4, // CHANNEL_LAYOUT_3_1 5, // CHANNEL_LAYOUT_4_1 6, // CHANNEL_LAYOUT_6_0 6, // CHANNEL_LAYOUT_6_0_FRONT 6, // CHANNEL_LAYOUT_HEXAGONAL 7, // CHANNEL_LAYOUT_6_1 7, // CHANNEL_LAYOUT_6_1_BACK 7, // CHANNEL_LAYOUT_6_1_FRONT 7, // CHANNEL_LAYOUT_7_0_FRONT 8, // CHANNEL_LAYOUT_7_1_WIDE_BACK 8, // CHANNEL_LAYOUT_OCTAGONAL 0, // CHANNEL_LAYOUT_DISCRETE 3, // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC 5, // CHANNEL_LAYOUT_4_1_QUAD_SIDE 0, // CHANNEL_LAYOUT_BITSTREAM }; // The channel orderings for each layout as specified by FFmpeg. Each value // represents the index of each channel in each layout. Values of -1 mean the // channel at that index is not used for that layout. For example, the left side // surround sound channel in FFmpeg's 5.1 layout is in the 5th position (because // the order is L, R, C, LFE, LS, RS), so // kChannelOrderings[CHANNEL_LAYOUT_5_1][SIDE_LEFT] = 4; static const int kChannelOrderings[CHANNEL_LAYOUT_MAX + 1][CHANNELS_MAX + 1] = { // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR // CHANNEL_LAYOUT_NONE {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_UNSUPPORTED {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_MONO {-1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_STEREO {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_2_1 {0, 1, -1, -1, -1, -1, -1, -1, 2, -1, -1}, // CHANNEL_LAYOUT_SURROUND {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_4_0 {0, 1, 2, -1, -1, -1, -1, -1, 3, -1, -1}, // CHANNEL_LAYOUT_2_2 {0, 1, -1, -1, -1, -1, -1, -1, -1, 2, 3}, // CHANNEL_LAYOUT_QUAD {0, 1, -1, -1, 2, 3, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_5_0 {0, 1, 2, -1, -1, -1, -1, -1, -1, 3, 4}, // CHANNEL_LAYOUT_5_1 {0, 1, 2, 3, -1, -1, -1, -1, -1, 4, 5}, // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR // CHANNEL_LAYOUT_5_0_BACK {0, 1, 2, -1, 3, 4, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_5_1_BACK {0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_7_0 {0, 1, 2, -1, 5, 6, -1, -1, -1, 3, 4}, // CHANNEL_LAYOUT_7_1 {0, 1, 2, 3, 6, 7, -1, -1, -1, 4, 5}, // CHANNEL_LAYOUT_7_1_WIDE {0, 1, 2, 3, -1, -1, 6, 7, -1, 4, 5}, // CHANNEL_LAYOUT_STEREO_DOWNMIX {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_2POINT1 {0, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_3_1 {0, 1, 2, 3, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_4_1 {0, 1, 2, 4, -1, -1, -1, -1, 3, -1, -1}, // CHANNEL_LAYOUT_6_0 {0, 1, 2, -1, -1, -1, -1, -1, 5, 3, 4}, // CHANNEL_LAYOUT_6_0_FRONT {0, 1, -1, -1, -1, -1, 4, 5, -1, 2, 3}, // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR // CHANNEL_LAYOUT_HEXAGONAL {0, 1, 2, -1, 3, 4, -1, -1, 5, -1, -1}, // CHANNEL_LAYOUT_6_1 {0, 1, 2, 3, -1, -1, -1, -1, 6, 4, 5}, // CHANNEL_LAYOUT_6_1_BACK {0, 1, 2, 3, 4, 5, -1, -1, 6, -1, -1}, // CHANNEL_LAYOUT_6_1_FRONT {0, 1, -1, 6, -1, -1, 4, 5, -1, 2, 3}, // CHANNEL_LAYOUT_7_0_FRONT {0, 1, 2, -1, -1, -1, 5, 6, -1, 3, 4}, // CHANNEL_LAYOUT_7_1_WIDE_BACK {0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1}, // CHANNEL_LAYOUT_OCTAGONAL {0, 1, 2, -1, 5, 6, -1, -1, 7, 3, 4}, // CHANNEL_LAYOUT_DISCRETE {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1}, // CHANNEL_LAYOUT_4_1_QUAD_SIDE {0, 1, -1, 4, -1, -1, -1, -1, -1, 2, 3}, // CHANNEL_LAYOUT_BITSTREAM {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR }; int ChannelLayoutToChannelCount(ChannelLayout layout) { RTC_DCHECK_LT(static_cast(layout), arraysize(kLayoutToChannels)); RTC_DCHECK_LE(kLayoutToChannels[layout], kMaxConcurrentChannels); return kLayoutToChannels[layout]; } // Converts a channel count into a channel layout. ChannelLayout GuessChannelLayout(int channels) { switch (channels) { case 1: return CHANNEL_LAYOUT_MONO; case 2: return CHANNEL_LAYOUT_STEREO; case 3: return CHANNEL_LAYOUT_SURROUND; case 4: return CHANNEL_LAYOUT_QUAD; case 5: return CHANNEL_LAYOUT_5_0; case 6: return CHANNEL_LAYOUT_5_1; case 7: return CHANNEL_LAYOUT_6_1; case 8: return CHANNEL_LAYOUT_7_1; default: RTC_DLOG(LS_WARNING) << "Unsupported channel count: " << channels; } return CHANNEL_LAYOUT_UNSUPPORTED; } int ChannelOrder(ChannelLayout layout, Channels channel) { RTC_DCHECK_LT(static_cast(layout), arraysize(kChannelOrderings)); RTC_DCHECK_LT(static_cast(channel), arraysize(kChannelOrderings[0])); return kChannelOrderings[layout][channel]; } const char* ChannelLayoutToString(ChannelLayout layout) { switch (layout) { case CHANNEL_LAYOUT_NONE: return "NONE"; case CHANNEL_LAYOUT_UNSUPPORTED: return "UNSUPPORTED"; case CHANNEL_LAYOUT_MONO: return "MONO"; case CHANNEL_LAYOUT_STEREO: return "STEREO"; case CHANNEL_LAYOUT_2_1: return "2.1"; case CHANNEL_LAYOUT_SURROUND: return "SURROUND"; case CHANNEL_LAYOUT_4_0: return "4.0"; case CHANNEL_LAYOUT_2_2: return "QUAD_SIDE"; case CHANNEL_LAYOUT_QUAD: return "QUAD"; case CHANNEL_LAYOUT_5_0: return "5.0"; case CHANNEL_LAYOUT_5_1: return "5.1"; case CHANNEL_LAYOUT_5_0_BACK: return "5.0_BACK"; case CHANNEL_LAYOUT_5_1_BACK: return "5.1_BACK"; case CHANNEL_LAYOUT_7_0: return "7.0"; case CHANNEL_LAYOUT_7_1: return "7.1"; case CHANNEL_LAYOUT_7_1_WIDE: return "7.1_WIDE"; case CHANNEL_LAYOUT_STEREO_DOWNMIX: return "STEREO_DOWNMIX"; case CHANNEL_LAYOUT_2POINT1: return "2POINT1"; case CHANNEL_LAYOUT_3_1: return "3.1"; case CHANNEL_LAYOUT_4_1: return "4.1"; case CHANNEL_LAYOUT_6_0: return "6.0"; case CHANNEL_LAYOUT_6_0_FRONT: return "6.0_FRONT"; case CHANNEL_LAYOUT_HEXAGONAL: return "HEXAGONAL"; case CHANNEL_LAYOUT_6_1: return "6.1"; case CHANNEL_LAYOUT_6_1_BACK: return "6.1_BACK"; case CHANNEL_LAYOUT_6_1_FRONT: return "6.1_FRONT"; case CHANNEL_LAYOUT_7_0_FRONT: return "7.0_FRONT"; case CHANNEL_LAYOUT_7_1_WIDE_BACK: return "7.1_WIDE_BACK"; case CHANNEL_LAYOUT_OCTAGONAL: return "OCTAGONAL"; case CHANNEL_LAYOUT_DISCRETE: return "DISCRETE"; case CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC: return "STEREO_AND_KEYBOARD_MIC"; case CHANNEL_LAYOUT_4_1_QUAD_SIDE: return "4.1_QUAD_SIDE"; case CHANNEL_LAYOUT_BITSTREAM: return "BITSTREAM"; } RTC_NOTREACHED() << "Invalid channel layout provided: " << layout; return ""; } } // namespace webrtc