Use struct copy instead of memcpy().
[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/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"
41
42 #define FORMAT_CONFIG "codecs.conf"
43
44 /*!
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.
48  */
49 static struct ao2_container *interfaces;
50
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;
55 };
56
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;
67
68 static int interface_cmp_cb(void *obj, void *arg, int flags)
69 {
70         struct interface_ao2_wrapper *wrapper1 = obj;
71         struct interface_ao2_wrapper *wrapper2 = arg;
72
73         return (wrapper2->id == wrapper1->id) ? CMP_MATCH | CMP_STOP : 0;
74 }
75
76 static int interface_hash_cb(const void *obj, const int flags)
77 {
78         const struct interface_ao2_wrapper *wrapper = obj;
79         return wrapper->id;
80 }
81
82 void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
83 {
84         *dst = *src;
85 }
86
87 void ast_format_set_video_mark(struct ast_format *format)
88 {
89         format->fattr.rtp_marker_bit = 1;
90 }
91
92 int ast_format_get_video_mark(const struct ast_format *format)
93 {
94         return format->fattr.rtp_marker_bit;
95 }
96
97 static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
98 {
99         struct interface_ao2_wrapper tmp_wrapper = {
100                 .id = format->id,
101         };
102
103         return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
104 }
105
106 static int has_interface(const struct ast_format *format)
107 {
108         struct interface_ao2_wrapper *wrapper;
109
110         wrapper = find_interface(format);
111         if (!wrapper) {
112                 return 0;
113         }
114         ao2_ref(wrapper, -1);
115         return 1;
116 }
117
118 /*! \internal
119  * \brief set format attributes using an interface
120  */
121 static int format_set_helper(struct ast_format *format, va_list ap)
122 {
123         struct interface_ao2_wrapper *wrapper;
124
125         if (!(wrapper = find_interface(format))) {
126                 ast_log(LOG_WARNING, "Could not find format interface to set.\n");
127                 return -1;
128         }
129
130         ao2_rdlock(wrapper);
131         if (!wrapper->interface || !wrapper->interface->format_attr_set) {
132                 ao2_unlock(wrapper);
133                 ao2_ref(wrapper, -1);
134                 return -1;
135         }
136
137         wrapper->interface->format_attr_set(&format->fattr, ap);
138
139         ao2_unlock(wrapper);
140         ao2_ref(wrapper, -1);
141
142         return 0;
143 }
144
145 struct ast_format *ast_format_append(struct ast_format *format, ... )
146 {
147         va_list ap;
148         va_start(ap, format);
149         format_set_helper(format, ap);
150         va_end(ap);
151
152         return format;
153 }
154
155 struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... )
156 {
157         /* initialize the structure before setting it. */
158         ast_format_clear(format);
159
160         format->id = id;
161
162         if (set_attributes) {
163                 va_list ap;
164                 va_start(ap, set_attributes);
165                 format_set_helper(format, ap);
166                 va_end(ap);
167         }
168
169         return format;
170 }
171
172 void ast_format_clear(struct ast_format *format)
173 {
174         format->id = 0;
175         memset(&format->fattr, 0, sizeof(format->fattr));
176 }
177
178 /*! \internal
179  * \brief determine if a list of attribute key value pairs are set on a format
180  */
181 static int format_isset_helper(const struct ast_format *format, va_list ap)
182 {
183         int res;
184         struct interface_ao2_wrapper *wrapper;
185         struct ast_format tmp = {
186                 .id = format->id,
187                 .fattr = { { 0, }, },
188         };
189
190         if (!(wrapper = find_interface(format))) {
191                 return -1;
192         }
193
194         ao2_rdlock(wrapper);
195         if (!wrapper->interface ||
196                 !wrapper->interface->format_attr_set ||
197                 !wrapper->interface->format_attr_cmp) {
198
199                 ao2_unlock(wrapper);
200                 ao2_ref(wrapper, -1);
201                 return -1;
202         }
203
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);
208         } else {
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;
213         }
214
215         ao2_unlock(wrapper);
216         ao2_ref(wrapper, -1);
217
218         return res;
219 }
220
221 int ast_format_isset(const struct ast_format *format, ... )
222 {
223         va_list ap;
224         int res;
225
226         va_start(ap, format);
227         res = format_isset_helper(format, ap);
228         va_end(ap);
229         return res;
230 }
231
232 int ast_format_get_value(const struct ast_format *format, int key, void *value)
233 {
234         int res = 0;
235         struct interface_ao2_wrapper *wrapper;
236
237         if (!(wrapper = find_interface(format))) {
238                 return -1;
239         }
240         ao2_rdlock(wrapper);
241         if (!wrapper->interface ||
242                 !wrapper->interface->format_attr_get_val) {
243
244                 ao2_unlock(wrapper);
245                 ao2_ref(wrapper, -1);
246                 return -1;
247         }
248
249         res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
250
251         ao2_unlock(wrapper);
252         ao2_ref(wrapper, -1);
253
254         return res;
255 }
256
257 /*! \internal
258  * \brief cmp format attributes using an interface
259  */
260 static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format1, const struct ast_format *format2)
261 {
262         enum ast_format_cmp_res res = AST_FORMAT_CMP_EQUAL;
263         struct interface_ao2_wrapper *wrapper;
264
265         if (!(wrapper = find_interface(format1))) {
266                 return res;
267         }
268
269         ao2_rdlock(wrapper);
270         if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
271                 ao2_unlock(wrapper);
272                 ao2_ref(wrapper, -1);
273                 return res;
274         }
275
276         res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
277
278         ao2_unlock(wrapper);
279         ao2_ref(wrapper, -1);
280
281         return res;
282 }
283
284 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
285 {
286         if (format1->id != format2->id) {
287                 return AST_FORMAT_CMP_NOT_EQUAL;
288         }
289
290         return format_cmp_helper(format1, format2);
291 }
292
293 /*! \internal
294  * \brief get joint format attributes using an interface
295  */
296 static int format_joint_helper(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
297 {
298         int res = 0;
299         struct interface_ao2_wrapper *wrapper;
300
301         if (!(wrapper = find_interface(format1))) {
302                 /* if no interface is present, we assume formats are joint by id alone */
303                 return res;
304         }
305
306         ao2_rdlock(wrapper);
307         if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
308                 res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
309         }
310         ao2_unlock(wrapper);
311
312         ao2_ref(wrapper, -1);
313
314         return res;
315 }
316
317 int ast_format_joint(const struct ast_format *format1, const struct ast_format *format2, struct ast_format *result)
318 {
319         if (format1->id != format2->id) {
320                 return -1;
321         }
322         result->id = format1->id;
323         return format_joint_helper(format1, format2, result);
324 }
325
326
327 uint64_t ast_format_id_to_old_bitfield(enum ast_format_id id)
328 {
329         switch (id) {
330         /*! G.723.1 compression */
331         case AST_FORMAT_G723_1:
332                 return (1ULL << 0);
333         /*! GSM compression */
334         case AST_FORMAT_GSM:
335                 return (1ULL << 1);
336         /*! Raw mu-law data (G.711) */
337         case AST_FORMAT_ULAW:
338                 return (1ULL << 2);
339         /*! Raw A-law data (G.711) */
340         case AST_FORMAT_ALAW:
341                 return (1ULL << 3);
342         /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
343         case AST_FORMAT_G726_AAL2:
344                 return (1ULL << 4);
345         /*! ADPCM (IMA) */
346         case AST_FORMAT_ADPCM:
347                 return (1ULL << 5);
348         /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
349         case AST_FORMAT_SLINEAR:
350                 return (1ULL << 6);
351         /*! LPC10, 180 samples/frame */
352         case AST_FORMAT_LPC10:
353                 return (1ULL << 7);
354         /*! G.729A audio */
355         case AST_FORMAT_G729A:
356                 return (1ULL << 8);
357         /*! SpeeX Free Compression */
358         case AST_FORMAT_SPEEX:
359                 return (1ULL << 9);
360         /*! iLBC Free Compression */
361         case AST_FORMAT_ILBC:
362                 return (1ULL << 10);
363         /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
364         case AST_FORMAT_G726:
365                 return (1ULL << 11);
366         /*! G.722 */
367         case AST_FORMAT_G722:
368                 return (1ULL << 12);
369         /*! G.722.1 (also known as Siren7, 32kbps assumed) */
370         case AST_FORMAT_SIREN7:
371                 return (1ULL << 13);
372         /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
373         case AST_FORMAT_SIREN14:
374                 return (1ULL << 14);
375         /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
376         case AST_FORMAT_SLINEAR16:
377                 return (1ULL << 15);
378         /*! G.719 (64 kbps assumed) */
379         case AST_FORMAT_G719:
380                 return (1ULL << 32);
381         /*! SpeeX Wideband (16kHz) Free Compression */
382         case AST_FORMAT_SPEEX16:
383                 return (1ULL << 33);
384         /*! Raw mu-law data (G.711) */
385         case AST_FORMAT_TESTLAW:
386                 return (1ULL << 47);
387
388         /*! H.261 Video */
389         case AST_FORMAT_H261:
390                 return (1ULL << 18);
391         /*! H.263 Video */
392         case AST_FORMAT_H263:
393                 return (1ULL << 19);
394         /*! H.263+ Video */
395         case AST_FORMAT_H263_PLUS:
396                 return (1ULL << 20);
397         /*! H.264 Video */
398         case AST_FORMAT_H264:
399                 return (1ULL << 21);
400         /*! MPEG4 Video */
401         case AST_FORMAT_MP4_VIDEO:
402                 return (1ULL << 22);
403
404         /*! JPEG Images */
405         case AST_FORMAT_JPEG:
406                 return (1ULL << 16);
407         /*! PNG Images */
408         case AST_FORMAT_PNG:
409                 return (1ULL << 17);
410
411         /*! T.140 RED Text format RFC 4103 */
412         case AST_FORMAT_T140RED:
413                 return (1ULL << 26);
414         /*! T.140 Text format - ITU T.140, RFC 4103 */
415         case AST_FORMAT_T140:
416                 return (1ULL << 27);
417         default:
418                 return 0; /* not supported by old bitfield. */
419         }
420
421         return 0;
422
423 }
424 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
425 {
426         return ast_format_id_to_old_bitfield(format->id);
427 }
428
429 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
430 {
431         switch (src) {
432         /*! G.723.1 compression */
433         case (1ULL << 0):
434                 return ast_format_set(dst, AST_FORMAT_G723_1, 0);
435         /*! GSM compression */
436         case (1ULL << 1):
437                 return ast_format_set(dst, AST_FORMAT_GSM, 0);
438         /*! Raw mu-law data (G.711) */
439         case (1ULL << 2):
440                 return ast_format_set(dst, AST_FORMAT_ULAW, 0);
441         /*! Raw A-law data (G.711) */
442         case (1ULL << 3):
443                 return ast_format_set(dst, AST_FORMAT_ALAW, 0);
444         /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
445         case (1ULL << 4):
446                 return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
447         /*! ADPCM (IMA) */
448         case (1ULL << 5):
449                 return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
450         /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
451         case (1ULL << 6):
452                 return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
453         /*! LPC10, 180 samples/frame */
454         case (1ULL << 7):
455                 return ast_format_set(dst, AST_FORMAT_LPC10, 0);
456         /*! G.729A audio */
457         case (1ULL << 8):
458                 return ast_format_set(dst, AST_FORMAT_G729A, 0);
459         /*! SpeeX Free Compression */
460         case (1ULL << 9):
461                 return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
462         /*! iLBC Free Compression */
463         case (1ULL << 10):
464                 return ast_format_set(dst, AST_FORMAT_ILBC, 0);
465         /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
466         case (1ULL << 11):
467                 return ast_format_set(dst, AST_FORMAT_G726, 0);
468         /*! G.722 */
469         case (1ULL << 12):
470                 return ast_format_set(dst, AST_FORMAT_G722, 0);
471         /*! G.722.1 (also known as Siren7, 32kbps assumed) */
472         case (1ULL << 13):
473                 return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
474         /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
475         case (1ULL << 14):
476                 return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
477         /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
478         case (1ULL << 15):
479                 return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
480         /*! G.719 (64 kbps assumed) */
481         case (1ULL << 32):
482                 return ast_format_set(dst, AST_FORMAT_G719, 0);
483         /*! SpeeX Wideband (16kHz) Free Compression */
484         case (1ULL << 33):
485                 return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
486         /*! Raw mu-law data (G.711) */
487         case (1ULL << 47):
488                 return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
489
490         /*! H.261 Video */
491         case (1ULL << 18):
492                 return ast_format_set(dst, AST_FORMAT_H261, 0);
493         /*! H.263 Video */
494         case (1ULL << 19):
495                 return ast_format_set(dst, AST_FORMAT_H263, 0);
496         /*! H.263+ Video */
497         case (1ULL << 20):
498                 return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
499         /*! H.264 Video */
500         case (1ULL << 21):
501                 return ast_format_set(dst, AST_FORMAT_H264, 0);
502         /*! MPEG4 Video */
503         case (1ULL << 22):
504                 return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
505
506         /*! JPEG Images */
507         case (1ULL << 16):
508                 return ast_format_set(dst, AST_FORMAT_JPEG, 0);
509         /*! PNG Images */
510         case (1ULL << 17):
511                 return ast_format_set(dst, AST_FORMAT_PNG, 0);
512
513         /*! T.140 RED Text format RFC 4103 */
514         case (1ULL << 26):
515                 return ast_format_set(dst, AST_FORMAT_T140RED, 0);
516         /*! T.140 Text format - ITU T.140, RFC 4103 */
517         case (1ULL << 27):
518                 return ast_format_set(dst, AST_FORMAT_T140, 0);
519         }
520         ast_format_clear(dst);
521         return NULL;
522 }
523
524 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
525 {
526         struct ast_format dst;
527         if (ast_format_from_old_bitfield(&dst, src)) {
528                 return dst.id;
529         }
530         return 0;
531 }
532
533 int ast_format_is_slinear(const struct ast_format *format)
534 {
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) {
544                 return 1;
545         }
546         return 0;
547 }
548
549 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
550 {
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;
567         }
568         return AST_FORMAT_SLINEAR;
569 }
570
571 const char* ast_getformatname(const struct ast_format *format)
572 {
573         int x;
574         const char *ret = "unknown";
575         size_t f_len;
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;
580                         break;
581                 }
582         }
583         f_list = ast_format_list_destroy(f_list);
584         return ret;
585 }
586
587
588 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
589 {
590         int x;
591         unsigned len;
592         char *start, *end = buf;
593         size_t f_len;
594         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
595
596         if (!size) {
597                 f_list = ast_format_list_destroy(f_list);
598                 return buf;
599         }
600         snprintf(end, size, "(");
601         len = strlen(end);
602         end += len;
603         size -= len;
604         start = end;
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);
608                         len = strlen(end);
609                         end += len;
610                         size -= len;
611                 }
612         }
613         if (start == end) {
614                 ast_copy_string(start, "nothing)", size);
615         } else if (size > 1) {
616                 *(end - 1) = ')';
617         }
618         f_list = ast_format_list_destroy(f_list);
619         return buf;
620 }
621
622 static struct ast_codec_alias_table {
623         const char *alias;
624         const char *realname;
625 } ast_codec_alias_table[] = {
626         { "slinear", "slin"},
627         { "slinear16", "slin16"},
628         { "g723.1", "g723"},
629         { "g722.1", "siren7"},
630         { "g722.1c", "siren14"},
631 };
632
633 static const char *ast_expand_codec_alias(const char *in)
634 {
635         int x;
636
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;
640         }
641         return in;
642 }
643
644 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
645 {
646         int x;
647         size_t f_len;
648         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
649
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))) {
653
654                         ast_format_copy(result, &f_list[x].format);
655                         f_list = ast_format_list_destroy(f_list);
656                         return result;
657                 }
658         }
659         f_list = ast_format_list_destroy(f_list);
660
661         return NULL;
662 }
663
664 const char *ast_codec2str(struct ast_format *format)
665 {
666         int x;
667         const char *ret = "unknown";
668         size_t f_len;
669         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
670
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;
674                         break;
675                 }
676         }
677         f_list = ast_format_list_destroy(f_list);
678         return ret;
679 }
680
681 int ast_format_rate(const struct ast_format *format)
682 {
683         switch (format->id) {
684         case AST_FORMAT_SLINEAR12:
685                 return 12000;
686         case AST_FORMAT_SLINEAR24:
687                 return 24000;
688         case AST_FORMAT_SLINEAR32:
689                 return 32000;
690         case AST_FORMAT_SLINEAR44:
691                 return 44100;
692         case AST_FORMAT_SLINEAR48:
693                 return 48000;
694         case AST_FORMAT_SLINEAR96:
695                 return 96000;
696         case AST_FORMAT_SLINEAR192:
697                 return 192000;
698         case AST_FORMAT_G722:
699         case AST_FORMAT_SLINEAR16:
700         case AST_FORMAT_SIREN7:
701         case AST_FORMAT_SPEEX16:
702                 return 16000;
703         case AST_FORMAT_SIREN14:
704         case AST_FORMAT_SPEEX32:
705                 return 32000;
706         case AST_FORMAT_G719:
707                 return 48000;
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))) {
713                         return 24000;
714                 } else if (!(ast_format_isset(format,
715                         SILK_ATTR_KEY_SAMP_RATE,
716                         SILK_ATTR_VAL_SAMP_16KHZ,
717                         AST_FORMAT_ATTR_END))) {
718                         return 16000;
719                 } else if (!(ast_format_isset(format,
720                         SILK_ATTR_KEY_SAMP_RATE,
721                         SILK_ATTR_VAL_SAMP_12KHZ,
722                         AST_FORMAT_ATTR_END))) {
723                         return 12000;
724                 } else {
725                         return 8000;
726                 }
727         case AST_FORMAT_CELT:
728         {
729                 int samplerate;
730                 if (!(ast_format_get_value(format,
731                         CELT_ATTR_KEY_SAMP_RATE,
732                         &samplerate))) {
733                         return samplerate;
734                 }
735         }
736         default:
737                 return 8000;
738         }
739 }
740
741 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
742 {
743         int x, found=0;
744         size_t f_len;
745         const struct ast_format_list *f_list;
746
747         switch (cmd) {
748         case CLI_INIT:
749                 e->command = "core show codecs [audio|video|image|text]";
750                 e->usage =
751                         "Usage: core show codecs [audio|video|image|text]\n"
752                         "       Displays codec mapping\n";
753                 return NULL;
754         case CLI_GENERATE:
755                 return NULL;
756         }
757
758         if ((a->argc < 3) || (a->argc > 4)) {
759                 return CLI_SHOWUSAGE;
760         }
761
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");
766         }
767
768         ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
769         ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
770
771         for (x = 0; x < f_len; x++) {
772                 if (a->argc == 4) {
773                         if (!strcasecmp(a->argv[3], "audio")) {
774                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
775                                         continue;
776                                 }
777                         } else if (!strcasecmp(a->argv[3], "video")) {
778                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
779                                         continue;
780                                 }
781                         } else if (!strcasecmp(a->argv[3], "image")) {
782                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
783                                         continue;
784                                 }
785                         } else if (!strcasecmp(a->argv[3], "text")) {
786                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
787                                         continue;
788                                 }
789                         } else {
790                                 continue;
791                         }
792                 }
793
794                 ast_cli(a->fd, "%8u %5s %8s (%s)\n",
795                         f_list[x].format.id,
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"  :
800                         "(unk)",
801                         f_list[x].name,
802                         f_list[x].desc);
803                 found = 1;
804         }
805
806         f_list = ast_format_list_destroy(f_list);
807         if (!found) {
808                 return CLI_SHOWUSAGE;
809         } else {
810                 return CLI_SUCCESS;
811         }
812 }
813
814 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
815 {
816         enum ast_format_id format_id;
817         int x, found = 0;
818         int type_punned_codec;
819         size_t f_len;
820         const struct ast_format_list *f_list;
821
822         switch (cmd) {
823         case CLI_INIT:
824                 e->command = "core show codec";
825                 e->usage =
826                         "Usage: core show codec <number>\n"
827                         "       Displays codec mapping\n";
828                 return NULL;
829         case CLI_GENERATE:
830                 return NULL;
831         }
832
833         if (a->argc != 4) {
834                 return CLI_SHOWUSAGE;
835         }
836
837         if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
838                 return CLI_SHOWUSAGE;
839         }
840         format_id = type_punned_codec;
841
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) {
845                         found = 1;
846                         ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
847                 }
848         }
849
850         if (!found) {
851                 ast_cli(a->fd, "Codec %d not found\n", format_id);
852         }
853
854         f_list = ast_format_list_destroy(f_list);
855         return CLI_SUCCESS;
856 }
857
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"),
862 };
863 int init_framer(void)
864 {
865         ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
866         return 0;
867 }
868
869 static int format_list_add_custom(struct ast_format_list *new)
870 {
871         struct ast_format_list *entry;
872         if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
873                 return -1;
874         }
875         memcpy(entry, new, sizeof(struct ast_format_list));
876         entry->custom_entry = 1;
877         ao2_link(format_list, entry);
878         return 0;
879 }
880 static int format_list_add_static(
881         const struct ast_format *format,
882         const char *name,
883         int samplespersecond,
884         const char *description,
885         int fr_len,
886         int min_ms,
887         int max_ms,
888         int inc_ms,
889         int def_ms,
890         unsigned int flags,
891         int cur_ms)
892 {
893         struct ast_format_list *entry;
894         if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
895                 return -1;
896         }
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;
909
910         ao2_link(format_list, entry);
911         return 0;
912 }
913
914 static int list_all_custom(void *obj, void *arg, int flag)
915 {
916         struct ast_format_list *entry = obj;
917         return entry->custom_entry ? CMP_MATCH : 0;
918 }
919
920 static int list_cmp_cb(void *obj, void *arg, int flags)
921 {
922         struct ast_format_list *entry1 = obj;
923         struct ast_format_list *entry2 = arg;
924
925         return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
926 }
927 static int list_hash_cb(const void *obj, const int flags)
928 {
929         return ao2_container_count(format_list);
930 }
931
932 const struct ast_format_list *ast_format_list_get(size_t *size)
933 {
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);
940         return list;
941 }
942 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
943 {
944         ao2_ref((void *) list, -1);
945         return NULL;
946 }
947
948 static int build_format_list_array(void)
949 {
950         struct ast_format_list *tmp;
951         size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
952         int i = 0;
953         struct ao2_iterator it;
954
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);
960                 return -1;
961         }
962         format_list_array_len = ao2_container_count(format_list);
963         if (tmp) {
964                 ao2_ref(tmp, -1);
965         }
966
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));
971                 ao2_ref(tmp, -1);
972                 i++;
973         }
974         ao2_iterator_destroy(&it);
975
976         ast_rwlock_unlock(&format_list_array_lock);
977         return 0;
978 }
979 static int format_list_init(void)
980 {
981         struct ast_format tmpfmt;
982         if (!(format_list = ao2_container_alloc(283, list_hash_cb, list_cmp_cb))) {
983                 return -1;
984         }
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);
1014
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) */
1024
1025         return 0;
1026 }
1027
1028 int ast_format_list_init(void)
1029 {
1030         if (ast_rwlock_init(&format_list_array_lock)) {
1031                 return -1;
1032         }
1033         if (format_list_init()) {
1034                 goto init_list_cleanup;
1035         }
1036         if (build_format_list_array()) {
1037                 goto init_list_cleanup;
1038         }
1039
1040         return 0;
1041 init_list_cleanup:
1042
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);
1047         }
1048         return -1;
1049 }
1050
1051 int ast_format_attr_init(void)
1052 {
1053         ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
1054
1055         interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
1056                 283, interface_hash_cb, interface_cmp_cb);
1057         if (!interfaces) {
1058                 return -1;
1059         }
1060         return 0;
1061 }
1062
1063 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
1064 {
1065         if (!entry->samplespersecond) {
1066                 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
1067         }
1068         ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
1069         if (!has_interface(&entry->format)) {
1070                 return -1;
1071         }
1072
1073         snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %dkhz", entry->samplespersecond/1000);
1074
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);
1080
1081         entry->fr_len = 80;
1082         entry->min_ms = 20;
1083         entry->max_ms = 20;
1084         entry->inc_ms = 20;
1085         entry->def_ms = 20;
1086         return 0;
1087 }
1088
1089 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
1090 {
1091         if (!entry->samplespersecond) {
1092                 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
1093         }
1094         ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
1095
1096         if (!has_interface(&entry->format)) {
1097                 return -1;
1098         }
1099
1100         switch (entry->samplespersecond) {
1101         case 8000:
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);
1106                 break;
1107         case 12000:
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);
1112                 break;
1113         case 16000:
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);
1118                 break;
1119         case 24000:
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);
1124                 break;
1125         default:
1126                 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %d\n", entry->name, entry->samplespersecond);
1127                 return -1;
1128         }
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);
1135
1136         entry->fr_len = 80;
1137         entry->min_ms = 20;
1138         entry->max_ms = 20;
1139         entry->inc_ms = 20;
1140         entry->def_ms = 20;
1141         return 0;
1142 }
1143
1144 static int conf_process_format_name(const char *name, enum ast_format_id *id)
1145 {
1146         if (!strcasecmp(name, "silk")) {
1147                 *id = AST_FORMAT_SILK;
1148         } else if (!strcasecmp(name, "celt")) {
1149                 *id = AST_FORMAT_CELT;
1150         } else {
1151                 *id = 0;
1152                 return -1;
1153         }
1154         return 0;
1155 }
1156
1157 static int conf_process_sample_rate(const char *rate, unsigned int *result)
1158 {
1159         if (!strcasecmp(rate, "8000")) {
1160                 *result = 8000;
1161         } else if (!strcasecmp(rate, "12000")) {
1162                 *result = 12000;
1163         } else if (!strcasecmp(rate, "16000")) {
1164                 *result = 16000;
1165         } else if (!strcasecmp(rate, "24000")) {
1166                 *result = 24000;
1167         } else if (!strcasecmp(rate, "32000")) {
1168                 *result = 32000;
1169         } else if (!strcasecmp(rate, "44100")) {
1170                 *result = 44100;
1171         } else if (!strcasecmp(rate, "48000")) {
1172                 *result = 48000;
1173         } else if (!strcasecmp(rate, "96000")) {
1174                 *result = 96000;
1175         } else if (!strcasecmp(rate, "192000")) {
1176                 *result = 192000;
1177         } else {
1178                 *result = 0;
1179                 return -1;
1180         }
1181
1182         return 0;
1183 }
1184 static int load_format_config(void)
1185 {
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;
1190         char *cat = NULL;
1191         int add_it = 0;
1192
1193         struct {
1194                 enum ast_format_id id;
1195                 unsigned int maxbitrate;
1196                 unsigned int framesize;
1197                 unsigned int packetloss_percentage;
1198                 int usefec;
1199                 int usedtx;
1200         } settings;
1201
1202         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1203                 return 0;
1204         }
1205
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);
1210
1211         while ((cat = ast_category_browse(cfg, cat))) {
1212                 memset(&entry, 0, sizeof(entry));
1213                 memset(&settings, 0, sizeof(settings));
1214                 add_it = 0;
1215
1216                 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
1217                         continue;
1218                 }
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);
1225                                 continue;
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);
1233                                 }
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);
1238                                 }
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);
1247                                 }
1248                         }
1249                 }
1250
1251                 switch (settings.id) {
1252                 case AST_FORMAT_SILK:
1253                         if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
1254                                 add_it = 1;
1255                         }
1256                         break;
1257                 case AST_FORMAT_CELT:
1258                         if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
1259                                 add_it = 1;
1260                         }
1261                         break;
1262                 default:
1263                         ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
1264                 }
1265
1266                 if (add_it) {
1267                         format_list_add_custom(&entry);
1268                 }
1269         }
1270         ast_config_destroy(cfg);
1271         build_format_list_array();
1272         return 0;
1273 }
1274
1275 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
1276 {
1277         int x;
1278         size_t f_len;
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,
1283         };
1284
1285         /*
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.
1289          */
1290         ao2_wrlock(interfaces);
1291
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);
1297                 return -1;
1298         }
1299
1300         wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
1301         if (!wrapper) {
1302                 ao2_unlock(interfaces);
1303                 return -1;
1304         }
1305
1306         wrapper->interface = interface;
1307         wrapper->id = interface->id;
1308
1309         /* The write lock is already held. */
1310         ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
1311         ao2_unlock(interfaces);
1312
1313         ao2_ref(wrapper, -1);
1314
1315         /* This will find all custom formats in codecs.conf for this new registered interface */
1316         load_format_config();
1317
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);
1323                 }
1324         }
1325
1326         return 0;
1327 }
1328
1329 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
1330 {
1331         int x;
1332         size_t f_len;
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,
1337         };
1338
1339         if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
1340                 return -1;
1341         }
1342
1343         ao2_wrlock(wrapper);
1344         wrapper->interface = NULL;
1345         ao2_unlock(wrapper);
1346
1347         ao2_ref(wrapper, -1);
1348
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);
1354                 }
1355         }
1356
1357         /* This will remove all custom formats previously created for this interface */
1358         load_format_config();
1359
1360         return 0;
1361 }