]> code.delx.au - pulseaudio/blob - src/pulse/format.c
core-format: Add pa_format_info_get_channel_map()
[pulseaudio] / src / pulse / format.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2011 Intel Corporation
5 Copyright 2011 Collabora Multimedia
6 Copyright 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <json.h>
29
30 #include <pulse/internal.h>
31 #include <pulse/xmalloc.h>
32
33 #include <pulsecore/core-format.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/i18n.h>
36 #include <pulsecore/macro.h>
37
38 #include "format.h"
39
40 #define PA_JSON_MIN_KEY "min"
41 #define PA_JSON_MAX_KEY "max"
42
43 static int pa_format_info_prop_compatible(const char *one, const char *two);
44
45 static const char* const _encoding_str_table[]= {
46 [PA_ENCODING_PCM] = "pcm",
47 [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
48 [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
49 [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
50 [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
51 [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937",
52 [PA_ENCODING_ANY] = "any",
53 };
54
55 const char *pa_encoding_to_string(pa_encoding_t e) {
56 if (e < 0 || e >= PA_ENCODING_MAX)
57 return NULL;
58
59 return _encoding_str_table[e];
60 }
61
62 pa_encoding_t pa_encoding_from_string(const char *encoding) {
63 pa_encoding_t e;
64
65 for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
66 if (pa_streq(_encoding_str_table[e], encoding))
67 return e;
68
69 return PA_ENCODING_INVALID;
70 }
71
72 pa_format_info* pa_format_info_new(void) {
73 pa_format_info *f = pa_xnew(pa_format_info, 1);
74
75 f->encoding = PA_ENCODING_INVALID;
76 f->plist = pa_proplist_new();
77
78 return f;
79 }
80
81 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
82 pa_format_info *dest;
83
84 pa_assert(src);
85
86 dest = pa_xnew(pa_format_info, 1);
87
88 dest->encoding = src->encoding;
89
90 if (src->plist)
91 dest->plist = pa_proplist_copy(src->plist);
92 else
93 dest->plist = NULL;
94
95 return dest;
96 }
97
98 void pa_format_info_free(pa_format_info *f) {
99 pa_assert(f);
100
101 pa_proplist_free(f->plist);
102 pa_xfree(f);
103 }
104
105 int pa_format_info_valid(const pa_format_info *f) {
106 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
107 }
108
109 int pa_format_info_is_pcm(const pa_format_info *f) {
110 return f->encoding == PA_ENCODING_PCM;
111 }
112
113 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
114 char *tmp;
115
116 pa_assert(s);
117 pa_assert(l > 0);
118 pa_assert(f);
119
120 pa_init_i18n();
121
122 if (!pa_format_info_valid(f))
123 pa_snprintf(s, l, _("(invalid)"));
124 else {
125 tmp = pa_proplist_to_string_sep(f->plist, " ");
126 if (tmp[0])
127 pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
128 else
129 pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
130 pa_xfree(tmp);
131 }
132
133 return s;
134 }
135
136 pa_format_info* pa_format_info_from_string(const char *str) {
137 pa_format_info *f = pa_format_info_new();
138 char *encoding = NULL, *properties = NULL;
139 size_t pos;
140
141 pos = strcspn(str, ",");
142
143 encoding = pa_xstrndup(str, pos);
144 f->encoding = pa_encoding_from_string(pa_strip(encoding));
145 if (f->encoding == PA_ENCODING_INVALID)
146 goto error;
147
148 if (pos != strlen(str)) {
149 pa_proplist *plist;
150
151 properties = pa_xstrdup(&str[pos+1]);
152 plist = pa_proplist_from_string(properties);
153
154 if (!plist)
155 goto error;
156
157 pa_proplist_free(f->plist);
158 f->plist = plist;
159 }
160
161 out:
162 if (encoding)
163 pa_xfree(encoding);
164 if (properties)
165 pa_xfree(properties);
166 return f;
167
168 error:
169 pa_format_info_free(f);
170 f = NULL;
171 goto out;
172 }
173
174 int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
175 const char *key;
176 void *state = NULL;
177
178 pa_assert(first);
179 pa_assert(second);
180
181 if (first->encoding != second->encoding)
182 return false;
183
184 while ((key = pa_proplist_iterate(first->plist, &state))) {
185 const char *value_one, *value_two;
186
187 value_one = pa_proplist_gets(first->plist, key);
188 value_two = pa_proplist_gets(second->plist, key);
189
190 if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
191 return false;
192 }
193
194 return true;
195 }
196
197 pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) {
198 char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
199 pa_format_info *f;
200
201 pa_assert(ss && pa_sample_spec_valid(ss));
202 pa_assert(!map || pa_channel_map_valid(map));
203
204 f = pa_format_info_new();
205 f->encoding = PA_ENCODING_PCM;
206
207 pa_format_info_set_sample_format(f, ss->format);
208 pa_format_info_set_rate(f, ss->rate);
209 pa_format_info_set_channels(f, ss->channels);
210
211 if (map) {
212 pa_channel_map_snprint(cm, sizeof(cm), map);
213 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
214 }
215
216 return f;
217 }
218
219 /* For PCM streams */
220 int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
221 int ret = -PA_ERR_INVALID;
222
223 pa_assert(f);
224 pa_assert(ss);
225
226 if (!pa_format_info_is_pcm(f))
227 return pa_format_info_to_sample_spec_fake(f, ss, map);
228
229 if (pa_format_info_get_sample_format(f, &ss->format) < 0)
230 goto out;
231 if (pa_format_info_get_rate(f, &ss->rate) < 0)
232 goto out;
233 if (pa_format_info_get_channels(f, &ss->channels) < 0)
234 goto out;
235 if (map && pa_format_info_get_channel_map(f, map) < 0)
236 goto out;
237
238 ret = 0;
239
240 out:
241 return ret;
242 }
243
244 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
245 const char *str;
246 json_object *o, *o1;
247 pa_prop_type_t type;
248
249 pa_assert(f);
250 pa_assert(key);
251
252 str = pa_proplist_gets(f->plist, key);
253 if (!str)
254 return PA_PROP_TYPE_INVALID;
255
256 o = json_tokener_parse(str);
257 if (is_error(o))
258 return PA_PROP_TYPE_INVALID;
259
260 switch (json_object_get_type(o)) {
261 case json_type_int:
262 type = PA_PROP_TYPE_INT;
263 break;
264
265 case json_type_string:
266 type = PA_PROP_TYPE_STRING;
267 break;
268
269 case json_type_array:
270 if (json_object_array_length(o) == 0) {
271 /* Unlikely, but let's account for this anyway. We need at
272 * least one element to figure out the array type. */
273 type = PA_PROP_TYPE_INVALID;
274 break;
275 }
276
277 o1 = json_object_array_get_idx(o, 1);
278
279 if (json_object_get_type(o1) == json_type_int)
280 type = PA_PROP_TYPE_INT_ARRAY;
281 else if (json_object_get_type(o1) == json_type_string)
282 type = PA_PROP_TYPE_STRING_ARRAY;
283 else
284 type = PA_PROP_TYPE_INVALID;
285
286 json_object_put(o1);
287 break;
288
289 case json_type_object:
290 /* We actually know at this point that it's a int range, but let's
291 * confirm. */
292 o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
293 if (!o1) {
294 type = PA_PROP_TYPE_INVALID;
295 break;
296 }
297 json_object_put(o1);
298
299 o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
300 if (!o1) {
301 type = PA_PROP_TYPE_INVALID;
302 break;
303 }
304 json_object_put(o1);
305
306 type = PA_PROP_TYPE_INT_RANGE;
307 break;
308
309 default:
310 type = PA_PROP_TYPE_INVALID;
311 break;
312 }
313
314 json_object_put(o);
315 return type;
316 }
317
318 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
319 const char *str;
320 json_object *o;
321
322 pa_assert(f);
323 pa_assert(key);
324 pa_assert(v);
325
326 str = pa_proplist_gets(f->plist, key);
327 if (!str)
328 return -PA_ERR_NOENTITY;
329
330 o = json_tokener_parse(str);
331 if (is_error(o))
332 return -PA_ERR_INVALID;
333
334 if (json_object_get_type(o) != json_type_int) {
335 json_object_put(o);
336 return -PA_ERR_INVALID;
337 }
338
339 *v = json_object_get_int(o);
340 json_object_put(o);
341
342 return 0;
343 }
344
345 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
346 const char *str;
347 json_object *o, *o1;
348 int ret = -PA_ERR_INVALID;
349
350 pa_assert(f);
351 pa_assert(key);
352 pa_assert(min);
353 pa_assert(max);
354
355 str = pa_proplist_gets(f->plist, key);
356 if (!str)
357 return -PA_ERR_NOENTITY;
358
359 o = json_tokener_parse(str);
360 if (is_error(o))
361 return -PA_ERR_INVALID;
362
363 if (json_object_get_type(o) != json_type_object)
364 goto out;
365
366 if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
367 goto out;
368
369 *min = json_object_get_int(o1);
370 json_object_put(o1);
371
372 if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
373 goto out;
374
375 *max = json_object_get_int(o1);
376 json_object_put(o1);
377
378 ret = 0;
379
380 out:
381 json_object_put(o);
382 return ret;
383 }
384
385 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
386 const char *str;
387 json_object *o, *o1;
388 int i, ret = -PA_ERR_INVALID;
389
390 pa_assert(f);
391 pa_assert(key);
392 pa_assert(values);
393 pa_assert(n_values);
394
395 str = pa_proplist_gets(f->plist, key);
396 if (!str)
397 return -PA_ERR_NOENTITY;
398
399 o = json_tokener_parse(str);
400 if (is_error(o))
401 return -PA_ERR_INVALID;
402
403 if (json_object_get_type(o) != json_type_array)
404 goto out;
405
406 *n_values = json_object_array_length(o);
407 *values = pa_xnew(int, *n_values);
408
409 for (i = 0; i < *n_values; i++) {
410 o1 = json_object_array_get_idx(o, i);
411
412 if (json_object_get_type(o1) != json_type_int) {
413 json_object_put(o1);
414 goto out;
415 }
416
417 (*values)[i] = json_object_get_int(o1);
418 json_object_put(o1);
419 }
420
421 ret = 0;
422
423 out:
424 json_object_put(o);
425 return ret;
426 }
427
428 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
429 const char *str = NULL;
430 json_object *o;
431
432 pa_assert(f);
433 pa_assert(key);
434 pa_assert(v);
435
436 str = pa_proplist_gets(f->plist, key);
437 if (!str)
438 return -PA_ERR_NOENTITY;
439
440 o = json_tokener_parse(str);
441 if (is_error(o))
442 return -PA_ERR_INVALID;
443
444 if (json_object_get_type(o) != json_type_string) {
445 json_object_put(o);
446 return -PA_ERR_INVALID;
447 }
448
449 *v = pa_xstrdup(json_object_get_string(o));
450 json_object_put(o);
451
452 return 0;
453 }
454
455 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
456 const char *str;
457 json_object *o, *o1;
458 int i, ret = -PA_ERR_INVALID;
459
460 pa_assert(f);
461 pa_assert(key);
462 pa_assert(values);
463 pa_assert(n_values);
464
465 str = pa_proplist_gets(f->plist, key);
466 if (!str)
467 return -PA_ERR_NOENTITY;
468
469 o = json_tokener_parse(str);
470 if (is_error(o))
471 return -PA_ERR_INVALID;
472
473 if (json_object_get_type(o) != json_type_array)
474 goto out;
475
476 *n_values = json_object_array_length(o);
477 *values = pa_xnew(char *, *n_values);
478
479 for (i = 0; i < *n_values; i++) {
480 o1 = json_object_array_get_idx(o, i);
481
482 if (json_object_get_type(o1) != json_type_string) {
483 json_object_put(o1);
484 goto out;
485 }
486
487 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
488 json_object_put(o1);
489 }
490
491 ret = 0;
492
493 out:
494 json_object_put(o);
495 return ret;
496 }
497
498 void pa_format_info_free_string_array(char **values, int n_values) {
499 int i;
500
501 for (i = 0; i < n_values; i++)
502 pa_xfree(values[i]);
503
504 pa_xfree(values);
505 }
506
507 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
508 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
509 }
510
511 void pa_format_info_set_rate(pa_format_info *f, int rate) {
512 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
513 }
514
515 void pa_format_info_set_channels(pa_format_info *f, int channels) {
516 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
517 }
518
519 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
520 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
521
522 pa_channel_map_snprint(map_str, sizeof(map_str), map);
523
524 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
525 }
526
527 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
528 json_object *o;
529
530 pa_assert(f);
531 pa_assert(key);
532
533 o = json_object_new_int(value);
534
535 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
536
537 json_object_put(o);
538 }
539
540 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
541 json_object *o;
542 int i;
543
544 pa_assert(f);
545 pa_assert(key);
546
547 o = json_object_new_array();
548
549 for (i = 0; i < n_values; i++)
550 json_object_array_add(o, json_object_new_int(values[i]));
551
552 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
553
554 json_object_put(o);
555 }
556
557 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
558 json_object *o;
559
560 pa_assert(f);
561 pa_assert(key);
562
563 o = json_object_new_object();
564
565 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
566 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
567
568 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
569
570 json_object_put(o);
571 }
572
573 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
574 json_object *o;
575
576 pa_assert(f);
577 pa_assert(key);
578
579 o = json_object_new_string(value);
580
581 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
582
583 json_object_put(o);
584 }
585
586 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
587 json_object *o;
588 int i;
589
590 pa_assert(f);
591 pa_assert(key);
592
593 o = json_object_new_array();
594
595 for (i = 0; i < n_values; i++)
596 json_object_array_add(o, json_object_new_string(values[i]));
597
598 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
599
600 json_object_put(o);
601 }
602
603 static bool pa_json_is_fixed_type(json_object *o) {
604 switch(json_object_get_type(o)) {
605 case json_type_object:
606 case json_type_array:
607 return false;
608
609 default:
610 return true;
611 }
612 }
613
614 static int pa_json_value_equal(json_object *o1, json_object *o2) {
615 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
616 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
617 }
618
619 static int pa_format_info_prop_compatible(const char *one, const char *two) {
620 json_object *o1 = NULL, *o2 = NULL;
621 int i, ret = 0;
622
623 o1 = json_tokener_parse(one);
624 if (is_error(o1))
625 goto out;
626
627 o2 = json_tokener_parse(two);
628 if (is_error(o2))
629 goto out;
630
631 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
632 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
633
634 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
635 ret = pa_json_value_equal(o1, o2);
636 goto out;
637 }
638
639 if (pa_json_is_fixed_type(o1)) {
640 json_object *tmp = o2;
641 o2 = o1;
642 o1 = tmp;
643 }
644
645 /* o2 is now a fixed type, and o1 is not */
646
647 if (json_object_get_type(o1) == json_type_array) {
648 for (i = 0; i < json_object_array_length(o1); i++) {
649 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
650 ret = 1;
651 break;
652 }
653 }
654 } else if (json_object_get_type(o1) == json_type_object) {
655 /* o1 should be a range type */
656 int min, max, v;
657 json_object *o_min = NULL, *o_max = NULL;
658
659 if (json_object_get_type(o2) != json_type_int) {
660 /* We don't support non-integer ranges */
661 goto out;
662 }
663
664 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
665 if (!o_min || json_object_get_type(o_min) != json_type_int)
666 goto out;
667
668 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
669 if (!o_max || json_object_get_type(o_max) != json_type_int)
670 goto out;
671
672 v = json_object_get_int(o2);
673 min = json_object_get_int(o_min);
674 max = json_object_get_int(o_max);
675
676 ret = v >= min && v <= max;
677 } else {
678 pa_log_warn("Got a format type that we don't support");
679 }
680
681 out:
682 if (o1)
683 json_object_put(o1);
684 if (o2)
685 json_object_put(o2);
686
687 return ret;
688 }