]> code.delx.au - pulseaudio/blob - src/pulse/format.c
format: Add string to pa_format_info conversion function
[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-util.h>
34 #include <pulsecore/i18n.h>
35 #include <pulsecore/macro.h>
36
37 #include "format.h"
38
39 #define PA_JSON_MIN_KEY "min"
40 #define PA_JSON_MAX_KEY "max"
41
42 static int pa_format_info_prop_compatible(const char *one, const char *two);
43
44 static const char* const _encoding_str_table[]= {
45 [PA_ENCODING_PCM] = "pcm",
46 [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
47 [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
48 [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
49 [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
50 [PA_ENCODING_ANY] = "any",
51 };
52
53 const char *pa_encoding_to_string(pa_encoding_t e) {
54 if (e < 0 || e >= PA_ENCODING_MAX)
55 return NULL;
56
57 return _encoding_str_table[e];
58 }
59
60 pa_encoding_t pa_encoding_from_string(const char *encoding) {
61 pa_encoding_t e;
62
63 for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
64 if (pa_streq(_encoding_str_table[e], encoding))
65 return e;
66
67 return PA_ENCODING_INVALID;
68 }
69
70 pa_format_info* pa_format_info_new(void) {
71 pa_format_info *f = pa_xnew(pa_format_info, 1);
72
73 f->encoding = PA_ENCODING_INVALID;
74 f->plist = pa_proplist_new();
75
76 return f;
77 }
78
79 pa_format_info* pa_format_info_copy(const pa_format_info *src) {
80 pa_format_info *dest;
81
82 pa_assert(src);
83
84 dest = pa_xnew(pa_format_info, 1);
85
86 dest->encoding = src->encoding;
87
88 if (src->plist)
89 dest->plist = pa_proplist_copy(src->plist);
90 else
91 dest->plist = NULL;
92
93 return dest;
94 }
95
96 void pa_format_info_free(pa_format_info *f) {
97 pa_assert(f);
98
99 pa_proplist_free(f->plist);
100 pa_xfree(f);
101 }
102
103 void pa_format_info_free2(pa_format_info *f, void *userdata) {
104 pa_format_info_free(f);
105 }
106
107 int pa_format_info_valid(const pa_format_info *f) {
108 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL);
109 }
110
111 int pa_format_info_is_pcm(const pa_format_info *f) {
112 return f->encoding == PA_ENCODING_PCM;
113 }
114
115 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
116 char *tmp;
117
118 pa_assert(s);
119 pa_assert(l > 0);
120 pa_assert(f);
121
122 pa_init_i18n();
123
124 if (!pa_format_info_valid(f))
125 pa_snprintf(s, l, _("(invalid)"));
126 else {
127 tmp = pa_proplist_to_string_sep(f->plist, " ");
128 if (tmp[0])
129 pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
130 else
131 pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
132 pa_xfree(tmp);
133 }
134
135 return s;
136 }
137
138 pa_format_info* pa_format_info_from_string(const char *str) {
139 pa_format_info *f = pa_format_info_new();
140 char *encoding = NULL, *properties = NULL;
141 size_t pos;
142
143 pos = strcspn(str, ",");
144
145 encoding = pa_xstrndup(str, pos);
146 f->encoding = pa_encoding_from_string(pa_strip(encoding));
147 if (f->encoding == PA_ENCODING_INVALID)
148 goto error;
149
150 if (pos != strlen(str)) {
151 pa_proplist *plist;
152
153 properties = pa_xstrdup(&str[pos+1]);
154 plist = pa_proplist_from_string(properties);
155
156 if (!plist)
157 goto error;
158
159 pa_proplist_free(f->plist);
160 f->plist = plist;
161 }
162
163 out:
164 if (encoding)
165 pa_xfree(encoding);
166 if (properties)
167 pa_xfree(properties);
168 return f;
169
170 error:
171 pa_format_info_free(f);
172 f = NULL;
173 goto out;
174 }
175
176 int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
177 const char *key;
178 void *state = NULL;
179
180 pa_assert(first);
181 pa_assert(second);
182
183 if (first->encoding != second->encoding)
184 return FALSE;
185
186 while ((key = pa_proplist_iterate(first->plist, &state))) {
187 const char *value_one, *value_two;
188
189 value_one = pa_proplist_gets(first->plist, key);
190 value_two = pa_proplist_gets(second->plist, key);
191
192 if (!value_two || !pa_format_info_prop_compatible(value_one, value_two))
193 return FALSE;
194 }
195
196 return TRUE;
197 }
198
199 pa_format_info* pa_format_info_from_sample_spec(pa_sample_spec *ss, pa_channel_map *map) {
200 char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
201 pa_format_info *f;
202
203 pa_assert(ss && pa_sample_spec_valid(ss));
204 pa_assert(!map || pa_channel_map_valid(map));
205
206 f = pa_format_info_new();
207 f->encoding = PA_ENCODING_PCM;
208
209 pa_format_info_set_sample_format(f, ss->format);
210 pa_format_info_set_rate(f, ss->rate);
211 pa_format_info_set_channels(f, ss->channels);
212
213 if (map) {
214 pa_channel_map_snprint(cm, sizeof(cm), map);
215 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, cm);
216 }
217
218 return f;
219 }
220
221 /* For PCM streams */
222 pa_bool_t pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) {
223 char *sf = NULL, *m = NULL;
224 int rate, channels;
225 pa_bool_t ret = FALSE;
226
227 pa_assert(f);
228 pa_assert(ss);
229 pa_return_val_if_fail(f->encoding == PA_ENCODING_PCM, FALSE);
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))
248 if (pa_channel_map_parse(map, m) == NULL)
249 goto out;
250 }
251
252 ret = TRUE;
253
254 out:
255 if (sf)
256 pa_xfree(sf);
257 if (m)
258 pa_xfree(m);
259
260 return ret;
261 }
262
263 /* For compressed streams */
264 pa_bool_t pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) {
265 int rate;
266
267 pa_assert(f);
268 pa_assert(ss);
269 pa_return_val_if_fail(f->encoding != PA_ENCODING_PCM, FALSE);
270
271 ss->format = PA_SAMPLE_S16LE;
272 ss->channels = 2;
273
274 pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate), FALSE);
275 ss->rate = (uint32_t) rate;
276
277 if (f->encoding == PA_ENCODING_EAC3_IEC61937)
278 ss->rate *= 4;
279
280 return TRUE;
281 }
282
283 void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) {
284 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf));
285 }
286
287 void pa_format_info_set_rate(pa_format_info *f, int rate) {
288 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate);
289 }
290
291 void pa_format_info_set_channels(pa_format_info *f, int channels) {
292 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels);
293 }
294
295 void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) {
296 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX];
297
298 pa_channel_map_snprint(map_str, sizeof(map_str), map);
299
300 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str);
301 }
302
303 pa_bool_t pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) {
304 const char *str;
305 json_object *o;
306
307 pa_assert(f);
308 pa_assert(key);
309 pa_assert(v);
310
311 pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE);
312 o = json_tokener_parse(str);
313 pa_return_val_if_fail(!is_error(o), FALSE);
314 if (json_object_get_type(o) != json_type_int) {
315 json_object_put(o);
316 return FALSE;
317 }
318
319 *v = json_object_get_int(o);
320 json_object_put(o);
321
322 return TRUE;
323 }
324
325 pa_bool_t pa_format_info_get_prop_string(pa_format_info *f, const char *key, char **v) {
326 const char *str = NULL;
327 json_object *o;
328
329 pa_assert(f);
330 pa_assert(key);
331 pa_assert(v);
332
333 str = pa_proplist_gets(f->plist, key), FALSE;
334 if (!str)
335 return FALSE;
336
337 o = json_tokener_parse(str);
338 pa_return_val_if_fail(!is_error(o), FALSE);
339 if (json_object_get_type(o) != json_type_string) {
340 json_object_put(o);
341 return FALSE;
342 }
343
344 *v = pa_xstrdup(json_object_get_string(o));
345 json_object_put(o);
346
347 return TRUE;
348 }
349
350 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) {
351 json_object *o;
352
353 pa_assert(f);
354 pa_assert(key);
355
356 o = json_object_new_int(value);
357
358 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
359
360 json_object_put(o);
361 }
362
363 void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) {
364 json_object *o;
365 int i;
366
367 pa_assert(f);
368 pa_assert(key);
369
370 o = json_object_new_array();
371
372 for (i = 0; i < n_values; i++)
373 json_object_array_add(o, json_object_new_int(values[i]));
374
375 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
376
377 json_object_put(o);
378 }
379
380 void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) {
381 json_object *o;
382
383 pa_assert(f);
384 pa_assert(key);
385
386 o = json_object_new_object();
387
388 json_object_object_add(o, PA_JSON_MIN_KEY, json_object_new_int(min));
389 json_object_object_add(o, PA_JSON_MAX_KEY, json_object_new_int(max));
390
391 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
392
393 json_object_put(o);
394 }
395
396 void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) {
397 json_object *o;
398
399 pa_assert(f);
400 pa_assert(key);
401
402 o = json_object_new_string(value);
403
404 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
405
406 json_object_put(o);
407 }
408
409 void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) {
410 json_object *o;
411 int i;
412
413 pa_assert(f);
414 pa_assert(key);
415
416 o = json_object_new_array();
417
418 for (i = 0; i < n_values; i++)
419 json_object_array_add(o, json_object_new_string(values[i]));
420
421 pa_proplist_sets(f->plist, key, json_object_to_json_string(o));
422
423 json_object_put(o);
424 }
425
426 static pa_bool_t pa_json_is_fixed_type(json_object *o)
427 {
428 switch(json_object_get_type(o)) {
429 case json_type_object:
430 case json_type_array:
431 return FALSE;
432
433 default:
434 return TRUE;
435 }
436 }
437
438 static int pa_json_value_equal(json_object *o1, json_object *o2) {
439 return (json_object_get_type(o1) == json_object_get_type(o2)) &&
440 pa_streq(json_object_to_json_string(o1), json_object_to_json_string(o2));
441 }
442
443 static int pa_format_info_prop_compatible(const char *one, const char *two) {
444 json_object *o1 = NULL, *o2 = NULL;
445 int i, ret = 0;
446
447 o1 = json_tokener_parse(one);
448 if (is_error(o1))
449 goto out;
450
451 o2 = json_tokener_parse(two);
452 if (is_error(o2))
453 goto out;
454
455 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */
456 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), FALSE);
457
458 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) {
459 ret = pa_json_value_equal(o1, o2);
460 goto out;
461 }
462
463 if (pa_json_is_fixed_type(o1)) {
464 json_object *tmp = o2;
465 o2 = o1;
466 o1 = tmp;
467 }
468
469 /* o2 is now a fixed type, and o1 is not */
470
471 if (json_object_get_type(o1) == json_type_array) {
472 for (i = 0; i < json_object_array_length(o1); i++) {
473 if (pa_json_value_equal(json_object_array_get_idx(o1, i), o2)) {
474 ret = 1;
475 break;
476 }
477 }
478 } else if (json_object_get_type(o1) == json_type_object) {
479 /* o1 should be a range type */
480 int min, max, v;
481 json_object *o_min = NULL, *o_max = NULL;
482
483 if (json_object_get_type(o2) != json_type_int) {
484 /* We don't support non-integer ranges */
485 goto out;
486 }
487
488 o_min = json_object_object_get(o1, PA_JSON_MIN_KEY);
489 if (!o_min || json_object_get_type(o_min) != json_type_int)
490 goto out;
491
492 o_max = json_object_object_get(o1, PA_JSON_MAX_KEY);
493 if (!o_max || json_object_get_type(o_max) != json_type_int)
494 goto out;
495
496 v = json_object_get_int(o2);
497 min = json_object_get_int(o_min);
498 max = json_object_get_int(o_max);
499
500 ret = v >= min && v <= max;
501 } else {
502 pa_log_warn("Got a format type that we don't support");
503 }
504
505 out:
506 if (o1)
507 json_object_put(o1);
508 if (o2)
509 json_object_put(o2);
510
511 return ret;
512 }