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