1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2005-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <pulse/xmalloc.h>
30
31 #include <pulsecore/i18n.h>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/bitset.h>
35 #include <pulsecore/sample-util.h>
36
37 #include "channelmap.h"
38
39 static const char *const table[PA_CHANNEL_POSITION_MAX] = {
40 [PA_CHANNEL_POSITION_MONO] = "mono",
41
42 [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center",
43 [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left",
44 [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right",
45
46 [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center",
47 [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left",
48 [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right",
49
50 [PA_CHANNEL_POSITION_LFE] = "lfe",
51
52 [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center",
53 [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center",
54
55 [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left",
56 [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right",
57
58 [PA_CHANNEL_POSITION_AUX0] = "aux0",
59 [PA_CHANNEL_POSITION_AUX1] = "aux1",
60 [PA_CHANNEL_POSITION_AUX2] = "aux2",
61 [PA_CHANNEL_POSITION_AUX3] = "aux3",
62 [PA_CHANNEL_POSITION_AUX4] = "aux4",
63 [PA_CHANNEL_POSITION_AUX5] = "aux5",
64 [PA_CHANNEL_POSITION_AUX6] = "aux6",
65 [PA_CHANNEL_POSITION_AUX7] = "aux7",
66 [PA_CHANNEL_POSITION_AUX8] = "aux8",
67 [PA_CHANNEL_POSITION_AUX9] = "aux9",
68 [PA_CHANNEL_POSITION_AUX10] = "aux10",
69 [PA_CHANNEL_POSITION_AUX11] = "aux11",
70 [PA_CHANNEL_POSITION_AUX12] = "aux12",
71 [PA_CHANNEL_POSITION_AUX13] = "aux13",
72 [PA_CHANNEL_POSITION_AUX14] = "aux14",
73 [PA_CHANNEL_POSITION_AUX15] = "aux15",
74 [PA_CHANNEL_POSITION_AUX16] = "aux16",
75 [PA_CHANNEL_POSITION_AUX17] = "aux17",
76 [PA_CHANNEL_POSITION_AUX18] = "aux18",
77 [PA_CHANNEL_POSITION_AUX19] = "aux19",
78 [PA_CHANNEL_POSITION_AUX20] = "aux20",
79 [PA_CHANNEL_POSITION_AUX21] = "aux21",
80 [PA_CHANNEL_POSITION_AUX22] = "aux22",
81 [PA_CHANNEL_POSITION_AUX23] = "aux23",
82 [PA_CHANNEL_POSITION_AUX24] = "aux24",
83 [PA_CHANNEL_POSITION_AUX25] = "aux25",
84 [PA_CHANNEL_POSITION_AUX26] = "aux26",
85 [PA_CHANNEL_POSITION_AUX27] = "aux27",
86 [PA_CHANNEL_POSITION_AUX28] = "aux28",
87 [PA_CHANNEL_POSITION_AUX29] = "aux29",
88 [PA_CHANNEL_POSITION_AUX30] = "aux30",
89 [PA_CHANNEL_POSITION_AUX31] = "aux31",
90
91 [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center",
92
93 [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center",
94 [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left",
95 [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right",
96
97 [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center",
98 [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left",
99 [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right"
100 };
101
102 static const char *const pretty_table[PA_CHANNEL_POSITION_MAX] = {
103 [PA_CHANNEL_POSITION_MONO] = N_("Mono"),
104
105 [PA_CHANNEL_POSITION_FRONT_CENTER] = N_("Front Center"),
106 [PA_CHANNEL_POSITION_FRONT_LEFT] = N_("Front Left"),
107 [PA_CHANNEL_POSITION_FRONT_RIGHT] = N_("Front Right"),
108
109 [PA_CHANNEL_POSITION_REAR_CENTER] = N_("Rear Center"),
110 [PA_CHANNEL_POSITION_REAR_LEFT] = N_("Rear Left"),
111 [PA_CHANNEL_POSITION_REAR_RIGHT] = N_("Rear Right"),
112
113 [PA_CHANNEL_POSITION_LFE] = N_("Subwoofer"),
114
115 [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = N_("Front Left-of-center"),
116 [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = N_("Front Right-of-center"),
117
118 [PA_CHANNEL_POSITION_SIDE_LEFT] = N_("Side Left"),
119 [PA_CHANNEL_POSITION_SIDE_RIGHT] = N_("Side Right"),
120
121 [PA_CHANNEL_POSITION_AUX0] = N_("Auxiliary 0"),
122 [PA_CHANNEL_POSITION_AUX1] = N_("Auxiliary 1"),
123 [PA_CHANNEL_POSITION_AUX2] = N_("Auxiliary 2"),
124 [PA_CHANNEL_POSITION_AUX3] = N_("Auxiliary 3"),
125 [PA_CHANNEL_POSITION_AUX4] = N_("Auxiliary 4"),
126 [PA_CHANNEL_POSITION_AUX5] = N_("Auxiliary 5"),
127 [PA_CHANNEL_POSITION_AUX6] = N_("Auxiliary 6"),
128 [PA_CHANNEL_POSITION_AUX7] = N_("Auxiliary 7"),
129 [PA_CHANNEL_POSITION_AUX8] = N_("Auxiliary 8"),
130 [PA_CHANNEL_POSITION_AUX9] = N_("Auxiliary 9"),
131 [PA_CHANNEL_POSITION_AUX10] = N_("Auxiliary 10"),
132 [PA_CHANNEL_POSITION_AUX11] = N_("Auxiliary 11"),
133 [PA_CHANNEL_POSITION_AUX12] = N_("Auxiliary 12"),
134 [PA_CHANNEL_POSITION_AUX13] = N_("Auxiliary 13"),
135 [PA_CHANNEL_POSITION_AUX14] = N_("Auxiliary 14"),
136 [PA_CHANNEL_POSITION_AUX15] = N_("Auxiliary 15"),
137 [PA_CHANNEL_POSITION_AUX16] = N_("Auxiliary 16"),
138 [PA_CHANNEL_POSITION_AUX17] = N_("Auxiliary 17"),
139 [PA_CHANNEL_POSITION_AUX18] = N_("Auxiliary 18"),
140 [PA_CHANNEL_POSITION_AUX19] = N_("Auxiliary 19"),
141 [PA_CHANNEL_POSITION_AUX20] = N_("Auxiliary 20"),
142 [PA_CHANNEL_POSITION_AUX21] = N_("Auxiliary 21"),
143 [PA_CHANNEL_POSITION_AUX22] = N_("Auxiliary 22"),
144 [PA_CHANNEL_POSITION_AUX23] = N_("Auxiliary 23"),
145 [PA_CHANNEL_POSITION_AUX24] = N_("Auxiliary 24"),
146 [PA_CHANNEL_POSITION_AUX25] = N_("Auxiliary 25"),
147 [PA_CHANNEL_POSITION_AUX26] = N_("Auxiliary 26"),
148 [PA_CHANNEL_POSITION_AUX27] = N_("Auxiliary 27"),
149 [PA_CHANNEL_POSITION_AUX28] = N_("Auxiliary 28"),
150 [PA_CHANNEL_POSITION_AUX29] = N_("Auxiliary 29"),
151 [PA_CHANNEL_POSITION_AUX30] = N_("Auxiliary 30"),
152 [PA_CHANNEL_POSITION_AUX31] = N_("Auxiliary 31"),
153
154 [PA_CHANNEL_POSITION_TOP_CENTER] = N_("Top Center"),
155
156 [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = N_("Top Front Center"),
157 [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = N_("Top Front Left"),
158 [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = N_("Top Front Right"),
159
160 [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = N_("Top Rear Center"),
161 [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = N_("Top Rear Left"),
162 [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = N_("Top Rear Right")
163 };
164
pa_channel_map_init(pa_channel_map * m)165 pa_channel_map* pa_channel_map_init(pa_channel_map *m) {
166 unsigned c;
167 pa_assert(m);
168
169 m->channels = 0;
170
171 for (c = 0; c < PA_CHANNELS_MAX; c++)
172 m->map[c] = PA_CHANNEL_POSITION_INVALID;
173
174 return m;
175 }
176
pa_channel_map_init_mono(pa_channel_map * m)177 pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) {
178 pa_assert(m);
179
180 pa_channel_map_init(m);
181
182 m->channels = 1;
183 m->map[0] = PA_CHANNEL_POSITION_MONO;
184 return m;
185 }
186
pa_channel_map_init_stereo(pa_channel_map * m)187 pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) {
188 pa_assert(m);
189
190 pa_channel_map_init(m);
191
192 m->channels = 2;
193 m->map[0] = PA_CHANNEL_POSITION_LEFT;
194 m->map[1] = PA_CHANNEL_POSITION_RIGHT;
195 return m;
196 }
197
pa_channel_map_init_auto(pa_channel_map * m,unsigned channels,pa_channel_map_def_t def)198 pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
199 pa_assert(m);
200 pa_assert(pa_channels_valid(channels));
201 pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
202
203 pa_channel_map_init(m);
204
205 m->channels = (uint8_t) channels;
206
207 switch (def) {
208 case PA_CHANNEL_MAP_AIFF:
209
210 /* This is somewhat compatible with RFC3551 */
211
212 switch (channels) {
213 case 1:
214 m->map[0] = PA_CHANNEL_POSITION_MONO;
215 return m;
216
217 case 6:
218 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
219 m->map[1] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
220 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
221 m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT;
222 m->map[4] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
223 m->map[5] = PA_CHANNEL_POSITION_REAR_CENTER;
224 return m;
225
226 case 5:
227 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
228 m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT;
229 m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT;
230 /* Fall through */
231
232 case 2:
233 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
234 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
235 return m;
236
237 case 3:
238 m->map[0] = PA_CHANNEL_POSITION_LEFT;
239 m->map[1] = PA_CHANNEL_POSITION_RIGHT;
240 m->map[2] = PA_CHANNEL_POSITION_CENTER;
241 return m;
242
243 case 4:
244 m->map[0] = PA_CHANNEL_POSITION_LEFT;
245 m->map[1] = PA_CHANNEL_POSITION_CENTER;
246 m->map[2] = PA_CHANNEL_POSITION_RIGHT;
247 m->map[3] = PA_CHANNEL_POSITION_REAR_CENTER;
248 return m;
249
250 default:
251 return NULL;
252 }
253
254 case PA_CHANNEL_MAP_ALSA:
255
256 switch (channels) {
257 case 1:
258 m->map[0] = PA_CHANNEL_POSITION_MONO;
259 return m;
260
261 case 8:
262 m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
263 m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
264 /* Fall through */
265
266 case 6:
267 m->map[5] = PA_CHANNEL_POSITION_LFE;
268 /* Fall through */
269
270 case 5:
271 m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
272 /* Fall through */
273
274 case 4:
275 m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
276 m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
277 /* Fall through */
278
279 case 2:
280 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
281 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
282 return m;
283
284 default:
285 return NULL;
286 }
287
288 case PA_CHANNEL_MAP_AUX: {
289 unsigned i;
290
291 for (i = 0; i < channels; i++)
292 m->map[i] = PA_CHANNEL_POSITION_AUX0 + i;
293
294 return m;
295 }
296
297 case PA_CHANNEL_MAP_WAVEEX:
298
299 /* following: https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85) */
300 switch (channels) {
301 case 1:
302 m->map[0] = PA_CHANNEL_POSITION_MONO;
303 return m;
304
305 case 18:
306 m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
307 m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
308 m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
309 /* Fall through */
310
311 case 15:
312 m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
313 m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
314 m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
315 /* Fall through */
316
317 case 12:
318 m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER;
319 /* Fall through */
320
321 case 11:
322 m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT;
323 m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT;
324 /* Fall through */
325
326 case 9:
327 m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER;
328 /* Fall through */
329
330 case 8:
331 m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
332 m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
333 /* Fall through */
334
335 case 6:
336 m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
337 m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
338 /* Fall through */
339
340 case 4:
341 m->map[3] = PA_CHANNEL_POSITION_LFE;
342 /* Fall through */
343
344 case 3:
345 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
346 /* Fall through */
347
348 case 2:
349 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
350 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
351 return m;
352
353 default:
354 return NULL;
355 }
356
357 case PA_CHANNEL_MAP_OSS:
358
359 switch (channels) {
360 case 1:
361 m->map[0] = PA_CHANNEL_POSITION_MONO;
362 return m;
363
364 case 8:
365 m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
366 m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
367 /* Fall through */
368
369 case 6:
370 m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
371 m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
372 /* Fall through */
373
374 case 4:
375 m->map[3] = PA_CHANNEL_POSITION_LFE;
376 /* Fall through */
377
378 case 3:
379 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
380 /* Fall through */
381
382 case 2:
383 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
384 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
385 return m;
386
387 default:
388 return NULL;
389 }
390
391 default:
392 pa_assert_not_reached();
393 }
394 }
395
pa_channel_map_init_extend(pa_channel_map * m,unsigned channels,pa_channel_map_def_t def)396 pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
397 unsigned c;
398
399 pa_assert(m);
400 pa_assert(pa_channels_valid(channels));
401 pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
402
403 pa_channel_map_init(m);
404
405 for (c = channels; c > 0; c--) {
406
407 if (pa_channel_map_init_auto(m, c, def)) {
408 unsigned i = 0;
409
410 for (; c < channels; c++) {
411
412 m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
413 i++;
414 }
415
416 m->channels = (uint8_t) channels;
417
418 return m;
419 }
420 }
421
422 return NULL;
423 }
424
pa_channel_position_to_string(pa_channel_position_t pos)425 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
426
427 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
428 return NULL;
429
430 return table[pos];
431 }
432
pa_channel_position_to_pretty_string(pa_channel_position_t pos)433 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
434
435 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
436 return NULL;
437
438 pa_init_i18n();
439
440 return _(pretty_table[pos]);
441 }
442
pa_channel_map_equal(const pa_channel_map * a,const pa_channel_map * b)443 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
444 unsigned c;
445
446 pa_assert(a);
447 pa_assert(b);
448
449 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
450
451 if (PA_UNLIKELY(a == b))
452 return 1;
453
454 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
455
456 if (a->channels != b->channels)
457 return 0;
458
459 for (c = 0; c < a->channels; c++)
460 if (a->map[c] != b->map[c])
461 return 0;
462
463 return 1;
464 }
465
pa_channel_map_snprint(char * s,size_t l,const pa_channel_map * map)466 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
467 unsigned channel;
468 bool first = true;
469 char *e;
470
471 pa_assert(s);
472 pa_assert(l > 0);
473 pa_assert(map);
474
475 pa_init_i18n();
476
477 if (!pa_channel_map_valid(map)) {
478 pa_snprintf(s, l, _("(invalid)"));
479 return s;
480 }
481
482 *(e = s) = 0;
483
484 for (channel = 0; channel < map->channels && l > 1; channel++) {
485 l -= pa_snprintf(e, l, "%s%s",
486 first ? "" : ",",
487 pa_channel_position_to_string(map->map[channel]));
488
489 e = strchr(e, 0);
490 first = false;
491 }
492
493 return s;
494 }
495
pa_channel_position_from_string(const char * p)496 pa_channel_position_t pa_channel_position_from_string(const char *p) {
497 pa_channel_position_t i;
498 pa_assert(p);
499
500 /* Some special aliases */
501 if (pa_streq(p, "left"))
502 return PA_CHANNEL_POSITION_LEFT;
503 else if (pa_streq(p, "right"))
504 return PA_CHANNEL_POSITION_RIGHT;
505 else if (pa_streq(p, "center"))
506 return PA_CHANNEL_POSITION_CENTER;
507 else if (pa_streq(p, "subwoofer"))
508 return PA_CHANNEL_POSITION_SUBWOOFER;
509
510 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
511 if (pa_streq(p, table[i]))
512 return i;
513
514 return PA_CHANNEL_POSITION_INVALID;
515 }
516
pa_channel_map_parse(pa_channel_map * rmap,const char * s)517 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
518 const char *state;
519 pa_channel_map map;
520 char *p;
521
522 pa_assert(rmap);
523 pa_assert(s);
524
525 pa_channel_map_init(&map);
526
527 /* We don't need to match against the well known channel mapping
528 * "mono" here explicitly, because that can be understood as
529 * listing with one channel called "mono". */
530
531 if (pa_streq(s, "stereo")) {
532 map.channels = 2;
533 map.map[0] = PA_CHANNEL_POSITION_LEFT;
534 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
535 goto finish;
536 } else if (pa_streq(s, "surround-21")) {
537 map.channels = 3;
538 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
539 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
540 map.map[2] = PA_CHANNEL_POSITION_LFE;
541 goto finish;
542 } else if (pa_streq(s, "surround-40")) {
543 map.channels = 4;
544 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
545 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
546 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
547 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
548 goto finish;
549 } else if (pa_streq(s, "surround-41")) {
550 map.channels = 5;
551 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
552 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
553 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
554 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
555 map.map[4] = PA_CHANNEL_POSITION_LFE;
556 goto finish;
557 } else if (pa_streq(s, "surround-50")) {
558 map.channels = 5;
559 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
560 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
561 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
562 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
563 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
564 goto finish;
565 } else if (pa_streq(s, "surround-51")) {
566 map.channels = 6;
567 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
568 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
569 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
570 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
571 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
572 map.map[5] = PA_CHANNEL_POSITION_LFE;
573 goto finish;
574 } else if (pa_streq(s, "surround-71")) {
575 map.channels = 8;
576 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
577 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
578 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
579 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
580 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
581 map.map[5] = PA_CHANNEL_POSITION_LFE;
582 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
583 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
584 goto finish;
585 }
586
587 state = NULL;
588 map.channels = 0;
589
590 while ((p = pa_split(s, ",", &state))) {
591 pa_channel_position_t f;
592
593 if (map.channels >= PA_CHANNELS_MAX) {
594 pa_xfree(p);
595 return NULL;
596 }
597
598 if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
599 pa_xfree(p);
600 return NULL;
601 }
602
603 map.map[map.channels++] = f;
604 pa_xfree(p);
605 }
606
607 finish:
608
609 if (!pa_channel_map_valid(&map))
610 return NULL;
611
612 *rmap = map;
613 return rmap;
614 }
615
pa_channel_map_valid(const pa_channel_map * map)616 int pa_channel_map_valid(const pa_channel_map *map) {
617 unsigned c;
618
619 pa_assert(map);
620
621 if (!pa_channels_valid(map->channels))
622 return 0;
623
624 for (c = 0; c < map->channels; c++)
625 if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
626 return 0;
627
628 return 1;
629 }
630
pa_channel_map_compatible(const pa_channel_map * map,const pa_sample_spec * ss)631 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
632 pa_assert(map);
633 pa_assert(ss);
634
635 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
636 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
637
638 return map->channels == ss->channels;
639 }
640
pa_channel_map_superset(const pa_channel_map * a,const pa_channel_map * b)641 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
642 pa_channel_position_mask_t am, bm;
643
644 pa_assert(a);
645 pa_assert(b);
646
647 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
648
649 if (PA_UNLIKELY(a == b))
650 return 1;
651
652 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
653
654 am = pa_channel_map_mask(a);
655 bm = pa_channel_map_mask(b);
656
657 return (bm & am) == bm;
658 }
659
pa_channel_map_can_balance(const pa_channel_map * map)660 int pa_channel_map_can_balance(const pa_channel_map *map) {
661 pa_channel_position_mask_t m;
662
663 pa_assert(map);
664 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
665
666 m = pa_channel_map_mask(map);
667
668 return
669 (PA_CHANNEL_POSITION_MASK_LEFT & m) &&
670 (PA_CHANNEL_POSITION_MASK_RIGHT & m);
671 }
672
pa_channel_map_can_fade(const pa_channel_map * map)673 int pa_channel_map_can_fade(const pa_channel_map *map) {
674 pa_channel_position_mask_t m;
675
676 pa_assert(map);
677 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
678
679 m = pa_channel_map_mask(map);
680
681 return
682 (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
683 (PA_CHANNEL_POSITION_MASK_REAR & m);
684 }
685
pa_channel_map_can_lfe_balance(const pa_channel_map * map)686 int pa_channel_map_can_lfe_balance(const pa_channel_map *map) {
687 pa_channel_position_mask_t m;
688
689 pa_assert(map);
690 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
691
692 m = pa_channel_map_mask(map);
693
694 return
695 (PA_CHANNEL_POSITION_MASK_LFE & m) &&
696 (PA_CHANNEL_POSITION_MASK_HFE & m);
697 }
698
pa_channel_map_to_name(const pa_channel_map * map)699 const char* pa_channel_map_to_name(const pa_channel_map *map) {
700 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
701 unsigned c;
702
703 pa_assert(map);
704
705 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
706
707 memset(in_map, 0, sizeof(in_map));
708
709 for (c = 0; c < map->channels; c++)
710 pa_bitset_set(in_map, map->map[c], true);
711
712 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
713 PA_CHANNEL_POSITION_MONO, -1))
714 return "mono";
715
716 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
717 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
718 return "stereo";
719
720 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
721 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
722 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
723 return "surround-40";
724
725 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
726 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
727 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
728 PA_CHANNEL_POSITION_LFE, -1))
729 return "surround-41";
730
731 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
732 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
733 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
734 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
735 return "surround-50";
736
737 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
738 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
739 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
740 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
741 return "surround-51";
742
743 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
744 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
745 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
746 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
747 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
748 return "surround-71";
749
750 return NULL;
751 }
752
pa_channel_map_to_pretty_name(const pa_channel_map * map)753 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
754 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
755 unsigned c;
756
757 pa_assert(map);
758
759 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
760
761 memset(in_map, 0, sizeof(in_map));
762
763 for (c = 0; c < map->channels; c++)
764 pa_bitset_set(in_map, map->map[c], true);
765
766 pa_init_i18n();
767
768 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
769 PA_CHANNEL_POSITION_MONO, -1))
770 return _("Mono");
771
772 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
773 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
774 return _("Stereo");
775
776 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
777 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
778 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
779 return _("Surround 4.0");
780
781 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
782 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
783 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
784 PA_CHANNEL_POSITION_LFE, -1))
785 return _("Surround 4.1");
786
787 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
788 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
789 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
790 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
791 return _("Surround 5.0");
792
793 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
794 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
795 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
796 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
797 return _("Surround 5.1");
798
799 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
800 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
801 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
802 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
803 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
804 return _("Surround 7.1");
805
806 return NULL;
807 }
808
pa_channel_map_has_position(const pa_channel_map * map,pa_channel_position_t p)809 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
810 unsigned c;
811
812 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
813 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
814
815 for (c = 0; c < map->channels; c++)
816 if (map->map[c] == p)
817 return 1;
818
819 return 0;
820 }
821
pa_channel_map_mask(const pa_channel_map * map)822 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
823 unsigned c;
824 pa_channel_position_mask_t r = 0;
825
826 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
827
828 for (c = 0; c < map->channels; c++)
829 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
830
831 return r;
832 }
833