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: 415728 $");
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 %u 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
00977 const struct ast_format_list *ast_format_list_get(size_t *size)
00978 {
00979 struct ast_format_list *list;
00980 ast_rwlock_rdlock(&format_list_array_lock);
00981 ao2_ref(format_list_array, 1);
00982 list = format_list_array;
00983 *size = format_list_array_len;
00984 ast_rwlock_unlock(&format_list_array_lock);
00985 return list;
00986 }
00987 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
00988 {
00989 ao2_ref((void *) list, -1);
00990 return NULL;
00991 }
00992
00993 static int build_format_list_array(void)
00994 {
00995 struct ast_format_list *tmp;
00996 size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
00997 int i = 0;
00998 struct ao2_iterator it;
00999
01000 ast_rwlock_wrlock(&format_list_array_lock);
01001 tmp = format_list_array;
01002 if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
01003 format_list_array = tmp;
01004 ast_rwlock_unlock(&format_list_array_lock);
01005 return -1;
01006 }
01007 format_list_array_len = ao2_container_count(format_list);
01008 if (tmp) {
01009 ao2_ref(tmp, -1);
01010 }
01011
01012
01013 it = ao2_iterator_init(format_list, 0);
01014 while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
01015 memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
01016 ao2_ref(tmp, -1);
01017 i++;
01018 }
01019 ao2_iterator_destroy(&it);
01020
01021 ast_rwlock_unlock(&format_list_array_lock);
01022 return 0;
01023 }
01024
01025 static int format_list_init(void)
01026 {
01027 struct ast_format tmpfmt;
01028 if (!(format_list = ao2_container_alloc(1, NULL, list_cmp_cb))) {
01029 return -1;
01030 }
01031
01032 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);
01033 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm", 8000, "GSM", 33, 20, 300, 20, 20, 0, 0);
01034 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);
01035 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);
01036 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0);
01037 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "ADPCM", 40, 10, 300, 10, 20, 0, 0);
01038 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);
01039 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0);
01040 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);
01041 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0);
01042 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0);
01043 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0);
01044 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);
01045 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0);
01046 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);
01047 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0);
01048 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0);
01049 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0);
01050 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0);
01051 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);
01052 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0);
01053 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0);
01054 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);
01055 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);
01056 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);
01057 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);
01058 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);
01059 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
01060
01061
01062 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0);
01063 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);
01064 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);
01065 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);
01066 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);
01067 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);
01068 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);
01069 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);
01070
01071 return 0;
01072 }
01073
01074
01075 static void format_list_shutdown(void)
01076 {
01077 ast_rwlock_destroy(&format_list_array_lock);
01078 if (format_list) {
01079 ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
01080 format_list = NULL;
01081 }
01082 if (format_list_array) {
01083 ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
01084 format_list_array = NULL;
01085 }
01086 }
01087
01088 int ast_format_list_init(void)
01089 {
01090 if (ast_rwlock_init(&format_list_array_lock)) {
01091 return -1;
01092 }
01093 if (format_list_init()) {
01094 goto init_list_cleanup;
01095 }
01096 if (build_format_list_array()) {
01097 goto init_list_cleanup;
01098 }
01099
01100 ast_register_atexit(format_list_shutdown);
01101 return 0;
01102 init_list_cleanup:
01103
01104 format_list_shutdown();
01105 return -1;
01106 }
01107
01108
01109 static void format_attr_shutdown(void)
01110 {
01111 ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
01112 if (interfaces) {
01113 ao2_ref(interfaces, -1);
01114 interfaces = NULL;
01115 }
01116 }
01117
01118 int ast_format_attr_init(void)
01119 {
01120 interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
01121 283, interface_hash_cb, interface_cmp_cb);
01122 if (!interfaces) {
01123 return -1;
01124 }
01125
01126 ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
01127 ast_register_cleanup(format_attr_shutdown);
01128 return 0;
01129 }
01130
01131 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
01132 {
01133 if (!entry->samplespersecond) {
01134 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
01135 }
01136 ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
01137 if (!has_interface(&entry->format)) {
01138 return -1;
01139 }
01140
01141 snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %ukhz", entry->samplespersecond/1000);
01142
01143 ast_format_append(&entry->format,
01144 CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
01145 CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
01146 CELT_ATTR_KEY_FRAME_SIZE, framesize,
01147 AST_FORMAT_ATTR_END);
01148
01149 entry->fr_len = 80;
01150 entry->min_ms = 20;
01151 entry->max_ms = 20;
01152 entry->inc_ms = 20;
01153 entry->def_ms = 20;
01154 return 0;
01155 }
01156
01157 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
01158 {
01159 if (!entry->samplespersecond) {
01160 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
01161 }
01162 ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
01163
01164 if (!has_interface(&entry->format)) {
01165 return -1;
01166 }
01167
01168 switch (entry->samplespersecond) {
01169 case 8000:
01170 ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
01171 ast_format_append(&entry->format,
01172 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
01173 AST_FORMAT_ATTR_END);
01174 break;
01175 case 12000:
01176 ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
01177 ast_format_append(&entry->format,
01178 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
01179 AST_FORMAT_ATTR_END);
01180 break;
01181 case 16000:
01182 ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
01183 ast_format_append(&entry->format,
01184 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
01185 AST_FORMAT_ATTR_END);
01186 break;
01187 case 24000:
01188 ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
01189 ast_format_append(&entry->format,
01190 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
01191 AST_FORMAT_ATTR_END);
01192 break;
01193 default:
01194 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %u\n", entry->name, entry->samplespersecond);
01195 return -1;
01196 }
01197 ast_format_append(&entry->format,
01198 SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
01199 SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
01200 SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
01201 SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
01202 AST_FORMAT_ATTR_END);
01203
01204 entry->fr_len = 80;
01205 entry->min_ms = 20;
01206 entry->max_ms = 20;
01207 entry->inc_ms = 20;
01208 entry->def_ms = 20;
01209 return 0;
01210 }
01211
01212 static int conf_process_format_name(const char *name, enum ast_format_id *id)
01213 {
01214 if (!strcasecmp(name, "silk")) {
01215 *id = AST_FORMAT_SILK;
01216 } else if (!strcasecmp(name, "celt")) {
01217 *id = AST_FORMAT_CELT;
01218 } else {
01219 *id = 0;
01220 return -1;
01221 }
01222 return 0;
01223 }
01224
01225 static int conf_process_sample_rate(const char *rate, unsigned int *result)
01226 {
01227 if (!strcasecmp(rate, "8000")) {
01228 *result = 8000;
01229 } else if (!strcasecmp(rate, "12000")) {
01230 *result = 12000;
01231 } else if (!strcasecmp(rate, "16000")) {
01232 *result = 16000;
01233 } else if (!strcasecmp(rate, "24000")) {
01234 *result = 24000;
01235 } else if (!strcasecmp(rate, "32000")) {
01236 *result = 32000;
01237 } else if (!strcasecmp(rate, "44100")) {
01238 *result = 44100;
01239 } else if (!strcasecmp(rate, "48000")) {
01240 *result = 48000;
01241 } else if (!strcasecmp(rate, "96000")) {
01242 *result = 96000;
01243 } else if (!strcasecmp(rate, "192000")) {
01244 *result = 192000;
01245 } else {
01246 *result = 0;
01247 return -1;
01248 }
01249
01250 return 0;
01251 }
01252 static int load_format_config(void)
01253 {
01254 struct ast_flags config_flags = { 0, };
01255 struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
01256 struct ast_format_list entry;
01257 struct ast_variable *var;
01258 char *cat = NULL;
01259 int add_it = 0;
01260
01261 struct {
01262 enum ast_format_id id;
01263 unsigned int maxbitrate;
01264 unsigned int framesize;
01265 unsigned int packetloss_percentage;
01266 int usefec;
01267 int usedtx;
01268 } settings;
01269
01270 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
01271 return 0;
01272 }
01273
01274
01275
01276
01277 ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
01278
01279 while ((cat = ast_category_browse(cfg, cat))) {
01280 memset(&entry, 0, sizeof(entry));
01281 memset(&settings, 0, sizeof(settings));
01282 add_it = 0;
01283
01284 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
01285 continue;
01286 }
01287 ast_copy_string(entry.name, cat, sizeof(entry.name));
01288 var = ast_variable_browse(cfg, cat);
01289 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
01290 if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
01291 ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
01292 var->value, var->lineno, FORMAT_CONFIG);
01293 continue;
01294 } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
01295 ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
01296 var->value, var->lineno, FORMAT_CONFIG);
01297 } else if (!strcasecmp(var->name, "maxbitrate")) {
01298 if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
01299 ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
01300 var->value, var->lineno, FORMAT_CONFIG);
01301 }
01302 } else if (!strcasecmp(var->name, "framesize")) {
01303 if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
01304 ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
01305 var->value, var->lineno, FORMAT_CONFIG);
01306 }
01307 } else if (!strcasecmp(var->name, "dtx")) {
01308 settings.usedtx = ast_true(var->value) ? 1 : 0;
01309 } else if (!strcasecmp(var->name, "fec")) {
01310 settings.usefec = ast_true(var->value) ? 1 : 0;
01311 } else if (!strcasecmp(var->name, "packetloss_percentage")) {
01312 if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
01313 ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
01314 var->value, var->lineno, FORMAT_CONFIG);
01315 }
01316 }
01317 }
01318
01319 switch (settings.id) {
01320 case AST_FORMAT_SILK:
01321 if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
01322 add_it = 1;
01323 }
01324 break;
01325 case AST_FORMAT_CELT:
01326 if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
01327 add_it = 1;
01328 }
01329 break;
01330 default:
01331 ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
01332 }
01333
01334 if (add_it) {
01335 format_list_add_custom(&entry);
01336 }
01337 }
01338 ast_config_destroy(cfg);
01339 build_format_list_array();
01340 return 0;
01341 }
01342
01343 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
01344 {
01345 int x;
01346 size_t f_len;
01347 const struct ast_format_list *f_list;
01348 struct interface_ao2_wrapper *wrapper;
01349 struct interface_ao2_wrapper tmp_wrapper = {
01350 .id = interface->id,
01351 };
01352
01353
01354
01355
01356
01357
01358 ao2_wrlock(interfaces);
01359
01360
01361 if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
01362 ao2_unlock(interfaces);
01363 ast_log(LOG_WARNING, "Can not register attribute interface for format id %u, interface already exists.\n", interface->id);
01364 ao2_ref(wrapper, -1);
01365 return -1;
01366 }
01367
01368 wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
01369 if (!wrapper) {
01370 ao2_unlock(interfaces);
01371 return -1;
01372 }
01373
01374 wrapper->interface = interface;
01375 wrapper->id = interface->id;
01376
01377
01378 ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
01379 ao2_unlock(interfaces);
01380
01381 ao2_ref(wrapper, -1);
01382
01383
01384 load_format_config();
01385
01386
01387 f_list = ast_format_list_get(&f_len);
01388 for (x = 0; x < f_len; x++) {
01389 if (f_list[x].format.id == tmp_wrapper.id) {
01390 ast_rtp_engine_load_format(&f_list[x].format);
01391 }
01392 }
01393 f_list = ast_format_list_destroy(f_list);
01394 return 0;
01395 }
01396
01397 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
01398 {
01399 int x;
01400 size_t f_len;
01401 const struct ast_format_list *f_list;
01402 struct interface_ao2_wrapper *wrapper;
01403 struct interface_ao2_wrapper tmp_wrapper = {
01404 .id = interface->id,
01405 };
01406
01407 if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
01408 return -1;
01409 }
01410
01411 ao2_wrlock(wrapper);
01412 wrapper->interface = NULL;
01413 ao2_unlock(wrapper);
01414
01415 ao2_ref(wrapper, -1);
01416
01417
01418 f_list = ast_format_list_get(&f_len);
01419 for (x = 0; x < f_len; x++) {
01420 if (f_list[x].format.id == tmp_wrapper.id) {
01421 ast_rtp_engine_unload_format(&f_list[x].format);
01422 }
01423 }
01424
01425
01426 load_format_config();
01427 f_list = ast_format_list_destroy(f_list);
01428 return 0;
01429 }