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>
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
32 #include "asterisk/_private.h"
33 #include "asterisk/format.h"
34 #include "asterisk/astobj2.h"
35 #include "asterisk/lock.h"
36 #include "asterisk/frame.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/rtp_engine.h"
40 #include "asterisk/config.h"
42 #define FORMAT_CONFIG "codecs.conf"
45 * \brief Container for all the format attribute interfaces.
46 * \note This container uses RWLOCKs instead of MUTEX locks. .
47 * \note An ao2 container was chosen for fast lookup.
49 static struct ao2_container *interfaces;
51 /*! a wrapper is used put interfaces into the ao2 container. */
52 struct interface_ao2_wrapper {
53 enum ast_format_id id;
54 const struct ast_format_attr_interface *interface;
57 /*! \brief Format List container, This container is never directly accessed outside
58 * of this file, and It only exists for building the format_list_array. */
59 static struct ao2_container *format_list;
60 /*! \brief Format List array is a read only array protected by a read write lock.
61 * This array may be used outside this file with the use of reference counting to
62 * guarantee safety for access by multiple threads. */
63 static struct ast_format_list *format_list_array;
64 static size_t format_list_array_len = 0;
65 /*! \brief Locks the format list array so a reference can be taken safely. */
66 static ast_rwlock_t format_list_array_lock;
68 static int interface_cmp_cb(void *obj, void *arg, int flags)
70 struct interface_ao2_wrapper *wrapper1 = obj;
71 struct interface_ao2_wrapper *wrapper2 = arg;
73 return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
76 static int interface_hash_cb(const void *obj, const int flags)
78 const struct interface_ao2_wrapper *wrapper = obj;
82 void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
87 void ast_format_set_video_mark(struct ast_format *format)
89 format->fattr.rtp_marker_bit = 1;
92 int ast_format_get_video_mark(const struct ast_format *format)
94 return format->fattr.rtp_marker_bit;
97 static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
99 struct interface_ao2_wrapper tmp_wrapper = {
103 return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
106 static int has_interface(const struct ast_format *format)
108 struct interface_ao2_wrapper *wrapper;
110 wrapper = find_interface(format);
114 ao2_ref(wrapper, -1);
119 * \brief set format attributes using an interface
121 static int format_set_helper(struct ast_format *format, va_list ap)
123 struct interface_ao2_wrapper *wrapper;
125 if (!(wrapper = find_interface(format))) {
126 ast_log(LOG_WARNING, "Could not find format interface to set.\n");
131 if (!wrapper->interface || !wrapper->interface->format_attr_set) {
133 ao2_ref(wrapper, -1);
137 wrapper->interface->format_attr_set(&format->fattr, ap);
140 ao2_ref(wrapper, -1);
145 struct ast_format *ast_format_append(struct ast_format *format, ... )
148 va_start(ap, format);
149 format_set_helper(format, ap);
155 struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
157 /* initialize the structure before setting it. */
158 ast_format_clear(format);
162 if (set_attributes) {
164 va_start(ap, set_attributes);
165 format_set_helper(format, ap);
172 void ast_format_clear(struct ast_format *format)
175 memset(&format->fattr, 0, sizeof(format->fattr));
179 * \brief determine if a list of attribute key value pairs are set on a format
181 static int format_isset_helper(const struct ast_format *format, va_list ap)
184 struct interface_ao2_wrapper *wrapper;
185 struct ast_format tmp = {
187 .fattr = { { 0, }, },
190 if (!(wrapper = find_interface(format))) {
195 if (!wrapper->interface ||
196 !wrapper->interface->format_attr_set ||
197 !wrapper->interface->format_attr_cmp) {
200 ao2_ref(wrapper, -1);
204 /* if isset is present, use that function, else just build a new
205 * format and use the cmp function */
206 if (wrapper->interface->format_attr_isset) {
207 res = wrapper->interface->format_attr_isset(&format->fattr, ap);
209 wrapper->interface->format_attr_set(&tmp.fattr, ap);
210 /* use our tmp structure to tell if the attributes are set or not */
211 res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
212 res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
216 ao2_ref(wrapper, -1);
221 int ast_format_isset(const struct ast_format *format, ... )
226 va_start(ap, format);
227 res = format_isset_helper(format, ap);
232 int ast_format_get_value(const struct ast_format *format, int key, void *value)
235 struct interface_ao2_wrapper *wrapper;
237 if (!(wrapper = find_interface(format))) {
241 if (!wrapper->interface ||
242 !wrapper->interface->format_attr_get_val) {
245 ao2_ref(wrapper, -1);
249 res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
252 ao2_ref(wrapper, -1);
258 * \brief cmp format attributes using an interface
260 static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
262 enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
263 struct interface_ao2_wrapper *wrapper;
265 if (!(wrapper = find_interface(format1))) {
270 if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
272 ao2_ref(wrapper, -1);
276 res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
279 ao2_ref(wrapper, -1);
284 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
286 if (format1->id != format2->id) {
287 return AST_FORMAT_CMP_NOT_EQUAL;
290 return format_cmp_helper(format1, format2);
294 * \brief get joint format attributes using an interface
296 static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
299 struct interface_ao2_wrapper *wrapper;
301 if (!(wrapper = find_interface(format1))) {
302 /* if no interface is present, we assume formats are joint by id alone */
307 if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
308 res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
312 ao2_ref(wrapper, -1);
317 int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
319 if (format1->id != format2->id) {
322 result->id = format1->id;
323 return format_joint_helper(format1, format2, result);
327 uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
330 /*! G.723.1 compression */
331 case AST_FORMAT_G723_1:
333 /*! GSM compression */
336 /*! Raw mu-law data (G.711) */
337 case AST_FORMAT_ULAW:
339 /*! Raw A-law data (G.711) */
340 case AST_FORMAT_ALAW:
342 /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
343 case AST_FORMAT_G726_AAL2:
346 case AST_FORMAT_ADPCM:
348 /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
349 case AST_FORMAT_SLINEAR:
351 /*! LPC10, 180 samples/frame */
352 case AST_FORMAT_LPC10:
355 case AST_FORMAT_G729A:
357 /*! SpeeX Free Compression */
358 case AST_FORMAT_SPEEX:
360 /*! iLBC Free Compression */
361 case AST_FORMAT_ILBC:
363 /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
364 case AST_FORMAT_G726:
367 case AST_FORMAT_G722:
369 /*! G.722.1 (also known as Siren7, 32kbps assumed) */
370 case AST_FORMAT_SIREN7:
372 /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
373 case AST_FORMAT_SIREN14:
375 /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
376 case AST_FORMAT_SLINEAR16:
378 /*! G.719 (64 kbps assumed) */
379 case AST_FORMAT_G719:
381 /*! SpeeX Wideband (16kHz) Free Compression */
382 case AST_FORMAT_SPEEX16:
384 /*! Raw mu-law data (G.711) */
385 case AST_FORMAT_TESTLAW:
389 case AST_FORMAT_H261:
392 case AST_FORMAT_H263:
395 case AST_FORMAT_H263_PLUS:
398 case AST_FORMAT_H264:
401 case AST_FORMAT_MP4_VIDEO:
405 case AST_FORMAT_JPEG:
411 /*! T.140 RED Text format RFC 4103 */
412 case AST_FORMAT_T140RED:
414 /*! T.140 Text format - ITU T.140, RFC 4103 */
415 case AST_FORMAT_T140:
418 return 0; /* not supported by old bitfield. */
424 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
426 return ast_format_id_to_old_bitfield(format->id);
429 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
432 /*! G.723.1 compression */
434 return ast_format_set(dst, AST_FORMAT_G723_1, 0);
435 /*! GSM compression */
437 return ast_format_set(dst, AST_FORMAT_GSM, 0);
438 /*! Raw mu-law data (G.711) */
440 return ast_format_set(dst, AST_FORMAT_ULAW, 0);
441 /*! Raw A-law data (G.711) */
443 return ast_format_set(dst, AST_FORMAT_ALAW, 0);
444 /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
446 return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
449 return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
450 /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
452 return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
453 /*! LPC10, 180 samples/frame */
455 return ast_format_set(dst, AST_FORMAT_LPC10, 0);
458 return ast_format_set(dst, AST_FORMAT_G729A, 0);
459 /*! SpeeX Free Compression */
461 return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
462 /*! iLBC Free Compression */
464 return ast_format_set(dst, AST_FORMAT_ILBC, 0);
465 /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
467 return ast_format_set(dst, AST_FORMAT_G726, 0);
470 return ast_format_set(dst, AST_FORMAT_G722, 0);
471 /*! G.722.1 (also known as Siren7, 32kbps assumed) */
473 return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
474 /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
476 return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
477 /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
479 return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
480 /*! G.719 (64 kbps assumed) */
482 return ast_format_set(dst, AST_FORMAT_G719, 0);
483 /*! SpeeX Wideband (16kHz) Free Compression */
485 return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
486 /*! Raw mu-law data (G.711) */
488 return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
492 return ast_format_set(dst, AST_FORMAT_H261, 0);
495 return ast_format_set(dst, AST_FORMAT_H263, 0);
498 return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
501 return ast_format_set(dst, AST_FORMAT_H264, 0);
504 return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
508 return ast_format_set(dst, AST_FORMAT_JPEG, 0);
511 return ast_format_set(dst, AST_FORMAT_PNG, 0);
513 /*! T.140 RED Text format RFC 4103 */
515 return ast_format_set(dst, AST_FORMAT_T140RED, 0);
516 /*! T.140 Text format - ITU T.140, RFC 4103 */
518 return ast_format_set(dst, AST_FORMAT_T140, 0);
520 ast_format_clear(dst);
524 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
526 struct ast_format dst;
527 if (ast_format_from_old_bitfield(&dst, src)) {
533 int ast_format_is_slinear(const struct ast_format *format)
535 if (format->id == AST_FORMAT_SLINEAR ||
536 format->id == AST_FORMAT_SLINEAR12 ||
537 format->id == AST_FORMAT_SLINEAR16 ||
538 format->id == AST_FORMAT_SLINEAR24 ||
539 format->id == AST_FORMAT_SLINEAR32 ||
540 format->id == AST_FORMAT_SLINEAR44 ||
541 format->id == AST_FORMAT_SLINEAR48 ||
542 format->id == AST_FORMAT_SLINEAR96 ||
543 format->id == AST_FORMAT_SLINEAR192) {
549 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
551 if (rate >= 192000) {
552 return AST_FORMAT_SLINEAR192;
553 } else if (rate >= 96000) {
554 return AST_FORMAT_SLINEAR96;
555 } else if (rate >= 48000) {
556 return AST_FORMAT_SLINEAR48;
557 } else if (rate >= 44100) {
558 return AST_FORMAT_SLINEAR44;
559 } else if (rate >= 32000) {
560 return AST_FORMAT_SLINEAR32;
561 } else if (rate >= 24000) {
562 return AST_FORMAT_SLINEAR24;
563 } else if (rate >= 16000) {
564 return AST_FORMAT_SLINEAR16;
565 } else if (rate >= 12000) {
566 return AST_FORMAT_SLINEAR12;
568 return AST_FORMAT_SLINEAR;
571 const char* ast_getformatname(const struct ast_format *format)
574 const char *ret = "unknown";
576 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
577 for (x = 0; x < f_len; x++) {
578 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
579 ret = f_list[x].name;
583 f_list = ast_format_list_destroy(f_list);
588 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
592 char *start, *end = buf;
594 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
597 f_list = ast_format_list_destroy(f_list);
600 snprintf(end, size, "(");
605 for (x = 0; x < f_len; x++) {
606 if (f_list[x].format.id == id) {
607 snprintf(end, size, "%s|", f_list[x].name);
614 ast_copy_string(start, "nothing)", size);
615 } else if (size > 1) {
618 f_list = ast_format_list_destroy(f_list);
622 static struct ast_codec_alias_table {
624 const char *realname;
625 } ast_codec_alias_table[] = {
626 { "slinear", "slin"},
627 { "slinear16", "slin16"},
629 { "g722.1", "siren7"},
630 { "g722.1c", "siren14"},
633 static const char *ast_expand_codec_alias(const char *in)
637 for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
638 if (!strcmp(in,ast_codec_alias_table[x].alias))
639 return ast_codec_alias_table[x].realname;
644 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
648 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
650 for (x = 0; x < f_len; x++) {
651 if (!strcasecmp(f_list[x].name, name) ||
652 !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
654 ast_format_copy(result, &f_list[x].format);
655 f_list = ast_format_list_destroy(f_list);
659 f_list = ast_format_list_destroy(f_list);
664 const char *ast_codec2str(struct ast_format *format)
667 const char *ret = "unknown";
669 const struct ast_format_list *f_list = ast_format_list_get(&f_len);
671 for (x = 0; x < f_len; x++) {
672 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
673 ret = f_list[x].desc;
677 f_list = ast_format_list_destroy(f_list);
681 int ast_format_rate(const struct ast_format *format)
683 switch (format->id) {
684 case AST_FORMAT_SLINEAR12:
686 case AST_FORMAT_SLINEAR24:
688 case AST_FORMAT_SLINEAR32:
690 case AST_FORMAT_SLINEAR44:
692 case AST_FORMAT_SLINEAR48:
694 case AST_FORMAT_SLINEAR96:
696 case AST_FORMAT_SLINEAR192:
698 case AST_FORMAT_G722:
699 case AST_FORMAT_SLINEAR16:
700 case AST_FORMAT_SIREN7:
701 case AST_FORMAT_SPEEX16:
703 case AST_FORMAT_SIREN14:
704 case AST_FORMAT_SPEEX32:
706 case AST_FORMAT_G719:
708 case AST_FORMAT_SILK:
709 if (!(ast_format_isset(format,
710 SILK_ATTR_KEY_SAMP_RATE,
711 SILK_ATTR_VAL_SAMP_24KHZ,
712 AST_FORMAT_ATTR_END))) {
714 } else if (!(ast_format_isset(format,
715 SILK_ATTR_KEY_SAMP_RATE,
716 SILK_ATTR_VAL_SAMP_16KHZ,
717 AST_FORMAT_ATTR_END))) {
719 } else if (!(ast_format_isset(format,
720 SILK_ATTR_KEY_SAMP_RATE,
721 SILK_ATTR_VAL_SAMP_12KHZ,
722 AST_FORMAT_ATTR_END))) {
727 case AST_FORMAT_CELT:
730 if (!(ast_format_get_value(format,
731 CELT_ATTR_KEY_SAMP_RATE,
741 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
745 const struct ast_format_list *f_list;
749 e->command = "core show codecs [audio|video|image|text]";
751 "Usage: core show codecs [audio|video|image|text]\n"
752 " Displays codec mapping\n";
758 if ((a->argc < 3) || (a->argc > 4)) {
759 return CLI_SHOWUSAGE;
762 f_list = ast_format_list_get(&f_len);
763 if (!ast_opt_dont_warn) {
764 ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
765 "\tIt does not indicate anything about your configuration.\n");
768 ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
769 ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
771 for (x = 0; x < f_len; x++) {
773 if (!strcasecmp(a->argv[3], "audio")) {
774 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
777 } else if (!strcasecmp(a->argv[3], "video")) {
778 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
781 } else if (!strcasecmp(a->argv[3], "image")) {
782 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
785 } else if (!strcasecmp(a->argv[3], "text")) {
786 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
794 ast_cli(a->fd, "%8u %5s %8s (%s)\n",
796 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
797 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_IMAGE) ? "image" :
798 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_VIDEO) ? "video" :
799 (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_TEXT) ? "text" :
806 f_list = ast_format_list_destroy(f_list);
808 return CLI_SHOWUSAGE;
814 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
816 enum ast_format_id format_id;
818 int type_punned_codec;
820 const struct ast_format_list *f_list;
824 e->command = "core show codec";
826 "Usage: core show codec <number>\n"
827 " Displays codec mapping\n";
834 return CLI_SHOWUSAGE;
837 if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
838 return CLI_SHOWUSAGE;
840 format_id = type_punned_codec;
842 f_list = ast_format_list_get(&f_len);
843 for (x = 0; x < f_len; x++) {
844 if (f_list[x].format.id == format_id) {
846 ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
851 ast_cli(a->fd, "Codec %d not found\n", format_id);
854 f_list = ast_format_list_destroy(f_list);
858 /* Builtin Asterisk CLI-commands for debugging */
859 static struct ast_cli_entry my_clis[] = {
860 AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
861 AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
863 int init_framer(void)
865 ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
869 static int format_list_add_custom(struct ast_format_list *new)
871 struct ast_format_list *entry;
872 if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
875 memcpy(entry, new, sizeof(struct ast_format_list));
876 entry->custom_entry = 1;
877 ao2_link(format_list, entry);
880 static int format_list_add_static(
881 const struct ast_format *format,
883 int samplespersecond,
884 const char *description,
893 struct ast_format_list *entry;
894 if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
897 ast_format_copy(&entry->format, format);
898 ast_copy_string(entry->name, name, sizeof(entry->name));
899 ast_copy_string(entry->desc, description, sizeof(entry->desc));
900 entry->samplespersecond = samplespersecond;
901 entry->fr_len = fr_len;
902 entry->min_ms = min_ms;
903 entry->max_ms = max_ms;
904 entry->inc_ms = inc_ms;
905 entry->def_ms = def_ms;
906 entry->flags = flags;
907 entry->cur_ms = cur_ms;
908 entry->custom_entry = 0;
910 ao2_link(format_list, entry);
914 static int list_all_custom(void *obj, void *arg, int flag)
916 struct ast_format_list *entry = obj;
917 return entry->custom_entry ? CMP_MATCH : 0;
920 static int list_cmp_cb(void *obj, void *arg, int flags)
922 struct ast_format_list *entry1 = obj;
923 struct ast_format_list *entry2 = arg;
925 return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
927 static int list_hash_cb(const void *obj, const int flags)
929 return ao2_container_count(format_list);
932 const struct ast_format_list *ast_format_list_get(size_t *size)
934 struct ast_format_list *list;
935 ast_rwlock_rdlock(&format_list_array_lock);
936 ao2_ref(format_list_array, 1);
937 list = format_list_array;
938 *size = format_list_array_len;
939 ast_rwlock_unlock(&format_list_array_lock);
942 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
944 ao2_ref((void *) list, -1);
948 static int build_format_list_array(void)
950 struct ast_format_list *tmp;
951 size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
953 struct ao2_iterator it;
955 ast_rwlock_wrlock(&format_list_array_lock);
956 tmp = format_list_array;
957 if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
958 format_list_array = tmp;
959 ast_rwlock_unlock(&format_list_array_lock);
962 format_list_array_len = ao2_container_count(format_list);
967 /* walk through the container adding elements to the static array */
968 it = ao2_iterator_init(format_list, 0);
969 while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
970 memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
974 ao2_iterator_destroy(&it);
976 ast_rwlock_unlock(&format_list_array_lock);
979 static int format_list_init(void)
981 struct ast_format tmpfmt;
982 if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
985 /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
986 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 */
987 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 */
988 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 */
989 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 */
990 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 */
991 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 */
992 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 */
993 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 */
994 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 */
995 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 */
996 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 */
997 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 */
998 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 */
999 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 */
1000 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) */
1001 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 */
1002 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 */
1003 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 */
1004 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 */
1005 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 */
1006 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 */
1007 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 */
1008 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 */
1009 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 */
1010 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 */
1011 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 */
1012 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 */
1013 format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
1015 /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
1016 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 */
1017 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) */
1018 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) */
1019 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) */
1020 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) */
1021 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) */
1022 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) */
1023 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) */
1028 int ast_format_list_init(void)
1030 if (ast_rwlock_init(&format_list_array_lock)) {
1033 if (format_list_init()) {
1034 goto init_list_cleanup;
1036 if (build_format_list_array()) {
1037 goto init_list_cleanup;
1043 ast_rwlock_destroy(&format_list_array_lock);
1044 ao2_ref(format_list, -1);
1045 if (format_list_array) {
1046 ao2_ref(format_list_array, -1);
1051 int ast_format_attr_init(void)
1053 ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
1055 interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
1056 283, interface_hash_cb, interface_cmp_cb);
1063 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
1065 if (!entry->samplespersecond) {
1066 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
1068 ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
1069 if (!has_interface(&entry->format)) {
1073 snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
1075 ast_format_append(&entry->format,
1076 CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
1077 CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
1078 CELT_ATTR_KEY_FRAME_SIZE, framesize,
1079 AST_FORMAT_ATTR_END);
1089 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
1091 if (!entry->samplespersecond) {
1092 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
1094 ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
1096 if (!has_interface(&entry->format)) {
1100 switch (entry->samplespersecond) {
1102 ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
1103 ast_format_append(&entry->format,
1104 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
1105 AST_FORMAT_ATTR_END);
1108 ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
1109 ast_format_append(&entry->format,
1110 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
1111 AST_FORMAT_ATTR_END);
1114 ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
1115 ast_format_append(&entry->format,
1116 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
1117 AST_FORMAT_ATTR_END);
1120 ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
1121 ast_format_append(&entry->format,
1122 SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
1123 AST_FORMAT_ATTR_END);
1126 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %d\n", entry->name, entry->samplespersecond);
1129 ast_format_append(&entry->format,
1130 SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
1131 SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
1132 SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
1133 SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
1134 AST_FORMAT_ATTR_END);
1144 static int conf_process_format_name(const char *name, enum ast_format_id *id)
1146 if (!strcasecmp(name, "silk")) {
1147 *id = AST_FORMAT_SILK;
1148 } else if (!strcasecmp(name, "celt")) {
1149 *id = AST_FORMAT_CELT;
1157 static int conf_process_sample_rate(const char *rate, unsigned int *result)
1159 if (!strcasecmp(rate, "8000")) {
1161 } else if (!strcasecmp(rate, "12000")) {
1163 } else if (!strcasecmp(rate, "16000")) {
1165 } else if (!strcasecmp(rate, "24000")) {
1167 } else if (!strcasecmp(rate, "32000")) {
1169 } else if (!strcasecmp(rate, "44100")) {
1171 } else if (!strcasecmp(rate, "48000")) {
1173 } else if (!strcasecmp(rate, "96000")) {
1175 } else if (!strcasecmp(rate, "192000")) {
1184 static int load_format_config(void)
1186 struct ast_flags config_flags = { 0, };
1187 struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
1188 struct ast_format_list entry;
1189 struct ast_variable *var;
1194 enum ast_format_id id;
1195 unsigned int maxbitrate;
1196 unsigned int framesize;
1197 unsigned int packetloss_percentage;
1202 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1206 /* remove all custom formats from the AO2 Container. Note, this has no affect on the
1207 * global format list until the list is rebuild. That is why this is okay to do while
1208 * reloading the config. */
1209 ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
1211 while ((cat = ast_category_browse(cfg, cat))) {
1212 memset(&entry, 0, sizeof(entry));
1213 memset(&settings, 0, sizeof(settings));
1216 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
1219 ast_copy_string(entry.name, cat, sizeof(entry.name));
1220 var = ast_variable_browse(cfg, cat);
1221 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1222 if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
1223 ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
1224 var->value, var->lineno, FORMAT_CONFIG);
1226 } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
1227 ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
1228 var->value, var->lineno, FORMAT_CONFIG);
1229 } else if (!strcasecmp(var->name, "maxbitrate")) {
1230 if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
1231 ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
1232 var->value, var->lineno, FORMAT_CONFIG);
1234 } else if (!strcasecmp(var->name, "framesize")) {
1235 if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
1236 ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
1237 var->value, var->lineno, FORMAT_CONFIG);
1239 } else if (!strcasecmp(var->name, "dtx")) {
1240 settings.usedtx = ast_true(var->value) ? 1 : 0;
1241 } else if (!strcasecmp(var->name, "fec")) {
1242 settings.usefec = ast_true(var->value) ? 1 : 0;
1243 } else if (!strcasecmp(var->name, "packetloss_percentage")) {
1244 if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
1245 ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
1246 var->value, var->lineno, FORMAT_CONFIG);
1251 switch (settings.id) {
1252 case AST_FORMAT_SILK:
1253 if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
1257 case AST_FORMAT_CELT:
1258 if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
1263 ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
1267 format_list_add_custom(&entry);
1270 ast_config_destroy(cfg);
1271 build_format_list_array();
1275 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
1279 const struct ast_format_list *f_list;
1280 struct interface_ao2_wrapper *wrapper;
1281 struct interface_ao2_wrapper tmp_wrapper = {
1282 .id = interface->id,
1286 * Grab the write lock before checking for duplicates in
1287 * anticipation of adding a new interface and to prevent a
1288 * duplicate from sneaking in between the check and add.
1290 ao2_wrlock(interfaces);
1292 /* check for duplicates first*/
1293 if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
1294 ao2_unlock(interfaces);
1295 ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
1296 ao2_ref(wrapper, -1);
1300 wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
1302 ao2_unlock(interfaces);
1306 wrapper->interface = interface;
1307 wrapper->id = interface->id;
1309 /* The write lock is already held. */
1310 ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
1311 ao2_unlock(interfaces);
1313 ao2_ref(wrapper, -1);
1315 /* This will find all custom formats in codecs.conf for this new registered interface */
1316 load_format_config();
1318 /* update the RTP engine to all custom formats created for this interface */
1319 f_list = ast_format_list_get(&f_len);
1320 for (x = 0; x < f_len; x++) {
1321 if (f_list[x].format.id == tmp_wrapper.id) {
1322 ast_rtp_engine_load_format(&f_list[x].format);
1329 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
1333 const struct ast_format_list *f_list;
1334 struct interface_ao2_wrapper *wrapper;
1335 struct interface_ao2_wrapper tmp_wrapper = {
1336 .id = interface->id,
1339 if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
1343 ao2_wrlock(wrapper);
1344 wrapper->interface = NULL;
1345 ao2_unlock(wrapper);
1347 ao2_ref(wrapper, -1);
1349 /* update the RTP engine to remove all custom formats created for this interface */
1350 f_list = ast_format_list_get(&f_len);
1351 for (x = 0; x < f_len; x++) {
1352 if (f_list[x].format.id == tmp_wrapper.id) {
1353 ast_rtp_engine_unload_format(&f_list[x].format);
1357 /* This will remove all custom formats previously created for this interface */
1358 load_format_config();