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
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411310 $");
00035
00036 #include "asterisk/_private.h"
00037 #include "asterisk/format.h"
00038 #include "asterisk/astobj2.h"
00039 #include "asterisk/lock.h"
00040 #include "asterisk/frame.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/rtp_engine.h"
00044 #include "asterisk/config.h"
00045
00046 #define FORMAT_CONFIG "codecs.conf"
00047
00048
00049
00050
00051
00052
00053 static struct ao2_container *interfaces;
00054
00055
00056 struct interface_ao2_wrapper {
00057 enum ast_format_id id;
00058 const struct ast_format_attr_interface *interface;
00059 };
00060
00061
00062
00063 static struct ao2_container *format_list;
00064
00065
00066
00067 static struct ast_format_list *format_list_array;
00068 static size_t format_list_array_len = 0;
00069
00070 static ast_rwlock_t format_list_array_lock;
00071
00072 static int interface_cmp_cb(void *obj, void *arg, int flags)
00073 {
00074 struct interface_ao2_wrapper *wrapper1 = obj;
00075 struct interface_ao2_wrapper *wrapper2 = arg;
00076
00077 return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
00078 }
00079
00080 static int interface_hash_cb(const void *obj, const int flags)
00081 {
00082 const struct interface_ao2_wrapper *wrapper = obj;
00083 return wrapper->id;
00084 }
00085
00086 void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
00087 {
00088 *dst = *src;
00089 }
00090
00091 void ast_format_set_video_mark(struct ast_format *format)
00092 {
00093 format->fattr.rtp_marker_bit = 1;
00094 }
00095
00096 int ast_format_get_video_mark(const struct ast_format *format)
00097 {
00098 return format->fattr.rtp_marker_bit;
00099 }
00100
00101 static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
00102 {
00103 struct interface_ao2_wrapper tmp_wrapper = {
00104 .id = format->id,
00105 };
00106
00107 return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
00108 }
00109
00110 static int has_interface(const struct ast_format *format)
00111 {
00112 struct interface_ao2_wrapper *wrapper;
00113
00114 wrapper = find_interface(format);
00115 if (!wrapper) {
00116 return 0;
00117 }
00118 ao2_ref(wrapper, -1);
00119 return 1;
00120 }
00121
00122 int ast_format_sdp_parse(struct ast_format *format, const char *attributes)
00123 {
00124 struct interface_ao2_wrapper *wrapper;
00125 int res;
00126
00127 if (!(wrapper = find_interface(format))) {
00128 return 0;
00129 }
00130
00131 ao2_rdlock(wrapper);
00132 if (!wrapper->interface || !wrapper->interface->format_attr_sdp_parse) {
00133 ao2_unlock(wrapper);
00134 ao2_ref(wrapper, -1);
00135 return 0;
00136 }
00137
00138 res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes);
00139
00140 ao2_unlock(wrapper);
00141 ao2_ref(wrapper, -1);
00142
00143 return res;
00144 }
00145
00146 void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str)
00147 {
00148 struct interface_ao2_wrapper *wrapper;
00149
00150 if (!(wrapper = find_interface(format))) {
00151 return;
00152 }
00153
00154 ao2_rdlock(wrapper);
00155 if (!wrapper->interface || !wrapper->interface->format_attr_sdp_generate) {
00156 ao2_unlock(wrapper);
00157 ao2_ref(wrapper, -1);
00158 return;
00159 }
00160
00161 wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str);
00162
00163 ao2_unlock(wrapper);
00164 ao2_ref(wrapper, -1);
00165 }
00166
00167
00168
00169
00170 static int format_set_helper(struct ast_format *format, va_list ap)
00171 {
00172 struct interface_ao2_wrapper *wrapper;
00173
00174 if (!(wrapper = find_interface(format))) {
00175 ast_log(LOG_WARNING, "Could not find format interface to set.\n");
00176 return -1;
00177 }
00178
00179 ao2_rdlock(wrapper);
00180 if (!wrapper->interface || !wrapper->interface->format_attr_set) {
00181 ao2_unlock(wrapper);
00182 ao2_ref(wrapper, -1);
00183 return -1;
00184 }
00185
00186 wrapper->interface->format_attr_set(&format->fattr, ap);
00187
00188 ao2_unlock(wrapper);
00189 ao2_ref(wrapper, -1);
00190
00191 return 0;
00192 }
00193
00194 struct ast_format *ast_format_append(struct ast_format *format, ... )
00195 {
00196 va_list ap;
00197 va_start(ap, format);
00198 format_set_helper(format, ap);
00199 va_end(ap);
00200
00201 return format;
00202 }
00203
00204 struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
00205 {
00206
00207 ast_format_clear(format);
00208
00209 format->id = id;
00210
00211 if (set_attributes) {
00212 va_list ap;
00213 va_start(ap, set_attributes);
00214 format_set_helper(format, ap);
00215 va_end(ap);
00216 }
00217
00218 return format;
00219 }
00220
00221 void ast_format_clear(struct ast_format *format)
00222 {
00223 format->id = 0;
00224 memset(&format->fattr, 0, sizeof(format->fattr));
00225 }
00226
00227
00228
00229
00230 static int format_isset_helper(const struct ast_format *format, va_list ap)
00231 {
00232 int res;
00233 struct interface_ao2_wrapper *wrapper;
00234 struct ast_format tmp = {
00235 .id = format->id,
00236 .fattr = { { 0, }, },
00237 };
00238
00239 if (!(wrapper = find_interface(format))) {
00240 return -1;
00241 }
00242
00243 ao2_rdlock(wrapper);
00244 if (!wrapper->interface ||
00245 !wrapper->interface->format_attr_set ||
00246 !wrapper->interface->format_attr_cmp) {
00247
00248 ao2_unlock(wrapper);
00249 ao2_ref(wrapper, -1);
00250 return -1;
00251 }
00252
00253
00254
00255 if (wrapper->interface->format_attr_isset) {
00256 res = wrapper->interface->format_attr_isset(&format->fattr, ap);
00257 } else {
00258 wrapper->interface->format_attr_set(&tmp.fattr, ap);
00259
00260 res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
00261 res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
00262 }
00263
00264 ao2_unlock(wrapper);
00265 ao2_ref(wrapper, -1);
00266
00267 return res;
00268 }
00269
00270 int ast_format_isset(const struct ast_format *format, ... )
00271 {
00272 va_list ap;
00273 int res;
00274
00275 va_start(ap, format);
00276 res = format_isset_helper(format, ap);
00277 va_end(ap);
00278 return res;
00279 }
00280
00281 int ast_format_get_value(const struct ast_format *format, int key, void *value)
00282 {
00283 int res = 0;
00284 struct interface_ao2_wrapper *wrapper;
00285
00286 if (!(wrapper = find_interface(format))) {
00287 return -1;
00288 }
00289 ao2_rdlock(wrapper);
00290 if (!wrapper->interface ||
00291 !wrapper->interface->format_attr_get_val) {
00292
00293 ao2_unlock(wrapper);
00294 ao2_ref(wrapper, -1);
00295 return -1;
00296 }
00297
00298 res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
00299
00300 ao2_unlock(wrapper);
00301 ao2_ref(wrapper, -1);
00302
00303 return res;
00304 }
00305
00306
00307
00308
00309 static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
00310 {
00311 enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
00312 struct interface_ao2_wrapper *wrapper;
00313
00314 if (!(wrapper = find_interface(format1))) {
00315 return res;
00316 }
00317
00318 ao2_rdlock(wrapper);
00319 if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
00320 ao2_unlock(wrapper);
00321 ao2_ref(wrapper, -1);
00322 return res;
00323 }
00324
00325 res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
00326
00327 ao2_unlock(wrapper);
00328 ao2_ref(wrapper, -1);
00329
00330 return res;
00331 }
00332
00333 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
00334 {
00335 if (format1->id != format2->id) {
00336 return AST_FORMAT_CMP_NOT_EQUAL;
00337 }
00338
00339 return format_cmp_helper(format1, format2);
00340 }
00341
00342
00343
00344
00345 static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
00346 {
00347 int res = 0;
00348 struct interface_ao2_wrapper *wrapper;
00349
00350 if (!(wrapper = find_interface(format1))) {
00351
00352 return res;
00353 }
00354
00355 ao2_rdlock(wrapper);
00356 if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
00357 res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
00358 }
00359 ao2_unlock(wrapper);
00360
00361 ao2_ref(wrapper, -1);
00362
00363 return res;
00364 }
00365
00366 int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
00367 {
00368 if (format1->id != format2->id) {
00369 return -1;
00370 }
00371 result->id = format1->id;
00372 return format_joint_helper(format1, format2, result);
00373 }
00374
00375
00376 uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
00377 {
00378 switch (id) {
00379
00380 case AST_FORMAT_G723_1:
00381 return (1ULL << 0);
00382
00383 case AST_FORMAT_GSM:
00384 return (1ULL << 1);
00385
00386 case AST_FORMAT_ULAW:
00387 return (1ULL << 2);
00388
00389 case AST_FORMAT_ALAW:
00390 return (1ULL << 3);
00391
00392 case AST_FORMAT_G726_AAL2:
00393 return (1ULL << 4);
00394
00395 case AST_FORMAT_ADPCM:
00396 return (1ULL << 5);
00397
00398 case AST_FORMAT_SLINEAR:
00399 return (1ULL << 6);
00400
00401 case AST_FORMAT_LPC10:
00402 return (1ULL << 7);
00403
00404 case AST_FORMAT_G729A:
00405 return (1ULL << 8);
00406
00407 case AST_FORMAT_SPEEX:
00408 return (1ULL << 9);
00409
00410 case AST_FORMAT_ILBC:
00411 return (1ULL << 10);
00412
00413 case AST_FORMAT_G726:
00414 return (1ULL << 11);
00415
00416 case AST_FORMAT_G722:
00417 return (1ULL << 12);
00418
00419 case AST_FORMAT_SIREN7:
00420 return (1ULL << 13);
00421
00422 case AST_FORMAT_SIREN14:
00423 return (1ULL << 14);
00424
00425 case AST_FORMAT_SLINEAR16:
00426 return (1ULL << 15);
00427
00428 case AST_FORMAT_G719:
00429 return (1ULL << 32);
00430
00431 case AST_FORMAT_SPEEX16:
00432 return (1ULL << 33);
00433
00434 case AST_FORMAT_TESTLAW:
00435 return (1ULL << 47);
00436
00437
00438 case AST_FORMAT_H261:
00439 return (1ULL << 18);
00440
00441 case AST_FORMAT_H263:
00442 return (1ULL << 19);
00443
00444 case AST_FORMAT_H263_PLUS:
00445 return (1ULL << 20);
00446
00447 case AST_FORMAT_H264:
00448 return (1ULL << 21);
00449
00450 case AST_FORMAT_MP4_VIDEO:
00451 return (1ULL << 22);
00452
00453
00454 case AST_FORMAT_JPEG:
00455 return (1ULL << 16);
00456
00457 case AST_FORMAT_PNG:
00458 return (1ULL << 17);
00459
00460
00461 case AST_FORMAT_T140RED:
00462 return (1ULL << 26);
00463
00464 case AST_FORMAT_T140:
00465 return (1ULL << 27);
00466 default:
00467 return 0;
00468 }
00469
00470 return 0;
00471
00472 }
00473 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
00474 {
00475 return ast_format_id_to_old_bitfield(format->id);
00476 }
00477
00478 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
00479 {
00480 switch (src) {
00481
00482 case (1ULL << 0):
00483 return ast_format_set(dst, AST_FORMAT_G723_1, 0);
00484
00485 case (1ULL << 1):
00486 return ast_format_set(dst, AST_FORMAT_GSM, 0);
00487
00488 case (1ULL << 2):
00489 return ast_format_set(dst, AST_FORMAT_ULAW, 0);
00490
00491 case (1ULL << 3):
00492 return ast_format_set(dst, AST_FORMAT_ALAW, 0);
00493
00494 case (1ULL << 4):
00495 return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
00496
00497 case (1ULL << 5):
00498 return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
00499
00500 case (1ULL << 6):
00501 return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
00502
00503 case (1ULL << 7):
00504 return ast_format_set(dst, AST_FORMAT_LPC10, 0);
00505
00506 case (1ULL << 8):
00507 return ast_format_set(dst, AST_FORMAT_G729A, 0);
00508
00509 case (1ULL << 9):
00510 return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
00511
00512 case (1ULL << 10):
00513 return ast_format_set(dst, AST_FORMAT_ILBC, 0);
00514
00515 case (1ULL << 11):
00516 return ast_format_set(dst, AST_FORMAT_G726, 0);
00517
00518 case (1ULL << 12):
00519 return ast_format_set(dst, AST_FORMAT_G722, 0);
00520
00521 case (1ULL << 13):
00522 return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
00523
00524 case (1ULL << 14):
00525 return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
00526
00527 case (1ULL << 15):
00528 return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
00529
00530 case (1ULL << 32):
00531 return ast_format_set(dst, AST_FORMAT_G719, 0);
00532
00533 case (1ULL << 33):
00534 return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
00535
00536 case (1ULL << 47):
00537 return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
00538
00539
00540 case (1ULL << 18):
00541 return ast_format_set(dst, AST_FORMAT_H261, 0);
00542
00543 case (1ULL << 19):
00544 return ast_format_set(dst, AST_FORMAT_H263, 0);
00545
00546 case (1ULL << 20):
00547 return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
00548
00549 case (1ULL << 21):
00550 return ast_format_set(dst, AST_FORMAT_H264, 0);
00551
00552 case (1ULL << 22):
00553 return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
00554
00555
00556 case (1ULL << 16):
00557 return ast_format_set(dst, AST_FORMAT_JPEG, 0);
00558
00559 case (1ULL << 17):
00560 return ast_format_set(dst, AST_FORMAT_PNG, 0);
00561
00562
00563 case (1ULL << 26):
00564 return ast_format_set(dst, AST_FORMAT_T140RED, 0);
00565
00566 case (1ULL << 27):
00567 return ast_format_set(dst, AST_FORMAT_T140, 0);
00568 }
00569 ast_format_clear(dst);
00570 return NULL;
00571 }
00572
00573 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
00574 {
00575 struct ast_format dst;
00576 if (ast_format_from_old_bitfield(&dst, src)) {
00577 return dst.id;
00578 }
00579 return 0;
00580 }
00581
00582 int ast_format_is_slinear(const struct ast_format *format)
00583 {
00584 if (format->id == AST_FORMAT_SLINEAR ||
00585 format->id == AST_FORMAT_SLINEAR12 ||
00586 format->id == AST_FORMAT_SLINEAR16 ||
00587 format->id == AST_FORMAT_SLINEAR24 ||
00588 format->id == AST_FORMAT_SLINEAR32 ||
00589 format->id == AST_FORMAT_SLINEAR44 ||
00590 format->id == AST_FORMAT_SLINEAR48 ||
00591 format->id == AST_FORMAT_SLINEAR96 ||
00592 format->id == AST_FORMAT_SLINEAR192) {
00593 return 1;
00594 }
00595 return 0;
00596 }
00597
00598 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
00599 {
00600 if (rate >= 192000) {
00601 return AST_FORMAT_SLINEAR192;
00602 } else if (rate >= 96000) {
00603 return AST_FORMAT_SLINEAR96;
00604 } else if (rate >= 48000) {
00605 return AST_FORMAT_SLINEAR48;
00606 } else if (rate >= 44100) {
00607 return AST_FORMAT_SLINEAR44;
00608 } else if (rate >= 32000) {
00609 return AST_FORMAT_SLINEAR32;
00610 } else if (rate >= 24000) {
00611 return AST_FORMAT_SLINEAR24;
00612 } else if (rate >= 16000) {
00613 return AST_FORMAT_SLINEAR16;
00614 } else if (rate >= 12000) {
00615 return AST_FORMAT_SLINEAR12;
00616 }
00617 return AST_FORMAT_SLINEAR;
00618 }
00619
00620 const char* ast_getformatname(const struct ast_format *format)
00621 {
00622 int x;
00623 const char *ret = "unknown";
00624 size_t f_len;
00625 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00626 for (x = 0; x < f_len; x++) {
00627 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00628 ret = f_list[x].name;
00629 break;
00630 }
00631 }
00632 f_list = ast_format_list_destroy(f_list);
00633 return ret;
00634 }
00635
00636
00637 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
00638 {
00639 int x;
00640 unsigned len;
00641 char *start, *end = buf;
00642 size_t f_len;
00643 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00644
00645 if (!size) {
00646 f_list = ast_format_list_destroy(f_list);
00647 return buf;
00648 }
00649 snprintf(end, size, "(");
00650 len = strlen(end);
00651 end += len;
00652 size -= len;
00653 start = end;
00654 for (x = 0; x < f_len; x++) {
00655 if (f_list[x].format.id == id) {
00656 snprintf(end, size, "%s|", f_list[x].name);
00657 len = strlen(end);
00658 end += len;
00659 size -= len;
00660 }
00661 }
00662 if (start == end) {
00663 ast_copy_string(start, "nothing)", size);
00664 } else if (size > 1) {
00665 *(end - 1) = ')';
00666 }
00667 f_list = ast_format_list_destroy(f_list);
00668 return buf;
00669 }
00670
00671 static struct ast_codec_alias_table {
00672 const char *alias;
00673 const char *realname;
00674 } ast_codec_alias_table[] = {
00675 { "slinear", "slin"},
00676 { "slinear16", "slin16"},
00677 { "g723.1", "g723"},
00678 { "g722.1", "siren7"},
00679 { "g722.1c", "siren14"},
00680 };
00681
00682 static const char *ast_expand_codec_alias(const char *in)
00683 {
00684 int x;
00685
00686 for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
00687 if (!strcmp(in,ast_codec_alias_table[x].alias))
00688 return ast_codec_alias_table[x].realname;
00689 }
00690 return in;
00691 }
00692
00693 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
00694 {
00695 int x;
00696 size_t f_len;
00697 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00698
00699 for (x = 0; x < f_len; x++) {
00700 if (!strcasecmp(f_list[x].name, name) ||
00701 !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
00702
00703 ast_format_copy(result, &f_list[x].format);
00704 f_list = ast_format_list_destroy(f_list);
00705 return result;
00706 }
00707 }
00708 f_list = ast_format_list_destroy(f_list);
00709
00710 return NULL;
00711 }
00712
00713 const char *ast_codec2str(struct ast_format *format)
00714 {
00715 int x;
00716 const char *ret = "unknown";
00717 size_t f_len;
00718 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
00719
00720 for (x = 0; x < f_len; x++) {
00721 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
00722 ret = f_list[x].desc;
00723 break;
00724 }
00725 }
00726 f_list = ast_format_list_destroy(f_list);
00727 return ret;
00728 }
00729
00730 int ast_format_rate(const struct ast_format *format)
00731 {
00732 switch (format->id) {
00733 case AST_FORMAT_SLINEAR12:
00734 return 12000;
00735 case AST_FORMAT_SLINEAR24:
00736 return 24000;
00737 case AST_FORMAT_SLINEAR32:
00738 return 32000;
00739 case AST_FORMAT_SLINEAR44:
00740 return 44100;
00741 case AST_FORMAT_SLINEAR48:
00742 return 48000;
00743 case AST_FORMAT_SLINEAR96:
00744 return 96000;
00745 case AST_FORMAT_SLINEAR192:
00746 return 192000;
00747 case AST_FORMAT_G722:
00748 case AST_FORMAT_SLINEAR16:
00749 case AST_FORMAT_SIREN7:
00750 case AST_FORMAT_SPEEX16:
00751 return 16000;
00752 case AST_FORMAT_SIREN14:
00753 case AST_FORMAT_SPEEX32:
00754 return 32000;
00755 case AST_FORMAT_G719:
00756 return 48000;
00757 case AST_FORMAT_SILK:
00758 if (!(ast_format_isset(format,
00759 SILK_ATTR_KEY_SAMP_RATE,
00760 SILK_ATTR_VAL_SAMP_24KHZ,
00761 AST_FORMAT_ATTR_END))) {
00762 return 24000;
00763 } else if (!(ast_format_isset(format,
00764 SILK_ATTR_KEY_SAMP_RATE,
00765 SILK_ATTR_VAL_SAMP_16KHZ,
00766 AST_FORMAT_ATTR_END))) {
00767 return 16000;
00768 } else if (!(ast_format_isset(format,
00769 SILK_ATTR_KEY_SAMP_RATE,
00770 SILK_ATTR_VAL_SAMP_12KHZ,
00771 AST_FORMAT_ATTR_END))) {
00772 return 12000;
00773 } else {
00774 return 8000;
00775 }
00776 case AST_FORMAT_CELT:
00777 {
00778 int samplerate;
00779 if (!(ast_format_get_value(format,
00780 CELT_ATTR_KEY_SAMP_RATE,
00781 &samplerate))) {
00782 return samplerate;
00783 }
00784 }
00785 default:
00786 return 8000;
00787 }
00788 }
00789
00790 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00791 {
00792 int x, found=0;
00793 size_t f_len;
00794 const struct ast_format_list *f_list;
00795
00796 switch (cmd) {
00797 case CLI_INIT:
00798 e->command = "core show codecs [audio|video|image|text]";
00799 e->usage =
00800 "Usage: core show codecs [audio|video|image|text]\n"
00801 " Displays codec mapping\n";
00802 return NULL;
00803 case CLI_GENERATE:
00804 return NULL;
00805 }
00806
00807 if ((a->argc < 3) || (a->argc > 4)) {
00808 return CLI_SHOWUSAGE;
00809 }
00810
00811 f_list = ast_format_list_get(&f_len);
00812 if (!ast_opt_dont_warn) {
00813 ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
00814 "\tIt does not indicate anything about your configuration.\n");
00815 }
00816
00817 ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
00818 ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
00819
00820 for (x = 0; x < f_len; x++) {
00821 if (a->argc == 4) {
00822 if (!strcasecmp(a->argv[3], "audio")) {
00823 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
00824 continue;
00825 }
00826 } else if (!strcasecmp(a->argv[3], "video")) {
00827 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
00828 continue;
00829 }
00830 } else if (!strcasecmp(a->argv[3], "image")) {
00831 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
00832 continue;
00833 }
00834 } else if (!strcasecmp(a->argv[3], "text")) {
00835 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
00836 continue;
00837 }
00838 } else {
00839 continue;
00840 }
00841 }
00842
00843 ast_cli(a->fd, "%8u %5s %8s (%s)\n",
00844 f_list[x].format.id,
00845 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
00846 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_IMAGE) ? "image" :
00847 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_VIDEO) ? "video" :
00848 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_TEXT) ? "text" :
00849 "(unk)",
00850 f_list[x].name,
00851 f_list[x].desc);
00852 found = 1;
00853 }
00854
00855 f_list = ast_format_list_destroy(f_list);
00856 if (!found) {
00857 return CLI_SHOWUSAGE;
00858 } else {
00859 return CLI_SUCCESS;
00860 }
00861 }
00862
00863 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00864 {
00865 enum ast_format_id format_id;
00866 int x, found = 0;
00867 int type_punned_codec;
00868 size_t f_len;
00869 const struct ast_format_list *f_list;
00870
00871 switch (cmd) {
00872 case CLI_INIT:
00873 e->command = "core show codec";
00874 e->usage =
00875 "Usage: core show codec <number>\n"
00876 " Displays codec mapping\n";
00877 return NULL;
00878 case CLI_GENERATE:
00879 return NULL;
00880 }
00881
00882 if (a->argc != 4) {
00883 return CLI_SHOWUSAGE;
00884 }
00885
00886 if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
00887 return CLI_SHOWUSAGE;
00888 }
00889 format_id = type_punned_codec;
00890
00891 f_list = ast_format_list_get(&f_len);
00892 for (x = 0; x < f_len; x++) {
00893 if (f_list[x].format.id == format_id) {
00894 found = 1;
00895 ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
00896 }
00897 }
00898
00899 if (!found) {
00900 ast_cli(a->fd, "Codec %d not found\n", format_id);
00901 }
00902
00903 f_list = ast_format_list_destroy(f_list);
00904 return CLI_SUCCESS;
00905 }
00906
00907
00908 static struct ast_cli_entry my_clis[] = {
00909 AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
00910 AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
00911 };
00912 int init_framer(void)
00913 {
00914 return 0;
00915 }
00916
00917 static int format_list_add_custom(struct ast_format_list *new)
00918 {
00919 RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup);
00920 if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
00921 return -1;
00922 }
00923 memcpy(entry, new, sizeof(struct ast_format_list));
00924 entry->custom_entry = 1;
00925 ao2_link(format_list, entry);
00926 return 0;
00927 }
00928 static int format_list_add_static(
00929 const struct ast_format *format,
00930 const char *name,
00931 int samplespersecond,
00932 const char *description,
00933 int fr_len,
00934 int min_ms,
00935 int max_ms,
00936 int inc_ms,
00937 int def_ms,
00938 unsigned int flags,
00939 int cur_ms)
00940 {
00941 struct ast_format_list *entry;
00942 if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
00943 return -1;
00944 }
00945 ast_format_copy(&entry->format, format);
00946 ast_copy_string(entry->name, name, sizeof(entry->name));
00947 ast_copy_string(entry->desc, description, sizeof(entry->desc));
00948 entry->samplespersecond = samplespersecond;
00949 entry->fr_len = fr_len;
00950 entry->min_ms = min_ms;
00951 entry->max_ms = max_ms;
00952 entry->inc_ms = inc_ms;
00953 entry->def_ms = def_ms;
00954 entry->flags = flags;
00955 entry->cur_ms = cur_ms;
00956 entry->custom_entry = 0;
00957
00958 ao2_link(format_list, entry);
00959 ao2_ref(entry, -1);
00960 return 0;
00961 }
00962
00963 static int list_all_custom(void *obj, void *arg, int flag)
00964 {
00965 struct ast_format_list *entry = obj;
00966 return entry->custom_entry ? CMP_MATCH : 0;
00967 }
00968
00969 static int list_cmp_cb(void *obj, void *arg, int flags)
00970 {
00971 struct ast_format_list *entry1 = obj;
00972 struct ast_format_list *entry2 = arg;
00973
00974 return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
00975 }
00976 static int list_hash_cb(const void *obj, const int flags)
00977 {
00978 return ao2_container_count(format_list);
00979 }
00980
00981 const struct ast_format_list *ast_format_list_get(size_t *size)
00982 {
00983 struct ast_format_list *list;
00984 ast_rwlock_rdlock(&format_list_array_lock);
00985 ao2_ref(format_list_array, 1);
00986 list = format_list_array;
00987 *size = format_list_array_len;
00988 ast_rwlock_unlock(&format_list_array_lock);
00989 return list;
00990 }
00991 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
00992 {
00993 ao2_ref((void *) list, -1);
00994 return NULL;
00995 }
00996
00997 static int build_format_list_array(void)
00998 {
00999 struct ast_format_list *tmp;
01000 size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
01001 int i = 0;
01002 struct ao2_iterator it;
01003
01004 ast_rwlock_wrlock(&format_list_array_lock);
01005 tmp = format_list_array;
01006 if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
01007 format_list_array = tmp;
01008 ast_rwlock_unlock(&format_list_array_lock);
01009 return -1;
01010 }
01011 format_list_array_len = ao2_container_count(format_list);
01012 if (tmp) {
01013 ao2_ref(tmp, -1);
01014 }
01015
01016
01017 it = ao2_iterator_init(format_list, 0);
01018 while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
01019 memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
01020 ao2_ref(tmp, -1);
01021 i++;
01022 }
01023 ao2_iterator_destroy(&it);
01024
01025 ast_rwlock_unlock(&format_list_array_lock);
01026 return 0;
01027 }
01028
01029 static int format_list_init(void)
01030 {
01031 struct ast_format tmpfmt;
01032 if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
01033 return -1;
01034 }
01035
01036 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), "g723", 8000, "G.723.1", 20, 30, 300, 30, 30, 0, 0);
01037 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm", 8000, "GSM", 33, 20, 300, 20, 20, 0, 0);
01038 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20, 0, 0);
01039 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), "alaw", 8000, "G.711 A-law", 80, 10, 150, 10, 20, 0, 0);
01040 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0);
01041 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "ADPCM", 40, 10, 300, 10, 20, 0, 0);
01042 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0), "slin", 8000, "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01043 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0);
01044 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0), "g729", 8000, "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729, 0);
01045 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0);
01046 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0);
01047 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0);
01048 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726_AAL2, 0), "g726aal2", 8000, "G.726 AAL2", 40, 10, 300, 10, 20, 0, 0);
01049 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0);
01050 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR16, 0), "slin16", 16000, "16 bit Signed Linear PCM (16kHz)", 320, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01051 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0);
01052 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0);
01053 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0);
01054 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0);
01055 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), "h263p", 0, "H.263+ Video", 0, 0, 0,0 ,0 ,0, 0);
01056 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0);
01057 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0);
01058 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140RED, 0), "red", 1, "T.140 Realtime Text with redundancy", 0, 0, 0,0 ,0 ,0, 0);
01059 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_T140, 0), "t140", 0, "Passthrough T.140 Realtime Text", 0, 0, 0, 0 ,0 ,0, 0);
01060 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN7, 0), "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20, 0, 0);
01061 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SIREN14, 0), "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20, 0, 0);
01062 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_TESTLAW, 0), "testlaw", 8000, "G.711 test-law", 80, 10, 150, 10, 20, 0, 0);
01063 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
01064
01065
01066 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0);
01067 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0), "slin12", 12000, "16 bit Signed Linear PCM (12kHz)", 240, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01068 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0), "slin24", 24000, "16 bit Signed Linear PCM (24kHz)", 480, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01069 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR32, 0), "slin32", 32000, "16 bit Signed Linear PCM (32kHz)", 640, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01070 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR44, 0), "slin44", 44100, "16 bit Signed Linear PCM (44kHz)", 882, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01071 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR48, 0), "slin48", 48000, "16 bit Signed Linear PCM (48kHz)", 960, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01072 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR96, 0), "slin96", 96000, "16 bit Signed Linear PCM (96kHz)", 1920, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01073 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR192, 0), "slin192", 192000, "16 bit Signed Linear PCM (192kHz)", 3840, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);
01074
01075 return 0;
01076 }
01077
01078
01079 static void format_list_shutdown(void)
01080 {
01081 ast_rwlock_destroy(&format_list_array_lock);
01082 if (format_list) {
01083 ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
01084 format_list = NULL;
01085 }
01086 if (format_list_array) {
01087 ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
01088 format_list_array = NULL;
01089 }
01090 }
01091
01092 int ast_format_list_init(void)
01093 {
01094 if (ast_rwlock_init(&format_list_array_lock)) {
01095 return -1;
01096 }
01097 if (format_list_init()) {
01098 goto init_list_cleanup;
01099 }
01100 if (build_format_list_array()) {
01101 goto init_list_cleanup;
01102 }
01103
01104 ast_register_atexit(format_list_shutdown);
01105 return 0;
01106 init_list_cleanup:
01107
01108 format_list_shutdown();
01109 return -1;
01110 }
01111
01112
01113 static void format_attr_shutdown(void)
01114 {
01115 ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
01116 if (interfaces) {
01117 ao2_ref(interfaces, -1);
01118 interfaces = NULL;
01119 }
01120 }
01121
01122 int ast_format_attr_init(void)
01123 {
01124 interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
01125 283, interface_hash_cb, interface_cmp_cb);
01126 if (!interfaces) {
01127 return -1;
01128 }
01129
01130 ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
01131 ast_register_cleanup(format_attr_shutdown);
01132 return 0;
01133 }
01134
01135 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
01136 {
01137 if (!entry->samplespersecond) {
01138 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
01139 }
01140 ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
01141 if (!has_interface(&entry->format)) {
01142 return -1;
01143 }
01144
01145 snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
01146
01147 ast_format_append(&entry->format,
01148 CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
01149 CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
01150 CELT_ATTR_KEY_FRAME_SIZE, framesize,
01151 AST_FORMAT_ATTR_END);
01152
01153 entry->fr_len = 80;
01154 entry->min_ms = 20;
01155 entry->max_ms = 20;
01156 entry->inc_ms = 20;
01157 entry->def_ms = 20;
01158 return 0;
01159 }
01160
01161 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
01162 {
01163 if (!entry->samplespersecond) {
01164 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
01165 }
01166 ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
01167
01168 if (!has_interface(&entry->format)) {
01169 return -1;
01170 }
01171
01172 switch (entry->samplespersecond) {
01173 case 8000:
01174 ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
01175 ast_format_append(&entry->format,
01176 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
01177 AST_FORMAT_ATTR_END);
01178 break;
01179 case 12000:
01180 ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
01181 ast_format_append(&entry->format,
01182 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
01183 AST_FORMAT_ATTR_END);
01184 break;
01185 case 16000:
01186 ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
01187 ast_format_append(&entry->format,
01188 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
01189 AST_FORMAT_ATTR_END);
01190 break;
01191 case 24000:
01192 ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
01193 ast_format_append(&entry->format,
01194 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
01195 AST_FORMAT_ATTR_END);
01196 break;
01197 default:
01198 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %d\n", entry->name, entry->samplespersecond);
01199 return -1;
01200 }
01201 ast_format_append(&entry->format,
01202 SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
01203 SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
01204 SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
01205 SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
01206 AST_FORMAT_ATTR_END);
01207
01208 entry->fr_len = 80;
01209 entry->min_ms = 20;
01210 entry->max_ms = 20;
01211 entry->inc_ms = 20;
01212 entry->def_ms = 20;
01213 return 0;
01214 }
01215
01216 static int conf_process_format_name(const char *name, enum ast_format_id *id)
01217 {
01218 if (!strcasecmp(name, "silk")) {
01219 *id = AST_FORMAT_SILK;
01220 } else if (!strcasecmp(name, "celt")) {
01221 *id = AST_FORMAT_CELT;
01222 } else {
01223 *id = 0;
01224 return -1;
01225 }
01226 return 0;
01227 }
01228
01229 static int conf_process_sample_rate(const char *rate, unsigned int *result)
01230 {
01231 if (!strcasecmp(rate, "8000")) {
01232 *result = 8000;
01233 } else if (!strcasecmp(rate, "12000")) {
01234 *result = 12000;
01235 } else if (!strcasecmp(rate, "16000")) {
01236 *result = 16000;
01237 } else if (!strcasecmp(rate, "24000")) {
01238 *result = 24000;
01239 } else if (!strcasecmp(rate, "32000")) {
01240 *result = 32000;
01241 } else if (!strcasecmp(rate, "44100")) {
01242 *result = 44100;
01243 } else if (!strcasecmp(rate, "48000")) {
01244 *result = 48000;
01245 } else if (!strcasecmp(rate, "96000")) {
01246 *result = 96000;
01247 } else if (!strcasecmp(rate, "192000")) {
01248 *result = 192000;
01249 } else {
01250 *result = 0;
01251 return -1;
01252 }
01253
01254 return 0;
01255 }
01256 static int load_format_config(void)
01257 {
01258 struct ast_flags config_flags = { 0, };
01259 struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
01260 struct ast_format_list entry;
01261 struct ast_variable *var;
01262 char *cat = NULL;
01263 int add_it = 0;
01264
01265 struct {
01266 enum ast_format_id id;
01267 unsigned int maxbitrate;
01268 unsigned int framesize;
01269 unsigned int packetloss_percentage;
01270 int usefec;
01271 int usedtx;
01272 } settings;
01273
01274 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01275 return 0;
01276 }
01277
01278
01279
01280
01281 ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
01282
01283 while ((cat = ast_category_browse(cfg, cat))) {
01284 memset(&entry, 0, sizeof(entry));
01285 memset(&settings, 0, sizeof(settings));
01286 add_it = 0;
01287
01288 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
01289 continue;
01290 }
01291 ast_copy_string(entry.name, cat, sizeof(entry.name));
01292 var = ast_variable_browse(cfg, cat);
01293 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
01294 if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
01295 ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
01296 var->value, var->lineno, FORMAT_CONFIG);
01297 continue;
01298 } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
01299 ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
01300 var->value, var->lineno, FORMAT_CONFIG);
01301 } else if (!strcasecmp(var->name, "maxbitrate")) {
01302 if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
01303 ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
01304 var->value, var->lineno, FORMAT_CONFIG);
01305 }
01306 } else if (!strcasecmp(var->name, "framesize")) {
01307 if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
01308 ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
01309 var->value, var->lineno, FORMAT_CONFIG);
01310 }
01311 } else if (!strcasecmp(var->name, "dtx")) {
01312 settings.usedtx = ast_true(var->value) ? 1 : 0;
01313 } else if (!strcasecmp(var->name, "fec")) {
01314 settings.usefec = ast_true(var->value) ? 1 : 0;
01315 } else if (!strcasecmp(var->name, "packetloss_percentage")) {
01316 if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
01317 ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
01318 var->value, var->lineno, FORMAT_CONFIG);
01319 }
01320 }
01321 }
01322
01323 switch (settings.id) {
01324 case AST_FORMAT_SILK:
01325 if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
01326 add_it = 1;
01327 }
01328 break;
01329 case AST_FORMAT_CELT:
01330 if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
01331 add_it = 1;
01332 }
01333 break;
01334 default:
01335 ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
01336 }
01337
01338 if (add_it) {
01339 format_list_add_custom(&entry);
01340 }
01341 }
01342 ast_config_destroy(cfg);
01343 build_format_list_array();
01344 return 0;
01345 }
01346
01347 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
01348 {
01349 int x;
01350 size_t f_len;
01351 const struct ast_format_list *f_list;
01352 struct interface_ao2_wrapper *wrapper;
01353 struct interface_ao2_wrapper tmp_wrapper = {
01354 .id = interface->id,
01355 };
01356
01357
01358
01359
01360
01361
01362 ao2_wrlock(interfaces);
01363
01364
01365 if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
01366 ao2_unlock(interfaces);
01367 ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
01368 ao2_ref(wrapper, -1);
01369 return -1;
01370 }
01371
01372 wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
01373 if (!wrapper) {
01374 ao2_unlock(interfaces);
01375 return -1;
01376 }
01377
01378 wrapper->interface = interface;
01379 wrapper->id = interface->id;
01380
01381
01382 ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
01383 ao2_unlock(interfaces);
01384
01385 ao2_ref(wrapper, -1);
01386
01387
01388 load_format_config();
01389
01390
01391 f_list = ast_format_list_get(&f_len);
01392 for (x = 0; x < f_len; x++) {
01393 if (f_list[x].format.id == tmp_wrapper.id) {
01394 ast_rtp_engine_load_format(&f_list[x].format);
01395 }
01396 }
01397 f_list = ast_format_list_destroy(f_list);
01398 return 0;
01399 }
01400
01401 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
01402 {
01403 int x;
01404 size_t f_len;
01405 const struct ast_format_list *f_list;
01406 struct interface_ao2_wrapper *wrapper;
01407 struct interface_ao2_wrapper tmp_wrapper = {
01408 .id = interface->id,
01409 };
01410
01411 if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
01412 return -1;
01413 }
01414
01415 ao2_wrlock(wrapper);
01416 wrapper->interface = NULL;
01417 ao2_unlock(wrapper);
01418
01419 ao2_ref(wrapper, -1);
01420
01421
01422 f_list = ast_format_list_get(&f_len);
01423 for (x = 0; x < f_len; x++) {
01424 if (f_list[x].format.id == tmp_wrapper.id) {
01425 ast_rtp_engine_unload_format(&f_list[x].format);
01426 }
01427 }
01428
01429
01430 load_format_config();
01431 f_list = ast_format_list_destroy(f_list);
01432 return 0;
01433 }