]> code.delx.au - pulseaudio/blob - src/pulse/channelmap.c
channelmap: document where the WAVEX channelmap is documented
[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 #include <pulse/i18n.h>
33
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_("Low Frequency Emmiter"),
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
396 default:
397 pa_assert_not_reached();
398 }
399 }
400
401 pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
402 unsigned c;
403
404 pa_assert(m);
405 pa_assert(channels > 0);
406 pa_assert(channels <= PA_CHANNELS_MAX);
407 pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
408
409 pa_channel_map_init(m);
410
411 for (c = channels; c > 0; c--) {
412
413 if (pa_channel_map_init_auto(m, c, def)) {
414 unsigned i = 0;
415
416 for (; c < channels; c++) {
417
418 m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
419 i++;
420 }
421
422 m->channels = (uint8_t) channels;
423
424 return m;
425 }
426 }
427
428 return NULL;
429 }
430
431 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
432
433 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
434 return NULL;
435
436 return table[pos];
437 }
438
439 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
440
441 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
442 return NULL;
443
444 pa_init_i18n();
445
446 return _(pretty_table[pos]);
447 }
448
449 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
450 unsigned c;
451
452 pa_assert(a);
453 pa_assert(b);
454
455 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
456 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
457
458 if (a->channels != b->channels)
459 return 0;
460
461 for (c = 0; c < a->channels; c++)
462 if (a->map[c] != b->map[c])
463 return 0;
464
465 return 1;
466 }
467
468 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
469 unsigned channel;
470 pa_bool_t first = TRUE;
471 char *e;
472
473 pa_assert(s);
474 pa_assert(l > 0);
475 pa_assert(map);
476
477 pa_init_i18n();
478
479 if (!pa_channel_map_valid(map)) {
480 pa_snprintf(s, l, _("(invalid)"));
481 return s;
482 }
483
484 *(e = s) = 0;
485
486 for (channel = 0; channel < map->channels && l > 1; channel++) {
487 l -= pa_snprintf(e, l, "%s%s",
488 first ? "" : ",",
489 pa_channel_position_to_string(map->map[channel]));
490
491 e = strchr(e, 0);
492 first = FALSE;
493 }
494
495 return s;
496 }
497
498 pa_channel_position_t pa_channel_position_from_string(const char *p) {
499 pa_channel_position_t i;
500 pa_assert(p);
501
502 /* Some special aliases */
503 if (pa_streq(p, "left"))
504 return PA_CHANNEL_POSITION_LEFT;
505 else if (pa_streq(p, "right"))
506 return PA_CHANNEL_POSITION_RIGHT;
507 else if (pa_streq(p, "center"))
508 return PA_CHANNEL_POSITION_CENTER;
509 else if (pa_streq(p, "subwoofer"))
510 return PA_CHANNEL_POSITION_SUBWOOFER;
511
512 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
513 if (pa_streq(p, table[i]))
514 return i;
515
516 return PA_CHANNEL_POSITION_INVALID;
517 }
518
519 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
520 const char *state;
521 pa_channel_map map;
522 char *p;
523
524 pa_assert(rmap);
525 pa_assert(s);
526
527 pa_channel_map_init(&map);
528
529 /* We don't need to match against the well known channel mapping
530 * "mono" here explicitly, because that can be understood as
531 * listing with one channel called "mono". */
532
533 if (pa_streq(s, "stereo")) {
534 map.channels = 2;
535 map.map[0] = PA_CHANNEL_POSITION_LEFT;
536 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
537 goto finish;
538 } else if (pa_streq(s, "surround-40")) {
539 map.channels = 4;
540 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
541 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
542 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
543 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
544 goto finish;
545 } else if (pa_streq(s, "surround-41")) {
546 map.channels = 5;
547 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
548 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
549 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
550 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
551 map.map[4] = PA_CHANNEL_POSITION_LFE;
552 goto finish;
553 } else if (pa_streq(s, "surround-50")) {
554 map.channels = 5;
555 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
556 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
557 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
558 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
559 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
560 goto finish;
561 } else if (pa_streq(s, "surround-51")) {
562 map.channels = 6;
563 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
564 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
565 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
566 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
567 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
568 map.map[5] = PA_CHANNEL_POSITION_LFE;
569 goto finish;
570 } else if (pa_streq(s, "surround-71")) {
571 map.channels = 8;
572 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
573 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
574 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
575 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
576 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
577 map.map[5] = PA_CHANNEL_POSITION_LFE;
578 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
579 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
580 goto finish;
581 }
582
583 state = NULL;
584 map.channels = 0;
585
586 while ((p = pa_split(s, ",", &state))) {
587 pa_channel_position_t f;
588
589 if (map.channels >= PA_CHANNELS_MAX) {
590 pa_xfree(p);
591 return NULL;
592 }
593
594 if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
595 pa_xfree(p);
596 return NULL;
597 }
598
599 map.map[map.channels++] = f;
600 pa_xfree(p);
601 }
602
603 finish:
604
605 if (!pa_channel_map_valid(&map))
606 return NULL;
607
608 *rmap = map;
609 return rmap;
610 }
611
612 int pa_channel_map_valid(const pa_channel_map *map) {
613 unsigned c;
614
615 pa_assert(map);
616
617 if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
618 return 0;
619
620 for (c = 0; c < map->channels; c++)
621 if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
622 return 0;
623
624 return 1;
625 }
626
627 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
628 pa_assert(map);
629 pa_assert(ss);
630
631 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
632 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
633
634 return map->channels == ss->channels;
635 }
636
637 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
638 pa_channel_position_mask_t am, bm;
639
640 pa_assert(a);
641 pa_assert(b);
642
643 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
644 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
645
646 am = pa_channel_map_mask(a);
647 bm = pa_channel_map_mask(b);
648
649 return (bm & am) == bm;
650 }
651
652 int pa_channel_map_can_balance(const pa_channel_map *map) {
653 pa_channel_position_mask_t m;
654
655 pa_assert(map);
656 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
657
658 m = pa_channel_map_mask(map);
659
660 return
661 (PA_CHANNEL_POSITION_MASK_LEFT & m) &&
662 (PA_CHANNEL_POSITION_MASK_RIGHT & m);
663 }
664
665 int pa_channel_map_can_fade(const pa_channel_map *map) {
666 pa_channel_position_mask_t m;
667
668 pa_assert(map);
669 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
670
671 m = pa_channel_map_mask(map);
672
673 return
674 (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
675 (PA_CHANNEL_POSITION_MASK_REAR & m);
676 }
677
678 const char* pa_channel_map_to_name(const pa_channel_map *map) {
679 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
680 unsigned c;
681
682 pa_assert(map);
683
684 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
685
686 memset(in_map, 0, sizeof(in_map));
687
688 for (c = 0; c < map->channels; c++)
689 pa_bitset_set(in_map, map->map[c], TRUE);
690
691 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
692 PA_CHANNEL_POSITION_MONO, -1))
693 return "mono";
694
695 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
696 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
697 return "stereo";
698
699 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
700 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
701 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
702 return "surround-40";
703
704 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
705 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
706 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
707 PA_CHANNEL_POSITION_LFE, -1))
708 return "surround-41";
709
710 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
711 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
712 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
713 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
714 return "surround-50";
715
716 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
717 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
718 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
719 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
720 return "surround-51";
721
722 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
723 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
724 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
725 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
726 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
727 return "surround-71";
728
729 return NULL;
730 }
731
732 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
733 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
734 unsigned c;
735
736 pa_assert(map);
737
738 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
739
740 memset(in_map, 0, sizeof(in_map));
741
742 for (c = 0; c < map->channels; c++)
743 pa_bitset_set(in_map, map->map[c], TRUE);
744
745 pa_init_i18n();
746
747 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
748 PA_CHANNEL_POSITION_MONO, -1))
749 return _("Mono");
750
751 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
752 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
753 return _("Stereo");
754
755 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
756 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
757 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
758 return _("Surround 4.0");
759
760 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
761 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
762 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
763 PA_CHANNEL_POSITION_LFE, -1))
764 return _("Surround 4.1");
765
766 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
767 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
768 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
769 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
770 return _("Surround 5.0");
771
772 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
773 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
774 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
775 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
776 return _("Surround 5.1");
777
778 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
779 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
780 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
781 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
782 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
783 return _("Surround 7.1");
784
785 return NULL;
786 }
787
788 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
789 unsigned c;
790
791 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
792 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
793
794 for (c = 0; c < map->channels; c++)
795 if (map->map[c] == p)
796 return 1;
797
798 return 0;
799 }
800
801 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
802 unsigned c;
803 pa_channel_position_mask_t r = 0;
804
805 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
806
807 for (c = 0; c < map->channels; c++)
808 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
809
810 return r;
811 }