]> code.delx.au - pulseaudio/blob - src/pulse/channelmap.c
72e4130eeffcae0afee44f02cf4e93c6bf2bf3f9
[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(pa_channels_valid(channels));
203 pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
204
205 pa_channel_map_init(m);
206
207 m->channels = (uint8_t) channels;
208
209 switch (def) {
210 case PA_CHANNEL_MAP_AIFF:
211
212 /* This is somewhat compatible with RFC3551 */
213
214 switch (channels) {
215 case 1:
216 m->map[0] = PA_CHANNEL_POSITION_MONO;
217 return m;
218
219 case 6:
220 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
221 m->map[1] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
222 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
223 m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT;
224 m->map[4] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
225 m->map[5] = PA_CHANNEL_POSITION_REAR_CENTER;
226 return m;
227
228 case 5:
229 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
230 m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT;
231 m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT;
232 /* Fall through */
233
234 case 2:
235 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
236 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
237 return m;
238
239 case 3:
240 m->map[0] = PA_CHANNEL_POSITION_LEFT;
241 m->map[1] = PA_CHANNEL_POSITION_RIGHT;
242 m->map[2] = PA_CHANNEL_POSITION_CENTER;
243 return m;
244
245 case 4:
246 m->map[0] = PA_CHANNEL_POSITION_LEFT;
247 m->map[1] = PA_CHANNEL_POSITION_CENTER;
248 m->map[2] = PA_CHANNEL_POSITION_RIGHT;
249 m->map[3] = PA_CHANNEL_POSITION_REAR_CENTER;
250 return m;
251
252 default:
253 return NULL;
254 }
255
256 case PA_CHANNEL_MAP_ALSA:
257
258 switch (channels) {
259 case 1:
260 m->map[0] = PA_CHANNEL_POSITION_MONO;
261 return m;
262
263 case 8:
264 m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
265 m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
266 /* Fall through */
267
268 case 6:
269 m->map[5] = PA_CHANNEL_POSITION_LFE;
270 /* Fall through */
271
272 case 5:
273 m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
274 /* Fall through */
275
276 case 4:
277 m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
278 m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
279 /* Fall through */
280
281 case 2:
282 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
283 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
284 return m;
285
286 default:
287 return NULL;
288 }
289
290 case PA_CHANNEL_MAP_AUX: {
291 unsigned i;
292
293 for (i = 0; i < channels; i++)
294 m->map[i] = PA_CHANNEL_POSITION_AUX0 + i;
295
296 return m;
297 }
298
299 case PA_CHANNEL_MAP_WAVEEX:
300
301 /* Following http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EKLAC */
302
303 switch (channels) {
304 case 1:
305 m->map[0] = PA_CHANNEL_POSITION_MONO;
306 return m;
307
308 case 18:
309 m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
310 m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
311 m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
312 /* Fall through */
313
314 case 15:
315 m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
316 m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
317 m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
318 /* Fall through */
319
320 case 12:
321 m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER;
322 /* Fall through */
323
324 case 11:
325 m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT;
326 m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT;
327 /* Fall through */
328
329 case 9:
330 m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER;
331 /* Fall through */
332
333 case 8:
334 m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
335 m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
336 /* Fall through */
337
338 case 6:
339 m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
340 m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
341 /* Fall through */
342
343 case 4:
344 m->map[3] = PA_CHANNEL_POSITION_LFE;
345 /* Fall through */
346
347 case 3:
348 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
349 /* Fall through */
350
351 case 2:
352 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
353 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
354 return m;
355
356 default:
357 return NULL;
358 }
359
360 case PA_CHANNEL_MAP_OSS:
361
362 switch (channels) {
363 case 1:
364 m->map[0] = PA_CHANNEL_POSITION_MONO;
365 return m;
366
367 case 8:
368 m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
369 m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
370 /* Fall through */
371
372 case 6:
373 m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
374 m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
375 /* Fall through */
376
377 case 4:
378 m->map[3] = PA_CHANNEL_POSITION_LFE;
379 /* Fall through */
380
381 case 3:
382 m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
383 /* Fall through */
384
385 case 2:
386 m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
387 m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
388 return m;
389
390 default:
391 return NULL;
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(pa_channels_valid(channels));
404 pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
405
406 pa_channel_map_init(m);
407
408 for (c = channels; c > 0; c--) {
409
410 if (pa_channel_map_init_auto(m, c, def)) {
411 unsigned i = 0;
412
413 for (; c < channels; c++) {
414
415 m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
416 i++;
417 }
418
419 m->channels = (uint8_t) channels;
420
421 return m;
422 }
423 }
424
425 return NULL;
426 }
427
428 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
429
430 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
431 return NULL;
432
433 return table[pos];
434 }
435
436 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
437
438 if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
439 return NULL;
440
441 pa_init_i18n();
442
443 return _(pretty_table[pos]);
444 }
445
446 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
447 unsigned c;
448
449 pa_assert(a);
450 pa_assert(b);
451
452 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
453
454 if (PA_UNLIKELY(a == b))
455 return 1;
456
457 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
458
459 if (a->channels != b->channels)
460 return 0;
461
462 for (c = 0; c < a->channels; c++)
463 if (a->map[c] != b->map[c])
464 return 0;
465
466 return 1;
467 }
468
469 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
470 unsigned channel;
471 bool first = true;
472 char *e;
473
474 pa_assert(s);
475 pa_assert(l > 0);
476 pa_assert(map);
477
478 pa_init_i18n();
479
480 if (!pa_channel_map_valid(map)) {
481 pa_snprintf(s, l, _("(invalid)"));
482 return s;
483 }
484
485 *(e = s) = 0;
486
487 for (channel = 0; channel < map->channels && l > 1; channel++) {
488 l -= pa_snprintf(e, l, "%s%s",
489 first ? "" : ",",
490 pa_channel_position_to_string(map->map[channel]));
491
492 e = strchr(e, 0);
493 first = false;
494 }
495
496 return s;
497 }
498
499 pa_channel_position_t pa_channel_position_from_string(const char *p) {
500 pa_channel_position_t i;
501 pa_assert(p);
502
503 /* Some special aliases */
504 if (pa_streq(p, "left"))
505 return PA_CHANNEL_POSITION_LEFT;
506 else if (pa_streq(p, "right"))
507 return PA_CHANNEL_POSITION_RIGHT;
508 else if (pa_streq(p, "center"))
509 return PA_CHANNEL_POSITION_CENTER;
510 else if (pa_streq(p, "subwoofer"))
511 return PA_CHANNEL_POSITION_SUBWOOFER;
512
513 for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
514 if (pa_streq(p, table[i]))
515 return i;
516
517 return PA_CHANNEL_POSITION_INVALID;
518 }
519
520 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
521 const char *state;
522 pa_channel_map map;
523 char *p;
524
525 pa_assert(rmap);
526 pa_assert(s);
527
528 pa_channel_map_init(&map);
529
530 /* We don't need to match against the well known channel mapping
531 * "mono" here explicitly, because that can be understood as
532 * listing with one channel called "mono". */
533
534 if (pa_streq(s, "stereo")) {
535 map.channels = 2;
536 map.map[0] = PA_CHANNEL_POSITION_LEFT;
537 map.map[1] = PA_CHANNEL_POSITION_RIGHT;
538 goto finish;
539 } else if (pa_streq(s, "surround-40")) {
540 map.channels = 4;
541 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
542 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
543 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
544 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
545 goto finish;
546 } else if (pa_streq(s, "surround-41")) {
547 map.channels = 5;
548 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
549 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
550 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
551 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
552 map.map[4] = PA_CHANNEL_POSITION_LFE;
553 goto finish;
554 } else if (pa_streq(s, "surround-50")) {
555 map.channels = 5;
556 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
557 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
558 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
559 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
560 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
561 goto finish;
562 } else if (pa_streq(s, "surround-51")) {
563 map.channels = 6;
564 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
565 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
566 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
567 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
568 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
569 map.map[5] = PA_CHANNEL_POSITION_LFE;
570 goto finish;
571 } else if (pa_streq(s, "surround-71")) {
572 map.channels = 8;
573 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
574 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
575 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
576 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
577 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
578 map.map[5] = PA_CHANNEL_POSITION_LFE;
579 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
580 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
581 goto finish;
582 }
583
584 state = NULL;
585 map.channels = 0;
586
587 while ((p = pa_split(s, ",", &state))) {
588 pa_channel_position_t f;
589
590 if (map.channels >= PA_CHANNELS_MAX) {
591 pa_xfree(p);
592 return NULL;
593 }
594
595 if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
596 pa_xfree(p);
597 return NULL;
598 }
599
600 map.map[map.channels++] = f;
601 pa_xfree(p);
602 }
603
604 finish:
605
606 if (!pa_channel_map_valid(&map))
607 return NULL;
608
609 *rmap = map;
610 return rmap;
611 }
612
613 int pa_channel_map_valid(const pa_channel_map *map) {
614 unsigned c;
615
616 pa_assert(map);
617
618 if (!pa_channels_valid(map->channels))
619 return 0;
620
621 for (c = 0; c < map->channels; c++)
622 if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
623 return 0;
624
625 return 1;
626 }
627
628 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
629 pa_assert(map);
630 pa_assert(ss);
631
632 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
633 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
634
635 return map->channels == ss->channels;
636 }
637
638 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
639 pa_channel_position_mask_t am, bm;
640
641 pa_assert(a);
642 pa_assert(b);
643
644 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
645
646 if (PA_UNLIKELY(a == b))
647 return 1;
648
649 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
650
651 am = pa_channel_map_mask(a);
652 bm = pa_channel_map_mask(b);
653
654 return (bm & am) == bm;
655 }
656
657 int pa_channel_map_can_balance(const pa_channel_map *map) {
658 pa_channel_position_mask_t m;
659
660 pa_assert(map);
661 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
662
663 m = pa_channel_map_mask(map);
664
665 return
666 (PA_CHANNEL_POSITION_MASK_LEFT & m) &&
667 (PA_CHANNEL_POSITION_MASK_RIGHT & m);
668 }
669
670 int pa_channel_map_can_fade(const pa_channel_map *map) {
671 pa_channel_position_mask_t m;
672
673 pa_assert(map);
674 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
675
676 m = pa_channel_map_mask(map);
677
678 return
679 (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
680 (PA_CHANNEL_POSITION_MASK_REAR & m);
681 }
682
683 const char* pa_channel_map_to_name(const pa_channel_map *map) {
684 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
685 unsigned c;
686
687 pa_assert(map);
688
689 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
690
691 memset(in_map, 0, sizeof(in_map));
692
693 for (c = 0; c < map->channels; c++)
694 pa_bitset_set(in_map, map->map[c], true);
695
696 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
697 PA_CHANNEL_POSITION_MONO, -1))
698 return "mono";
699
700 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
701 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
702 return "stereo";
703
704 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
705 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
706 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
707 return "surround-40";
708
709 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
710 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
711 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
712 PA_CHANNEL_POSITION_LFE, -1))
713 return "surround-41";
714
715 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
716 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
717 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
718 PA_CHANNEL_POSITION_FRONT_CENTER, -1))
719 return "surround-50";
720
721 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
722 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
723 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
724 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
725 return "surround-51";
726
727 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
728 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
729 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
730 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
731 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
732 return "surround-71";
733
734 return NULL;
735 }
736
737 const char* pa_channel_map_to_pretty_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 pa_init_i18n();
751
752 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
753 PA_CHANNEL_POSITION_MONO, -1))
754 return _("Mono");
755
756 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
757 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
758 return _("Stereo");
759
760 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
761 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
762 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
763 return _("Surround 4.0");
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_LFE, -1))
769 return _("Surround 4.1");
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, -1))
775 return _("Surround 5.0");
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, -1))
781 return _("Surround 5.1");
782
783 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
784 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
785 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
786 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
787 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
788 return _("Surround 7.1");
789
790 return NULL;
791 }
792
793 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
794 unsigned c;
795
796 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
797 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
798
799 for (c = 0; c < map->channels; c++)
800 if (map->map[c] == p)
801 return 1;
802
803 return 0;
804 }
805
806 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
807 unsigned c;
808 pa_channel_position_mask_t r = 0;
809
810 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
811
812 for (c = 0; c < map->channels; c++)
813 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
814
815 return r;
816 }