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, see <http://www.gnu.org/licenses/>. 20***/ 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24#endif 25 26#include <pulse/internal.h> 27#include <pulse/xmalloc.h> 28 29#include <pulsecore/core-format.h> 30#include <pulsecore/core-util.h> 31#include <pulsecore/i18n.h> 32#include <pulsecore/json.h> 33#include <pulsecore/macro.h> 34#include <pulsecore/strbuf.h> 35 36#include "format.h" 37 38#define PA_JSON_MIN_KEY "min" 39#define PA_JSON_MAX_KEY "max" 40 41static int pa_format_info_prop_compatible(const char *one, const char *two); 42 43static const char* const _encoding_str_table[]= { 44 [PA_ENCODING_PCM] = "pcm", 45 [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937", 46 [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937", 47 [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937", 48 [PA_ENCODING_DTS_IEC61937] = "dts-iec61937", 49 [PA_ENCODING_MPEG2_AAC_IEC61937] = "mpeg2-aac-iec61937", 50 [PA_ENCODING_TRUEHD_IEC61937] = "truehd-iec61937", 51 [PA_ENCODING_DTSHD_IEC61937] = "dtshd-iec61937", 52 [PA_ENCODING_ANY] = "any", 53}; 54 55const 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 62pa_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 72pa_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 81pa_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 98void 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 105int pa_format_info_valid(const pa_format_info *f) { 106 return (f->encoding >= 0 && f->encoding < PA_ENCODING_MAX && f->plist != NULL); 107} 108 109int pa_format_info_is_pcm(const pa_format_info *f) { 110 return f->encoding == PA_ENCODING_PCM; 111} 112 113char *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 136pa_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 161out: 162 if (encoding) 163 pa_xfree(encoding); 164 if (properties) 165 pa_xfree(properties); 166 return f; 167 168error: 169 pa_format_info_free(f); 170 f = NULL; 171 goto out; 172} 173 174int 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 197pa_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 */ 220int 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 239pa_prop_type_t pa_format_info_get_prop_type(const pa_format_info *f, const char *key) { 240 const char *str; 241 pa_json_object *o; 242 const pa_json_object *o1; 243 pa_prop_type_t type; 244 245 pa_assert(f); 246 pa_assert(key); 247 248 str = pa_proplist_gets(f->plist, key); 249 if (!str) 250 return PA_PROP_TYPE_INVALID; 251 252 o = pa_json_parse(str); 253 if (!o) 254 return PA_PROP_TYPE_INVALID; 255 256 switch (pa_json_object_get_type(o)) { 257 case PA_JSON_TYPE_INT: 258 type = PA_PROP_TYPE_INT; 259 break; 260 261 case PA_JSON_TYPE_STRING: 262 type = PA_PROP_TYPE_STRING; 263 break; 264 265 case PA_JSON_TYPE_ARRAY: 266 if (pa_json_object_get_array_length(o) == 0) { 267 /* Unlikely, but let's account for this anyway. We need at 268 * least one element to figure out the array type. */ 269 type = PA_PROP_TYPE_INVALID; 270 break; 271 } 272 273 o1 = pa_json_object_get_array_member(o, 0); 274 275 if (pa_json_object_get_type(o1) == PA_JSON_TYPE_INT) 276 type = PA_PROP_TYPE_INT_ARRAY; 277 else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_STRING) 278 type = PA_PROP_TYPE_STRING_ARRAY; 279 else 280 type = PA_PROP_TYPE_INVALID; 281 282 break; 283 284 case PA_JSON_TYPE_OBJECT: 285 /* We actually know at this point that it's a int range, but let's 286 * confirm. */ 287 if (!pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) { 288 type = PA_PROP_TYPE_INVALID; 289 break; 290 } 291 292 if (!pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) { 293 type = PA_PROP_TYPE_INVALID; 294 break; 295 } 296 297 type = PA_PROP_TYPE_INT_RANGE; 298 break; 299 300 default: 301 type = PA_PROP_TYPE_INVALID; 302 break; 303 } 304 305 pa_json_object_free(o); 306 return type; 307} 308 309int pa_format_info_get_prop_int(const pa_format_info *f, const char *key, int *v) { 310 const char *str; 311 pa_json_object *o; 312 313 pa_assert(f); 314 pa_assert(key); 315 pa_assert(v); 316 317 str = pa_proplist_gets(f->plist, key); 318 if (!str) 319 return -PA_ERR_NOENTITY; 320 321 o = pa_json_parse(str); 322 if (!o) { 323 pa_log_debug("Failed to parse format info property '%s'.", key); 324 return -PA_ERR_INVALID; 325 } 326 327 if (pa_json_object_get_type(o) != PA_JSON_TYPE_INT) { 328 pa_log_debug("Format info property '%s' type is not int.", key); 329 pa_json_object_free(o); 330 return -PA_ERR_INVALID; 331 } 332 333 *v = pa_json_object_get_int(o); 334 pa_json_object_free(o); 335 336 return 0; 337} 338 339int pa_format_info_get_prop_int_range(const pa_format_info *f, const char *key, int *min, int *max) { 340 const char *str; 341 pa_json_object *o; 342 const pa_json_object *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 = pa_json_parse(str); 355 if (!o) { 356 pa_log_debug("Failed to parse format info property '%s'.", key); 357 return -PA_ERR_INVALID; 358 } 359 360 if (pa_json_object_get_type(o) != PA_JSON_TYPE_OBJECT) 361 goto out; 362 363 if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MIN_KEY)) || 364 (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT)) 365 goto out; 366 367 *min = pa_json_object_get_int(o1); 368 369 if (!(o1 = pa_json_object_get_object_member(o, PA_JSON_MAX_KEY)) || 370 (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT)) 371 goto out; 372 373 *max = pa_json_object_get_int(o1); 374 375 ret = 0; 376 377out: 378 if (ret < 0) 379 pa_log_debug("Format info property '%s' is not a valid int range.", key); 380 381 pa_json_object_free(o); 382 return ret; 383} 384 385int pa_format_info_get_prop_int_array(const pa_format_info *f, const char *key, int **values, int *n_values) { 386 const char *str; 387 pa_json_object *o; 388 const pa_json_object *o1; 389 int i, ret = -PA_ERR_INVALID; 390 391 pa_assert(f); 392 pa_assert(key); 393 pa_assert(values); 394 pa_assert(n_values); 395 396 str = pa_proplist_gets(f->plist, key); 397 if (!str) 398 return -PA_ERR_NOENTITY; 399 400 o = pa_json_parse(str); 401 if (!o) { 402 pa_log_debug("Failed to parse format info property '%s'.", key); 403 return -PA_ERR_INVALID; 404 } 405 406 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY) 407 goto out; 408 409 *n_values = pa_json_object_get_array_length(o); 410 *values = pa_xnew(int, *n_values); 411 412 for (i = 0; i < *n_values; i++) { 413 o1 = pa_json_object_get_array_member(o, i); 414 415 if (pa_json_object_get_type(o1) != PA_JSON_TYPE_INT) { 416 goto out; 417 } 418 419 (*values)[i] = pa_json_object_get_int(o1); 420 } 421 422 ret = 0; 423 424out: 425 if (ret < 0) 426 pa_log_debug("Format info property '%s' is not a valid int array.", key); 427 428 pa_json_object_free(o); 429 return ret; 430} 431 432int pa_format_info_get_prop_string(const pa_format_info *f, const char *key, char **v) { 433 const char *str = NULL; 434 pa_json_object *o; 435 436 pa_assert(f); 437 pa_assert(key); 438 pa_assert(v); 439 440 str = pa_proplist_gets(f->plist, key); 441 if (!str) 442 return -PA_ERR_NOENTITY; 443 444 o = pa_json_parse(str); 445 if (!o) { 446 pa_log_debug("Failed to parse format info property '%s'.", key); 447 return -PA_ERR_INVALID; 448 } 449 450 if (pa_json_object_get_type(o) != PA_JSON_TYPE_STRING) { 451 pa_log_debug("Format info property '%s' type is not string.", key); 452 pa_json_object_free(o); 453 return -PA_ERR_INVALID; 454 } 455 456 *v = pa_xstrdup(pa_json_object_get_string(o)); 457 pa_json_object_free(o); 458 459 return 0; 460} 461 462int pa_format_info_get_prop_string_array(const pa_format_info *f, const char *key, char ***values, int *n_values) { 463 const char *str; 464 pa_json_object *o; 465 const pa_json_object *o1; 466 int i, ret = -PA_ERR_INVALID; 467 468 pa_assert(f); 469 pa_assert(key); 470 pa_assert(values); 471 pa_assert(n_values); 472 473 str = pa_proplist_gets(f->plist, key); 474 if (!str) 475 return -PA_ERR_NOENTITY; 476 477 o = pa_json_parse(str); 478 if (!o) { 479 pa_log_debug("Failed to parse format info property '%s'.", key); 480 return -PA_ERR_INVALID; 481 } 482 483 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY) 484 goto out; 485 486 *n_values = pa_json_object_get_array_length(o); 487 *values = pa_xnew(char *, *n_values); 488 489 for (i = 0; i < *n_values; i++) { 490 o1 = pa_json_object_get_array_member(o, i); 491 492 if (pa_json_object_get_type(o1) != PA_JSON_TYPE_STRING) { 493 goto out; 494 } 495 496 (*values)[i] = pa_xstrdup(pa_json_object_get_string(o1)); 497 } 498 499 ret = 0; 500 501out: 502 if (ret < 0) 503 pa_log_debug("Format info property '%s' is not a valid string array.", key); 504 505 pa_json_object_free(o); 506 return ret; 507} 508 509void pa_format_info_free_string_array(char **values, int n_values) { 510 int i; 511 512 for (i = 0; i < n_values; i++) 513 pa_xfree(values[i]); 514 515 pa_xfree(values); 516} 517 518int pa_format_info_get_sample_format(const pa_format_info *f, pa_sample_format_t *sf) { 519 int r; 520 char *sf_str; 521 pa_sample_format_t sf_local; 522 523 pa_assert(f); 524 pa_assert(sf); 525 526 r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf_str); 527 if (r < 0) 528 return r; 529 530 sf_local = pa_parse_sample_format(sf_str); 531 pa_xfree(sf_str); 532 533 if (!pa_sample_format_valid(sf_local)) { 534 pa_log_debug("Invalid sample format."); 535 return -PA_ERR_INVALID; 536 } 537 538 *sf = sf_local; 539 540 return 0; 541} 542 543int pa_format_info_get_rate(const pa_format_info *f, uint32_t *rate) { 544 int r; 545 int rate_local; 546 547 pa_assert(f); 548 pa_assert(rate); 549 550 r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate_local); 551 if (r < 0) 552 return r; 553 554 if (!pa_sample_rate_valid(rate_local)) { 555 pa_log_debug("Invalid sample rate: %i", rate_local); 556 return -PA_ERR_INVALID; 557 } 558 559 *rate = rate_local; 560 561 return 0; 562} 563 564int pa_format_info_get_channels(const pa_format_info *f, uint8_t *channels) { 565 int r; 566 int channels_local; 567 568 pa_assert(f); 569 pa_assert(channels); 570 571 r = pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels_local); 572 if (r < 0) 573 return r; 574 575 if (!pa_channels_valid(channels_local)) { 576 pa_log_debug("Invalid channel count: %i", channels_local); 577 return -PA_ERR_INVALID; 578 } 579 580 *channels = channels_local; 581 582 return 0; 583} 584 585int pa_format_info_get_channel_map(const pa_format_info *f, pa_channel_map *map) { 586 int r; 587 char *map_str; 588 589 pa_assert(f); 590 pa_assert(map); 591 592 r = pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &map_str); 593 if (r < 0) 594 return r; 595 596 map = pa_channel_map_parse(map, map_str); 597 pa_xfree(map_str); 598 599 if (!map) { 600 pa_log_debug("Failed to parse channel map."); 601 return -PA_ERR_INVALID; 602 } 603 604 return 0; 605} 606 607void pa_format_info_set_sample_format(pa_format_info *f, pa_sample_format_t sf) { 608 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, pa_sample_format_to_string(sf)); 609} 610 611void pa_format_info_set_rate(pa_format_info *f, int rate) { 612 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_RATE, rate); 613} 614 615void pa_format_info_set_channels(pa_format_info *f, int channels) { 616 pa_format_info_set_prop_int(f, PA_PROP_FORMAT_CHANNELS, channels); 617} 618 619void pa_format_info_set_channel_map(pa_format_info *f, const pa_channel_map *map) { 620 char map_str[PA_CHANNEL_MAP_SNPRINT_MAX]; 621 622 pa_channel_map_snprint(map_str, sizeof(map_str), map); 623 624 pa_format_info_set_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, map_str); 625} 626 627void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value) { 628 pa_assert(f); 629 pa_assert(key); 630 631 pa_proplist_setf(f->plist, key, "%d", value); 632} 633 634void pa_format_info_set_prop_int_array(pa_format_info *f, const char *key, const int *values, int n_values) { 635 pa_strbuf *buf; 636 char *str; 637 int i; 638 639 pa_assert(f); 640 pa_assert(key); 641 pa_assert(n_values > 0); 642 643 buf = pa_strbuf_new(); 644 645 pa_strbuf_printf(buf, "[ %d", values[0]); 646 647 for (i = 1; i < n_values; i++) 648 pa_strbuf_printf(buf, ", %d", values[i]); 649 650 pa_strbuf_printf(buf, " ]"); 651 str = pa_strbuf_to_string_free(buf); 652 653 pa_proplist_sets(f->plist, key, str); 654 pa_xfree (str); 655} 656 657void pa_format_info_set_prop_int_range(pa_format_info *f, const char *key, int min, int max) { 658 pa_assert(f); 659 pa_assert(key); 660 661 pa_proplist_setf(f->plist, key, "{ \"" PA_JSON_MIN_KEY "\": %d, \"" PA_JSON_MAX_KEY "\": %d }", 662 min, max); 663} 664 665void pa_format_info_set_prop_string(pa_format_info *f, const char *key, const char *value) { 666 pa_assert(f); 667 pa_assert(key); 668 669 pa_proplist_setf(f->plist, key, "\"%s\"", value); 670} 671 672void pa_format_info_set_prop_string_array(pa_format_info *f, const char *key, const char **values, int n_values) { 673 pa_strbuf *buf; 674 char *str; 675 int i; 676 677 pa_assert(f); 678 pa_assert(key); 679 680 buf = pa_strbuf_new(); 681 682 pa_strbuf_printf(buf, "[ \"%s\"", values[0]); 683 684 for (i = 1; i < n_values; i++) 685 pa_strbuf_printf(buf, ", \"%s\"", values[i]); 686 687 pa_strbuf_printf(buf, " ]"); 688 str = pa_strbuf_to_string_free(buf); 689 690 pa_proplist_sets(f->plist, key, str); 691 pa_xfree (str); 692} 693 694static bool pa_json_is_fixed_type(pa_json_object *o) { 695 switch(pa_json_object_get_type(o)) { 696 case PA_JSON_TYPE_OBJECT: 697 case PA_JSON_TYPE_ARRAY: 698 return false; 699 700 default: 701 return true; 702 } 703} 704 705static int pa_format_info_prop_compatible(const char *one, const char *two) { 706 pa_json_object *o1 = NULL, *o2 = NULL; 707 int i, ret = 0; 708 709 o1 = pa_json_parse(one); 710 if (!o1) 711 goto out; 712 713 o2 = pa_json_parse(two); 714 if (!o2) 715 goto out; 716 717 /* We don't deal with both values being non-fixed - just because there is no immediate need (FIXME) */ 718 pa_return_val_if_fail(pa_json_is_fixed_type(o1) || pa_json_is_fixed_type(o2), false); 719 720 if (pa_json_is_fixed_type(o1) && pa_json_is_fixed_type(o2)) { 721 ret = pa_json_object_equal(o1, o2); 722 goto out; 723 } 724 725 if (pa_json_is_fixed_type(o1)) { 726 pa_json_object *tmp = o2; 727 o2 = o1; 728 o1 = tmp; 729 } 730 731 /* o2 is now a fixed type, and o1 is not */ 732 733 if (pa_json_object_get_type(o1) == PA_JSON_TYPE_ARRAY) { 734 for (i = 0; i < pa_json_object_get_array_length(o1); i++) { 735 if (pa_json_object_equal(pa_json_object_get_array_member(o1, i), o2)) { 736 ret = 1; 737 break; 738 } 739 } 740 } else if (pa_json_object_get_type(o1) == PA_JSON_TYPE_OBJECT) { 741 /* o1 should be a range type */ 742 int min, max, v; 743 const pa_json_object *o_min = NULL, *o_max = NULL; 744 745 if (pa_json_object_get_type(o2) != PA_JSON_TYPE_INT) { 746 /* We don't support non-integer ranges */ 747 goto out; 748 } 749 750 if (!(o_min = pa_json_object_get_object_member(o1, PA_JSON_MIN_KEY)) || 751 pa_json_object_get_type(o_min) != PA_JSON_TYPE_INT) 752 goto out; 753 754 if (!(o_max = pa_json_object_get_object_member(o1, PA_JSON_MAX_KEY)) || 755 pa_json_object_get_type(o_max) != PA_JSON_TYPE_INT) 756 goto out; 757 758 v = pa_json_object_get_int(o2); 759 min = pa_json_object_get_int(o_min); 760 max = pa_json_object_get_int(o_max); 761 762 ret = v >= min && v <= max; 763 } else { 764 pa_log_warn("Got a format type that we don't support"); 765 } 766 767out: 768 if (o1) 769 pa_json_object_free(o1); 770 if (o2) 771 pa_json_object_free(o2); 772 773 return ret; 774} 775