Git init
[framework/multimedia/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_FRONT_LEFT_OF_CENTER;
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_FRONT_RIGHT_OF_CENTER;
226                     m->map[5] = PA_CHANNEL_POSITION_REAR_CENTER;
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_REAR_CENTER;
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             /* Following http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EKLAC */
303
304             switch (channels) {
305                 case 1:
306                     m->map[0] = PA_CHANNEL_POSITION_MONO;
307                     return m;
308
309                 case 18:
310                     m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
311                     m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
312                     m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
313                     /* Fall through */
314
315                 case 15:
316                     m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
317                     m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
318                     m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
319                     /* Fall through */
320
321                 case 12:
322                     m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER;
323                     /* Fall through */
324
325                 case 11:
326                     m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT;
327                     m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT;
328                     /* Fall through */
329
330                 case 9:
331                     m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER;
332                     /* Fall through */
333
334                 case 8:
335                     m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
336                     m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
337                     /* Fall through */
338
339                 case 6:
340                     m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
341                     m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
342                     /* Fall through */
343
344                 case 4:
345                     m->map[3] = PA_CHANNEL_POSITION_LFE;
346                     /* Fall through */
347
348                 case 3:
349                     m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
350                     /* Fall through */
351
352                 case 2:
353                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
354                     m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
355                     return m;
356
357                 default:
358                     return NULL;
359             }
360
361         case PA_CHANNEL_MAP_OSS:
362
363             switch (channels) {
364                 case 1:
365                     m->map[0] = PA_CHANNEL_POSITION_MONO;
366                     return m;
367
368                 case 8:
369                     m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
370                     m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
371                     /* Fall through */
372
373                 case 6:
374                     m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
375                     m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
376                     /* Fall through */
377
378                 case 4:
379                     m->map[3] = PA_CHANNEL_POSITION_LFE;
380                     /* Fall through */
381
382                 case 3:
383                     m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
384                     /* Fall through */
385
386                 case 2:
387                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
388                     m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
389                     return m;
390
391                 default:
392                     return NULL;
393             }
394
395
396         default:
397             pa_assert_not_reached();
398     }
399 }
400
401 pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
402     unsigned c;
403
404     pa_assert(m);
405     pa_assert(channels > 0);
406     pa_assert(channels <= PA_CHANNELS_MAX);
407     pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
408
409     pa_channel_map_init(m);
410
411     for (c = channels; c > 0; c--) {
412
413         if (pa_channel_map_init_auto(m, c, def)) {
414             unsigned i = 0;
415
416             for (; c < channels; c++) {
417
418                 m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
419                 i++;
420             }
421
422             m->channels = (uint8_t) channels;
423
424             return m;
425         }
426     }
427
428     return NULL;
429 }
430
431 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
432
433     if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
434         return NULL;
435
436     return table[pos];
437 }
438
439 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
440
441     if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
442         return NULL;
443
444     pa_init_i18n();
445
446     return _(pretty_table[pos]);
447 }
448
449 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
450     unsigned c;
451
452     pa_assert(a);
453     pa_assert(b);
454
455     pa_return_val_if_fail(pa_channel_map_valid(a), 0);
456
457     if (PA_UNLIKELY(a == b))
458         return 1;
459
460     pa_return_val_if_fail(pa_channel_map_valid(b), 0);
461
462     if (a->channels != b->channels)
463         return 0;
464
465     for (c = 0; c < a->channels; c++)
466         if (a->map[c] != b->map[c])
467             return 0;
468
469     return 1;
470 }
471
472 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
473     unsigned channel;
474     pa_bool_t first = TRUE;
475     char *e;
476
477     pa_assert(s);
478     pa_assert(l > 0);
479     pa_assert(map);
480
481     pa_init_i18n();
482
483     if (!pa_channel_map_valid(map)) {
484         pa_snprintf(s, l, _("(invalid)"));
485         return s;
486     }
487
488     *(e = s) = 0;
489
490     for (channel = 0; channel < map->channels && l > 1; channel++) {
491         l -= pa_snprintf(e, l, "%s%s",
492                       first ? "" : ",",
493                       pa_channel_position_to_string(map->map[channel]));
494
495         e = strchr(e, 0);
496         first = FALSE;
497     }
498
499     return s;
500 }
501
502 pa_channel_position_t pa_channel_position_from_string(const char *p) {
503     pa_channel_position_t i;
504     pa_assert(p);
505
506     /* Some special aliases */
507     if (pa_streq(p, "left"))
508         return PA_CHANNEL_POSITION_LEFT;
509     else if (pa_streq(p, "right"))
510         return PA_CHANNEL_POSITION_RIGHT;
511     else if (pa_streq(p, "center"))
512         return PA_CHANNEL_POSITION_CENTER;
513     else if (pa_streq(p, "subwoofer"))
514         return PA_CHANNEL_POSITION_SUBWOOFER;
515
516     for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
517         if (pa_streq(p, table[i]))
518             return i;
519
520     return PA_CHANNEL_POSITION_INVALID;
521 }
522
523 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
524     const char *state;
525     pa_channel_map map;
526     char *p;
527
528     pa_assert(rmap);
529     pa_assert(s);
530
531     pa_channel_map_init(&map);
532
533     /* We don't need to match against the well known channel mapping
534      * "mono" here explicitly, because that can be understood as
535      * listing with one channel called "mono". */
536
537     if (pa_streq(s, "stereo")) {
538         map.channels = 2;
539         map.map[0] = PA_CHANNEL_POSITION_LEFT;
540         map.map[1] = PA_CHANNEL_POSITION_RIGHT;
541         goto finish;
542     } else if (pa_streq(s, "surround-40")) {
543         map.channels = 4;
544         map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
545         map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
546         map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
547         map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
548         goto finish;
549     } else if (pa_streq(s, "surround-41")) {
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_LFE;
556         goto finish;
557     } else if (pa_streq(s, "surround-50")) {
558         map.channels = 5;
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         goto finish;
565     } else if (pa_streq(s, "surround-51")) {
566         map.channels = 6;
567         map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
568         map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
569         map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
570         map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
571         map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
572         map.map[5] = PA_CHANNEL_POSITION_LFE;
573         goto finish;
574     } else if (pa_streq(s, "surround-71")) {
575         map.channels = 8;
576         map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
577         map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
578         map.map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
579         map.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
580         map.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
581         map.map[5] = PA_CHANNEL_POSITION_LFE;
582         map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
583         map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
584         goto finish;
585     }
586
587     state = NULL;
588     map.channels = 0;
589
590     while ((p = pa_split(s, ",", &state))) {
591         pa_channel_position_t f;
592
593         if (map.channels >= PA_CHANNELS_MAX) {
594             pa_xfree(p);
595             return NULL;
596         }
597
598         if ((f = pa_channel_position_from_string(p)) == PA_CHANNEL_POSITION_INVALID) {
599             pa_xfree(p);
600             return NULL;
601         }
602
603         map.map[map.channels++] = f;
604         pa_xfree(p);
605     }
606
607 finish:
608
609     if (!pa_channel_map_valid(&map))
610         return NULL;
611
612     *rmap = map;
613     return rmap;
614 }
615
616 int pa_channel_map_valid(const pa_channel_map *map) {
617     unsigned c;
618
619     pa_assert(map);
620
621     if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
622         return 0;
623
624     for (c = 0; c < map->channels; c++)
625         if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
626             return 0;
627
628     return 1;
629 }
630
631 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
632     pa_assert(map);
633     pa_assert(ss);
634
635     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
636     pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
637
638     return map->channels == ss->channels;
639 }
640
641 int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) {
642     pa_channel_position_mask_t am, bm;
643
644     pa_assert(a);
645     pa_assert(b);
646
647     pa_return_val_if_fail(pa_channel_map_valid(a), 0);
648
649     if (PA_UNLIKELY(a == b))
650         return 1;
651
652     pa_return_val_if_fail(pa_channel_map_valid(b), 0);
653
654     am = pa_channel_map_mask(a);
655     bm = pa_channel_map_mask(b);
656
657     return (bm & am) == bm;
658 }
659
660 int pa_channel_map_can_balance(const pa_channel_map *map) {
661     pa_channel_position_mask_t m;
662
663     pa_assert(map);
664     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
665
666     m = pa_channel_map_mask(map);
667
668     return
669         (PA_CHANNEL_POSITION_MASK_LEFT & m) &&
670         (PA_CHANNEL_POSITION_MASK_RIGHT & m);
671 }
672
673 int pa_channel_map_can_fade(const pa_channel_map *map) {
674     pa_channel_position_mask_t m;
675
676     pa_assert(map);
677     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
678
679     m = pa_channel_map_mask(map);
680
681     return
682         (PA_CHANNEL_POSITION_MASK_FRONT & m) &&
683         (PA_CHANNEL_POSITION_MASK_REAR & m);
684 }
685
686 const char* pa_channel_map_to_name(const pa_channel_map *map) {
687     pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
688     unsigned c;
689
690     pa_assert(map);
691
692     pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
693
694     memset(in_map, 0, sizeof(in_map));
695
696     for (c = 0; c < map->channels; c++)
697         pa_bitset_set(in_map, map->map[c], TRUE);
698
699     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
700                          PA_CHANNEL_POSITION_MONO, -1))
701         return "mono";
702
703     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
704                          PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
705         return "stereo";
706
707     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
708                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
709                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
710         return "surround-40";
711
712     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
713                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
714                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
715                          PA_CHANNEL_POSITION_LFE, -1))
716         return "surround-41";
717
718     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
719                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
720                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
721                          PA_CHANNEL_POSITION_FRONT_CENTER, -1))
722         return "surround-50";
723
724     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
725                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
726                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
727                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
728         return "surround-51";
729
730     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
731                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
732                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
733                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
734                          PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
735         return "surround-71";
736
737     return NULL;
738 }
739
740 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
741     pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
742     unsigned c;
743
744     pa_assert(map);
745
746     pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
747
748     memset(in_map, 0, sizeof(in_map));
749
750     for (c = 0; c < map->channels; c++)
751         pa_bitset_set(in_map, map->map[c], TRUE);
752
753     pa_init_i18n();
754
755     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
756                          PA_CHANNEL_POSITION_MONO, -1))
757         return _("Mono");
758
759     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
760                          PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
761         return _("Stereo");
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, -1))
766         return _("Surround 4.0");
767
768     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
769                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
770                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
771                          PA_CHANNEL_POSITION_LFE, -1))
772         return _("Surround 4.1");
773
774     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
775                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
776                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
777                          PA_CHANNEL_POSITION_FRONT_CENTER, -1))
778         return _("Surround 5.0");
779
780     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
781                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
782                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
783                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
784         return _("Surround 5.1");
785
786     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
787                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
788                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
789                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
790                          PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
791         return _("Surround 7.1");
792
793     return NULL;
794 }
795
796 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
797     unsigned c;
798
799     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
800     pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
801
802     for (c = 0; c < map->channels; c++)
803         if (map->map[c] == p)
804             return 1;
805
806     return 0;
807 }
808
809 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
810     unsigned c;
811     pa_channel_position_mask_t r = 0;
812
813     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
814
815     for (c = 0; c < map->channels; c++)
816         r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
817
818     return r;
819 }