1 /*
2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "api/audio/channel_layout.h"
12
13 #include <stddef.h>
14
15 #include "rtc_base/arraysize.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/logging.h"
18
19 namespace webrtc {
20
21 static const int kLayoutToChannels[] = {
22 0, // CHANNEL_LAYOUT_NONE
23 0, // CHANNEL_LAYOUT_UNSUPPORTED
24 1, // CHANNEL_LAYOUT_MONO
25 2, // CHANNEL_LAYOUT_STEREO
26 3, // CHANNEL_LAYOUT_2_1
27 3, // CHANNEL_LAYOUT_SURROUND
28 4, // CHANNEL_LAYOUT_4_0
29 4, // CHANNEL_LAYOUT_2_2
30 4, // CHANNEL_LAYOUT_QUAD
31 5, // CHANNEL_LAYOUT_5_0
32 6, // CHANNEL_LAYOUT_5_1
33 5, // CHANNEL_LAYOUT_5_0_BACK
34 6, // CHANNEL_LAYOUT_5_1_BACK
35 7, // CHANNEL_LAYOUT_7_0
36 8, // CHANNEL_LAYOUT_7_1
37 8, // CHANNEL_LAYOUT_7_1_WIDE
38 2, // CHANNEL_LAYOUT_STEREO_DOWNMIX
39 3, // CHANNEL_LAYOUT_2POINT1
40 4, // CHANNEL_LAYOUT_3_1
41 5, // CHANNEL_LAYOUT_4_1
42 6, // CHANNEL_LAYOUT_6_0
43 6, // CHANNEL_LAYOUT_6_0_FRONT
44 6, // CHANNEL_LAYOUT_HEXAGONAL
45 7, // CHANNEL_LAYOUT_6_1
46 7, // CHANNEL_LAYOUT_6_1_BACK
47 7, // CHANNEL_LAYOUT_6_1_FRONT
48 7, // CHANNEL_LAYOUT_7_0_FRONT
49 8, // CHANNEL_LAYOUT_7_1_WIDE_BACK
50 8, // CHANNEL_LAYOUT_OCTAGONAL
51 0, // CHANNEL_LAYOUT_DISCRETE
52 3, // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC
53 5, // CHANNEL_LAYOUT_4_1_QUAD_SIDE
54 0, // CHANNEL_LAYOUT_BITSTREAM
55 };
56
57 // The channel orderings for each layout as specified by FFmpeg. Each value
58 // represents the index of each channel in each layout. Values of -1 mean the
59 // channel at that index is not used for that layout. For example, the left side
60 // surround sound channel in FFmpeg's 5.1 layout is in the 5th position (because
61 // the order is L, R, C, LFE, LS, RS), so
62 // kChannelOrderings[CHANNEL_LAYOUT_5_1][SIDE_LEFT] = 4;
63 static const int kChannelOrderings[CHANNEL_LAYOUT_MAX + 1][CHANNELS_MAX + 1] = {
64 // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
65
66 // CHANNEL_LAYOUT_NONE
67 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
68
69 // CHANNEL_LAYOUT_UNSUPPORTED
70 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
71
72 // CHANNEL_LAYOUT_MONO
73 {-1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1},
74
75 // CHANNEL_LAYOUT_STEREO
76 {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
77
78 // CHANNEL_LAYOUT_2_1
79 {0, 1, -1, -1, -1, -1, -1, -1, 2, -1, -1},
80
81 // CHANNEL_LAYOUT_SURROUND
82 {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1},
83
84 // CHANNEL_LAYOUT_4_0
85 {0, 1, 2, -1, -1, -1, -1, -1, 3, -1, -1},
86
87 // CHANNEL_LAYOUT_2_2
88 {0, 1, -1, -1, -1, -1, -1, -1, -1, 2, 3},
89
90 // CHANNEL_LAYOUT_QUAD
91 {0, 1, -1, -1, 2, 3, -1, -1, -1, -1, -1},
92
93 // CHANNEL_LAYOUT_5_0
94 {0, 1, 2, -1, -1, -1, -1, -1, -1, 3, 4},
95
96 // CHANNEL_LAYOUT_5_1
97 {0, 1, 2, 3, -1, -1, -1, -1, -1, 4, 5},
98
99 // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
100
101 // CHANNEL_LAYOUT_5_0_BACK
102 {0, 1, 2, -1, 3, 4, -1, -1, -1, -1, -1},
103
104 // CHANNEL_LAYOUT_5_1_BACK
105 {0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1},
106
107 // CHANNEL_LAYOUT_7_0
108 {0, 1, 2, -1, 5, 6, -1, -1, -1, 3, 4},
109
110 // CHANNEL_LAYOUT_7_1
111 {0, 1, 2, 3, 6, 7, -1, -1, -1, 4, 5},
112
113 // CHANNEL_LAYOUT_7_1_WIDE
114 {0, 1, 2, 3, -1, -1, 6, 7, -1, 4, 5},
115
116 // CHANNEL_LAYOUT_STEREO_DOWNMIX
117 {0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
118
119 // CHANNEL_LAYOUT_2POINT1
120 {0, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1},
121
122 // CHANNEL_LAYOUT_3_1
123 {0, 1, 2, 3, -1, -1, -1, -1, -1, -1, -1},
124
125 // CHANNEL_LAYOUT_4_1
126 {0, 1, 2, 4, -1, -1, -1, -1, 3, -1, -1},
127
128 // CHANNEL_LAYOUT_6_0
129 {0, 1, 2, -1, -1, -1, -1, -1, 5, 3, 4},
130
131 // CHANNEL_LAYOUT_6_0_FRONT
132 {0, 1, -1, -1, -1, -1, 4, 5, -1, 2, 3},
133
134 // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
135
136 // CHANNEL_LAYOUT_HEXAGONAL
137 {0, 1, 2, -1, 3, 4, -1, -1, 5, -1, -1},
138
139 // CHANNEL_LAYOUT_6_1
140 {0, 1, 2, 3, -1, -1, -1, -1, 6, 4, 5},
141
142 // CHANNEL_LAYOUT_6_1_BACK
143 {0, 1, 2, 3, 4, 5, -1, -1, 6, -1, -1},
144
145 // CHANNEL_LAYOUT_6_1_FRONT
146 {0, 1, -1, 6, -1, -1, 4, 5, -1, 2, 3},
147
148 // CHANNEL_LAYOUT_7_0_FRONT
149 {0, 1, 2, -1, -1, -1, 5, 6, -1, 3, 4},
150
151 // CHANNEL_LAYOUT_7_1_WIDE_BACK
152 {0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1},
153
154 // CHANNEL_LAYOUT_OCTAGONAL
155 {0, 1, 2, -1, 5, 6, -1, -1, 7, 3, 4},
156
157 // CHANNEL_LAYOUT_DISCRETE
158 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
159
160 // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC
161 {0, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1},
162
163 // CHANNEL_LAYOUT_4_1_QUAD_SIDE
164 {0, 1, -1, 4, -1, -1, -1, -1, -1, 2, 3},
165
166 // CHANNEL_LAYOUT_BITSTREAM
167 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
168
169 // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR
170 };
171
ChannelLayoutToChannelCount(ChannelLayout layout)172 int ChannelLayoutToChannelCount(ChannelLayout layout) {
173 RTC_DCHECK_LT(static_cast<size_t>(layout), arraysize(kLayoutToChannels));
174 RTC_DCHECK_LE(kLayoutToChannels[layout], kMaxConcurrentChannels);
175 return kLayoutToChannels[layout];
176 }
177
178 // Converts a channel count into a channel layout.
GuessChannelLayout(int channels)179 ChannelLayout GuessChannelLayout(int channels) {
180 switch (channels) {
181 case 1:
182 return CHANNEL_LAYOUT_MONO;
183 case 2:
184 return CHANNEL_LAYOUT_STEREO;
185 case 3:
186 return CHANNEL_LAYOUT_SURROUND;
187 case 4:
188 return CHANNEL_LAYOUT_QUAD;
189 case 5:
190 return CHANNEL_LAYOUT_5_0;
191 case 6:
192 return CHANNEL_LAYOUT_5_1;
193 case 7:
194 return CHANNEL_LAYOUT_6_1;
195 case 8:
196 return CHANNEL_LAYOUT_7_1;
197 default:
198 RTC_DLOG(LS_WARNING) << "Unsupported channel count: " << channels;
199 }
200 return CHANNEL_LAYOUT_UNSUPPORTED;
201 }
202
ChannelOrder(ChannelLayout layout,Channels channel)203 int ChannelOrder(ChannelLayout layout, Channels channel) {
204 RTC_DCHECK_LT(static_cast<size_t>(layout), arraysize(kChannelOrderings));
205 RTC_DCHECK_LT(static_cast<size_t>(channel), arraysize(kChannelOrderings[0]));
206 return kChannelOrderings[layout][channel];
207 }
208
ChannelLayoutToString(ChannelLayout layout)209 const char* ChannelLayoutToString(ChannelLayout layout) {
210 switch (layout) {
211 case CHANNEL_LAYOUT_NONE:
212 return "NONE";
213 case CHANNEL_LAYOUT_UNSUPPORTED:
214 return "UNSUPPORTED";
215 case CHANNEL_LAYOUT_MONO:
216 return "MONO";
217 case CHANNEL_LAYOUT_STEREO:
218 return "STEREO";
219 case CHANNEL_LAYOUT_2_1:
220 return "2.1";
221 case CHANNEL_LAYOUT_SURROUND:
222 return "SURROUND";
223 case CHANNEL_LAYOUT_4_0:
224 return "4.0";
225 case CHANNEL_LAYOUT_2_2:
226 return "QUAD_SIDE";
227 case CHANNEL_LAYOUT_QUAD:
228 return "QUAD";
229 case CHANNEL_LAYOUT_5_0:
230 return "5.0";
231 case CHANNEL_LAYOUT_5_1:
232 return "5.1";
233 case CHANNEL_LAYOUT_5_0_BACK:
234 return "5.0_BACK";
235 case CHANNEL_LAYOUT_5_1_BACK:
236 return "5.1_BACK";
237 case CHANNEL_LAYOUT_7_0:
238 return "7.0";
239 case CHANNEL_LAYOUT_7_1:
240 return "7.1";
241 case CHANNEL_LAYOUT_7_1_WIDE:
242 return "7.1_WIDE";
243 case CHANNEL_LAYOUT_STEREO_DOWNMIX:
244 return "STEREO_DOWNMIX";
245 case CHANNEL_LAYOUT_2POINT1:
246 return "2POINT1";
247 case CHANNEL_LAYOUT_3_1:
248 return "3.1";
249 case CHANNEL_LAYOUT_4_1:
250 return "4.1";
251 case CHANNEL_LAYOUT_6_0:
252 return "6.0";
253 case CHANNEL_LAYOUT_6_0_FRONT:
254 return "6.0_FRONT";
255 case CHANNEL_LAYOUT_HEXAGONAL:
256 return "HEXAGONAL";
257 case CHANNEL_LAYOUT_6_1:
258 return "6.1";
259 case CHANNEL_LAYOUT_6_1_BACK:
260 return "6.1_BACK";
261 case CHANNEL_LAYOUT_6_1_FRONT:
262 return "6.1_FRONT";
263 case CHANNEL_LAYOUT_7_0_FRONT:
264 return "7.0_FRONT";
265 case CHANNEL_LAYOUT_7_1_WIDE_BACK:
266 return "7.1_WIDE_BACK";
267 case CHANNEL_LAYOUT_OCTAGONAL:
268 return "OCTAGONAL";
269 case CHANNEL_LAYOUT_DISCRETE:
270 return "DISCRETE";
271 case CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC:
272 return "STEREO_AND_KEYBOARD_MIC";
273 case CHANNEL_LAYOUT_4_1_QUAD_SIDE:
274 return "4.1_QUAD_SIDE";
275 case CHANNEL_LAYOUT_BITSTREAM:
276 return "BITSTREAM";
277 }
278 RTC_DCHECK_NOTREACHED() << "Invalid channel layout provided: " << layout;
279 return "";
280 }
281
282 } // namespace webrtc
283