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