]> code.delx.au - pulseaudio/blob - src/pulse/channelmap.c
channelmap: implement pa_channel_position_from_string()
[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_position_t pa_channel_position_from_string(const char *p) {
495 pa_channel_position_t i;
496 pa_assert(p);
497
498 /* Some special aliases */
499 if (pa_streq(p, "left"))
500 return PA_CHANNEL_POSITION_LEFT;
501 else if (pa_streq(p, "right"))
502 return PA_CHANNEL_POSITION_RIGHT;
503 else if (pa_streq(p, "center"))
504 return PA_CHANNEL_POSITION_CENTER;
505 else if (pa_streq(p, "subwoofer"))
506 return PA_CHANNEL_POSITION_SUBWOOFER;
507
508 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
509 if (pa_streq(p, table[i]))
510 return i;
511
512 return PA_CHANNEL_POSITION_INVALID;
513 }
514
515 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
516 const char *state;
517 pa_channel_map map;
518 char *p;
519
520 pa_assert(rmap);
521 pa_assert(s);
522
523 pa_channel_map_init(&map);
524
525 /* We don't need to match against the well known channel mapping
526 * "mono" here explicitly, because that can be understood as
527 * listing with one channel called "mono". */
528
529 if (pa_streq(s, "stereo")) {
530 map.channels = 2;
531 map.map[0] = PA_CHANNEL_POSITION_LEFT;
532 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
533 goto finish;
534 } else if (pa_streq(s, "surround-40")) {
535 map.channels = 4;
536 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
537 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
538 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
539 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
540 goto finish;
541 } else if (pa_streq(s, "surround-41")) {
542 map.channels = 5;
543 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
544 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
545 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
546 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
547 map.map[4] = PA_CHANNEL_POSITION_LFE;
548 goto finish;
549 } else if (pa_streq(s, "surround-50")) {
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_FRONT_CENTER;
556 goto finish;
557 } else if (pa_streq(s, "surround-51")) {
558 map.channels = 6;
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 map.map[5] = PA_CHANNEL_POSITION_LFE;
565 goto finish;
566 } else if (pa_streq(s, "surround-71")) {
567 map.channels = 8;
568 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
569 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
570 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
571 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
572 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
573 map.map[5] = PA_CHANNEL_POSITION_LFE;
574 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
575 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
576 goto finish;
577 }
578
579 state = NULL;
580 map.channels = 0;
581
582 while ((p = pa_split(s, ",", &state))) {
583 pa_channel_position_t f;
584
585 if (map.channels >= PA_CHANNELS_MAX) {
586 pa_xfree(p);
587 return NULL;
588 }
589
590 if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
591 pa_xfree(p);
592 return NULL;
593 }
594
595 map.map[map.channels++] = f;
596 pa_xfree(p);
597 }
598
599 finish:
600
601 if (!pa_channel_map_valid(&map))
602 return NULL;
603
604 *rmap = map;
605 return rmap;
606 }
607
608 int pa_channel_map_valid(const pa_channel_map *map) {
609 unsigned c;
610
611 pa_assert(map);
612
613 if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
614 return 0;
615
616 for (c = 0; c < map->channels; c++)
617 if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
618 return 0;
619
620 return 1;
621 }
622
623 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
624 pa_assert(map);
625 pa_assert(ss);
626
627 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
628 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
629
630 return map->channels == ss->channels;
631 }
632
633 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
634 pa_bitset_t in_a[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
635 unsigned i;
636
637 pa_assert(a);
638 pa_assert(b);
639
640 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
641 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
642
643 memset(in_a, 0, sizeof(in_a));
644
645 for (i = 0; i < a->channels; i++)
646 pa_bitset_set(in_a, a->map[i], TRUE);
647
648 for (i = 0; i < b->channels; i++)
649 if (!pa_bitset_get(in_a, b->map[i]))
650 return 0;
651
652 return 1;
653 }
654
655 int pa_channel_map_can_balance(const pa_channel_map *map) {
656 unsigned c;
657 pa_bool_t left = FALSE, right = FALSE;
658
659 pa_assert(map);
660
661 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
662
663 for (c = 0; c < map->channels; c++) {
664
665 switch (map->map[c]) {
666 case PA_CHANNEL_POSITION_LEFT:
667 case PA_CHANNEL_POSITION_REAR_LEFT:
668 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
669 case PA_CHANNEL_POSITION_SIDE_LEFT:
670 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
671 case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
672 left = TRUE;
673 break;
674
675 case PA_CHANNEL_POSITION_RIGHT:
676 case PA_CHANNEL_POSITION_REAR_RIGHT:
677 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
678 case PA_CHANNEL_POSITION_SIDE_RIGHT:
679 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
680 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
681 right = TRUE;
682 break;
683
684 default:
685 ;
686 }
687
688 if (left && right)
689 return 1;
690 }
691
692 return 0;
693 }
694
695 int pa_channel_map_can_fade(const pa_channel_map *map) {
696 unsigned c;
697 pa_bool_t front = FALSE, rear = FALSE;
698
699 pa_assert(map);
700
701 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
702
703 for (c = 0; c < map->channels; c++) {
704
705 switch (map->map[c]) {
706 case PA_CHANNEL_POSITION_FRONT_LEFT:
707 case PA_CHANNEL_POSITION_FRONT_RIGHT:
708 case PA_CHANNEL_POSITION_FRONT_CENTER:
709 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
710 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
711 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
712 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
713 case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
714 front = TRUE;
715 break;
716
717 case PA_CHANNEL_POSITION_REAR_LEFT:
718 case PA_CHANNEL_POSITION_REAR_RIGHT:
719 case PA_CHANNEL_POSITION_REAR_CENTER:
720 case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
721 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
722 case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
723 rear = TRUE;
724 break;
725
726 default:
727 ;
728 }
729
730 if (front && rear)
731 return 1;
732 }
733
734 return 0;
735 }
736
737 const char* pa_channel_map_to_name(const pa_channel_map *map) {
738 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
739 unsigned c;
740
741 pa_assert(map);
742
743 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
744
745 memset(in_map, 0, sizeof(in_map));
746
747 for (c = 0; c < map->channels; c++)
748 pa_bitset_set(in_map, map->map[c], TRUE);
749
750 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
751 PA_CHANNEL_POSITION_MONO, -1))
752 return "mono";
753
754 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
755 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
756 return "stereo";
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, -1))
761 return "surround-40";
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,
766 PA_CHANNEL_POSITION_LFE, -1))
767 return "surround-41";
768
769 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
770 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
771 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
772 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
773 return "surround-50";
774
775 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
776 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
777 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
778 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
779 return "surround-51";
780
781 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
782 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
783 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
784 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
785 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
786 return "surround-71";
787
788 return NULL;
789 }
790
791 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
792 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
793 unsigned c;
794
795 pa_assert(map);
796
797 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
798
799 memset(in_map, 0, sizeof(in_map));
800
801 for (c = 0; c < map->channels; c++)
802 pa_bitset_set(in_map, map->map[c], TRUE);
803
804 pa_init_i18n();
805
806 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
807 PA_CHANNEL_POSITION_MONO, -1))
808 return _("Mono");
809
810 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
811 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
812 return _("Stereo");
813
814 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
815 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
816 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
817 return _("Surround 4.0");
818
819 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
820 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
821 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
822 PA_CHANNEL_POSITION_LFE, -1))
823 return _("Surround 4.1");
824
825 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
826 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
827 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
828 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
829 return _("Surround 5.0");
830
831 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
832 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
833 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
834 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
835 return _("Surround 5.1");
836
837 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
838 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
839 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
840 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
841 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
842 return _("Surround 7.1");
843
844 return NULL;
845 }
846
847 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
848 unsigned c;
849
850 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
851 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
852
853 for (c = 0; c < map->channels; c++)
854 if (map->map[c] == p)
855 return 1;
856
857 return 0;
858 }
859
860 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
861 unsigned c;
862 pa_channel_position_mask_t r = 0;
863
864 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
865
866 for (c = 0; c < map->channels; c++)
867 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
868
869 return r;
870 }