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