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