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