Merge branch 'master' of git://git.0pointer.de/pulseaudio
[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 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
202     pa_channel_map_init(m);
203
204     m->channels = (uint8_t) channels;
205
206     switch (def) {
207         case PA_CHANNEL_MAP_AIFF:
208
209             /* This is somewhat compatible with RFC3551 */
210
211             switch (channels) {
212                 case 1:
213                     m->map[0] = PA_CHANNEL_POSITION_MONO;
214                     return m;
215
216                 case 6:
217                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
218                     m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT;
219                     m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
220                     m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT;
221                     m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT;
222                     m->map[5] = PA_CHANNEL_POSITION_LFE;
223                     return m;
224
225                 case 5:
226                     m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
227                     m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT;
228                     m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT;
229                     /* Fall through */
230
231                 case 2:
232                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
233                     m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
234                     return m;
235
236                 case 3:
237                     m->map[0] = PA_CHANNEL_POSITION_LEFT;
238                     m->map[1] = PA_CHANNEL_POSITION_RIGHT;
239                     m->map[2] = PA_CHANNEL_POSITION_CENTER;
240                     return m;
241
242                 case 4:
243                     m->map[0] = PA_CHANNEL_POSITION_LEFT;
244                     m->map[1] = PA_CHANNEL_POSITION_CENTER;
245                     m->map[2] = PA_CHANNEL_POSITION_RIGHT;
246                     m->map[3] = PA_CHANNEL_POSITION_LFE;
247                     return m;
248
249                 default:
250                     return NULL;
251             }
252
253         case PA_CHANNEL_MAP_ALSA:
254
255             switch (channels) {
256                 case 1:
257                     m->map[0] = PA_CHANNEL_POSITION_MONO;
258                     return m;
259
260                 case 8:
261                     m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
262                     m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
263                     /* Fall through */
264
265                 case 6:
266                     m->map[5] = PA_CHANNEL_POSITION_LFE;
267                     /* Fall through */
268
269                 case 5:
270                     m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
271                     /* Fall through */
272
273                 case 4:
274                     m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
275                     m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
276                     /* Fall through */
277
278                 case 2:
279                     m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
280                     m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
281                     return m;
282
283                 default:
284                     return NULL;
285             }
286
287         case PA_CHANNEL_MAP_AUX: {
288             unsigned i;
289
290             if (channels >= PA_CHANNELS_MAX)
291                 return NULL;
292
293             for (i = 0; i < channels; i++)
294                 m->map[i] = PA_CHANNEL_POSITION_AUX0 + i;
295
296             return m;
297         }
298
299         case PA_CHANNEL_MAP_WAVEEX:
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
393         default:
394             return NULL;
395     }
396 }
397
398 pa_channel_map* pa_channel_map_init_extend(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
399     unsigned c;
400
401     pa_assert(m);
402     pa_assert(channels > 0);
403     pa_assert(channels <= PA_CHANNELS_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     pa_init_i18n();
438
439     if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
440         return NULL;
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     if (a->channels != b->channels)
452         return 0;
453
454     for (c = 0; c < a->channels; c++)
455         if (a->map[c] != b->map[c])
456             return 0;
457
458     return 1;
459 }
460
461 char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
462     unsigned channel;
463     pa_bool_t first = TRUE;
464     char *e;
465
466     pa_assert(s);
467     pa_assert(l > 0);
468     pa_assert(map);
469
470     *(e = s) = 0;
471
472     for (channel = 0; channel < map->channels && l > 1; channel++) {
473         l -= pa_snprintf(e, l, "%s%s",
474                       first ? "" : ",",
475                       pa_channel_position_to_string(map->map[channel]));
476
477         e = strchr(e, 0);
478         first = FALSE;
479     }
480
481     return s;
482 }
483
484 pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) {
485     const char *state;
486     pa_channel_map map;
487     char *p;
488
489     pa_assert(rmap);
490     pa_assert(s);
491
492     memset(&map, 0, sizeof(map));
493
494     if (strcmp(s, "stereo") == 0) {
495         map.channels = 2;
496         map.map[0] = PA_CHANNEL_POSITION_LEFT;
497         map.map[1] = PA_CHANNEL_POSITION_RIGHT;
498         goto finish;
499     }
500
501     state = NULL;
502     map.channels = 0;
503
504     while ((p = pa_split(s, ",", &state))) {
505
506         if (map.channels >= PA_CHANNELS_MAX) {
507             pa_xfree(p);
508             return NULL;
509         }
510
511         /* Some special aliases */
512         if (strcmp(p, "left") == 0)
513             map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT;
514         else if (strcmp(p, "right") == 0)
515             map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT;
516         else if (strcmp(p, "center") == 0)
517             map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER;
518         else if (strcmp(p, "subwoofer") == 0)
519             map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER;
520         else {
521             pa_channel_position_t i;
522
523             for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++)
524                 if (strcmp(p, table[i]) == 0) {
525                     map.map[map.channels++] = i;
526                     break;
527                 }
528
529             if (i >= PA_CHANNEL_POSITION_MAX) {
530                 pa_xfree(p);
531                 return NULL;
532             }
533         }
534
535         pa_xfree(p);
536     }
537
538 finish:
539
540     if (!pa_channel_map_valid(&map))
541         return NULL;
542
543     *rmap = map;
544     return rmap;
545 }
546
547 int pa_channel_map_valid(const pa_channel_map *map) {
548     unsigned c;
549
550     pa_assert(map);
551
552     if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
553         return 0;
554
555     for (c = 0; c < map->channels; c++) {
556
557         if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX)
558             return 0;
559     }
560
561     return 1;
562 }