]> code.delx.au - pulseaudio/blob - src/pulse/channelmap.c
0d199f350e446707f60df64ce1ce3ce34b887a84
[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
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
457 if (PA_UNLIKELY(a == b))
458 return 1;
459
460 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
461
462 if (a->channels != b->channels)
463 return 0;
464
465 for (c = 0; c < a->channels; c++)
466 if (a->map[c] != b->map[c])
467 return 0;
468
469 return 1;
470 }
471
472 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
473 unsigned channel;
474 pa_bool_t first = TRUE;
475 char *e;
476
477 pa_assert(s);
478 pa_assert(l > 0);
479 pa_assert(map);
480
481 pa_init_i18n();
482
483 if (!pa_channel_map_valid(map)) {
484 pa_snprintf(s, l, _("(invalid)"));
485 return s;
486 }
487
488 *(e = s) = 0;
489
490 for (channel = 0; channel < map->channels && l > 1; channel++) {
491 l -= pa_snprintf(e, l, "%s%s",
492 first ? "" : ",",
493 pa_channel_position_to_string(map->map[channel]));
494
495 e = strchr(e, 0);
496 first = FALSE;
497 }
498
499 return s;
500 }
501
502 pa_channel_position_t pa_channel_position_from_string(const char *p) {
503 pa_channel_position_t i;
504 pa_assert(p);
505
506 /* Some special aliases */
507 if (pa_streq(p, "left"))
508 return PA_CHANNEL_POSITION_LEFT;
509 else if (pa_streq(p, "right"))
510 return PA_CHANNEL_POSITION_RIGHT;
511 else if (pa_streq(p, "center"))
512 return PA_CHANNEL_POSITION_CENTER;
513 else if (pa_streq(p, "subwoofer"))
514 return PA_CHANNEL_POSITION_SUBWOOFER;
515
516 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
517 if (pa_streq(p, table[i]))
518 return i;
519
520 return PA_CHANNEL_POSITION_INVALID;
521 }
522
523 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
524 const char *state;
525 pa_channel_map map;
526 char *p;
527
528 pa_assert(rmap);
529 pa_assert(s);
530
531 pa_channel_map_init(&map);
532
533 /* We don't need to match against the well known channel mapping
534 * "mono" here explicitly, because that can be understood as
535 * listing with one channel called "mono". */
536
537 if (pa_streq(s, "stereo")) {
538 map.channels = 2;
539 map.map[0] = PA_CHANNEL_POSITION_LEFT;
540 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
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
616 int pa_channel_map_valid(const pa_channel_map *map) {
617 unsigned c;
618
619 pa_assert(map);
620
621 if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
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
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
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
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
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
686 const char* pa_channel_map_to_name(const pa_channel_map *map) {
687 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
688 unsigned c;
689
690 pa_assert(map);
691
692 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
693
694 memset(in_map, 0, sizeof(in_map));
695
696 for (c = 0; c < map->channels; c++)
697 pa_bitset_set(in_map, map->map[c], TRUE);
698
699 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
700 PA_CHANNEL_POSITION_MONO, -1))
701 return "mono";
702
703 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
704 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
705 return "stereo";
706
707 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
708 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
709 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
710 return "surround-40";
711
712 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
713 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
714 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
715 PA_CHANNEL_POSITION_LFE, -1))
716 return "surround-41";
717
718 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
719 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
720 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
721 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
722 return "surround-50";
723
724 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
725 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
726 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
727 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
728 return "surround-51";
729
730 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
731 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
732 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
733 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
734 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
735 return "surround-71";
736
737 return NULL;
738 }
739
740 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
741 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
742 unsigned c;
743
744 pa_assert(map);
745
746 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
747
748 memset(in_map, 0, sizeof(in_map));
749
750 for (c = 0; c < map->channels; c++)
751 pa_bitset_set(in_map, map->map[c], TRUE);
752
753 pa_init_i18n();
754
755 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
756 PA_CHANNEL_POSITION_MONO, -1))
757 return _("Mono");
758
759 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
760 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
761 return _("Stereo");
762
763 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
764 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
765 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
766 return _("Surround 4.0");
767
768 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
769 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
770 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
771 PA_CHANNEL_POSITION_LFE, -1))
772 return _("Surround 4.1");
773
774 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
775 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
776 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
777 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
778 return _("Surround 5.0");
779
780 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
781 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
782 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
783 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
784 return _("Surround 5.1");
785
786 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
787 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
788 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
789 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
790 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
791 return _("Surround 7.1");
792
793 return NULL;
794 }
795
796 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
797 unsigned c;
798
799 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
800 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
801
802 for (c = 0; c < map->channels; c++)
803 if (map->map[c] == p)
804 return 1;
805
806 return 0;
807 }
808
809 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
810 unsigned c;
811 pa_channel_position_mask_t r = 0;
812
813 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
814
815 for (c = 0; c < map->channels; c++)
816 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
817
818 return r;
819 }