00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369013 $");
00033
00034 #include "asterisk/_private.h"
00035 #include "asterisk/format.h"
00036 #include "asterisk/format_cap.h"
00037 #include "asterisk/frame.h"
00038 #include "asterisk/astobj2.h"
00039 #include "asterisk/utils.h"
00040
00041
00042 struct ast_format_cap {
00043
00044 struct ao2_container *formats;
00045 struct ao2_iterator it;
00046
00047 int nolock;
00048 };
00049
00050
00051
00052 static int cmp_cb(void *obj, void *arg, int flags)
00053 {
00054 struct ast_format *format1 = arg;
00055 struct ast_format *format2 = obj;
00056 enum ast_format_cmp_res res = ast_format_cmp(format1, format2);
00057
00058 return ((res == AST_FORMAT_CMP_EQUAL) ||
00059 (res == AST_FORMAT_CMP_SUBSET)) ?
00060 CMP_MATCH | CMP_STOP :
00061 0;
00062 }
00063
00064 static int hash_cb(const void *obj, const int flags)
00065 {
00066 const struct ast_format *format = obj;
00067 return format->id;
00068 }
00069
00070 static struct ast_format_cap *cap_alloc_helper(int nolock)
00071 {
00072 struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));
00073
00074 if (!cap) {
00075 return NULL;
00076 }
00077 cap->nolock = nolock;
00078 cap->formats = ao2_container_alloc_options(
00079 nolock ? AO2_ALLOC_OPT_LOCK_NOLOCK : AO2_ALLOC_OPT_LOCK_MUTEX,
00080 283, hash_cb, cmp_cb);
00081 if (!cap->formats) {
00082 ast_free(cap);
00083 return NULL;
00084 }
00085
00086 return cap;
00087 }
00088
00089 struct ast_format_cap *ast_format_cap_alloc_nolock(void)
00090 {
00091 return cap_alloc_helper(1);
00092 }
00093
00094 struct ast_format_cap *ast_format_cap_alloc(void)
00095 {
00096 return cap_alloc_helper(0);
00097 }
00098
00099 void *ast_format_cap_destroy(struct ast_format_cap *cap)
00100 {
00101 if (!cap) {
00102 return NULL;
00103 }
00104 ao2_ref(cap->formats, -1);
00105 ast_free(cap);
00106 return NULL;
00107 }
00108
00109 void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format)
00110 {
00111 struct ast_format *fnew;
00112
00113 if (!format || !format->id) {
00114 return;
00115 }
00116 if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) {
00117 return;
00118 }
00119 ast_format_copy(fnew, format);
00120 ao2_link(cap->formats, fnew);
00121 ao2_ref(fnew, -1);
00122 }
00123
00124 void ast_format_cap_add_all_by_type(struct ast_format_cap *cap, enum ast_format_type type)
00125 {
00126 int x;
00127 size_t f_len = 0;
00128 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00129
00130 for (x = 0; x < f_len; x++) {
00131 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) == type) {
00132 ast_format_cap_add(cap, &f_list[x].format);
00133 }
00134 }
00135 ast_format_list_destroy(f_list);
00136 }
00137
00138 void ast_format_cap_add_all(struct ast_format_cap *cap)
00139 {
00140 int x;
00141 size_t f_len = 0;
00142 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00143
00144 for (x = 0; x < f_len; x++) {
00145 ast_format_cap_add(cap, &f_list[x].format);
00146 }
00147 ast_format_list_destroy(f_list);
00148 }
00149
00150 static int append_cb(void *obj, void *arg, int flag)
00151 {
00152 struct ast_format_cap *result = (struct ast_format_cap *) arg;
00153 struct ast_format *format = (struct ast_format *) obj;
00154
00155 if (!ast_format_cap_iscompatible(result, format)) {
00156 ast_format_cap_add(result, format);
00157 }
00158
00159 return 0;
00160 }
00161
00162 void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
00163 {
00164 ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
00165 }
00166
00167 static int copy_cb(void *obj, void *arg, int flag)
00168 {
00169 struct ast_format_cap *result = (struct ast_format_cap *) arg;
00170 struct ast_format *format = (struct ast_format *) obj;
00171
00172 ast_format_cap_add(result, format);
00173 return 0;
00174 }
00175
00176 void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
00177 {
00178 ast_format_cap_remove_all(dst);
00179 ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
00180 }
00181
00182 struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
00183 {
00184 struct ast_format_cap *dst;
00185 if (cap->nolock) {
00186 dst = ast_format_cap_alloc_nolock();
00187 } else {
00188 dst = ast_format_cap_alloc();
00189 }
00190 if (!dst) {
00191 return NULL;
00192 }
00193 ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
00194 return dst;
00195 }
00196
00197 int ast_format_cap_is_empty(const struct ast_format_cap *cap)
00198 {
00199 if (!cap) {
00200 return 1;
00201 }
00202 return ao2_container_count(cap->formats) == 0 ? 1 : 0;
00203 }
00204
00205 static int find_exact_cb(void *obj, void *arg, int flag)
00206 {
00207 struct ast_format *format1 = (struct ast_format *) arg;
00208 struct ast_format *format2 = (struct ast_format *) obj;
00209
00210 return (ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH : 0;
00211 }
00212
00213 int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
00214 {
00215 struct ast_format *fremove;
00216
00217 fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
00218 if (fremove) {
00219 ao2_ref(fremove, -1);
00220 return 0;
00221 }
00222
00223 return -1;
00224 }
00225
00226 struct multiple_by_id_data {
00227 struct ast_format *format;
00228 int match_found;
00229 };
00230
00231 static int multiple_by_id_cb(void *obj, void *arg, int flag)
00232 {
00233 struct multiple_by_id_data *data = arg;
00234 struct ast_format *format = obj;
00235 int res;
00236
00237 res = (format->id == data->format->id) ? CMP_MATCH : 0;
00238 if (res) {
00239 data->match_found = 1;
00240 }
00241
00242 return res;
00243 }
00244
00245 int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id)
00246 {
00247 struct ast_format format = {
00248 .id = id,
00249 };
00250 struct multiple_by_id_data data = {
00251 .format = &format,
00252 .match_found = 0,
00253 };
00254
00255 ao2_callback(cap->formats,
00256 OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
00257 multiple_by_id_cb,
00258 &data);
00259
00260
00261 if (data.match_found) {
00262 return 0;
00263 }
00264
00265 return -1;
00266 }
00267
00268 static int multiple_by_type_cb(void *obj, void *arg, int flag)
00269 {
00270 int *type = arg;
00271 struct ast_format *format = obj;
00272 return ((AST_FORMAT_GET_TYPE(format->id)) == *type) ? CMP_MATCH : 0;
00273 }
00274
00275 void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
00276 {
00277 ao2_callback(cap->formats,
00278 OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
00279 multiple_by_type_cb,
00280 &type);
00281 }
00282
00283 void ast_format_cap_remove_all(struct ast_format_cap *cap)
00284 {
00285 ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
00286 }
00287
00288 void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
00289 {
00290 ast_format_cap_remove_all(cap);
00291 ast_format_cap_add(cap, format);
00292 }
00293
00294 int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result)
00295 {
00296 struct ast_format *f;
00297 struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
00298
00299 f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
00300 if (f) {
00301 ast_format_copy(result, f);
00302 ao2_ref(f, -1);
00303 return 1;
00304 }
00305 ast_format_clear(result);
00306 return 0;
00307 }
00308
00309 int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct ast_format *format)
00310 {
00311 struct ast_format *f;
00312 struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
00313
00314 if (!tmp_cap) {
00315 return 0;
00316 }
00317
00318 f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
00319 if (f) {
00320 ao2_ref(f, -1);
00321 return 1;
00322 }
00323
00324 return 0;
00325 }
00326
00327 struct byid_data {
00328 struct ast_format *result;
00329 enum ast_format_id id;
00330 };
00331 static int find_best_byid_cb(void *obj, void *arg, int flag)
00332 {
00333 struct ast_format *format = obj;
00334 struct byid_data *data = arg;
00335
00336 if (data->id != format->id) {
00337 return 0;
00338 }
00339 if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) {
00340 ast_format_copy(data->result, format);
00341 }
00342 return 0;
00343 }
00344
00345 int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result)
00346 {
00347 struct byid_data data;
00348 data.result = result;
00349 data.id = id;
00350
00351 ast_format_clear(result);
00352 ao2_callback(cap->formats,
00353 OBJ_MULTIPLE | OBJ_NODATA,
00354 find_best_byid_cb,
00355 &data);
00356 return result->id ? 1 : 0;
00357 }
00358
00359
00360
00361
00362
00363
00364 struct find_joint_data {
00365
00366 struct ast_format *format;
00367
00368 struct ast_format_cap *joint_cap;
00369 int joint_found;
00370 };
00371
00372 static int find_joint_cb(void *obj, void *arg, int flag)
00373 {
00374 struct ast_format *format = obj;
00375 struct find_joint_data *data = arg;
00376
00377 struct ast_format tmp = { 0, };
00378 if (!ast_format_joint(format, data->format, &tmp)) {
00379 if (data->joint_cap) {
00380 ast_format_cap_add(data->joint_cap, &tmp);
00381 }
00382 data->joint_found++;
00383 }
00384
00385 return 0;
00386 }
00387
00388 int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00389 {
00390 struct ao2_iterator it;
00391 struct ast_format *tmp;
00392 struct find_joint_data data = {
00393 .joint_found = 0,
00394 .joint_cap = NULL,
00395 };
00396
00397 it = ao2_iterator_init(cap1->formats, 0);
00398 while ((tmp = ao2_iterator_next(&it))) {
00399 data.format = tmp;
00400 ao2_callback(cap2->formats,
00401 OBJ_MULTIPLE | OBJ_NODATA,
00402 find_joint_cb,
00403 &data);
00404 ao2_ref(tmp, -1);
00405 }
00406 ao2_iterator_destroy(&it);
00407
00408 return data.joint_found ? 1 : 0;
00409 }
00410
00411 int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00412 {
00413 struct ao2_iterator it;
00414 struct ast_format *tmp;
00415
00416 if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) {
00417 return 0;
00418 }
00419
00420 it = ao2_iterator_init(cap1->formats, 0);
00421 while ((tmp = ao2_iterator_next(&it))) {
00422 if (!ast_format_cap_iscompatible(cap2, tmp)) {
00423 ao2_ref(tmp, -1);
00424 ao2_iterator_destroy(&it);
00425 return 0;
00426 }
00427 ao2_ref(tmp, -1);
00428 }
00429 ao2_iterator_destroy(&it);
00430
00431 return 1;
00432 }
00433
00434 struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
00435 {
00436 struct ao2_iterator it;
00437 struct ast_format_cap *result = ast_format_cap_alloc_nolock();
00438 struct ast_format *tmp;
00439 struct find_joint_data data = {
00440 .joint_found = 0,
00441 .joint_cap = result,
00442 };
00443 if (!result) {
00444 return NULL;
00445 }
00446
00447 it = ao2_iterator_init(cap1->formats, 0);
00448 while ((tmp = ao2_iterator_next(&it))) {
00449 data.format = tmp;
00450 ao2_callback(cap2->formats,
00451 OBJ_MULTIPLE | OBJ_NODATA,
00452 find_joint_cb,
00453 &data);
00454 ao2_ref(tmp, -1);
00455 }
00456 ao2_iterator_destroy(&it);
00457
00458 if (ao2_container_count(result->formats)) {
00459 return result;
00460 }
00461
00462 result = ast_format_cap_destroy(result);
00463 return NULL;
00464 }
00465
00466 static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append)
00467 {
00468 struct ao2_iterator it;
00469 struct ast_format *tmp;
00470 struct find_joint_data data = {
00471 .joint_cap = result,
00472 .joint_found = 0,
00473 };
00474 if (!append) {
00475 ast_format_cap_remove_all(result);
00476 }
00477 it = ao2_iterator_init(cap1->formats, 0);
00478 while ((tmp = ao2_iterator_next(&it))) {
00479 data.format = tmp;
00480 ao2_callback(cap2->formats,
00481 OBJ_MULTIPLE | OBJ_NODATA,
00482 find_joint_cb,
00483 &data);
00484 ao2_ref(tmp, -1);
00485 }
00486 ao2_iterator_destroy(&it);
00487
00488 return ao2_container_count(result->formats) ? 1 : 0;
00489 }
00490
00491 int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
00492 {
00493 return joint_copy_helper(cap1, cap2, result, 1);
00494 }
00495
00496 int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
00497 {
00498 return joint_copy_helper(cap1, cap2, result, 0);
00499 }
00500
00501 struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype)
00502 {
00503 struct ao2_iterator it;
00504 struct ast_format_cap *result = ast_format_cap_alloc_nolock();
00505 struct ast_format *tmp;
00506
00507 if (!result) {
00508 return NULL;
00509 }
00510
00511
00512
00513 it = ao2_iterator_init(cap->formats, 0);
00514 while ((tmp = ao2_iterator_next(&it))) {
00515 if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
00516
00517 ast_format_cap_add(result, tmp);
00518 }
00519 ao2_ref(tmp, -1);
00520 }
00521 ao2_iterator_destroy(&it);
00522
00523 if (ao2_container_count(result->formats)) {
00524 return result;
00525 }
00526 result = ast_format_cap_destroy(result);
00527
00528 return NULL;
00529 }
00530
00531
00532 int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type)
00533 {
00534 struct ao2_iterator it;
00535 struct ast_format *tmp;
00536
00537 it = ao2_iterator_init(cap->formats, 0);
00538 while ((tmp = ao2_iterator_next(&it))) {
00539 if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
00540 ao2_ref(tmp, -1);
00541 ao2_iterator_destroy(&it);
00542 return 1;
00543 }
00544 ao2_ref(tmp, -1);
00545 }
00546 ao2_iterator_destroy(&it);
00547
00548 return 0;
00549 }
00550
00551 void ast_format_cap_iter_start(struct ast_format_cap *cap)
00552 {
00553
00554 ao2_lock(cap->formats);
00555 cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK);
00556 }
00557
00558 void ast_format_cap_iter_end(struct ast_format_cap *cap)
00559 {
00560 ao2_iterator_destroy(&cap->it);
00561
00562 ao2_unlock(cap->formats);
00563 }
00564
00565 int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
00566 {
00567 struct ast_format *tmp = ao2_iterator_next(&cap->it);
00568
00569 if (!tmp) {
00570 return -1;
00571 }
00572 ast_format_copy(format, tmp);
00573 ao2_ref(tmp, -1);
00574
00575 return 0;
00576 }
00577
00578 char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap)
00579 {
00580 int x;
00581 unsigned len;
00582 char *start, *end = buf;
00583 struct ast_format tmp_fmt;
00584 size_t f_len;
00585 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00586
00587 if (!size) {
00588 f_list = ast_format_list_destroy(f_list);
00589 return buf;
00590 }
00591 snprintf(end, size, "(");
00592 len = strlen(end);
00593 end += len;
00594 size -= len;
00595 start = end;
00596 for (x = 0; x < f_len; x++) {
00597 ast_format_copy(&tmp_fmt, &f_list[x].format);
00598 if (ast_format_cap_iscompatible(cap, &tmp_fmt)) {
00599 snprintf(end, size, "%s|", f_list[x].name);
00600 len = strlen(end);
00601 end += len;
00602 size -= len;
00603 }
00604 }
00605 if (start == end) {
00606 ast_copy_string(start, "nothing)", size);
00607 } else if (size > 1) {
00608 *(end - 1) = ')';
00609 }
00610 f_list = ast_format_list_destroy(f_list);
00611 return buf;
00612 }
00613
00614 uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
00615 {
00616 uint64_t res = 0;
00617 struct ao2_iterator it;
00618 struct ast_format *tmp;
00619
00620 it = ao2_iterator_init(cap->formats, 0);
00621 while ((tmp = ao2_iterator_next(&it))) {
00622 res |= ast_format_to_old_bitfield(tmp);
00623 ao2_ref(tmp, -1);
00624 }
00625 ao2_iterator_destroy(&it);
00626 return res;
00627 }
00628
00629 void ast_format_cap_from_old_bitfield(struct ast_format_cap *dst, uint64_t src)
00630 {
00631 uint64_t tmp = 0;
00632 int x;
00633 struct ast_format tmp_format = { 0, };
00634
00635 ast_format_cap_remove_all(dst);
00636 for (x = 0; x < 64; x++) {
00637 tmp = (1ULL << x);
00638 if (tmp & src) {
00639 ast_format_cap_add(dst, ast_format_from_old_bitfield(&tmp_format, tmp));
00640 }
00641 }
00642 }