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