2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2010, Digium, Inc.
6 * David Vossel <dvossel@digium.com>
7 * Mark Spencer <markster@digium.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
24 * \author David Vossel <dvossel@digium.com>
25 * \author Mark Spencer <markster@digium.com>
29 <support_level>core</support_level>
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
36 #include "asterisk/_private.h"
37 #include "asterisk/format.h"
38 #include "asterisk/astobj2.h"
39 #include "asterisk/lock.h"
40 #include "asterisk/frame.h"
41 #include "asterisk/utils.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/rtp_engine.h"
44 #include "asterisk/config.h"
46 #define FORMAT_CONFIG "codecs.conf"
49 * \brief Container for all the format attribute interfaces.
50 * \note This container uses RWLOCKs instead of MUTEX locks. .
51 * \note An ao2 container was chosen for fast lookup.
53 static struct ao2_container *interfaces;
55 /*! a wrapper is used put interfaces into the ao2 container. */
56 struct interface_ao2_wrapper {
57 enum ast_format_id id;
58 const struct ast_format_attr_interface *interface;
61 /*! \brief Format List container, This container is never directly accessed outside
62 * of this file, and It only exists for building the format_list_array. */
63 static struct ao2_container *format_list;
64 /*! \brief Format List array is a read only array protected by a read write lock.
65 * This array may be used outside this file with the use of reference counting to
66 * guarantee safety for access by multiple threads. */
67 static struct ast_format_list *format_list_array;
68 static size_t format_list_array_len = 0;
69 /*! \brief Locks the format list array so a reference can be taken safely. */
70 static ast_rwlock_t format_list_array_lock;
72 static int interface_cmp_cb(void *obj, void *arg, int flags)
74 struct interface_ao2_wrapper *wrapper1 = obj;
75 struct interface_ao2_wrapper *wrapper2 = arg;
77 return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
80 static int interface_hash_cb(const void *obj, const int flags)
82 const struct interface_ao2_wrapper *wrapper = obj;
86 void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
91 void ast_format_set_video_mark(struct ast_format *format)
93 format->fattr.rtp_marker_bit = 1;
96 int ast_format_get_video_mark(const struct ast_format *format)
98 return format->fattr.rtp_marker_bit;
101 static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
103 struct interface_ao2_wrapper tmp_wrapper = {
107 return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
110 static int has_interface(const struct ast_format *format)
112 struct interface_ao2_wrapper *wrapper;
114 wrapper = find_interface(format);
118 ao2_ref(wrapper, -1);
122 int ast_format_sdp_parse(struct ast_format *format, const char *attributes)
124 struct interface_ao2_wrapper *wrapper;
127 if (!(wrapper = find_interface(format))) {
132 if (!(wrapper->interface || !wrapper->interface->format_attr_sdp_parse)) {
134 ao2_ref(wrapper, -1);
138 res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes);
141 ao2_ref(wrapper, -1);
146 void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str)
148 struct interface_ao2_wrapper *wrapper;
150 if (!(wrapper = find_interface(format))) {
155 if (!(wrapper->interface || !wrapper->interface->format_attr_sdp_generate)) {
157 ao2_ref(wrapper, -1);
161 wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str);
164 ao2_ref(wrapper, -1);
168 * \brief set format attributes using an interface
170 static int format_set_helper(struct ast_format *format, va_list ap)
172 struct interface_ao2_wrapper *wrapper;
174 if (!(wrapper = find_interface(format))) {
175 ast_log(LOG_WARNING, "Could not find format interface to set.\n");
180 if (!wrapper->interface || !wrapper->interface->format_attr_set) {
182 ao2_ref(wrapper, -1);
186 wrapper->interface->format_attr_set(&format->fattr, ap);
189 ao2_ref(wrapper, -1);
194 struct ast_format *ast_format_append(struct ast_format *format, ... )
197 va_start(ap, format);
198 format_set_helper(format, ap);
204 struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
206 /* initialize the structure before setting it. */
207 ast_format_clear(format);
211 if (set_attributes) {
213 va_start(ap, set_attributes);
214 format_set_helper(format, ap);
221 void ast_format_clear(struct ast_format *format)
224 memset(&format->fattr, 0, sizeof(format->fattr));
228 * \brief determine if a list of attribute key value pairs are set on a format
230 static int format_isset_helper(const struct ast_format *format, va_list ap)
233 struct interface_ao2_wrapper *wrapper;
234 struct ast_format tmp = {
236 .fattr = { { 0, }, },
239 if (!(wrapper = find_interface(format))) {
244 if (!wrapper->interface ||
245 !wrapper->interface->format_attr_set ||
246 !wrapper->interface->format_attr_cmp) {
249 ao2_ref(wrapper, -1);
253 /* if isset is present, use that function, else just build a new
254 * format and use the cmp function */
255 if (wrapper->interface->format_attr_isset) {
256 res = wrapper->interface->format_attr_isset(&format->fattr, ap);
258 wrapper->interface->format_attr_set(&tmp.fattr, ap);
259 /* use our tmp structure to tell if the attributes are set or not */
260 res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
261 res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
265 ao2_ref(wrapper, -1);
270 int ast_format_isset(const struct ast_format *format, ... )
275 va_start(ap, format);
276 res = format_isset_helper(format, ap);
281 int ast_format_get_value(const struct ast_format *format, int key, void *value)
284 struct interface_ao2_wrapper *wrapper;
286 if (!(wrapper = find_interface(format))) {
290 if (!wrapper->interface ||
291 !wrapper->interface->format_attr_get_val) {
294 ao2_ref(wrapper, -1);
298 res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
301 ao2_ref(wrapper, -1);
307 * \brief cmp format attributes using an interface
309 static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
311 enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
312 struct interface_ao2_wrapper *wrapper;
314 if (!(wrapper = find_interface(format1))) {
319 if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
321 ao2_ref(wrapper, -1);
325 res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
328 ao2_ref(wrapper, -1);
333 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
335 if (format1->id != format2->id) {
336 return AST_FORMAT_CMP_NOT_EQUAL;
339 return format_cmp_helper(format1, format2);
343 * \brief get joint format attributes using an interface
345 static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
348 struct interface_ao2_wrapper *wrapper;
350 if (!(wrapper = find_interface(format1))) {
351 /* if no interface is present, we assume formats are joint by id alone */
356 if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
357 res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
361 ao2_ref(wrapper, -1);
366 int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
368 if (format1->id != format2->id) {
371 result->id = format1->id;
372 return format_joint_helper(format1, format2, result);
376 uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
379 /*! G.723.1 compression */
380 case AST_FORMAT_G723_1:
382 /*! GSM compression */
385 /*! Raw mu-law data (G.711) */
386 case AST_FORMAT_ULAW:
388 /*! Raw A-law data (G.711) */
389 case AST_FORMAT_ALAW:
391 /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
392 case AST_FORMAT_G726_AAL2:
395 case AST_FORMAT_ADPCM:
397 /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
398 case AST_FORMAT_SLINEAR:
400 /*! LPC10, 180 samples/frame */
401 case AST_FORMAT_LPC10:
404 case AST_FORMAT_G729A:
406 /*! SpeeX Free Compression */
407 case AST_FORMAT_SPEEX:
409 /*! iLBC Free Compression */
410 case AST_FORMAT_ILBC:
412 /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
413 case AST_FORMAT_G726:
416 case AST_FORMAT_G722:
418 /*! G.722.1 (also known as Siren7, 32kbps assumed) */
419 case AST_FORMAT_SIREN7:
421 /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
422 case AST_FORMAT_SIREN14:
424 /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
425 case AST_FORMAT_SLINEAR16:
427 /*! G.719 (64 kbps assumed) */
428 case AST_FORMAT_G719:
430 /*! SpeeX Wideband (16kHz) Free Compression */
431 case AST_FORMAT_SPEEX16:
433 /*! Raw mu-law data (G.711) */
434 case AST_FORMAT_TESTLAW:
438 case AST_FORMAT_H261:
441 case AST_FORMAT_H263:
444 case AST_FORMAT_H263_PLUS:
447 case AST_FORMAT_H264:
450 case AST_FORMAT_MP4_VIDEO:
454 case AST_FORMAT_JPEG:
460 /*! T.140 RED Text format RFC 4103 */
461 case AST_FORMAT_T140RED:
463 /*! T.140 Text format - ITU T.140, RFC 4103 */
464 case AST_FORMAT_T140:
467 return 0; /* not supported by old bitfield. */
473 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
475 return ast_format_id_to_old_bitfield(format->id);
478 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
481 /*! G.723.1 compression */
483 return ast_format_set(dst, AST_FORMAT_G723_1, 0);
484 /*! GSM compression */
486 return ast_format_set(dst, AST_FORMAT_GSM, 0);
487 /*! Raw mu-law data (G.711) */
489 return ast_format_set(dst, AST_FORMAT_ULAW, 0);
490 /*! Raw A-law data (G.711) */
492 return ast_format_set(dst, AST_FORMAT_ALAW, 0);
493 /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
495 return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
498 return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
499 /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
501 return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
502 /*! LPC10, 180 samples/frame */
504 return ast_format_set(dst, AST_FORMAT_LPC10, 0);
507 return ast_format_set(dst, AST_FORMAT_G729A, 0);
508 /*! SpeeX Free Compression */
510 return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
511 /*! iLBC Free Compression */
513 return ast_format_set(dst, AST_FORMAT_ILBC, 0);
514 /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
516 return ast_format_set(dst, AST_FORMAT_G726, 0);
519 return ast_format_set(dst, AST_FORMAT_G722, 0);
520 /*! G.722.1 (also known as Siren7, 32kbps assumed) */
522 return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
523 /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
525 return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
526 /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
528 return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
529 /*! G.719 (64 kbps assumed) */
531 return ast_format_set(dst, AST_FORMAT_G719, 0);
532 /*! SpeeX Wideband (16kHz) Free Compression */
534 return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
535 /*! Raw mu-law data (G.711) */
537 return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
541 return ast_format_set(dst, AST_FORMAT_H261, 0);
544 return ast_format_set(dst, AST_FORMAT_H263, 0);
547 return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
550 return ast_format_set(dst, AST_FORMAT_H264, 0);
553 return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
557 return ast_format_set(dst, AST_FORMAT_JPEG, 0);
560 return ast_format_set(dst, AST_FORMAT_PNG, 0);
562 /*! T.140 RED Text format RFC 4103 */
564 return ast_format_set(dst, AST_FORMAT_T140RED, 0);
565 /*! T.140 Text format - ITU T.140, RFC 4103 */
567 return ast_format_set(dst, AST_FORMAT_T140, 0);
569 ast_format_clear(dst);
573 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
575 struct ast_format dst;
576 if (ast_format_from_old_bitfield(&dst, src)) {
582 int ast_format_is_slinear(const struct ast_format *format)
584 if (format->id == AST_FORMAT_SLINEAR ||
585 format->id == AST_FORMAT_SLINEAR12 ||
586 format->id == AST_FORMAT_SLINEAR16 ||
587 format->id == AST_FORMAT_SLINEAR24 ||
588 format->id == AST_FORMAT_SLINEAR32 ||
589 format->id == AST_FORMAT_SLINEAR44 ||
590 format->id == AST_FORMAT_SLINEAR48 ||
591 format->id == AST_FORMAT_SLINEAR96 ||
592 format->id == AST_FORMAT_SLINEAR192) {
598 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
600 if (rate >= 192000) {
601 return AST_FORMAT_SLINEAR192;
602 } else if (rate >= 96000) {
603 return AST_FORMAT_SLINEAR96;
604 } else if (rate >= 48000) {
605 return AST_FORMAT_SLINEAR48;
606 } else if (rate >= 44100) {
607 return AST_FORMAT_SLINEAR44;
608 } else if (rate >= 32000) {
609 return AST_FORMAT_SLINEAR32;
610 } else if (rate >= 24000) {
611 return AST_FORMAT_SLINEAR24;
612 } else if (rate >= 16000) {
613 return AST_FORMAT_SLINEAR16;
614 } else if (rate >= 12000) {
615 return AST_FORMAT_SLINEAR12;
617 return AST_FORMAT_SLINEAR;
620 const char* ast_getformatname(const struct ast_format *format)
623 const char *ret = "unknown";
625 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
626 for (x = 0; x < f_len; x++) {
627 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
628 ret = f_list[x].name;
632 f_list = ast_format_list_destroy(f_list);
637 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
641 char *start, *end = buf;
643 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
646 f_list = ast_format_list_destroy(f_list);
649 snprintf(end, size, "(");
654 for (x = 0; x < f_len; x++) {
655 if (f_list[x].format.id == id) {
656 snprintf(end, size, "%s|", f_list[x].name);
663 ast_copy_string(start, "nothing)", size);
664 } else if (size > 1) {
667 f_list = ast_format_list_destroy(f_list);
671 static struct ast_codec_alias_table {
673 const char *realname;
674 } ast_codec_alias_table[] = {
675 { "slinear", "slin"},
676 { "slinear16", "slin16"},
678 { "g722.1", "siren7"},
679 { "g722.1c", "siren14"},
682 static const char *ast_expand_codec_alias(const char *in)
686 for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
687 if (!strcmp(in,ast_codec_alias_table[x].alias))
688 return ast_codec_alias_table[x].realname;
693 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
697 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
699 for (x = 0; x < f_len; x++) {
700 if (!strcasecmp(f_list[x].name, name) ||
701 !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
703 ast_format_copy(result, &f_list[x].format);
704 f_list = ast_format_list_destroy(f_list);
708 f_list = ast_format_list_destroy(f_list);
713 const char *ast_codec2str(struct ast_format *format)
716 const char *ret = "unknown";
718 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
720 for (x = 0; x < f_len; x++) {
721 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
722 ret = f_list[x].desc;
726 f_list = ast_format_list_destroy(f_list);
730 int ast_format_rate(const struct ast_format *format)
732 switch (format->id) {
733 case AST_FORMAT_SLINEAR12:
735 case AST_FORMAT_SLINEAR24:
737 case AST_FORMAT_SLINEAR32:
739 case AST_FORMAT_SLINEAR44:
741 case AST_FORMAT_SLINEAR48:
743 case AST_FORMAT_SLINEAR96:
745 case AST_FORMAT_SLINEAR192:
747 case AST_FORMAT_G722:
748 case AST_FORMAT_SLINEAR16:
749 case AST_FORMAT_SIREN7:
750 case AST_FORMAT_SPEEX16:
752 case AST_FORMAT_SIREN14:
753 case AST_FORMAT_SPEEX32:
755 case AST_FORMAT_G719:
757 case AST_FORMAT_SILK:
758 if (!(ast_format_isset(format,
759 SILK_ATTR_KEY_SAMP_RATE,
760 SILK_ATTR_VAL_SAMP_24KHZ,
761 AST_FORMAT_ATTR_END))) {
763 } else if (!(ast_format_isset(format,
764 SILK_ATTR_KEY_SAMP_RATE,
765 SILK_ATTR_VAL_SAMP_16KHZ,
766 AST_FORMAT_ATTR_END))) {
768 } else if (!(ast_format_isset(format,
769 SILK_ATTR_KEY_SAMP_RATE,
770 SILK_ATTR_VAL_SAMP_12KHZ,
771 AST_FORMAT_ATTR_END))) {
776 case AST_FORMAT_CELT:
779 if (!(ast_format_get_value(format,
780 CELT_ATTR_KEY_SAMP_RATE,
790 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
794 const struct ast_format_list *f_list;
798 e->command = "core show codecs [audio|video|image|text]";
800 "Usage: core show codecs [audio|video|image|text]\n"
801 " Displays codec mapping\n";
807 if ((a->argc < 3) || (a->argc > 4)) {
808 return CLI_SHOWUSAGE;
811 f_list = ast_format_list_get(&f_len);
812 if (!ast_opt_dont_warn) {
813 ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
814 "\tIt does not indicate anything about your configuration.\n");
817 ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
818 ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
820 for (x = 0; x < f_len; x++) {
822 if (!strcasecmp(a->argv[3], "audio")) {
823 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
826 } else if (!strcasecmp(a->argv[3], "video")) {
827 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
830 } else if (!strcasecmp(a->argv[3], "image")) {
831 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
834 } else if (!strcasecmp(a->argv[3], "text")) {
835 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
843 ast_cli(a->fd, "%8u %5s %8s (%s)\n",
845 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
846 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_IMAGE) ? "image" :
847 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_VIDEO) ? "video" :
848 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_TEXT) ? "text" :
855 f_list = ast_format_list_destroy(f_list);
857 return CLI_SHOWUSAGE;
863 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
865 enum ast_format_id format_id;
867 int type_punned_codec;
869 const struct ast_format_list *f_list;
873 e->command = "core show codec";
875 "Usage: core show codec <number>\n"
876 " Displays codec mapping\n";
883 return CLI_SHOWUSAGE;
886 if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
887 return CLI_SHOWUSAGE;
889 format_id = type_punned_codec;
891 f_list = ast_format_list_get(&f_len);
892 for (x = 0; x < f_len; x++) {
893 if (f_list[x].format.id == format_id) {
895 ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
900 ast_cli(a->fd, "Codec %d not found\n", format_id);
903 f_list = ast_format_list_destroy(f_list);
907 /* Builtin Asterisk CLI-commands for debugging */
908 static struct ast_cli_entry my_clis[] = {
909 AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
910 AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
913 static int format_list_add_custom(struct ast_format_list *new)
915 struct ast_format_list *entry;
916 if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
919 memcpy(entry, new, sizeof(struct ast_format_list));
920 entry->custom_entry = 1;
921 ao2_link(format_list, entry);
924 static int format_list_add_static(
925 const struct ast_format *format,
927 int samplespersecond,
928 const char *description,
937 struct ast_format_list *entry;
938 if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
941 ast_format_copy(&entry->format, format);
942 ast_copy_string(entry->name, name, sizeof(entry->name));
943 ast_copy_string(entry->desc, description, sizeof(entry->desc));
944 entry->samplespersecond = samplespersecond;
945 entry->fr_len = fr_len;
946 entry->min_ms = min_ms;
947 entry->max_ms = max_ms;
948 entry->inc_ms = inc_ms;
949 entry->def_ms = def_ms;
950 entry->flags = flags;
951 entry->cur_ms = cur_ms;
952 entry->custom_entry = 0;
954 ao2_link(format_list, entry);
959 static int list_all_custom(void *obj, void *arg, int flag)
961 struct ast_format_list *entry = obj;
962 return entry->custom_entry ? CMP_MATCH : 0;
965 static int list_cmp_cb(void *obj, void *arg, int flags)
967 struct ast_format_list *entry1 = obj;
968 struct ast_format_list *entry2 = arg;
970 return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
972 static int list_hash_cb(const void *obj, const int flags)
974 return ao2_container_count(format_list);
977 const struct ast_format_list *ast_format_list_get(size_t *size)
979 struct ast_format_list *list;
980 ast_rwlock_rdlock(&format_list_array_lock);
981 ao2_ref(format_list_array, 1);
982 list = format_list_array;
983 *size = format_list_array_len;
984 ast_rwlock_unlock(&format_list_array_lock);
987 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
989 ao2_ref((void *) list, -1);
993 static int build_format_list_array(void)
995 struct ast_format_list *tmp;
996 size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
998 struct ao2_iterator it;
1000 ast_rwlock_wrlock(&format_list_array_lock);
1001 tmp = format_list_array;
1002 if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
1003 format_list_array = tmp;
1004 ast_rwlock_unlock(&format_list_array_lock);
1007 format_list_array_len = ao2_container_count(format_list);
1012 /* walk through the container adding elements to the static array */
1013 it = ao2_iterator_init(format_list, 0);
1014 while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
1015 memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
1019 ao2_iterator_destroy(&it);
1021 ast_rwlock_unlock(&format_list_array_lock);
1025 static int format_list_init(void)
1027 struct ast_format tmpfmt;
1028 if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
1031 /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
1032 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); /*!< G723.1 */
1033 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), "gsm", 8000, "GSM", 33, 20, 300, 20, 20, 0, 0); /*!< codec_gsm.c */
1034 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); /*!< codec_ulaw.c */
1035 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); /*!< codec_alaw.c */
1036 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G726, 0), "g726", 8000, "G.726 RFC3551", 40, 10, 300, 10, 20, 0, 0); /*!< codec_g726.c */
1037 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "ADPCM", 40, 10, 300, 10, 20, 0, 0); /*!< codec_adpcm.c */
1038 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); /*!< Signed linear */
1039 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_LPC10, 0), "lpc10", 8000, "LPC10", 7, 20, 20, 20, 20, 0, 0); /*!< codec_lpc10.c */
1040 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); /*!< Binary commercial distribution */
1041 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX, 0), "speex", 8000, "SpeeX", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
1042 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX16, 0), "speex16", 16000, "SpeeX 16khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
1043 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), "ilbc", 8000, "iLBC", 50, 30, 30, 30, 30, 0, 0); /*!< codec_ilbc.c */ /* inc=30ms - workaround */
1044 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); /*!< codec_g726.c */
1045 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G722, 0), "g722", 16000, "G722", 80, 10, 150, 10, 20, 0, 0); /*!< codec_g722.c */
1046 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);/*!< Signed linear (16kHz) */
1047 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), "jpeg", 0, "JPEG image", 0, 0, 0, 0 ,0 ,0 ,0); /*!< See format_jpeg.c */
1048 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_PNG, 0), "png", 0, "PNG image", 0, 0, 0, 0 ,0 ,0 ,0); /*!< PNG Image format */
1049 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), "h261", 0, "H.261 Video", 0, 0, 0, 0 ,0 ,0 ,0); /*!< H.261 Video Passthrough */
1050 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), "h263", 0, "H.263 Video", 0, 0, 0, 0 ,0 ,0 ,0); /*!< H.263 Passthrough support, see format_h263.c */
1051 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); /*!< H.263plus passthrough support See format_h263.c */
1052 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), "h264", 0, "H.264 Video", 0, 0, 0, 0 ,0 ,0, 0); /*!< Passthrough support, see format_h263.c */
1053 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_MP4_VIDEO, 0), "mpeg4", 0, "MPEG4 Video", 0, 0, 0, 0, 0 ,0, 0); /*!< Passthrough support for MPEG4 */
1054 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); /*!< Redundant T.140 Realtime Text */
1055 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); /*!< Passthrough support for T.140 Realtime Text */
1056 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); /*!< Binary commercial distribution */
1057 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); /*!< Binary commercial distribution */
1058 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); /*!< codec_ulaw.c */
1059 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
1061 /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
1062 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
1063 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);/*!< Signed linear (12kHz) */
1064 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);/*!< Signed linear (24kHz) */
1065 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);/*!< Signed linear (32kHz) */
1066 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);/*!< Signed linear (44.1kHz) */
1067 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);/*!< Signed linear (48kHz) */
1068 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);/*!< Signed linear (96kHz) */
1069 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);/*!< Signed linear (192kHz) */
1074 /*! \internal \brief Clean up resources on Asterisk shutdown */
1075 static void format_list_shutdown(void)
1077 ast_rwlock_destroy(&format_list_array_lock);
1079 ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
1082 if (format_list_array) {
1083 ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
1084 format_list_array = NULL;
1088 int ast_format_list_init(void)
1090 if (ast_rwlock_init(&format_list_array_lock)) {
1093 if (format_list_init()) {
1094 goto init_list_cleanup;
1096 if (build_format_list_array()) {
1097 goto init_list_cleanup;
1100 ast_register_atexit(format_list_shutdown);
1104 format_list_shutdown();
1108 /*! \internal \brief Clean up resources on Asterisk shutdown */
1109 static void format_attr_shutdown(void)
1111 ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
1113 ao2_ref(interfaces, -1);
1118 int ast_format_attr_init(void)
1120 interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
1121 283, interface_hash_cb, interface_cmp_cb);
1126 ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
1127 ast_register_atexit(format_attr_shutdown);
1131 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
1133 if (!entry->samplespersecond) {
1134 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
1136 ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
1137 if (!has_interface(&entry->format)) {
1141 snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
1143 ast_format_append(&entry->format,
1144 CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
1145 CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
1146 CELT_ATTR_KEY_FRAME_SIZE, framesize,
1147 AST_FORMAT_ATTR_END);
1157 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
1159 if (!entry->samplespersecond) {
1160 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
1162 ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
1164 if (!has_interface(&entry->format)) {
1168 switch (entry->samplespersecond) {
1170 ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
1171 ast_format_append(&entry->format,
1172 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
1173 AST_FORMAT_ATTR_END);
1176 ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
1177 ast_format_append(&entry->format,
1178 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
1179 AST_FORMAT_ATTR_END);
1182 ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
1183 ast_format_append(&entry->format,
1184 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
1185 AST_FORMAT_ATTR_END);
1188 ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
1189 ast_format_append(&entry->format,
1190 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
1191 AST_FORMAT_ATTR_END);
1194 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %d\n", entry->name, entry->samplespersecond);
1197 ast_format_append(&entry->format,
1198 SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
1199 SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
1200 SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
1201 SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
1202 AST_FORMAT_ATTR_END);
1212 static int conf_process_format_name(const char *name, enum ast_format_id *id)
1214 if (!strcasecmp(name, "silk")) {
1215 *id = AST_FORMAT_SILK;
1216 } else if (!strcasecmp(name, "celt")) {
1217 *id = AST_FORMAT_CELT;
1225 static int conf_process_sample_rate(const char *rate, unsigned int *result)
1227 if (!strcasecmp(rate, "8000")) {
1229 } else if (!strcasecmp(rate, "12000")) {
1231 } else if (!strcasecmp(rate, "16000")) {
1233 } else if (!strcasecmp(rate, "24000")) {
1235 } else if (!strcasecmp(rate, "32000")) {
1237 } else if (!strcasecmp(rate, "44100")) {
1239 } else if (!strcasecmp(rate, "48000")) {
1241 } else if (!strcasecmp(rate, "96000")) {
1243 } else if (!strcasecmp(rate, "192000")) {
1252 static int load_format_config(void)
1254 struct ast_flags config_flags = { 0, };
1255 struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
1256 struct ast_format_list entry;
1257 struct ast_variable *var;
1262 enum ast_format_id id;
1263 unsigned int maxbitrate;
1264 unsigned int framesize;
1265 unsigned int packetloss_percentage;
1270 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1274 /* remove all custom formats from the AO2 Container. Note, this has no affect on the
1275 * global format list until the list is rebuild. That is why this is okay to do while
1276 * reloading the config. */
1277 ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
1279 while ((cat = ast_category_browse(cfg, cat))) {
1280 memset(&entry, 0, sizeof(entry));
1281 memset(&settings, 0, sizeof(settings));
1284 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
1287 ast_copy_string(entry.name, cat, sizeof(entry.name));
1288 var = ast_variable_browse(cfg, cat);
1289 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1290 if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
1291 ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
1292 var->value, var->lineno, FORMAT_CONFIG);
1294 } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
1295 ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
1296 var->value, var->lineno, FORMAT_CONFIG);
1297 } else if (!strcasecmp(var->name, "maxbitrate")) {
1298 if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
1299 ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
1300 var->value, var->lineno, FORMAT_CONFIG);
1302 } else if (!strcasecmp(var->name, "framesize")) {
1303 if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
1304 ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
1305 var->value, var->lineno, FORMAT_CONFIG);
1307 } else if (!strcasecmp(var->name, "dtx")) {
1308 settings.usedtx = ast_true(var->value) ? 1 : 0;
1309 } else if (!strcasecmp(var->name, "fec")) {
1310 settings.usefec = ast_true(var->value) ? 1 : 0;
1311 } else if (!strcasecmp(var->name, "packetloss_percentage")) {
1312 if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
1313 ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
1314 var->value, var->lineno, FORMAT_CONFIG);
1319 switch (settings.id) {
1320 case AST_FORMAT_SILK:
1321 if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
1325 case AST_FORMAT_CELT:
1326 if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
1331 ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
1335 format_list_add_custom(&entry);
1338 ast_config_destroy(cfg);
1339 build_format_list_array();
1343 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
1347 const struct ast_format_list *f_list;
1348 struct interface_ao2_wrapper *wrapper;
1349 struct interface_ao2_wrapper tmp_wrapper = {
1350 .id = interface->id,
1354 * Grab the write lock before checking for duplicates in
1355 * anticipation of adding a new interface and to prevent a
1356 * duplicate from sneaking in between the check and add.
1358 ao2_wrlock(interfaces);
1360 /* check for duplicates first*/
1361 if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
1362 ao2_unlock(interfaces);
1363 ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
1364 ao2_ref(wrapper, -1);
1368 wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
1370 ao2_unlock(interfaces);
1374 wrapper->interface = interface;
1375 wrapper->id = interface->id;
1377 /* The write lock is already held. */
1378 ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
1379 ao2_unlock(interfaces);
1381 ao2_ref(wrapper, -1);
1383 /* This will find all custom formats in codecs.conf for this new registered interface */
1384 load_format_config();
1386 /* update the RTP engine to all custom formats created for this interface */
1387 f_list = ast_format_list_get(&f_len);
1388 for (x = 0; x < f_len; x++) {
1389 if (f_list[x].format.id == tmp_wrapper.id) {
1390 ast_rtp_engine_load_format(&f_list[x].format);
1393 f_list = ast_format_list_destroy(f_list);
1397 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
1401 const struct ast_format_list *f_list;
1402 struct interface_ao2_wrapper *wrapper;
1403 struct interface_ao2_wrapper tmp_wrapper = {
1404 .id = interface->id,
1407 if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
1411 ao2_wrlock(wrapper);
1412 wrapper->interface = NULL;
1413 ao2_unlock(wrapper);
1415 ao2_ref(wrapper, -1);
1417 /* update the RTP engine to remove all custom formats created for this interface */
1418 f_list = ast_format_list_get(&f_len);
1419 for (x = 0; x < f_len; x++) {
1420 if (f_list[x].format.id == tmp_wrapper.id) {
1421 ast_rtp_engine_unload_format(&f_list[x].format);
1425 /* This will remove all custom formats previously created for this interface */
1426 load_format_config();
1427 f_list = ast_format_list_destroy(f_list);