|  | /* | 
|  | *  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 <cstddef> | 
|  | #include <iterator> | 
|  |  | 
|  | #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<size_t>(layout), std::size(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<size_t>(layout), std::size(kChannelOrderings)); | 
|  | RTC_DCHECK_LT(static_cast<size_t>(channel), std::size(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_DCHECK_NOTREACHED() << "Invalid channel layout provided: " << layout; | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |