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