]> code.delx.au - pulseaudio/blob - src/pulse/format.c
alsa-mixer: Add surround 2.1 profile
[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 pa_log_debug("Failed to parse format info property '%s'.", key);
328 return -PA_ERR_INVALID;
329 }
330
331 if (json_object_get_type(o) != json_type_int) {
332 pa_log_debug("Format info property '%s' type is not int.", key);
333 json_object_put(o);
334 return -PA_ERR_INVALID;
335 }
336
337 *v = json_object_get_int(o);
338 json_object_put(o);
339
340 return 0;
341 }
342
343 int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) {
344 const char *str;
345 json_object *o, *o1;
346 int ret = -PA_ERR_INVALID;
347
348 pa_assert(f);
349 pa_assert(key);
350 pa_assert(min);
351 pa_assert(max);
352
353 str = pa_proplist_gets(f->plist, key);
354 if (!str)
355 return -PA_ERR_NOENTITY;
356
357 o = json_tokener_parse(str);
358 if (is_error(o)) {
359 pa_log_debug("Failed to parse format info property '%s'.", key);
360 return -PA_ERR_INVALID;
361 }
362
363 if (json_object_get_type(o) != json_type_object)
364 goto out;
365
366 if (!(o1 = json_object_object_get(o, PA_JSON_MIN_KEY)))
367 goto out;
368
369 *min = json_object_get_int(o1);
370 json_object_put(o1);
371
372 if (!(o1 = json_object_object_get(o, PA_JSON_MAX_KEY)))
373 goto out;
374
375 *max = json_object_get_int(o1);
376 json_object_put(o1);
377
378 ret = 0;
379
380 out:
381 if (ret < 0)
382 pa_log_debug("Format info property '%s' is not a valid int range.", key);
383
384 json_object_put(o);
385 return ret;
386 }
387
388 int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) {
389 const char *str;
390 json_object *o, *o1;
391 int i, ret = -PA_ERR_INVALID;
392
393 pa_assert(f);
394 pa_assert(key);
395 pa_assert(values);
396 pa_assert(n_values);
397
398 str = pa_proplist_gets(f->plist, key);
399 if (!str)
400 return -PA_ERR_NOENTITY;
401
402 o = json_tokener_parse(str);
403 if (is_error(o)) {
404 pa_log_debug("Failed to parse format info property '%s'.", key);
405 return -PA_ERR_INVALID;
406 }
407
408 if (json_object_get_type(o) != json_type_array)
409 goto out;
410
411 *n_values = json_object_array_length(o);
412 *values = pa_xnew(int, *n_values);
413
414 for (i = 0; i < *n_values; i++) {
415 o1 = json_object_array_get_idx(o, i);
416
417 if (json_object_get_type(o1) != json_type_int) {
418 json_object_put(o1);
419 goto out;
420 }
421
422 (*values)[i] = json_object_get_int(o1);
423 json_object_put(o1);
424 }
425
426 ret = 0;
427
428 out:
429 if (ret < 0)
430 pa_log_debug("Format info property '%s' is not a valid int array.", key);
431
432 json_object_put(o);
433 return ret;
434 }
435
436 int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) {
437 const char *str = NULL;
438 json_object *o;
439
440 pa_assert(f);
441 pa_assert(key);
442 pa_assert(v);
443
444 str = pa_proplist_gets(f->plist, key);
445 if (!str)
446 return -PA_ERR_NOENTITY;
447
448 o = json_tokener_parse(str);
449 if (is_error(o)) {
450 pa_log_debug("Failed to parse format info property '%s'.", key);
451 return -PA_ERR_INVALID;
452 }
453
454 if (json_object_get_type(o) != json_type_string) {
455 pa_log_debug("Format info property '%s' type is not string.", key);
456 json_object_put(o);
457 return -PA_ERR_INVALID;
458 }
459
460 *v = pa_xstrdup(json_object_get_string(o));
461 json_object_put(o);
462
463 return 0;
464 }
465
466 int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) {
467 const char *str;
468 json_object *o, *o1;
469 int i, ret = -PA_ERR_INVALID;
470
471 pa_assert(f);
472 pa_assert(key);
473 pa_assert(values);
474 pa_assert(n_values);
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 pa_log_debug("Failed to parse format info property '%s'.", key);
483 return -PA_ERR_INVALID;
484 }
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 if (ret < 0)
508 pa_log_debug("Format info property '%s' is not a valid string array.", key);
509
510 json_object_put(o);
511 return ret;
512 }
513
514 void pa_format_info_free_string_array(char **values, int n_values) {
515 int i;
516
517 for (i = 0; i < n_values; i++)
518 pa_xfree(values[i]);
519
520 pa_xfree(values);
521 }
522
523 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
524 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
525 }
526
527 void pa_format_info_set_rate(pa_format_info *f, int rate) {
528 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
529 }
530
531 void pa_format_info_set_channels(pa_format_info *f, int channels) {
532 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
533 }
534
535 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
536 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
537
538 pa_channel_map_snprint(map_str, sizeof(map_str), map);
539
540 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
541 }
542
543 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
544 json_object *o;
545
546 pa_assert(f);
547 pa_assert(key);
548
549 o = json_object_new_int(value);
550
551 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
552
553 json_object_put(o);
554 }
555
556 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
557 json_object *o;
558 int i;
559
560 pa_assert(f);
561 pa_assert(key);
562
563 o = json_object_new_array();
564
565 for (i = 0; i < n_values; i++)
566 json_object_array_add(o, json_object_new_int(values[i]));
567
568 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
569
570 json_object_put(o);
571 }
572
573 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
574 json_object *o;
575
576 pa_assert(f);
577 pa_assert(key);
578
579 o = json_object_new_object();
580
581 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
582 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
583
584 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
585
586 json_object_put(o);
587 }
588
589 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
590 json_object *o;
591
592 pa_assert(f);
593 pa_assert(key);
594
595 o = json_object_new_string(value);
596
597 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
598
599 json_object_put(o);
600 }
601
602 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
603 json_object *o;
604 int i;
605
606 pa_assert(f);
607 pa_assert(key);
608
609 o = json_object_new_array();
610
611 for (i = 0; i < n_values; i++)
612 json_object_array_add(o, json_object_new_string(values[i]));
613
614 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
615
616 json_object_put(o);
617 }
618
619 static bool pa_json_is_fixed_type(json_object *o) {
620 switch(json_object_get_type(o)) {
621 case json_type_object:
622 case json_type_array:
623 return false;
624
625 default:
626 return true;
627 }
628 }
629
630 static int pa_json_value_equal(json_object *o1, json_object *o2) {
631 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
632 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
633 }
634
635 static int pa_format_info_prop_compatible(const char *one, const char *two) {
636 json_object *o1 = NULL, *o2 = NULL;
637 int i, ret = 0;
638
639 o1 = json_tokener_parse(one);
640 if (is_error(o1))
641 goto out;
642
643 o2 = json_tokener_parse(two);
644 if (is_error(o2))
645 goto out;
646
647 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
648 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false);
649
650 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
651 ret = pa_json_value_equal(o1, o2);
652 goto out;
653 }
654
655 if (pa_json_is_fixed_type(o1)) {
656 json_object *tmp = o2;
657 o2 = o1;
658 o1 = tmp;
659 }
660
661 /* o2 is now a fixed type, and o1 is not */
662
663 if (json_object_get_type(o1) == json_type_array) {
664 for (i = 0; i < json_object_array_length(o1); i++) {
665 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
666 ret = 1;
667 break;
668 }
669 }
670 } else if (json_object_get_type(o1) == json_type_object) {
671 /* o1 should be a range type */
672 int min, max, v;
673 json_object *o_min = NULL, *o_max = NULL;
674
675 if (json_object_get_type(o2) != json_type_int) {
676 /* We don't support non-integer ranges */
677 goto out;
678 }
679
680 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
681 if (!o_min || json_object_get_type(o_min) != json_type_int)
682 goto out;
683
684 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
685 if (!o_max || json_object_get_type(o_max) != json_type_int)
686 goto out;
687
688 v = json_object_get_int(o2);
689 min = json_object_get_int(o_min);
690 max = json_object_get_int(o_max);
691
692 ret = v >= min && v <= max;
693 } else {
694 pa_log_warn("Got a format type that we don't support");
695 }
696
697 out:
698 if (o1)
699 json_object_put(o1);
700 if (o2)
701 json_object_put(o2);
702
703 return ret;
704 }