if a volume or channel map is invalid show so when printing it
[profile/ivi/pulseaudio-panda.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 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
36 #include "channelmap.h"
37
38 const char *const table[PA_CHANNEL_POSITION_MAX] = {
39     [PA_CHANNEL_POSITION_MONO] = "mono",
40
41     [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center",
42     [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left",
43     [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right",
44
45     [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center",
46     [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left",
47     [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right",
48
49     [PA_CHANNEL_POSITION_LFE] = "lfe",
50
51     [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center",
52     [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center",
53
54     [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left",
55     [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right",
56
57     [PA_CHANNEL_POSITION_AUX0] = "aux0",
58     [PA_CHANNEL_POSITION_AUX1] = "aux1",
59     [PA_CHANNEL_POSITION_AUX2] = "aux2",
60     [PA_CHANNEL_POSITION_AUX3] = "aux3",
61     [PA_CHANNEL_POSITION_AUX4] = "aux4",
62     [PA_CHANNEL_POSITION_AUX5] = "aux5",
63     [PA_CHANNEL_POSITION_AUX6] = "aux6",
64     [PA_CHANNEL_POSITION_AUX7] = "aux7",
65     [PA_CHANNEL_POSITION_AUX8] = "aux8",
66     [PA_CHANNEL_POSITION_AUX9] = "aux9",
67     [PA_CHANNEL_POSITION_AUX10] = "aux10",
68     [PA_CHANNEL_POSITION_AUX11] = "aux11",
69     [PA_CHANNEL_POSITION_AUX12] = "aux12",
70     [PA_CHANNEL_POSITION_AUX13] = "aux13",
71     [PA_CHANNEL_POSITION_AUX14] = "aux14",
72     [PA_CHANNEL_POSITION_AUX15] = "aux15",
73     [PA_CHANNEL_POSITION_AUX16] = "aux16",
74     [PA_CHANNEL_POSITION_AUX17] = "aux17",
75     [PA_CHANNEL_POSITION_AUX18] = "aux18",
76     [PA_CHANNEL_POSITION_AUX19] = "aux19",
77     [PA_CHANNEL_POSITION_AUX20] = "aux20",
78     [PA_CHANNEL_POSITION_AUX21] = "aux21",
79     [PA_CHANNEL_POSITION_AUX22] = "aux22",
80     [PA_CHANNEL_POSITION_AUX23] = "aux23",
81     [PA_CHANNEL_POSITION_AUX24] = "aux24",
82     [PA_CHANNEL_POSITION_AUX25] = "aux25",
83     [PA_CHANNEL_POSITION_AUX26] = "aux26",
84     [PA_CHANNEL_POSITION_AUX27] = "aux27",
85     [PA_CHANNEL_POSITION_AUX28] = "aux28",
86     [PA_CHANNEL_POSITION_AUX29] = "aux29",
87     [PA_CHANNEL_POSITION_AUX30] = "aux30",
88     [PA_CHANNEL_POSITION_AUX31] = "aux31",
89
90     [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center",
91
92     [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center",
93     [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left",
94     [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right",
95
96     [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center",
97     [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left",
98     [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right"
99 };
100
101 const char *const pretty_table[PA_CHANNEL_POSITION_MAX] = {
102     [PA_CHANNEL_POSITION_MONO] = N_("Mono"),
103
104     [PA_CHANNEL_POSITION_FRONT_CENTER] = N_("Front Center"),
105     [PA_CHANNEL_POSITION_FRONT_LEFT] = N_("Front Left"),
106     [PA_CHANNEL_POSITION_FRONT_RIGHT] = N_("Front Right"),
107
108     [PA_CHANNEL_POSITION_REAR_CENTER] = N_("Rear Center"),
109     [PA_CHANNEL_POSITION_REAR_LEFT] = N_("Rear Left"),
110     [PA_CHANNEL_POSITION_REAR_RIGHT] = N_("Rear Right"),
111
112     [PA_CHANNEL_POSITION_LFE] = N_("Low Frequency Emmiter"),
113
114     [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = N_("Front Left-of-center"),
115     [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = N_("Front Right-of-center"),
116
117     [PA_CHANNEL_POSITION_SIDE_LEFT] = N_("Side Left"),
118     [PA_CHANNEL_POSITION_SIDE_RIGHT] = N_("Side Right"),
119
120     [PA_CHANNEL_POSITION_AUX0] = N_("Auxiliary 0"),
121     [PA_CHANNEL_POSITION_AUX1] = N_("Auxiliary 1"),
122     [PA_CHANNEL_POSITION_AUX2] = N_("Auxiliary 2"),
123     [PA_CHANNEL_POSITION_AUX3] = N_("Auxiliary 3"),
124     [PA_CHANNEL_POSITION_AUX4] = N_("Auxiliary 4"),
125     [PA_CHANNEL_POSITION_AUX5] = N_("Auxiliary 5"),
126     [PA_CHANNEL_POSITION_AUX6] = N_("Auxiliary 6"),
127     [PA_CHANNEL_POSITION_AUX7] = N_("Auxiliary 7"),
128     [PA_CHANNEL_POSITION_AUX8] = N_("Auxiliary 8"),
129     [PA_CHANNEL_POSITION_AUX9] = N_("Auxiliary 9"),
130     [PA_CHANNEL_POSITION_AUX10] = N_("Auxiliary 10"),
131     [PA_CHANNEL_POSITION_AUX11] = N_("Auxiliary 11"),
132     [PA_CHANNEL_POSITION_AUX12] = N_("Auxiliary 12"),
133     [PA_CHANNEL_POSITION_AUX13] = N_("Auxiliary 13"),
134     [PA_CHANNEL_POSITION_AUX14] = N_("Auxiliary 14"),
135     [PA_CHANNEL_POSITION_AUX15] = N_("Auxiliary 15"),
136     [PA_CHANNEL_POSITION_AUX16] = N_("Auxiliary 16"),
137     [PA_CHANNEL_POSITION_AUX17] = N_("Auxiliary 17"),
138     [PA_CHANNEL_POSITION_AUX18] = N_("Auxiliary 18"),
139     [PA_CHANNEL_POSITION_AUX19] = N_("Auxiliary 19"),
140     [PA_CHANNEL_POSITION_AUX20] = N_("Auxiliary 20"),
141     [PA_CHANNEL_POSITION_AUX21] = N_("Auxiliary 21"),
142     [PA_CHANNEL_POSITION_AUX22] = N_("Auxiliary 22"),
143     [PA_CHANNEL_POSITION_AUX23] = N_("Auxiliary 23"),
144     [PA_CHANNEL_POSITION_AUX24] = N_("Auxiliary 24"),
145     [PA_CHANNEL_POSITION_AUX25] = N_("Auxiliary 25"),
146     [PA_CHANNEL_POSITION_AUX26] = N_("Auxiliary 26"),
147     [PA_CHANNEL_POSITION_AUX27] = N_("Auxiliary 27"),
148     [PA_CHANNEL_POSITION_AUX28] = N_("Auxiliary 28"),
149     [PA_CHANNEL_POSITION_AUX29] = N_("Auxiliary 29"),
150     [PA_CHANNEL_POSITION_AUX30] = N_("Auxiliary 30"),
151     [PA_CHANNEL_POSITION_AUX31] = N_("Auxiliary 31"),
152
153     [PA_CHANNEL_POSITION_TOP_CENTER] = N_("Top Center"),
154
155     [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = N_("Top Front Center"),
156     [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = N_("Top Front Left"),
157     [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = N_("Top Front Right"),
158
159     [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = N_("Top Rear Center"),
160     [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = N_("Top Rear Left"),
161     [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = N_("Top Rear Right")
162 };
163
164 pa_channel_map* pa_channel_map_init(pa_channel_map *m) {
165     unsigned c;
166     pa_assert(m);
167
168     m->channels = 0;
169
170     for (c = 0; c < PA_CHANNELS_MAX; c++)
171         m->map[c] = PA_CHANNEL_POSITION_INVALID;
172
173     return m;
174 }
175
176 pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) {
177     pa_assert(m);
178
179     pa_channel_map_init(m);
180
181     m->channels = 1;
182     m->map[0] = PA_CHANNEL_POSITION_MONO;
183     return m;
184 }
185
186 pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) {
187     pa_assert(m);
188
189     pa_channel_map_init(m);
190
191     m->channels = 2;
192     m->map[0] = PA_CHANNEL_POSITION_LEFT;
193     m->map[1] = PA_CHANNEL_POSITION_RIGHT;
194     return m;
195 }
196
197 pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
198     pa_assert(m);
199     pa_assert(channels > 0);
200     pa_assert(channels <= PA_CHANNELS_MAX);
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_SIDE_LEFT;
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_SIDE_RIGHT;
223                     m->map[5] = PA_CHANNEL_POSITION_LFE;
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_LFE;
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             switch (channels) {
300                 case 1:
301                     m->map[0] = PA_CHANNEL_POSITION_MONO;
302                     return m;
303
304                 case 18:
305                     m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
306                     m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
307                     m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
308                     /* Fall through */
309
310                 case 15:
311                     m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
312                     m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
313                     m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
314                     /* Fall through */
315
316                 case 12:
317                     m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER;
318                     /* Fall through */
319
320                 case 11:
321                     m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT;
322                     m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT;
323                     /* Fall through */
324
325                 case 9:
326                     m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER;
327                     /* Fall through */
328
329                 case 8:
330                     m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
331                     m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
332                     /* Fall through */
333
334                 case 6:
335                     m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
336                     m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
337                     /* Fall through */
338
339                 case 4:
340                     m->map[3] = PA_CHANNEL_POSITION_LFE;
341                     /* Fall through */
342
343                 case 3:
344                     m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
345                     /* Fall through */
346
347                 case 2:
348                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
349                     m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
350                     return m;
351
352                 default:
353                     return NULL;
354             }
355
356         case PA_CHANNEL_MAP_OSS:
357
358             switch (channels) {
359                 case 1:
360                     m->map[0] = PA_CHANNEL_POSITION_MONO;
361                     return m;
362
363                 case 8:
364                     m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
365                     m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
366                     /* Fall through */
367
368                 case 6:
369                     m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
370                     m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
371                     /* Fall through */
372
373                 case 4:
374                     m->map[3] = PA_CHANNEL_POSITION_LFE;
375                     /* Fall through */
376
377                 case 3:
378                     m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
379                     /* Fall through */
380
381                 case 2:
382                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
383                     m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
384                     return m;
385
386                 default:
387                     return NULL;
388             }
389
390
391         default:
392             pa_assert_not_reached();
393     }
394 }
395
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(channels > 0);
401     pa_assert(channels <= PA_CHANNELS_MAX);
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
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
434 const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
435
436     pa_init_i18n();
437
438     if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
439         return NULL;
440
441     return _(pretty_table[pos]);
442 }
443
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     if (a->channels != b->channels)
451         return 0;
452
453     for (c = 0; c < a->channels; c++)
454         if (a->map[c] != b->map[c])
455             return 0;
456
457     return 1;
458 }
459
460 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
461     unsigned channel;
462     pa_bool_t first = TRUE;
463     char *e;
464
465     pa_assert(s);
466     pa_assert(l > 0);
467     pa_assert(map);
468
469     pa_init_i18n();
470
471     if (!pa_channel_map_valid(map)) {
472         pa_snprintf(s, l, _("(invalid)"));
473         return s;
474     }
475
476     *(e = s) = 0;
477
478     for (channel = 0; channel < map->channels && l > 1; channel++) {
479         l -= pa_snprintf(e, l, "%s%s",
480                       first ? "" : ",",
481                       pa_channel_position_to_string(map->map[channel]));
482
483         e = strchr(e, 0);
484         first = FALSE;
485     }
486
487     return s;
488 }
489
490 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
491     const char *state;
492     pa_channel_map map;
493     char *p;
494
495     pa_assert(rmap);
496     pa_assert(s);
497
498     pa_channel_map_init(&map);
499
500     if (strcmp(s, "stereo") == 0) {
501         map.channels = 2;
502         map.map[0] = PA_CHANNEL_POSITION_LEFT;
503         map.map[1] = PA_CHANNEL_POSITION_RIGHT;
504         goto finish;
505     }
506
507     state = NULL;
508     map.channels = 0;
509
510     while ((p = pa_split(s, ",", &state))) {
511
512         if (map.channels >= PA_CHANNELS_MAX) {
513             pa_xfree(p);
514             return NULL;
515         }
516
517         /* Some special aliases */
518         if (strcmp(p, "left") == 0)
519             map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT;
520         else if (strcmp(p, "right") == 0)
521             map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT;
522         else if (strcmp(p, "center") == 0)
523             map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER;
524         else if (strcmp(p, "subwoofer") == 0)
525             map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER;
526         else {
527             pa_channel_position_t i;
528
529             for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
530                 if (strcmp(p, table[i]) == 0) {
531                     map.map[map.channels++] = i;
532                     break;
533                 }
534
535             if (i >= PA_CHANNEL_POSITION_MAX) {
536                 pa_xfree(p);
537                 return NULL;
538             }
539         }
540
541         pa_xfree(p);
542     }
543
544 finish:
545
546     if (!pa_channel_map_valid(&map))
547         return NULL;
548
549     *rmap = map;
550     return rmap;
551 }
552
553 int pa_channel_map_valid(const pa_channel_map *map) {
554     unsigned c;
555
556     pa_assert(map);
557
558     if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
559         return 0;
560
561     for (c = 0; c < map->channels; c++)
562         if (map->map[c] < 0 || map->map[c] >= PA_CHANNEL_POSITION_MAX)
563             return 0;
564
565     return 1;
566 }
567
568 int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) {
569     pa_assert(map);
570     pa_assert(ss);
571
572     return map->channels == ss->channels;
573 }