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