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 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 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 http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EKLAC */
300
301 switch (channels) {
302 case 1:
303 m->map[0] = PA_CHANNEL_POSITION_MONO;
304 return m;
305
306 case 18:
307 m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
308 m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
309 m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
310 /* Fall through */
311
312 case 15:
313 m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
314 m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
315 m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
316 /* Fall through */
317
318 case 12:
319 m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER;
320 /* Fall through */
321
322 case 11:
323 m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT;
324 m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT;
325 /* Fall through */
326
327 case 9:
328 m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER;
329 /* Fall through */
330
331 case 8:
332 m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
333 m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
334 /* Fall through */
335
336 case 6:
337 m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
338 m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
339 /* Fall through */
340
341 case 4:
342 m->map[3] = PA_CHANNEL_POSITION_LFE;
343 /* Fall through */
344
345 case 3:
346 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
347 /* Fall through */
348
349 case 2:
350 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
351 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
352 return m;
353
354 default:
355 return NULL;
356 }
357
358 case PA_CHANNEL_MAP_OSS:
359
360 switch (channels) {
361 case 1:
362 m->map[0] = PA_CHANNEL_POSITION_MONO;
363 return m;
364
365 case 8:
366 m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
367 m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
368 /* Fall through */
369
370 case 6:
371 m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
372 m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
373 /* Fall through */
374
375 case 4:
376 m->map[3] = PA_CHANNEL_POSITION_LFE;
377 /* Fall through */
378
379 case 3:
380 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
381 /* Fall through */
382
383 case 2:
384 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
385 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
386 return m;
387
388 default:
389 return NULL;
390 }
391
392 default:
393 pa_assert_not_reached();
394 }
395 }
396
pa_channel_map_init_extend(pa_channel_map * m,unsigned channels,pa_channel_map_def_t def)397 pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
398 unsigned c;
399
400 pa_assert(m);
401 pa_assert(pa_channels_valid(channels));
402 pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
403
404 pa_channel_map_init(m);
405
406 for (c = channels; c > 0; c--) {
407
408 if (pa_channel_map_init_auto(m, c, def)) {
409 unsigned i = 0;
410
411 for (; c < channels; c++) {
412
413 m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
414 i++;
415 }
416
417 m->channels = (uint8_t) channels;
418
419 return m;
420 }
421 }
422
423 return NULL;
424 }
425
pa_channel_position_to_string(pa_channel_position_t pos)426 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
427
428 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
429 return NULL;
430
431 return table[pos];
432 }
433
pa_channel_position_to_pretty_string(pa_channel_position_t pos)434 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
435
436 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
437 return NULL;
438
439 pa_init_i18n();
440
441 return _(pretty_table[pos]);
442 }
443
pa_channel_map_equal(const pa_channel_map * a,const pa_channel_map * b)444 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
445 unsigned c;
446
447 pa_assert(a);
448 pa_assert(b);
449
450 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
451
452 if (PA_UNLIKELY(a == b))
453 return 1;
454
455 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
456
457 if (a->channels != b->channels)
458 return 0;
459
460 for (c = 0; c < a->channels; c++)
461 if (a->map[c] != b->map[c])
462 return 0;
463
464 return 1;
465 }
466
pa_channel_map_snprint(char * s,size_t l,const pa_channel_map * map)467 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
468 unsigned channel;
469 bool first = true;
470 char *e;
471
472 pa_assert(s);
473 pa_assert(l > 0);
474 pa_assert(map);
475
476 pa_init_i18n();
477
478 if (!pa_channel_map_valid(map)) {
479 pa_snprintf(s, l, _("(invalid)"));
480 return s;
481 }
482
483 *(e = s) = 0;
484
485 for (channel = 0; channel < map->channels && l > 1; channel++) {
486 l -= pa_snprintf(e, l, "%s%s",
487 first ? "" : ",",
488 pa_channel_position_to_string(map->map[channel]));
489
490 e = strchr(e, 0);
491 first = false;
492 }
493
494 return s;
495 }
496
pa_channel_position_from_string(const char * p)497 pa_channel_position_t pa_channel_position_from_string(const char *p) {
498 pa_channel_position_t i;
499 pa_assert(p);
500
501 /* Some special aliases */
502 if (pa_streq(p, "left"))
503 return PA_CHANNEL_POSITION_LEFT;
504 else if (pa_streq(p, "right"))
505 return PA_CHANNEL_POSITION_RIGHT;
506 else if (pa_streq(p, "center"))
507 return PA_CHANNEL_POSITION_CENTER;
508 else if (pa_streq(p, "subwoofer"))
509 return PA_CHANNEL_POSITION_SUBWOOFER;
510
511 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
512 if (pa_streq(p, table[i]))
513 return i;
514
515 return PA_CHANNEL_POSITION_INVALID;
516 }
517
pa_channel_map_parse(pa_channel_map * rmap,const char * s)518 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
519 const char *state;
520 pa_channel_map map;
521 char *p;
522
523 pa_assert(rmap);
524 pa_assert(s);
525
526 pa_channel_map_init(&map);
527
528 /* We don't need to match against the well known channel mapping
529 * "mono" here explicitly, because that can be understood as
530 * listing with one channel called "mono". */
531
532 if (pa_streq(s, "stereo")) {
533 map.channels = 2;
534 map.map[0] = PA_CHANNEL_POSITION_LEFT;
535 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
536 goto finish;
537 } else if (pa_streq(s, "surround-21")) {
538 map.channels = 3;
539 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
540 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
541 map.map[2] = PA_CHANNEL_POSITION_LFE;
542 goto finish;
543 } else if (pa_streq(s, "surround-40")) {
544 map.channels = 4;
545 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
546 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
547 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
548 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
549 goto finish;
550 } else if (pa_streq(s, "surround-41")) {
551 map.channels = 5;
552 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
553 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
554 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
555 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
556 map.map[4] = PA_CHANNEL_POSITION_LFE;
557 goto finish;
558 } else if (pa_streq(s, "surround-50")) {
559 map.channels = 5;
560 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
561 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
562 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
563 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
564 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
565 goto finish;
566 } else if (pa_streq(s, "surround-51")) {
567 map.channels = 6;
568 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
569 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
570 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
571 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
572 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
573 map.map[5] = PA_CHANNEL_POSITION_LFE;
574 goto finish;
575 } else if (pa_streq(s, "surround-71")) {
576 map.channels = 8;
577 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
578 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
579 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
580 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
581 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
582 map.map[5] = PA_CHANNEL_POSITION_LFE;
583 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
584 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
585 goto finish;
586 }
587
588 state = NULL;
589 map.channels = 0;
590
591 while ((p = pa_split(s, ",", &state))) {
592 pa_channel_position_t f;
593
594 if (map.channels >= PA_CHANNELS_MAX) {
595 pa_xfree(p);
596 return NULL;
597 }
598
599 if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
600 pa_xfree(p);
601 return NULL;
602 }
603
604 map.map[map.channels++] = f;
605 pa_xfree(p);
606 }
607
608 finish:
609
610 if (!pa_channel_map_valid(&map))
611 return NULL;
612
613 *rmap = map;
614 return rmap;
615 }
616
pa_channel_map_valid(const pa_channel_map * map)617 int pa_channel_map_valid(const pa_channel_map *map) {
618 unsigned c;
619
620 pa_assert(map);
621
622 if (!pa_channels_valid(map->channels))
623 return 0;
624
625 for (c = 0; c < map->channels; c++)
626 if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
627 return 0;
628
629 return 1;
630 }
631
pa_channel_map_compatible(const pa_channel_map * map,const pa_sample_spec * ss)632 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
633 pa_assert(map);
634 pa_assert(ss);
635
636 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
637 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
638
639 return map->channels == ss->channels;
640 }
641
pa_channel_map_superset(const pa_channel_map * a,const pa_channel_map * b)642 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
643 pa_channel_position_mask_t am, bm;
644
645 pa_assert(a);
646 pa_assert(b);
647
648 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
649
650 if (PA_UNLIKELY(a == b))
651 return 1;
652
653 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
654
655 am = pa_channel_map_mask(a);
656 bm = pa_channel_map_mask(b);
657
658 return (bm & am) == bm;
659 }
660
pa_channel_map_can_balance(const pa_channel_map * map)661 int pa_channel_map_can_balance(const pa_channel_map *map) {
662 pa_channel_position_mask_t m;
663
664 pa_assert(map);
665 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
666
667 m = pa_channel_map_mask(map);
668
669 return
670 (PA_CHANNEL_POSITION_MASK_LEFT & m) &&
671 (PA_CHANNEL_POSITION_MASK_RIGHT & m);
672 }
673
pa_channel_map_can_fade(const pa_channel_map * map)674 int pa_channel_map_can_fade(const pa_channel_map *map) {
675 pa_channel_position_mask_t m;
676
677 pa_assert(map);
678 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
679
680 m = pa_channel_map_mask(map);
681
682 return
683 (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
684 (PA_CHANNEL_POSITION_MASK_REAR & m);
685 }
686
pa_channel_map_can_lfe_balance(const pa_channel_map * map)687 int pa_channel_map_can_lfe_balance(const pa_channel_map *map) {
688 pa_channel_position_mask_t m;
689
690 pa_assert(map);
691 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
692
693 m = pa_channel_map_mask(map);
694
695 return
696 (PA_CHANNEL_POSITION_MASK_LFE & m) &&
697 (PA_CHANNEL_POSITION_MASK_HFE & m);
698 }
699
pa_channel_map_to_name(const pa_channel_map * map)700 const char* pa_channel_map_to_name(const pa_channel_map *map) {
701 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
702 unsigned c;
703
704 pa_assert(map);
705
706 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
707
708 memset(in_map, 0, sizeof(in_map));
709
710 for (c = 0; c < map->channels; c++)
711 pa_bitset_set(in_map, map->map[c], true);
712
713 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
714 PA_CHANNEL_POSITION_MONO, -1))
715 return "mono";
716
717 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
718 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
719 return "stereo";
720
721 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
722 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
723 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
724 return "surround-40";
725
726 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
727 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
728 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
729 PA_CHANNEL_POSITION_LFE, -1))
730 return "surround-41";
731
732 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
733 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
734 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
735 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
736 return "surround-50";
737
738 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
739 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
740 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
741 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
742 return "surround-51";
743
744 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
745 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
746 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
747 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
748 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
749 return "surround-71";
750
751 return NULL;
752 }
753
pa_channel_map_to_pretty_name(const pa_channel_map * map)754 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
755 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
756 unsigned c;
757
758 pa_assert(map);
759
760 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
761
762 memset(in_map, 0, sizeof(in_map));
763
764 for (c = 0; c < map->channels; c++)
765 pa_bitset_set(in_map, map->map[c], true);
766
767 pa_init_i18n();
768
769 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
770 PA_CHANNEL_POSITION_MONO, -1))
771 return _("Mono");
772
773 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
774 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
775 return _("Stereo");
776
777 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
778 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
779 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
780 return _("Surround 4.0");
781
782 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
783 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
784 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
785 PA_CHANNEL_POSITION_LFE, -1))
786 return _("Surround 4.1");
787
788 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
789 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
790 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
791 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
792 return _("Surround 5.0");
793
794 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
795 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
796 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
797 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
798 return _("Surround 5.1");
799
800 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
801 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
802 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
803 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
804 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
805 return _("Surround 7.1");
806
807 return NULL;
808 }
809
pa_channel_map_has_position(const pa_channel_map * map,pa_channel_position_t p)810 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
811 unsigned c;
812
813 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
814 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
815
816 for (c = 0; c < map->channels; c++)
817 if (map->map[c] == p)
818 return 1;
819
820 return 0;
821 }
822
pa_channel_map_mask(const pa_channel_map * map)823 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
824 unsigned c;
825 pa_channel_position_mask_t r = 0;
826
827 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
828
829 for (c = 0; c < map->channels; c++)
830 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
831
832 return r;
833 }
834