]> code.delx.au - pulseaudio/blob - src/pulse/channelmap.c
channelmap: Add 2.1 surround
[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-21")) {
540 map.channels = 3;
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_LFE;
544 goto finish;
545 } else if (pa_streq(s, "surround-40")) {
546 map.channels = 4;
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 goto finish;
552 } else if (pa_streq(s, "surround-41")) {
553 map.channels = 5;
554 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
555 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
556 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
557 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
558 map.map[4] = PA_CHANNEL_POSITION_LFE;
559 goto finish;
560 } else if (pa_streq(s, "surround-50")) {
561 map.channels = 5;
562 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
563 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
564 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
565 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
566 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
567 goto finish;
568 } else if (pa_streq(s, "surround-51")) {
569 map.channels = 6;
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 goto finish;
577 } else if (pa_streq(s, "surround-71")) {
578 map.channels = 8;
579 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
580 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
581 map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
582 map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
583 map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
584 map.map[5] = PA_CHANNEL_POSITION_LFE;
585 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
586 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
587 goto finish;
588 }
589
590 state = NULL;
591 map.channels = 0;
592
593 while ((p = pa_split(s, ",", &state))) {
594 pa_channel_position_t f;
595
596 if (map.channels >= PA_CHANNELS_MAX) {
597 pa_xfree(p);
598 return NULL;
599 }
600
601 if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
602 pa_xfree(p);
603 return NULL;
604 }
605
606 map.map[map.channels++] = f;
607 pa_xfree(p);
608 }
609
610 finish:
611
612 if (!pa_channel_map_valid(&map))
613 return NULL;
614
615 *rmap = map;
616 return rmap;
617 }
618
619 int pa_channel_map_valid(const pa_channel_map *map) {
620 unsigned c;
621
622 pa_assert(map);
623
624 if (!pa_channels_valid(map->channels))
625 return 0;
626
627 for (c = 0; c < map->channels; c++)
628 if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
629 return 0;
630
631 return 1;
632 }
633
634 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
635 pa_assert(map);
636 pa_assert(ss);
637
638 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
639 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
640
641 return map->channels == ss->channels;
642 }
643
644 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
645 pa_channel_position_mask_t am, bm;
646
647 pa_assert(a);
648 pa_assert(b);
649
650 pa_return_val_if_fail(pa_channel_map_valid(a), 0);
651
652 if (PA_UNLIKELY(a == b))
653 return 1;
654
655 pa_return_val_if_fail(pa_channel_map_valid(b), 0);
656
657 am = pa_channel_map_mask(a);
658 bm = pa_channel_map_mask(b);
659
660 return (bm & am) == bm;
661 }
662
663 int pa_channel_map_can_balance(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_LEFT & m) &&
673 (PA_CHANNEL_POSITION_MASK_RIGHT & m);
674 }
675
676 int pa_channel_map_can_fade(const pa_channel_map *map) {
677 pa_channel_position_mask_t m;
678
679 pa_assert(map);
680 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
681
682 m = pa_channel_map_mask(map);
683
684 return
685 (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
686 (PA_CHANNEL_POSITION_MASK_REAR & m);
687 }
688
689 const char* pa_channel_map_to_name(const pa_channel_map *map) {
690 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
691 unsigned c;
692
693 pa_assert(map);
694
695 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
696
697 memset(in_map, 0, sizeof(in_map));
698
699 for (c = 0; c < map->channels; c++)
700 pa_bitset_set(in_map, map->map[c], true);
701
702 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
703 PA_CHANNEL_POSITION_MONO, -1))
704 return "mono";
705
706 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
707 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
708 return "stereo";
709
710 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
711 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
712 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
713 return "surround-40";
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_LFE, -1))
719 return "surround-41";
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, -1))
725 return "surround-50";
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, -1))
731 return "surround-51";
732
733 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
734 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
735 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
736 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
737 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
738 return "surround-71";
739
740 return NULL;
741 }
742
743 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
744 pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
745 unsigned c;
746
747 pa_assert(map);
748
749 pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
750
751 memset(in_map, 0, sizeof(in_map));
752
753 for (c = 0; c < map->channels; c++)
754 pa_bitset_set(in_map, map->map[c], true);
755
756 pa_init_i18n();
757
758 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
759 PA_CHANNEL_POSITION_MONO, -1))
760 return _("Mono");
761
762 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
763 PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
764 return _("Stereo");
765
766 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
767 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
768 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
769 return _("Surround 4.0");
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_LFE, -1))
775 return _("Surround 4.1");
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, -1))
781 return _("Surround 5.0");
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, -1))
787 return _("Surround 5.1");
788
789 if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
790 PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
791 PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
792 PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
793 PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
794 return _("Surround 7.1");
795
796 return NULL;
797 }
798
799 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
800 unsigned c;
801
802 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
803 pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
804
805 for (c = 0; c < map->channels; c++)
806 if (map->map[c] == p)
807 return 1;
808
809 return 0;
810 }
811
812 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
813 unsigned c;
814 pa_channel_position_mask_t r = 0;
815
816 pa_return_val_if_fail(pa_channel_map_valid(map), 0);
817
818 for (c = 0; c < map->channels; c++)
819 r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
820
821 return r;
822 }