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