]> code.delx.au - pulseaudio/blob - src/pulse/format.c
core-format: Add pa_format_info_get_sample_format()
[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 char *m = NULL;
222 int rate, channels;
223 int ret = -PA_ERR_INVALID;
224
225 pa_assert(f);
226 pa_assert(ss);
227
228 if (!pa_format_info_is_pcm(f))
229 return pa_format_info_to_sample_spec_fake(f, ss, map);
230
231 if (pa_format_info_get_sample_format(f, &ss->format) < 0)
232 goto out;
233 if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate))
234 goto out;
235 if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels))
236 goto out;
237
238 ss->rate = (uint32_t) rate;
239 ss->channels = (uint8_t) channels;
240
241 if (map) {
242 pa_channel_map_init(map);
243
244 if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0)
245 if (pa_channel_map_parse(map, m) == NULL)
246 goto out;
247 }
248
249 ret = 0;
250
251 out:
252 if (m)
253 pa_xfree(m);
254
255 return ret;
256 }
257
258 pa_prop_type_t pa_format_info_get_prop_type(pa_format_info *f, const char *key) {
259 const char *str;
260 json_object *o, *o1;
261 pa_prop_type_t type;
262
263 pa_assert(f);
264 pa_assert(key);
265
266 str = pa_proplist_gets(f->plist, key);
267 if (!str)
268 return PA_PROP_TYPE_INVALID;
269
270 o = json_tokener_parse(str);
271 if (is_error(o))
272 return PA_PROP_TYPE_INVALID;
273
274 switch (json_object_get_type(o)) {
275 case json_type_int:
276 type = PA_PROP_TYPE_INT;
277 break;
278
279 case json_type_string:
280 type = PA_PROP_TYPE_STRING;
281 break;
282
283 case json_type_array:
284 if (json_object_array_length(o) == 0) {
285 /* Unlikely, but let's account for this anyway. We need at
286 * least one element to figure out the array type. */
287 type = PA_PROP_TYPE_INVALID;
288 break;
289 }
290
291 o1 = json_object_array_get_idx(o, 1);
292
293 if (json_object_get_type(o1) == json_type_int)
294 type = PA_PROP_TYPE_INT_ARRAY;
295 else if (json_object_get_type(o1) == json_type_string)
296 type = PA_PROP_TYPE_STRING_ARRAY;
297 else
298 type = PA_PROP_TYPE_INVALID;
299
300 json_object_put(o1);
301 break;
302
303 case json_type_object:
304 /* We actually know at this point that it's a int range, but let's
305 * confirm. */
306 o1 = json_object_object_get(o, PA_JSON_MIN_KEY);
307 if (!o1) {
308 type = PA_PROP_TYPE_INVALID;
309 break;
310 }
311 json_object_put(o1);
312
313 o1 = json_object_object_get(o, PA_JSON_MAX_KEY);
314 if (!o1) {
315 type = PA_PROP_TYPE_INVALID;
316 break;
317 }
318 json_object_put(o1);
319
320 type = PA_PROP_TYPE_INT_RANGE;
321 break;
322
323 default:
324 type = PA_PROP_TYPE_INVALID;
325 break;
326 }
327
328 json_object_put(o);
329 return type;
330 }
331
332 int pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
333 const char *str;
334 json_object *o;
335
336 pa_assert(f);
337 pa_assert(key);
338 pa_assert(v);
339
340 str = pa_proplist_gets(f->plist, key);
341 if (!str)
342 return -PA_ERR_NOENTITY;
343
344 o = json_tokener_parse(str);
345 if (is_error(o))
346 return -PA_ERR_INVALID;
347
348 if (json_object_get_type(o) != json_type_int) {
349 json_object_put(o);
350 return -PA_ERR_INVALID;
351 }
352
353 *v = json_object_get_int(o);
354 json_object_put(o);
355
356 return 0;
357 }
358
359 int pa_format_info_get_prop_int_range(pa_format_info *f, const char *key, int *min, int *max) {
360 const char *str;
361 json_object *o, *o1;
362 int ret = -PA_ERR_INVALID;
363
364 pa_assert(f);
365 pa_assert(key);
366 pa_assert(min);
367 pa_assert(max);
368
369 str = pa_proplist_gets(f->plist, key);
370 if (!str)
371 return -PA_ERR_NOENTITY;
372
373 o = json_tokener_parse(str);
374 if (is_error(o))
375 return -PA_ERR_INVALID;
376
377 if (json_object_get_type(o) != json_type_object)
378 goto out;
379
380 if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
381 goto out;
382
383 *min = json_object_get_int(o1);
384 json_object_put(o1);
385
386 if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
387 goto out;
388
389 *max = json_object_get_int(o1);
390 json_object_put(o1);
391
392 ret = 0;
393
394 out:
395 json_object_put(o);
396 return ret;
397 }
398
399 int pa_format_info_get_prop_int_array(pa_format_info *f, const char *key, int **values, int *n_values) {
400 const char *str;
401 json_object *o, *o1;
402 int i, ret = -PA_ERR_INVALID;
403
404 pa_assert(f);
405 pa_assert(key);
406 pa_assert(values);
407 pa_assert(n_values);
408
409 str = pa_proplist_gets(f->plist, key);
410 if (!str)
411 return -PA_ERR_NOENTITY;
412
413 o = json_tokener_parse(str);
414 if (is_error(o))
415 return -PA_ERR_INVALID;
416
417 if (json_object_get_type(o) != json_type_array)
418 goto out;
419
420 *n_values = json_object_array_length(o);
421 *values = pa_xnew(int, *n_values);
422
423 for (i = 0; i < *n_values; i++) {
424 o1 = json_object_array_get_idx(o, i);
425
426 if (json_object_get_type(o1) != json_type_int) {
427 json_object_put(o1);
428 goto out;
429 }
430
431 (*values)[i] = json_object_get_int(o1);
432 json_object_put(o1);
433 }
434
435 ret = 0;
436
437 out:
438 json_object_put(o);
439 return ret;
440 }
441
442 int pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
443 const char *str = NULL;
444 json_object *o;
445
446 pa_assert(f);
447 pa_assert(key);
448 pa_assert(v);
449
450 str = pa_proplist_gets(f->plist, key);
451 if (!str)
452 return -PA_ERR_NOENTITY;
453
454 o = json_tokener_parse(str);
455 if (is_error(o))
456 return -PA_ERR_INVALID;
457
458 if (json_object_get_type(o) != json_type_string) {
459 json_object_put(o);
460 return -PA_ERR_INVALID;
461 }
462
463 *v = pa_xstrdup(json_object_get_string(o));
464 json_object_put(o);
465
466 return 0;
467 }
468
469 int pa_format_info_get_prop_string_array(pa_format_info *f, const char *key, char ***values, int *n_values) {
470 const char *str;
471 json_object *o, *o1;
472 int i, ret = -PA_ERR_INVALID;
473
474 pa_assert(f);
475 pa_assert(key);
476 pa_assert(values);
477 pa_assert(n_values);
478
479 str = pa_proplist_gets(f->plist, key);
480 if (!str)
481 return -PA_ERR_NOENTITY;
482
483 o = json_tokener_parse(str);
484 if (is_error(o))
485 return -PA_ERR_INVALID;
486
487 if (json_object_get_type(o) != json_type_array)
488 goto out;
489
490 *n_values = json_object_array_length(o);
491 *values = pa_xnew(char *, *n_values);
492
493 for (i = 0; i < *n_values; i++) {
494 o1 = json_object_array_get_idx(o, i);
495
496 if (json_object_get_type(o1) != json_type_string) {
497 json_object_put(o1);
498 goto out;
499 }
500
501 (*values)[i] = pa_xstrdup(json_object_get_string(o1));
502 json_object_put(o1);
503 }
504
505 ret = 0;
506
507 out:
508 json_object_put(o);
509 return ret;
510 }
511
512 void pa_format_info_free_string_array(char **values, int n_values) {
513 int i;
514
515 for (i = 0; i < n_values; i++)
516 pa_xfree(values[i]);
517
518 pa_xfree(values);
519 }
520
521 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
522 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
523 }
524
525 void pa_format_info_set_rate(pa_format_info *f, int rate) {
526 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
527 }
528
529 void pa_format_info_set_channels(pa_format_info *f, int channels) {
530 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
531 }
532
533 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
534 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
535
536 pa_channel_map_snprint(map_str, sizeof(map_str), map);
537
538 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
539 }
540
541 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
542 json_object *o;
543
544 pa_assert(f);
545 pa_assert(key);
546
547 o = json_object_new_int(value);
548
549 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
550
551 json_object_put(o);
552 }
553
554 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
555 json_object *o;
556 int i;
557
558 pa_assert(f);
559 pa_assert(key);
560
561 o = json_object_new_array();
562
563 for (i = 0; i < n_values; i++)
564 json_object_array_add(o, json_object_new_int(values[i]));
565
566 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
567
568 json_object_put(o);
569 }
570
571 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
572 json_object *o;
573
574 pa_assert(f);
575 pa_assert(key);
576
577 o = json_object_new_object();
578
579 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
580 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
581
582 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
583
584 json_object_put(o);
585 }
586
587 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
588 json_object *o;
589
590 pa_assert(f);
591 pa_assert(key);
592
593 o = json_object_new_string(value);
594
595 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
596
597 json_object_put(o);
598 }
599
600 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
601 json_object *o;
602 int i;
603
604 pa_assert(f);
605 pa_assert(key);
606
607 o = json_object_new_array();
608
609 for (i = 0; i < n_values; i++)
610 json_object_array_add(o, json_object_new_string(values[i]));
611
612 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
613
614 json_object_put(o);
615 }
616
617 static bool pa_json_is_fixed_type(json_object *o) {
618 switch(json_object_get_type(o)) {
619 case json_type_object:
620 case json_type_array:
621 return false;
622
623 default:
624 return true;
625 }
626 }
627
628 static int pa_json_value_equal(json_object *o1, json_object *o2) {
629 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
630 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
631 }
632
633 static int pa_format_info_prop_compatible(const char *one, const char *two) {
634 json_object *o1 = NULL, *o2 = NULL;
635 int i, ret = 0;
636
637 o1 = json_tokener_parse(one);
638 if (is_error(o1))
639 goto out;
640
641 o2 = json_tokener_parse(two);
642 if (is_error(o2))
643 goto out;
644
645 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
646 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
647
648 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
649 ret = pa_json_value_equal(o1, o2);
650 goto out;
651 }
652
653 if (pa_json_is_fixed_type(o1)) {
654 json_object *tmp = o2;
655 o2 = o1;
656 o1 = tmp;
657 }
658
659 /* o2 is now a fixed type, and o1 is not */
660
661 if (json_object_get_type(o1) == json_type_array) {
662 for (i = 0; i < json_object_array_length(o1); i++) {
663 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
664 ret = 1;
665 break;
666 }
667 }
668 } else if (json_object_get_type(o1) == json_type_object) {
669 /* o1 should be a range type */
670 int min, max, v;
671 json_object *o_min = NULL, *o_max = NULL;
672
673 if (json_object_get_type(o2) != json_type_int) {
674 /* We don't support non-integer ranges */
675 goto out;
676 }
677
678 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
679 if (!o_min || json_object_get_type(o_min) != json_type_int)
680 goto out;
681
682 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
683 if (!o_max || json_object_get_type(o_max) != json_type_int)
684 goto out;
685
686 v = json_object_get_int(o2);
687 min = json_object_get_int(o_min);
688 max = json_object_get_int(o_max);
689
690 ret = v >= min && v <= max;
691 } else {
692 pa_log_warn("Got a format type that we don't support");
693 }
694
695 out:
696 if (o1)
697 json_object_put(o1);
698 if (o2)
699 json_object_put(o2);
700
701 return ret;
702 }