• 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 static 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 static 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: https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85) */
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         default:
392             pa_assert_not_reached();
393     }
394 }
395 
pa_channel_map_init_extend(pa_channel_map * m,unsigned channels,pa_channel_map_def_t def)396 pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
397     unsigned c;
398 
399     pa_assert(m);
400     pa_assert(pa_channels_valid(channels));
401     pa_assert(def < PA_CHANNEL_MAP_DEF_MAX);
402 
403     pa_channel_map_init(m);
404 
405     for (c = channels; c > 0; c--) {
406 
407         if (pa_channel_map_init_auto(m, c, def)) {
408             unsigned i = 0;
409 
410             for (; c < channels; c++) {
411 
412                 m->map[c] = PA_CHANNEL_POSITION_AUX0 + i;
413                 i++;
414             }
415 
416             m->channels = (uint8_t) channels;
417 
418             return m;
419         }
420     }
421 
422     return NULL;
423 }
424 
pa_channel_position_to_string(pa_channel_position_t pos)425 const char* pa_channel_position_to_string(pa_channel_position_t pos) {
426 
427     if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
428         return NULL;
429 
430     return table[pos];
431 }
432 
pa_channel_position_to_pretty_string(pa_channel_position_t pos)433 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
434 
435     if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
436         return NULL;
437 
438     pa_init_i18n();
439 
440     return _(pretty_table[pos]);
441 }
442 
pa_channel_map_equal(const pa_channel_map * a,const pa_channel_map * b)443 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
444     unsigned c;
445 
446     pa_assert(a);
447     pa_assert(b);
448 
449     pa_return_val_if_fail(pa_channel_map_valid(a), 0);
450 
451     if (PA_UNLIKELY(a == b))
452         return 1;
453 
454     pa_return_val_if_fail(pa_channel_map_valid(b), 0);
455 
456     if (a->channels != b->channels)
457         return 0;
458 
459     for (c = 0; c < a->channels; c++)
460         if (a->map[c] != b->map[c])
461             return 0;
462 
463     return 1;
464 }
465 
pa_channel_map_snprint(char * s,size_t l,const pa_channel_map * map)466 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
467     unsigned channel;
468     bool first = true;
469     char *e;
470 
471     pa_assert(s);
472     pa_assert(l > 0);
473     pa_assert(map);
474 
475     pa_init_i18n();
476 
477     if (!pa_channel_map_valid(map)) {
478         pa_snprintf(s, l, _("(invalid)"));
479         return s;
480     }
481 
482     *(e = s) = 0;
483 
484     for (channel = 0; channel < map->channels && l > 1; channel++) {
485         l -= pa_snprintf(e, l, "%s%s",
486                       first ? "" : ",",
487                       pa_channel_position_to_string(map->map[channel]));
488 
489         e = strchr(e, 0);
490         first = false;
491     }
492 
493     return s;
494 }
495 
pa_channel_position_from_string(const char * p)496 pa_channel_position_t pa_channel_position_from_string(const char *p) {
497     pa_channel_position_t i;
498     pa_assert(p);
499 
500     /* Some special aliases */
501     if (pa_streq(p, "left"))
502         return PA_CHANNEL_POSITION_LEFT;
503     else if (pa_streq(p, "right"))
504         return PA_CHANNEL_POSITION_RIGHT;
505     else if (pa_streq(p, "center"))
506         return PA_CHANNEL_POSITION_CENTER;
507     else if (pa_streq(p, "subwoofer"))
508         return PA_CHANNEL_POSITION_SUBWOOFER;
509 
510     for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
511         if (pa_streq(p, table[i]))
512             return i;
513 
514     return PA_CHANNEL_POSITION_INVALID;
515 }
516 
pa_channel_map_parse(pa_channel_map * rmap,const char * s)517 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
518     const char *state;
519     pa_channel_map map;
520     char *p;
521 
522     pa_assert(rmap);
523     pa_assert(s);
524 
525     pa_channel_map_init(&map);
526 
527     /* We don't need to match against the well known channel mapping
528      * "mono" here explicitly, because that can be understood as
529      * listing with one channel called "mono". */
530 
531     if (pa_streq(s, "stereo")) {
532         map.channels = 2;
533         map.map[0] = PA_CHANNEL_POSITION_LEFT;
534         map.map[1] = PA_CHANNEL_POSITION_RIGHT;
535         goto finish;
536     } else if (pa_streq(s, "surround-21")) {
537         map.channels = 3;
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_LFE;
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 
pa_channel_map_valid(const pa_channel_map * map)616 int pa_channel_map_valid(const pa_channel_map *map) {
617     unsigned c;
618 
619     pa_assert(map);
620 
621     if (!pa_channels_valid(map->channels))
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 
pa_channel_map_compatible(const pa_channel_map * map,const pa_sample_spec * ss)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 
pa_channel_map_superset(const pa_channel_map * a,const pa_channel_map * b)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 
pa_channel_map_can_balance(const pa_channel_map * map)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 
pa_channel_map_can_fade(const pa_channel_map * map)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 
pa_channel_map_can_lfe_balance(const pa_channel_map * map)686 int pa_channel_map_can_lfe_balance(const pa_channel_map *map) {
687     pa_channel_position_mask_t m;
688 
689     pa_assert(map);
690     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
691 
692     m = pa_channel_map_mask(map);
693 
694     return
695         (PA_CHANNEL_POSITION_MASK_LFE & m) &&
696         (PA_CHANNEL_POSITION_MASK_HFE & m);
697 }
698 
pa_channel_map_to_name(const pa_channel_map * map)699 const char* pa_channel_map_to_name(const pa_channel_map *map) {
700     pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
701     unsigned c;
702 
703     pa_assert(map);
704 
705     pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
706 
707     memset(in_map, 0, sizeof(in_map));
708 
709     for (c = 0; c < map->channels; c++)
710         pa_bitset_set(in_map, map->map[c], true);
711 
712     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
713                          PA_CHANNEL_POSITION_MONO, -1))
714         return "mono";
715 
716     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
717                          PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
718         return "stereo";
719 
720     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
721                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
722                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
723         return "surround-40";
724 
725     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
726                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
727                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
728                          PA_CHANNEL_POSITION_LFE, -1))
729         return "surround-41";
730 
731     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
732                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
733                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
734                          PA_CHANNEL_POSITION_FRONT_CENTER, -1))
735         return "surround-50";
736 
737     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
738                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
739                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
740                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
741         return "surround-51";
742 
743     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
744                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
745                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
746                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
747                          PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
748         return "surround-71";
749 
750     return NULL;
751 }
752 
pa_channel_map_to_pretty_name(const pa_channel_map * map)753 const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) {
754     pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)];
755     unsigned c;
756 
757     pa_assert(map);
758 
759     pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
760 
761     memset(in_map, 0, sizeof(in_map));
762 
763     for (c = 0; c < map->channels; c++)
764         pa_bitset_set(in_map, map->map[c], true);
765 
766     pa_init_i18n();
767 
768     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
769                          PA_CHANNEL_POSITION_MONO, -1))
770         return _("Mono");
771 
772     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
773                          PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1))
774         return _("Stereo");
775 
776     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
777                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
778                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1))
779         return _("Surround 4.0");
780 
781     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
782                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
783                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
784                          PA_CHANNEL_POSITION_LFE, -1))
785         return _("Surround 4.1");
786 
787     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
788                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
789                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
790                          PA_CHANNEL_POSITION_FRONT_CENTER, -1))
791         return _("Surround 5.0");
792 
793     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
794                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
795                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
796                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1))
797         return _("Surround 5.1");
798 
799     if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX,
800                          PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
801                          PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
802                          PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
803                          PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1))
804         return _("Surround 7.1");
805 
806     return NULL;
807 }
808 
pa_channel_map_has_position(const pa_channel_map * map,pa_channel_position_t p)809 int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) {
810     unsigned c;
811 
812     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
813     pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
814 
815     for (c = 0; c < map->channels; c++)
816         if (map->map[c] == p)
817             return 1;
818 
819     return 0;
820 }
821 
pa_channel_map_mask(const pa_channel_map * map)822 pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) {
823     unsigned c;
824     pa_channel_position_mask_t r = 0;
825 
826     pa_return_val_if_fail(pa_channel_map_valid(map), 0);
827 
828     for (c = 0; c < map->channels; c++)
829         r |= PA_CHANNEL_POSITION_MASK(map->map[c]);
830 
831     return r;
832 }
833