Adds pass-through support for codec CELT.
[asterisk/asterisk.git] / main / format.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * David Vossel <dvossel@digium.com>
7  * Mark Spencer <markster@digium.com>
8  *
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.
14  *
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.
18  */
19
20 /*!
21  * \file
22  * \brief Format API
23  *
24  * \author David Vossel <dvossel@digium.com>
25  * \author Mark Spencer <markster@digium.com>
26  */
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
31
32 #include "asterisk/_private.h"
33 #include "asterisk/version.h"
34 #include "asterisk/format.h"
35 #include "asterisk/astobj2.h"
36 #include "asterisk/lock.h"
37 #include "asterisk/frame.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/cli.h"
40 #include "asterisk/rtp_engine.h"
41 #include "asterisk/config.h"
42
43 #define FORMAT_CONFIG "codecs.conf"
44
45 /*! This is the container for all the format attribute interfaces.
46  *  An ao2 container was chosen for fast lookup. */
47 static struct ao2_container *interfaces;
48
49 /*! This is the lock used to protect the interfaces container.  Yes, ao2_containers
50  * do have their own locking, but we need the capability of performing read/write
51  * locks on this specific container. */
52 static ast_rwlock_t ilock;
53
54 /*! a wrapper is used put interfaces into the ao2 container. */
55 struct interface_ao2_wrapper {
56         enum ast_format_id id;
57         const struct ast_format_attr_interface *interface;
58         /*! a read write lock must be used to protect the wrapper instead
59          * of the ao2 lock. */
60         ast_rwlock_t wraplock;
61 };
62
63 /*! \brief Format List container, This container is never directly accessed outside
64  * of this file, and It only exists for building the format_list_array. */
65 static struct ao2_container *format_list;
66 /*! \brief Format List array is a read only array protected by a read write lock.
67  * This array may be used outside this file with the use of reference counting to
68  * guarantee safety for access by multiple threads. */
69 static struct ast_format_list *format_list_array;
70 static size_t format_list_array_len = 0;
71 /*! \brief Locks the format list array so a reference can be taken safely. */
72 static ast_rwlock_t format_list_array_lock;
73
74 static int interface_cmp_cb(void *obj, void *arg, int flags)
75 {
76         struct interface_ao2_wrapper *wrapper1 = obj;
77         struct interface_ao2_wrapper *wrapper2 = arg;
78
79         return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
80 }
81
82 static int interface_hash_cb(const void *obj, const int flags)
83 {
84         const struct interface_ao2_wrapper *wrapper = obj;
85         return wrapper->id;
86 }
87
88 static void interface_destroy_cb(void *obj)
89 {
90         struct interface_ao2_wrapper *wrapper = obj;
91         ast_rwlock_destroy(&wrapper->wraplock);
92 }
93
94 void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
95 {
96         memcpy(dst, src, sizeof(struct ast_format));
97 }
98
99 void ast_format_set_video_mark(struct ast_format *format)
100 {
101         format->fattr.rtp_marker_bit = 1;
102 }
103
104 int ast_format_get_video_mark(const struct ast_format *format)
105 {
106         return format->fattr.rtp_marker_bit;
107 }
108
109 static int has_interface(const struct ast_format *format)
110 {
111         struct interface_ao2_wrapper *wrapper;
112         struct interface_ao2_wrapper tmp_wrapper = {
113                 .id = format->id,
114         };
115
116         ast_rwlock_rdlock(&ilock);
117         if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
118                 ast_rwlock_unlock(&ilock);
119                 return 0;
120         }
121         ast_rwlock_unlock(&ilock);
122         ao2_ref(wrapper, -1);
123         return 1;
124 }
125
126 static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
127 {
128         struct interface_ao2_wrapper *wrapper;
129         struct interface_ao2_wrapper tmp_wrapper = {
130                 .id = format->id,
131         };
132
133         ast_rwlock_rdlock(&ilock);
134         if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
135                 ast_rwlock_unlock(&ilock);
136                 return NULL;
137         }
138         ast_rwlock_unlock(&ilock);
139
140         return wrapper;
141 }
142
143 /*! \internal
144  * \brief set format attributes using an interface
145  */
146 static int format_set_helper(struct ast_format *format, va_list ap)
147 {
148         struct interface_ao2_wrapper *wrapper;
149
150         if (!(wrapper = find_interface(format))) {
151                 ast_log(LOG_WARNING, "Could not find format interface to set.\n");
152                 return -1;
153         }
154
155         ast_rwlock_rdlock(&wrapper->wraplock);
156         if (!wrapper->interface || !wrapper->interface->format_attr_set) {
157                 ast_rwlock_unlock(&wrapper->wraplock);
158                 ao2_ref(wrapper, -1);
159                 return -1;
160         }
161
162         wrapper->interface->format_attr_set(&format->fattr, ap);
163
164         ast_rwlock_unlock(&wrapper->wraplock);
165         ao2_ref(wrapper, -1);
166
167         return 0;
168 }
169
170 struct ast_format *ast_format_append(struct ast_format *format, ... )
171 {
172         va_list ap;
173         va_start(ap, format);
174         format_set_helper(format, ap);
175         va_end(ap);
176
177         return format;
178 }
179
180 struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
181 {
182         /* initialize the structure before setting it. */
183         ast_format_clear(format);
184
185         format->id = id;
186
187         if (set_attributes) {
188                 va_list ap;
189                 va_start(ap, set_attributes);
190                 format_set_helper(format, ap);
191                 va_end(ap);
192         }
193
194         return format;
195 }
196
197 void ast_format_clear(struct ast_format *format)
198 {
199         format->id = 0;
200         memset(&format->fattr, 0, sizeof(format->fattr));
201 }
202
203 /*! \internal
204  * \brief determine if a list of attribute key value pairs are set on a format
205  */
206 static int format_isset_helper(const struct ast_format *format, va_list ap)
207 {
208         int res;
209         struct interface_ao2_wrapper *wrapper;
210         struct ast_format tmp = {
211                 .id = format->id,
212                 .fattr = { { 0, }, },
213         };
214
215         if (!(wrapper = find_interface(format))) {
216                 return -1;
217         }
218
219         ast_rwlock_rdlock(&wrapper->wraplock);
220         if (!wrapper->interface ||
221                 !wrapper->interface->format_attr_set ||
222                 !wrapper->interface->format_attr_cmp) {
223
224                 ast_rwlock_unlock(&wrapper->wraplock);
225                 ao2_ref(wrapper, -1);
226                 return -1;
227         }
228
229         /* if isset is present, use that function, else just build a new
230          * format and use the cmp function */
231         if (wrapper->interface->format_attr_isset) {
232                 res = wrapper->interface->format_attr_isset(&format->fattr, ap);
233         } else {
234                 wrapper->interface->format_attr_set(&tmp.fattr, ap);
235                 /* use our tmp structure to tell if the attributes are set or not */
236                 res = wrapper->interface->format_attr_cmp(&tmp.fattr, &format->fattr);
237                 res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
238         }
239
240         ast_rwlock_unlock(&wrapper->wraplock);
241         ao2_ref(wrapper, -1);
242
243         return res;
244 }
245
246 int ast_format_isset(const struct ast_format *format, ... )
247 {
248         va_list ap;
249         int res;
250
251         va_start(ap, format);
252         res = format_isset_helper(format, ap);
253         va_end(ap);
254         return res;
255 }
256
257 int ast_format_get_value(const struct ast_format *format, int key, void *value)
258 {
259         int res = 0;
260         struct interface_ao2_wrapper *wrapper;
261         if (!(wrapper = find_interface(format))) {
262                 return -1;
263         }
264         ast_rwlock_rdlock(&wrapper->wraplock);
265         if (!wrapper->interface ||
266                 !wrapper->interface->format_attr_get_val) {
267
268                 ast_rwlock_unlock(&wrapper->wraplock);
269                 ao2_ref(wrapper, -1);
270                 return -1;
271         }
272
273         res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
274
275         ast_rwlock_unlock(&wrapper->wraplock);
276         ao2_ref(wrapper, -1);
277
278         return res;
279 }
280
281 /*! \internal
282  * \brief cmp format attributes using an interface
283  */
284 static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
285 {
286         enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
287         struct interface_ao2_wrapper *wrapper;
288
289         if (!(wrapper = find_interface(format1))) {
290                 return res;
291         }
292
293         ast_rwlock_rdlock(&wrapper->wraplock);
294         if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
295                 ast_rwlock_unlock(&wrapper->wraplock);
296                 ao2_ref(wrapper, -1);
297                 return res;
298         }
299
300         res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
301
302         ast_rwlock_unlock(&wrapper->wraplock);
303         ao2_ref(wrapper, -1);
304
305         return res;
306 }
307
308 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
309 {
310         if (format1->id != format2->id) {
311                 return AST_FORMAT_CMP_NOT_EQUAL;
312         }
313
314         return format_cmp_helper(format1, format2);
315 }
316
317 /*! \internal
318  * \brief get joint format attributes using an interface
319  */
320 static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
321 {
322         int res = 0;
323         struct interface_ao2_wrapper *wrapper;
324
325         if (!(wrapper = find_interface(format1))) {
326                 /* if no interface is present, we assume formats are joint by id alone */
327                 return res;
328         }
329
330         ast_rwlock_rdlock(&wrapper->wraplock);
331         if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
332                 res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
333         }
334         ast_rwlock_unlock(&wrapper->wraplock);
335
336         ao2_ref(wrapper, -1);
337
338         return res;
339 }
340
341 int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
342 {
343         if (format1->id != format2->id) {
344                 return -1;
345         }
346         result->id = format1->id;
347         return format_joint_helper(format1, format2, result);
348 }
349
350
351 uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
352 {
353         switch (id) {
354         /*! G.723.1 compression */
355         case AST_FORMAT_G723_1:
356                 return (1ULL << 0);
357         /*! GSM compression */
358         case AST_FORMAT_GSM:
359                 return (1ULL << 1);
360         /*! Raw mu-law data (G.711) */
361         case AST_FORMAT_ULAW:
362                 return (1ULL << 2);
363         /*! Raw A-law data (G.711) */
364         case AST_FORMAT_ALAW:
365                 return (1ULL << 3);
366         /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
367         case AST_FORMAT_G726_AAL2:
368                 return (1ULL << 4);
369         /*! ADPCM (IMA) */
370         case AST_FORMAT_ADPCM:
371                 return (1ULL << 5);
372         /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
373         case AST_FORMAT_SLINEAR:
374                 return (1ULL << 6);
375         /*! LPC10, 180 samples/frame */
376         case AST_FORMAT_LPC10:
377                 return (1ULL << 7);
378         /*! G.729A audio */
379         case AST_FORMAT_G729A:
380                 return (1ULL << 8);
381         /*! SpeeX Free Compression */
382         case AST_FORMAT_SPEEX:
383                 return (1ULL << 9);
384         /*! iLBC Free Compression */
385         case AST_FORMAT_ILBC:
386                 return (1ULL << 10);
387         /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
388         case AST_FORMAT_G726:
389                 return (1ULL << 11);
390         /*! G.722 */
391         case AST_FORMAT_G722:
392                 return (1ULL << 12);
393         /*! G.722.1 (also known as Siren7, 32kbps assumed) */
394         case AST_FORMAT_SIREN7:
395                 return (1ULL << 13);
396         /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
397         case AST_FORMAT_SIREN14:
398                 return (1ULL << 14);
399         /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
400         case AST_FORMAT_SLINEAR16:
401                 return (1ULL << 15);
402         /*! G.719 (64 kbps assumed) */
403         case AST_FORMAT_G719:
404                 return (1ULL << 32);
405         /*! SpeeX Wideband (16kHz) Free Compression */
406         case AST_FORMAT_SPEEX16:
407                 return (1ULL << 33);
408         /*! Raw mu-law data (G.711) */
409         case AST_FORMAT_TESTLAW:
410                 return (1ULL << 47);
411
412         /*! H.261 Video */
413         case AST_FORMAT_H261:
414                 return (1ULL << 18);
415         /*! H.263 Video */
416         case AST_FORMAT_H263:
417                 return (1ULL << 19);
418         /*! H.263+ Video */
419         case AST_FORMAT_H263_PLUS:
420                 return (1ULL << 20);
421         /*! H.264 Video */
422         case AST_FORMAT_H264:
423                 return (1ULL << 21);
424         /*! MPEG4 Video */
425         case AST_FORMAT_MP4_VIDEO:
426                 return (1ULL << 22);
427
428         /*! JPEG Images */
429         case AST_FORMAT_JPEG:
430                 return (1ULL << 16);
431         /*! PNG Images */
432         case AST_FORMAT_PNG:
433                 return (1ULL << 17);
434
435         /*! T.140 RED Text format RFC 4103 */
436         case AST_FORMAT_T140RED:
437                 return (1ULL << 26);
438         /*! T.140 Text format - ITU T.140, RFC 4103 */
439         case AST_FORMAT_T140:
440                 return (1ULL << 27);
441         default:
442                 return 0; /* not supported by old bitfield. */
443         }
444
445         return 0;
446
447 }
448 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
449 {
450         return ast_format_id_to_old_bitfield(format->id);
451 }
452
453 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
454 {
455         switch (src) {
456         /*! G.723.1 compression */
457         case (1ULL << 0):
458                 return ast_format_set(dst, AST_FORMAT_G723_1, 0);
459         /*! GSM compression */
460         case (1ULL << 1):
461                 return ast_format_set(dst, AST_FORMAT_GSM, 0);
462         /*! Raw mu-law data (G.711) */
463         case (1ULL << 2):
464                 return ast_format_set(dst, AST_FORMAT_ULAW, 0);
465         /*! Raw A-law data (G.711) */
466         case (1ULL << 3):
467                 return ast_format_set(dst, AST_FORMAT_ALAW, 0);
468         /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
469         case (1ULL << 4):
470                 return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
471         /*! ADPCM (IMA) */
472         case (1ULL << 5):
473                 return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
474         /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
475         case (1ULL << 6):
476                 return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
477         /*! LPC10, 180 samples/frame */
478         case (1ULL << 7):
479                 return ast_format_set(dst, AST_FORMAT_LPC10, 0);
480         /*! G.729A audio */
481         case (1ULL << 8):
482                 return ast_format_set(dst, AST_FORMAT_G729A, 0);
483         /*! SpeeX Free Compression */
484         case (1ULL << 9):
485                 return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
486         /*! iLBC Free Compression */
487         case (1ULL << 10):
488                 return ast_format_set(dst, AST_FORMAT_ILBC, 0);
489         /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
490         case (1ULL << 11):
491                 return ast_format_set(dst, AST_FORMAT_G726, 0);
492         /*! G.722 */
493         case (1ULL << 12):
494                 return ast_format_set(dst, AST_FORMAT_G722, 0);
495         /*! G.722.1 (also known as Siren7, 32kbps assumed) */
496         case (1ULL << 13):
497                 return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
498         /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
499         case (1ULL << 14):
500                 return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
501         /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
502         case (1ULL << 15):
503                 return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
504         /*! G.719 (64 kbps assumed) */
505         case (1ULL << 32):
506                 return ast_format_set(dst, AST_FORMAT_G719, 0);
507         /*! SpeeX Wideband (16kHz) Free Compression */
508         case (1ULL << 33):
509                 return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
510         /*! Raw mu-law data (G.711) */
511         case (1ULL << 47):
512                 return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
513
514         /*! H.261 Video */
515         case (1ULL << 18):
516                 return ast_format_set(dst, AST_FORMAT_H261, 0);
517         /*! H.263 Video */
518         case (1ULL << 19):
519                 return ast_format_set(dst, AST_FORMAT_H263, 0);
520         /*! H.263+ Video */
521         case (1ULL << 20):
522                 return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
523         /*! H.264 Video */
524         case (1ULL << 21):
525                 return ast_format_set(dst, AST_FORMAT_H264, 0);
526         /*! MPEG4 Video */
527         case (1ULL << 22):
528                 return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
529
530         /*! JPEG Images */
531         case (1ULL << 16):
532                 return ast_format_set(dst, AST_FORMAT_JPEG, 0);
533         /*! PNG Images */
534         case (1ULL << 17):
535                 return ast_format_set(dst, AST_FORMAT_PNG, 0);
536
537         /*! T.140 RED Text format RFC 4103 */
538         case (1ULL << 26):
539                 return ast_format_set(dst, AST_FORMAT_T140RED, 0);
540         /*! T.140 Text format - ITU T.140, RFC 4103 */
541         case (1ULL << 27):
542                 return ast_format_set(dst, AST_FORMAT_T140, 0);
543         }
544         ast_format_clear(dst);
545         return NULL;
546 }
547
548 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
549 {
550         struct ast_format dst;
551         if (ast_format_from_old_bitfield(&dst, src)) {
552                 return dst.id;
553         }
554         return 0;
555 }
556
557 int ast_format_is_slinear(const struct ast_format *format)
558 {
559         if (format->id == AST_FORMAT_SLINEAR ||
560                 format->id == AST_FORMAT_SLINEAR12 ||
561                 format->id == AST_FORMAT_SLINEAR16 ||
562                 format->id == AST_FORMAT_SLINEAR24 ||
563                 format->id == AST_FORMAT_SLINEAR32 ||
564                 format->id == AST_FORMAT_SLINEAR44 ||
565                 format->id == AST_FORMAT_SLINEAR48 ||
566                 format->id == AST_FORMAT_SLINEAR96 ||
567                 format->id == AST_FORMAT_SLINEAR192) {
568                 return 1;
569         }
570         return 0;
571 }
572
573 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
574 {
575         if (rate >= 192000) {
576                 return AST_FORMAT_SLINEAR192;
577         } else if (rate >= 96000) {
578                 return AST_FORMAT_SLINEAR96;
579         } else if (rate >= 48000) {
580                 return AST_FORMAT_SLINEAR48;
581         } else if (rate >= 44100) {
582                 return AST_FORMAT_SLINEAR44;
583         } else if (rate >= 32000) {
584                 return AST_FORMAT_SLINEAR32;
585         } else if (rate >= 24000) {
586                 return AST_FORMAT_SLINEAR24;
587         } else if (rate >= 16000) {
588                 return AST_FORMAT_SLINEAR16;
589         } else if (rate >= 12000) {
590                 return AST_FORMAT_SLINEAR12;
591         }
592         return AST_FORMAT_SLINEAR;
593 }
594
595 const char* ast_getformatname(const struct ast_format *format)
596 {
597         int x;
598         const char *ret = "unknown";
599         size_t f_len;
600         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
601         for (x = 0; x < f_len; x++) {
602                 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
603                         ret = f_list[x].name;
604                         break;
605                 }
606         }
607         f_list = ast_format_list_destroy(f_list);
608         return ret;
609 }
610
611
612 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
613 {
614         int x;
615         unsigned len;
616         char *start, *end = buf;
617         size_t f_len;
618         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
619
620         if (!size) {
621                 f_list = ast_format_list_destroy(f_list);
622                 return buf;
623         }
624         snprintf(end, size, "(");
625         len = strlen(end);
626         end += len;
627         size -= len;
628         start = end;
629         for (x = 0; x < f_len; x++) {
630                 if (f_list[x].format.id == id) {
631                         snprintf(end, size, "%s|", f_list[x].name);
632                         len = strlen(end);
633                         end += len;
634                         size -= len;
635                 }
636         }
637         if (start == end) {
638                 ast_copy_string(start, "nothing)", size);
639         } else if (size > 1) {
640                 *(end - 1) = ')';
641         }
642         f_list = ast_format_list_destroy(f_list);
643         return buf;
644 }
645
646 static struct ast_codec_alias_table {
647         const char *alias;
648         const char *realname;
649 } ast_codec_alias_table[] = {
650         { "slinear", "slin"},
651         { "slinear16", "slin16"},
652         { "g723.1", "g723"},
653         { "g722.1", "siren7"},
654         { "g722.1c", "siren14"},
655 };
656
657 static const char *ast_expand_codec_alias(const char *in)
658 {
659         int x;
660
661         for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
662                 if (!strcmp(in,ast_codec_alias_table[x].alias))
663                         return ast_codec_alias_table[x].realname;
664         }
665         return in;
666 }
667
668 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
669 {
670         int x;
671         size_t f_len;
672         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
673
674         for (x = 0; x < f_len; x++) {
675                 if (!strcasecmp(f_list[x].name, name) ||
676                          !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
677
678                         ast_format_copy(result, &f_list[x].format);
679                         f_list = ast_format_list_destroy(f_list);
680                         return result;
681                 }
682         }
683         f_list = ast_format_list_destroy(f_list);
684
685         return NULL;
686 }
687
688 const char *ast_codec2str(struct ast_format *format)
689 {
690         int x;
691         const char *ret = "unknown";
692         size_t f_len;
693         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
694
695         for (x = 0; x < f_len; x++) {
696                 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
697                         ret = f_list[x].desc;
698                         break;
699                 }
700         }
701         f_list = ast_format_list_destroy(f_list);
702         return ret;
703 }
704
705 int ast_format_rate(const struct ast_format *format)
706 {
707         switch (format->id) {
708         case AST_FORMAT_SLINEAR12:
709                 return 12000;
710         case AST_FORMAT_SLINEAR24:
711                 return 24000;
712         case AST_FORMAT_SLINEAR32:
713                 return 32000;
714         case AST_FORMAT_SLINEAR44:
715                 return 44100;
716         case AST_FORMAT_SLINEAR48:
717                 return 48000;
718         case AST_FORMAT_SLINEAR96:
719                 return 96000;
720         case AST_FORMAT_SLINEAR192:
721                 return 192000;
722         case AST_FORMAT_G722:
723         case AST_FORMAT_SLINEAR16:
724         case AST_FORMAT_SIREN7:
725         case AST_FORMAT_SPEEX16:
726                 return 16000;
727         case AST_FORMAT_SIREN14:
728         case AST_FORMAT_SPEEX32:
729                 return 32000;
730         case AST_FORMAT_G719:
731                 return 48000;
732         case AST_FORMAT_SILK:
733                 if (!(ast_format_isset(format,
734                         SILK_ATTR_KEY_SAMP_RATE,
735                         SILK_ATTR_VAL_SAMP_24KHZ,
736                         AST_FORMAT_ATTR_END))) {
737                         return 24000;
738                 } else if (!(ast_format_isset(format,
739                         SILK_ATTR_KEY_SAMP_RATE,
740                         SILK_ATTR_VAL_SAMP_16KHZ,
741                         AST_FORMAT_ATTR_END))) {
742                         return 16000;
743                 } else if (!(ast_format_isset(format,
744                         SILK_ATTR_KEY_SAMP_RATE,
745                         SILK_ATTR_VAL_SAMP_12KHZ,
746                         AST_FORMAT_ATTR_END))) {
747                         return 12000;
748                 } else {
749                         return 8000;
750                 }
751         case AST_FORMAT_CELT:
752         {
753                 int samplerate;
754                 if (!(ast_format_get_value(format,
755                         CELT_ATTR_KEY_SAMP_RATE,
756                         &samplerate))) {
757                         return samplerate;
758                 }
759         }
760         default:
761                 return 8000;
762         }
763 }
764
765 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
766 {
767         int x, found=0;
768         size_t f_len;
769         const struct ast_format_list *f_list;
770
771         switch (cmd) {
772         case CLI_INIT:
773                 e->command = "core show codecs [audio|video|image|text]";
774                 e->usage =
775                         "Usage: core show codecs [audio|video|image|text]\n"
776                         "       Displays codec mapping\n";
777                 return NULL;
778         case CLI_GENERATE:
779                 return NULL;
780         }
781
782         if ((a->argc < 3) || (a->argc > 4)) {
783                 return CLI_SHOWUSAGE;
784         }
785
786         f_list = ast_format_list_get(&f_len);
787         if (!ast_opt_dont_warn) {
788                 ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
789                                 "\tIt does not indicate anything about your configuration.\n");
790         }
791
792         ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
793         ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
794
795         for (x = 0; x < f_len; x++) {
796                 if (a->argc == 4) {
797                         if (!strcasecmp(a->argv[3], "audio")) {
798                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
799                                         continue;
800                                 }
801                         } else if (!strcasecmp(a->argv[3], "video")) {
802                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
803                                         continue;
804                                 }
805                         } else if (!strcasecmp(a->argv[3], "image")) {
806                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
807                                         continue;
808                                 }
809                         } else if (!strcasecmp(a->argv[3], "text")) {
810                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
811                                         continue;
812                                 }
813                         } else {
814                                 continue;
815                         }
816                 }
817
818                 ast_cli(a->fd, "%8u %5s %8s (%s)\n",
819                         f_list[x].format.id,
820                         (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
821                         (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_IMAGE)  ? "image" :
822                         (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_VIDEO) ? "video" :
823                         (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_TEXT)  ? "text"  :
824                         "(unk)",
825                         f_list[x].name,
826                         f_list[x].desc);
827                 found = 1;
828         }
829
830         f_list = ast_format_list_destroy(f_list);
831         if (!found) {
832                 return CLI_SHOWUSAGE;
833         } else {
834                 return CLI_SUCCESS;
835         }
836 }
837
838 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
839 {
840         enum ast_format_id format_id;
841         int x, found = 0;
842         int type_punned_codec;
843         size_t f_len;
844         const struct ast_format_list *f_list;
845
846         switch (cmd) {
847         case CLI_INIT:
848                 e->command = "core show codec";
849                 e->usage =
850                         "Usage: core show codec <number>\n"
851                         "       Displays codec mapping\n";
852                 return NULL;
853         case CLI_GENERATE:
854                 return NULL;
855         }
856
857         if (a->argc != 4) {
858                 return CLI_SHOWUSAGE;
859         }
860
861         if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
862                 return CLI_SHOWUSAGE;
863         }
864         format_id = type_punned_codec;
865
866         f_list = ast_format_list_get(&f_len);
867         for (x = 0; x < f_len; x++) {
868                 if (f_list[x].format.id == format_id) {
869                         found = 1;
870                         ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
871                         break;
872                 }
873         }
874
875         if (!found) {
876                 ast_cli(a->fd, "Codec %d not found\n", format_id);
877         }
878
879         f_list = ast_format_list_destroy(f_list);
880         return CLI_SUCCESS;
881 }
882
883 /* Builtin Asterisk CLI-commands for debugging */
884 static struct ast_cli_entry my_clis[] = {
885         AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
886         AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
887 };
888 int init_framer(void)
889 {
890         ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
891         return 0;
892 }
893
894 static int format_list_add_custom(struct ast_format_list *new)
895 {
896         struct ast_format_list *entry;
897         if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
898                 return -1;
899         }
900         memcpy(entry, new, sizeof(struct ast_format_list));
901         entry->custom_entry = 1;
902         ao2_link(format_list, entry);
903         return 0;
904 }
905 static int format_list_add_static(
906         const struct ast_format *format,
907         const char *name,
908         int samplespersecond,
909         const char *description,
910         int fr_len,
911         int min_ms,
912         int max_ms,
913         int inc_ms,
914         int def_ms,
915         unsigned int flags,
916         int cur_ms)
917 {
918         struct ast_format_list *entry;
919         if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
920                 return -1;
921         }
922         ast_format_copy(&entry->format, format);
923         ast_copy_string(entry->name, name, sizeof(entry->name));
924         ast_copy_string(entry->desc, description, sizeof(entry->desc));
925         entry->samplespersecond = samplespersecond;
926         entry->fr_len = fr_len;
927         entry->min_ms = min_ms;
928         entry->max_ms = max_ms;
929         entry->inc_ms = inc_ms;
930         entry->def_ms = def_ms;
931         entry->flags = flags;
932         entry->cur_ms = cur_ms;
933         entry->custom_entry = 0;
934
935         ao2_link(format_list, entry);
936         return 0;
937 }
938
939 static int list_all_custom(void *obj, void *arg, int flag)
940 {
941         struct ast_format_list *entry = obj;
942         return entry->custom_entry ? CMP_MATCH : 0;
943 }
944
945 static int list_cmp_cb(void *obj, void *arg, int flags)
946 {
947         struct ast_format_list *entry1 = obj;
948         struct ast_format_list *entry2 = arg;
949
950         return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
951 }
952 static int list_hash_cb(const void *obj, const int flags)
953 {
954         return ao2_container_count(format_list);
955 }
956
957 const struct ast_format_list *ast_format_list_get(size_t *size)
958 {
959         struct ast_format_list *list;
960         ast_rwlock_rdlock(&format_list_array_lock);
961         ao2_ref(format_list_array, 1);
962         list = format_list_array;
963         *size = format_list_array_len;
964         ast_rwlock_unlock(&format_list_array_lock);
965         return list;
966 }
967 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
968 {
969         ao2_ref((void *) list, -1);
970         return NULL;
971 }
972
973 static int build_format_list_array(void)
974 {
975         struct ast_format_list *tmp;
976         size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
977         int i = 0;
978         struct ao2_iterator it;
979
980         ast_rwlock_wrlock(&format_list_array_lock);
981         tmp = format_list_array;
982         if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
983                 format_list_array = tmp;
984                 ast_rwlock_unlock(&format_list_array_lock);
985                 return -1;
986         }
987         format_list_array_len = ao2_container_count(format_list);
988         if (tmp) {
989                 ao2_ref(tmp, -1);
990         }
991
992         /* walk through the container adding elements to the static array */
993         it = ao2_iterator_init(format_list, 0);
994         while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
995                 memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
996                 ao2_ref(tmp, -1);
997                 i++;
998         }
999         ao2_iterator_destroy(&it);
1000
1001         ast_rwlock_unlock(&format_list_array_lock);
1002         return 0;
1003 }
1004 static int format_list_init(void)
1005 {
1006         struct ast_format tmpfmt;
1007         if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
1008                 return -1;
1009         }
1010         /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
1011         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 */
1012         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 */
1013         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 */
1014         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 */
1015         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 */
1016         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 */
1017         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 */
1018         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 */
1019         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 */
1020         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 */
1021         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 */
1022         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 */
1023         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 */
1024         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 */
1025         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) */
1026         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 */
1027         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 */
1028         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 */
1029         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 */
1030         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 */
1031         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 */
1032         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 */
1033         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 */
1034         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 */
1035         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 */
1036         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 */
1037         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 */
1038         format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
1039
1040         /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
1041         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 */
1042         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) */
1043         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) */
1044         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) */
1045         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) */
1046         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) */
1047         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) */
1048         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) */
1049
1050         return 0;
1051 }
1052
1053 int ast_format_list_init()
1054 {
1055         if (ast_rwlock_init(&format_list_array_lock)) {
1056                 return -1;
1057         }
1058         if (format_list_init()) {
1059                 goto init_list_cleanup;
1060         }
1061         if (build_format_list_array()) {
1062                 goto init_list_cleanup;
1063         }
1064
1065         return 0;
1066 init_list_cleanup:
1067
1068         ast_rwlock_destroy(&format_list_array_lock);
1069         ao2_ref(format_list, -1);
1070         if (format_list_array) {
1071                 ao2_ref(format_list_array, -1);
1072         }
1073         return -1;
1074 }
1075
1076 int ast_format_attr_init()
1077 {
1078         ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
1079         if (ast_rwlock_init(&ilock)) {
1080                 return -1;
1081         }
1082
1083         if (!(interfaces = ao2_container_alloc(283, interface_hash_cb, interface_cmp_cb))) {
1084                 ast_rwlock_destroy(&ilock);
1085                 goto init_cleanup;
1086         }
1087         return 0;
1088
1089 init_cleanup:
1090         ast_rwlock_destroy(&ilock);
1091         if (interfaces) {
1092                 ao2_ref(interfaces, -1);
1093         }
1094         return -1;
1095 }
1096
1097 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
1098 {
1099         if (!entry->samplespersecond) {
1100                 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
1101         }
1102         ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
1103         if (!has_interface(&entry->format)) {
1104                 return -1;
1105         }
1106
1107         snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
1108
1109         ast_format_append(&entry->format,
1110                 CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
1111                 CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
1112                 CELT_ATTR_KEY_FRAME_SIZE, framesize,
1113                 AST_FORMAT_ATTR_END);
1114
1115         entry->fr_len = 80;
1116         entry->min_ms = 20;
1117         entry->max_ms = 20;
1118         entry->inc_ms = 20;
1119         entry->def_ms = 20;
1120         return 0;
1121 }
1122
1123 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
1124 {
1125         if (!entry->samplespersecond) {
1126                 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
1127         }
1128         ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
1129
1130         if (!has_interface(&entry->format)) {
1131                 return -1;
1132         }
1133
1134         switch (entry->samplespersecond) {
1135         case 8000:
1136                 ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
1137                 ast_format_append(&entry->format,
1138                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
1139                         AST_FORMAT_ATTR_END);
1140                 break;
1141         case 12000:
1142                 ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
1143                 ast_format_append(&entry->format,
1144                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
1145                         AST_FORMAT_ATTR_END);
1146                 break;
1147         case 16000:
1148                 ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
1149                 ast_format_append(&entry->format,
1150                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
1151                         AST_FORMAT_ATTR_END);
1152                 break;
1153         case 24000:
1154                 ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
1155                 ast_format_append(&entry->format,
1156                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
1157                         AST_FORMAT_ATTR_END);
1158                 break;
1159         default:
1160                 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %d\n", entry->name, entry->samplespersecond);
1161                 return -1;
1162         }
1163         ast_format_append(&entry->format,
1164                         SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
1165                         SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
1166                         SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
1167                         SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
1168                         AST_FORMAT_ATTR_END);
1169
1170         entry->fr_len = 80;
1171         entry->min_ms = 20;
1172         entry->max_ms = 20;
1173         entry->inc_ms = 20;
1174         entry->def_ms = 20;
1175         return 0;
1176 }
1177
1178 static int conf_process_format_name(const char *name, enum ast_format_id *id)
1179 {
1180         if (!strcasecmp(name, "silk")) {
1181                 *id = AST_FORMAT_SILK;
1182         } else if (!strcasecmp(name, "celt")) {
1183                 *id = AST_FORMAT_CELT;
1184         } else {
1185                 *id = 0;
1186                 return -1;
1187         }
1188         return 0;
1189 }
1190
1191 static int conf_process_sample_rate(const char *rate, unsigned int *result)
1192 {
1193         if (!strcasecmp(rate, "8000")) {
1194                 *result = 8000;
1195         } else if (!strcasecmp(rate, "12000")) {
1196                 *result = 12000;
1197         } else if (!strcasecmp(rate, "16000")) {
1198                 *result = 16000;
1199         } else if (!strcasecmp(rate, "24000")) {
1200                 *result = 24000;
1201         } else if (!strcasecmp(rate, "32000")) {
1202                 *result = 32000;
1203         } else if (!strcasecmp(rate, "44100")) {
1204                 *result = 44100;
1205         } else if (!strcasecmp(rate, "48000")) {
1206                 *result = 48000;
1207         } else if (!strcasecmp(rate, "96000")) {
1208                 *result = 96000;
1209         } else if (!strcasecmp(rate, "192000")) {
1210                 *result = 192000;
1211         } else {
1212                 *result = 0;
1213                 return -1;
1214         }
1215
1216         return 0;
1217 }
1218 static int load_format_config(void)
1219 {
1220         struct ast_flags config_flags = { 0, };
1221         struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
1222         struct ast_format_list entry;
1223         struct ast_variable *var;
1224         char *cat = NULL;
1225         int add_it = 0;
1226
1227         struct {
1228                 enum ast_format_id id;
1229                 unsigned int maxbitrate;
1230                 unsigned int framesize;
1231                 unsigned int packetloss_percentage;
1232                 int usefec;
1233                 int usedtx;
1234         } settings;
1235
1236         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1237                 return 0;
1238         }
1239
1240         /* remove all custom formats from the AO2 Container. Note, this has no affect on the
1241          * global format list until the list is rebuild.  That is why this is okay to do while
1242          * reloading the config. */
1243         ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
1244
1245         while ((cat = ast_category_browse(cfg, cat))) {
1246                 memset(&entry, 0, sizeof(entry));
1247                 memset(&settings, 0, sizeof(settings));
1248                 add_it = 0;
1249
1250                 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
1251                         continue;
1252                 }
1253                 ast_copy_string(entry.name, cat, sizeof(entry.name));
1254                 var = ast_variable_browse(cfg, cat);
1255                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1256                         if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
1257                                 ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
1258                                         var->value, var->lineno, FORMAT_CONFIG);
1259                                 continue;
1260                         } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
1261                                 ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
1262                                                 var->value, var->lineno, FORMAT_CONFIG);
1263                         } else if (!strcasecmp(var->name, "maxbitrate")) {
1264                                 if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
1265                                         ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
1266                                                 var->value, var->lineno, FORMAT_CONFIG);
1267                                 }
1268                         } else if (!strcasecmp(var->name, "framesize")) {
1269                                 if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
1270                                         ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
1271                                                 var->value, var->lineno, FORMAT_CONFIG);
1272                                 }
1273                         } else if (!strcasecmp(var->name, "dtx")) {
1274                                 settings.usedtx = ast_true(var->value) ? 1 : 0;
1275                         } else if (!strcasecmp(var->name, "fec")) {
1276                                 settings.usefec = ast_true(var->value) ? 1 : 0;
1277                         } else if (!strcasecmp(var->name, "packetloss_percentage")) {
1278                                 if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
1279                                         ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
1280                                                 var->value, var->lineno, FORMAT_CONFIG);
1281                                 }
1282                         }
1283                 }
1284
1285                 switch (settings.id) {
1286                 case AST_FORMAT_SILK:
1287                         if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
1288                                 add_it = 1;
1289                         }
1290                         break;
1291                 case AST_FORMAT_CELT:
1292                         if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
1293                                 add_it = 1;
1294                         }
1295                         break;
1296                 default:
1297                         ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
1298                 }
1299
1300                 if (add_it) {
1301                         format_list_add_custom(&entry);
1302                 }
1303         }
1304         ast_config_destroy(cfg);
1305         build_format_list_array();
1306         return 0;
1307 }
1308
1309 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
1310 {
1311         int x;
1312         size_t f_len;
1313         const struct ast_format_list *f_list;
1314         struct interface_ao2_wrapper *wrapper;
1315         struct interface_ao2_wrapper tmp_wrapper = {
1316                 .id = interface->id,
1317         };
1318
1319         /* check for duplicates first*/
1320         ast_rwlock_wrlock(&ilock);
1321         if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
1322                 ast_rwlock_unlock(&ilock);
1323                 ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
1324                 ao2_ref(wrapper, -1);
1325                 return -1;
1326         }
1327         ast_rwlock_unlock(&ilock);
1328
1329         if (!(wrapper = ao2_alloc(sizeof(*wrapper), interface_destroy_cb))) {
1330                 return -1;
1331         }
1332
1333         wrapper->interface = interface;
1334         wrapper->id = interface->id;
1335         ast_rwlock_init(&wrapper->wraplock);
1336
1337         /* use the write lock whenever the interface container is modified */
1338         ast_rwlock_wrlock(&ilock);
1339         ao2_link(interfaces, wrapper);
1340         ast_rwlock_unlock(&ilock);
1341
1342         ao2_ref(wrapper, -1);
1343
1344         /* This will find all custom formats in codecs.conf for this new registered interface */
1345         load_format_config();
1346
1347         /* update the RTP engine to all custom formats created for this interface */
1348         f_list = ast_format_list_get(&f_len);
1349         for (x = 0; x < f_len; x++) {
1350                 if (f_list[x].format.id == tmp_wrapper.id) {
1351                         ast_rtp_engine_load_format(&f_list[x].format);
1352                 }
1353         }
1354
1355         return 0;
1356 }
1357
1358 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
1359 {
1360         int x;
1361         size_t f_len;
1362         const struct ast_format_list *f_list;
1363         struct interface_ao2_wrapper *wrapper;
1364         struct interface_ao2_wrapper tmp_wrapper = {
1365                 .id = interface->id,
1366         };
1367
1368         /* use the write lock whenever the interface container is modified */
1369         ast_rwlock_wrlock(&ilock);
1370         if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK | OBJ_NOLOCK)))) {
1371                 ast_rwlock_unlock(&ilock);
1372                 return -1;
1373         }
1374         ast_rwlock_unlock(&ilock);
1375
1376         ast_rwlock_wrlock(&wrapper->wraplock);
1377         wrapper->interface = NULL;
1378         ast_rwlock_unlock(&wrapper->wraplock);
1379
1380         ao2_ref(wrapper, -1);
1381
1382         /* update the RTP engine to remove all custom formats created for this interface */
1383         f_list = ast_format_list_get(&f_len);
1384         for (x = 0; x < f_len; x++) {
1385                 if (f_list[x].format.id == tmp_wrapper.id) {
1386                         ast_rtp_engine_unload_format(&f_list[x].format);
1387                 }
1388         }
1389
1390         /* This will remove all custom formats previously created for this interface */
1391         load_format_config();
1392
1393         return 0;
1394 }