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