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