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