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