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