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