codec_adpcm: Change description of codec "ADPCM" to "Dialogic ADPCM"
[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         /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
434         case AST_FORMAT_OPUS:
435                 return (1ULL << 34);
436         /*! Raw mu-law data (G.711) */
437         case AST_FORMAT_TESTLAW:
438                 return (1ULL << 47);
439
440         /*! H.261 Video */
441         case AST_FORMAT_H261:
442                 return (1ULL << 18);
443         /*! H.263 Video */
444         case AST_FORMAT_H263:
445                 return (1ULL << 19);
446         /*! H.263+ Video */
447         case AST_FORMAT_H263_PLUS:
448                 return (1ULL << 20);
449         /*! H.264 Video */
450         case AST_FORMAT_H264:
451                 return (1ULL << 21);
452         /*! MPEG4 Video */
453         case AST_FORMAT_MP4_VIDEO:
454                 return (1ULL << 22);
455         /*! VP8 Video */
456         case AST_FORMAT_VP8:
457                 return (1ULL << 23);
458
459         /*! JPEG Images */
460         case AST_FORMAT_JPEG:
461                 return (1ULL << 16);
462         /*! PNG Images */
463         case AST_FORMAT_PNG:
464                 return (1ULL << 17);
465
466         /*! T.140 RED Text format RFC 4103 */
467         case AST_FORMAT_T140RED:
468                 return (1ULL << 26);
469         /*! T.140 Text format - ITU T.140, RFC 4103 */
470         case AST_FORMAT_T140:
471                 return (1ULL << 27);
472         default:
473                 return 0; /* not supported by old bitfield. */
474         }
475
476         return 0;
477
478 }
479 uint64_t ast_format_to_old_bitfield(const struct ast_format *format)
480 {
481         return ast_format_id_to_old_bitfield(format->id);
482 }
483
484 struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src)
485 {
486         switch (src) {
487         /*! G.723.1 compression */
488         case (1ULL << 0):
489                 return ast_format_set(dst, AST_FORMAT_G723_1, 0);
490         /*! GSM compression */
491         case (1ULL << 1):
492                 return ast_format_set(dst, AST_FORMAT_GSM, 0);
493         /*! Raw mu-law data (G.711) */
494         case (1ULL << 2):
495                 return ast_format_set(dst, AST_FORMAT_ULAW, 0);
496         /*! Raw A-law data (G.711) */
497         case (1ULL << 3):
498                 return ast_format_set(dst, AST_FORMAT_ALAW, 0);
499         /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */
500         case (1ULL << 4):
501                 return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0);
502         /*! ADPCM (IMA) */
503         case (1ULL << 5):
504                 return ast_format_set(dst, AST_FORMAT_ADPCM, 0);
505         /*! Raw 16-bit Signed Linear (8000 Hz) PCM */
506         case (1ULL << 6):
507                 return ast_format_set(dst, AST_FORMAT_SLINEAR, 0);
508         /*! LPC10, 180 samples/frame */
509         case (1ULL << 7):
510                 return ast_format_set(dst, AST_FORMAT_LPC10, 0);
511         /*! G.729A audio */
512         case (1ULL << 8):
513                 return ast_format_set(dst, AST_FORMAT_G729A, 0);
514         /*! SpeeX Free Compression */
515         case (1ULL << 9):
516                 return ast_format_set(dst, AST_FORMAT_SPEEX, 0);
517         /*! iLBC Free Compression */
518         case (1ULL << 10):
519                 return ast_format_set(dst, AST_FORMAT_ILBC, 0);
520         /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */
521         case (1ULL << 11):
522                 return ast_format_set(dst, AST_FORMAT_G726, 0);
523         /*! G.722 */
524         case (1ULL << 12):
525                 return ast_format_set(dst, AST_FORMAT_G722, 0);
526         /*! G.722.1 (also known as Siren7, 32kbps assumed) */
527         case (1ULL << 13):
528                 return ast_format_set(dst, AST_FORMAT_SIREN7, 0);
529         /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
530         case (1ULL << 14):
531                 return ast_format_set(dst, AST_FORMAT_SIREN14, 0);
532         /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
533         case (1ULL << 15):
534                 return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0);
535         /*! G.719 (64 kbps assumed) */
536         case (1ULL << 32):
537                 return ast_format_set(dst, AST_FORMAT_G719, 0);
538         /*! SpeeX Wideband (16kHz) Free Compression */
539         case (1ULL << 33):
540                 return ast_format_set(dst, AST_FORMAT_SPEEX16, 0);
541         /*! Opus audio (8kHz, 16kHz, 24kHz, 48Khz) */
542         case (1ULL << 34):
543                 return ast_format_set(dst, AST_FORMAT_OPUS, 0);
544         /*! Raw mu-law data (G.711) */
545         case (1ULL << 47):
546                 return ast_format_set(dst, AST_FORMAT_TESTLAW, 0);
547
548         /*! H.261 Video */
549         case (1ULL << 18):
550                 return ast_format_set(dst, AST_FORMAT_H261, 0);
551         /*! H.263 Video */
552         case (1ULL << 19):
553                 return ast_format_set(dst, AST_FORMAT_H263, 0);
554         /*! H.263+ Video */
555         case (1ULL << 20):
556                 return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0);
557         /*! H.264 Video */
558         case (1ULL << 21):
559                 return ast_format_set(dst, AST_FORMAT_H264, 0);
560         /*! MPEG4 Video */
561         case (1ULL << 22):
562                 return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0);
563         /*! VP8 Video */
564         case (1ULL << 23):
565                 return ast_format_set(dst, AST_FORMAT_VP8, 0);
566
567         /*! JPEG Images */
568         case (1ULL << 16):
569                 return ast_format_set(dst, AST_FORMAT_JPEG, 0);
570         /*! PNG Images */
571         case (1ULL << 17):
572                 return ast_format_set(dst, AST_FORMAT_PNG, 0);
573
574         /*! T.140 RED Text format RFC 4103 */
575         case (1ULL << 26):
576                 return ast_format_set(dst, AST_FORMAT_T140RED, 0);
577         /*! T.140 Text format - ITU T.140, RFC 4103 */
578         case (1ULL << 27):
579                 return ast_format_set(dst, AST_FORMAT_T140, 0);
580         }
581         ast_format_clear(dst);
582         return NULL;
583 }
584
585 enum ast_format_id ast_format_id_from_old_bitfield(uint64_t src)
586 {
587         struct ast_format dst;
588         if (ast_format_from_old_bitfield(&dst, src)) {
589                 return dst.id;
590         }
591         return 0;
592 }
593
594 int ast_format_is_slinear(const struct ast_format *format)
595 {
596         if (format->id == AST_FORMAT_SLINEAR ||
597                 format->id == AST_FORMAT_SLINEAR12 ||
598                 format->id == AST_FORMAT_SLINEAR16 ||
599                 format->id == AST_FORMAT_SLINEAR24 ||
600                 format->id == AST_FORMAT_SLINEAR32 ||
601                 format->id == AST_FORMAT_SLINEAR44 ||
602                 format->id == AST_FORMAT_SLINEAR48 ||
603                 format->id == AST_FORMAT_SLINEAR96 ||
604                 format->id == AST_FORMAT_SLINEAR192) {
605                 return 1;
606         }
607         return 0;
608 }
609
610 enum ast_format_id ast_format_slin_by_rate(unsigned int rate)
611 {
612         if (rate >= 192000) {
613                 return AST_FORMAT_SLINEAR192;
614         } else if (rate >= 96000) {
615                 return AST_FORMAT_SLINEAR96;
616         } else if (rate >= 48000) {
617                 return AST_FORMAT_SLINEAR48;
618         } else if (rate >= 44100) {
619                 return AST_FORMAT_SLINEAR44;
620         } else if (rate >= 32000) {
621                 return AST_FORMAT_SLINEAR32;
622         } else if (rate >= 24000) {
623                 return AST_FORMAT_SLINEAR24;
624         } else if (rate >= 16000) {
625                 return AST_FORMAT_SLINEAR16;
626         } else if (rate >= 12000) {
627                 return AST_FORMAT_SLINEAR12;
628         }
629         return AST_FORMAT_SLINEAR;
630 }
631
632 const char* ast_getformatname(const struct ast_format *format)
633 {
634         int x;
635         const char *ret = "unknown";
636         size_t f_len;
637         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
638         for (x = 0; x < f_len; x++) {
639                 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
640                         ret = f_list[x].name;
641                         break;
642                 }
643         }
644         f_list = ast_format_list_destroy(f_list);
645         return ret;
646 }
647
648
649 char *ast_getformatname_multiple_byid(char *buf, size_t size, enum ast_format_id id)
650 {
651         int x;
652         unsigned len;
653         char *start, *end = buf;
654         size_t f_len;
655         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
656
657         if (!size) {
658                 f_list = ast_format_list_destroy(f_list);
659                 return buf;
660         }
661         snprintf(end, size, "(");
662         len = strlen(end);
663         end += len;
664         size -= len;
665         start = end;
666         for (x = 0; x < f_len; x++) {
667                 if (f_list[x].format.id == id) {
668                         snprintf(end, size, "%s|", f_list[x].name);
669                         len = strlen(end);
670                         end += len;
671                         size -= len;
672                 }
673         }
674         if (start == end) {
675                 ast_copy_string(start, "nothing)", size);
676         } else if (size > 1) {
677                 *(end - 1) = ')';
678         }
679         f_list = ast_format_list_destroy(f_list);
680         return buf;
681 }
682
683 static struct ast_codec_alias_table {
684         const char *alias;
685         const char *realname;
686 } ast_codec_alias_table[] = {
687         { "slinear", "slin"},
688         { "slinear16", "slin16"},
689         { "g723.1", "g723"},
690         { "g722.1", "siren7"},
691         { "g722.1c", "siren14"},
692 };
693
694 static const char *ast_expand_codec_alias(const char *in)
695 {
696         int x;
697
698         for (x = 0; x < ARRAY_LEN(ast_codec_alias_table); x++) {
699                 if (!strcmp(in,ast_codec_alias_table[x].alias))
700                         return ast_codec_alias_table[x].realname;
701         }
702         return in;
703 }
704
705 struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result)
706 {
707         int x;
708         size_t f_len;
709         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
710
711         for (x = 0; x < f_len; x++) {
712                 if (!strcasecmp(f_list[x].name, name) ||
713                          !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) {
714
715                         ast_format_copy(result, &f_list[x].format);
716                         f_list = ast_format_list_destroy(f_list);
717                         return result;
718                 }
719         }
720         f_list = ast_format_list_destroy(f_list);
721
722         return NULL;
723 }
724
725 const char *ast_codec2str(struct ast_format *format)
726 {
727         int x;
728         const char *ret = "unknown";
729         size_t f_len;
730         const struct ast_format_list *f_list = ast_format_list_get(&f_len);
731
732         for (x = 0; x < f_len; x++) {
733                 if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) {
734                         ret = f_list[x].desc;
735                         break;
736                 }
737         }
738         f_list = ast_format_list_destroy(f_list);
739         return ret;
740 }
741
742 int ast_format_rate(const struct ast_format *format)
743 {
744         switch (format->id) {
745         case AST_FORMAT_SLINEAR12:
746                 return 12000;
747         case AST_FORMAT_SLINEAR24:
748                 return 24000;
749         case AST_FORMAT_SLINEAR32:
750                 return 32000;
751         case AST_FORMAT_SLINEAR44:
752                 return 44100;
753         case AST_FORMAT_SLINEAR48:
754                 return 48000;
755         case AST_FORMAT_SLINEAR96:
756                 return 96000;
757         case AST_FORMAT_SLINEAR192:
758                 return 192000;
759         case AST_FORMAT_G722:
760         case AST_FORMAT_SLINEAR16:
761         case AST_FORMAT_SIREN7:
762         case AST_FORMAT_SPEEX16:
763                 return 16000;
764         case AST_FORMAT_SIREN14:
765         case AST_FORMAT_SPEEX32:
766                 return 32000;
767         case AST_FORMAT_G719:
768                 return 48000;
769         case AST_FORMAT_SILK:
770                 if (!(ast_format_isset(format,
771                         SILK_ATTR_KEY_SAMP_RATE,
772                         SILK_ATTR_VAL_SAMP_24KHZ,
773                         AST_FORMAT_ATTR_END))) {
774                         return 24000;
775                 } else if (!(ast_format_isset(format,
776                         SILK_ATTR_KEY_SAMP_RATE,
777                         SILK_ATTR_VAL_SAMP_16KHZ,
778                         AST_FORMAT_ATTR_END))) {
779                         return 16000;
780                 } else if (!(ast_format_isset(format,
781                         SILK_ATTR_KEY_SAMP_RATE,
782                         SILK_ATTR_VAL_SAMP_12KHZ,
783                         AST_FORMAT_ATTR_END))) {
784                         return 12000;
785                 } else {
786                         return 8000;
787                 }
788         case AST_FORMAT_CELT:
789         {
790                 int samplerate;
791                 if (!(ast_format_get_value(format,
792                         CELT_ATTR_KEY_SAMP_RATE,
793                         &samplerate))) {
794                         return samplerate;
795                 }
796         }
797         /* Opus */
798         case AST_FORMAT_OPUS:
799                 return 48000;
800         default:
801                 return 8000;
802         }
803 }
804
805 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
806 {
807         int x, found=0;
808         size_t f_len;
809         const struct ast_format_list *f_list;
810
811         switch (cmd) {
812         case CLI_INIT:
813                 e->command = "core show codecs [audio|video|image|text]";
814                 e->usage =
815                         "Usage: core show codecs [audio|video|image|text]\n"
816                         "       Displays codec mapping\n";
817                 return NULL;
818         case CLI_GENERATE:
819                 return NULL;
820         }
821
822         if ((a->argc < 3) || (a->argc > 4)) {
823                 return CLI_SHOWUSAGE;
824         }
825
826         f_list = ast_format_list_get(&f_len);
827         if (!ast_opt_dont_warn) {
828                 ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
829                                 "\tIt does not indicate anything about your configuration.\n");
830         }
831
832         ast_cli(a->fd, "%8s %5s %8s %s\n","ID","TYPE","NAME","DESCRIPTION");
833         ast_cli(a->fd, "-----------------------------------------------------------------------------------\n");
834
835         for (x = 0; x < f_len; x++) {
836                 if (a->argc == 4) {
837                         if (!strcasecmp(a->argv[3], "audio")) {
838                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_AUDIO) {
839                                         continue;
840                                 }
841                         } else if (!strcasecmp(a->argv[3], "video")) {
842                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_VIDEO) {
843                                         continue;
844                                 }
845                         } else if (!strcasecmp(a->argv[3], "image")) {
846                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_IMAGE) {
847                                         continue;
848                                 }
849                         } else if (!strcasecmp(a->argv[3], "text")) {
850                                 if (AST_FORMAT_GET_TYPE(f_list[x].format.id) != AST_FORMAT_TYPE_TEXT) {
851                                         continue;
852                                 }
853                         } else {
854                                 continue;
855                         }
856                 }
857
858                 ast_cli(a->fd, "%8u %5s %8s (%s)\n",
859                         f_list[x].format.id,
860                         (AST_FORMAT_GET_TYPE(f_list[x].format.id) == AST_FORMAT_TYPE_AUDIO) ? "audio" :
861                         (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_IMAGE)  ? "image" :
862                         (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_VIDEO) ? "video" :
863                         (AST_FORMAT_GET_TYPE(f_list[x].format.id)  == AST_FORMAT_TYPE_TEXT)  ? "text"  :
864                         "(unk)",
865                         f_list[x].name,
866                         f_list[x].desc);
867                 found = 1;
868         }
869
870         f_list = ast_format_list_destroy(f_list);
871         if (!found) {
872                 return CLI_SHOWUSAGE;
873         } else {
874                 return CLI_SUCCESS;
875         }
876 }
877
878 static char *show_codec_n(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
879 {
880         enum ast_format_id format_id;
881         int x, found = 0;
882         int type_punned_codec;
883         size_t f_len;
884         const struct ast_format_list *f_list;
885
886         switch (cmd) {
887         case CLI_INIT:
888                 e->command = "core show codec";
889                 e->usage =
890                         "Usage: core show codec <number>\n"
891                         "       Displays codec mapping\n";
892                 return NULL;
893         case CLI_GENERATE:
894                 return NULL;
895         }
896
897         if (a->argc != 4) {
898                 return CLI_SHOWUSAGE;
899         }
900
901         if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
902                 return CLI_SHOWUSAGE;
903         }
904         format_id = type_punned_codec;
905
906         f_list = ast_format_list_get(&f_len);
907         for (x = 0; x < f_len; x++) {
908                 if (f_list[x].format.id == format_id) {
909                         found = 1;
910                         ast_cli(a->fd, "%11u %s\n", (unsigned int) format_id, f_list[x].desc);
911                 }
912         }
913
914         if (!found) {
915                 ast_cli(a->fd, "Codec %u not found\n", format_id);
916         }
917
918         f_list = ast_format_list_destroy(f_list);
919         return CLI_SUCCESS;
920 }
921
922 /* Builtin Asterisk CLI-commands for debugging */
923 static struct ast_cli_entry my_clis[] = {
924         AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
925         AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
926 };
927
928 static int format_list_add_custom(struct ast_format_list *new)
929 {
930         RAII_VAR(struct ast_format_list *, entry, NULL, ao2_cleanup);
931         if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
932                 return -1;
933         }
934         memcpy(entry, new, sizeof(struct ast_format_list));
935         entry->custom_entry = 1;
936         ao2_link(format_list, entry);
937         return 0;
938 }
939 static int format_list_add_static(
940         const struct ast_format *format,
941         const char *name,
942         int samplespersecond,
943         const char *description,
944         int fr_len,
945         int min_ms,
946         int max_ms,
947         int inc_ms,
948         int def_ms,
949         unsigned int flags,
950         int cur_ms)
951 {
952         struct ast_format_list *entry;
953         if (!(entry = ao2_alloc(sizeof(*entry), NULL))) {
954                 return -1;
955         }
956         ast_format_copy(&entry->format, format);
957         ast_copy_string(entry->name, name, sizeof(entry->name));
958         ast_copy_string(entry->desc, description, sizeof(entry->desc));
959         entry->samplespersecond = samplespersecond;
960         entry->fr_len = fr_len;
961         entry->min_ms = min_ms;
962         entry->max_ms = max_ms;
963         entry->inc_ms = inc_ms;
964         entry->def_ms = def_ms;
965         entry->flags = flags;
966         entry->cur_ms = cur_ms;
967         entry->custom_entry = 0;
968
969         ao2_link(format_list, entry);
970         ao2_ref(entry, -1);
971         return 0;
972 }
973
974 static int list_all_custom(void *obj, void *arg, int flag)
975 {
976         struct ast_format_list *entry = obj;
977         return entry->custom_entry ? CMP_MATCH : 0;
978 }
979
980 static int list_cmp_cb(void *obj, void *arg, int flags)
981 {
982         struct ast_format_list *entry1 = obj;
983         struct ast_format_list *entry2 = arg;
984
985         return (ast_format_cmp(&entry1->format, &entry2->format) == AST_FORMAT_CMP_EQUAL) ? CMP_MATCH | CMP_STOP : 0;
986 }
987
988 const struct ast_format_list *ast_format_list_get(size_t *size)
989 {
990         struct ast_format_list *list;
991         ast_rwlock_rdlock(&format_list_array_lock);
992         ao2_ref(format_list_array, 1);
993         list = format_list_array;
994         *size = format_list_array_len;
995         ast_rwlock_unlock(&format_list_array_lock);
996         return list;
997 }
998 const struct ast_format_list *ast_format_list_destroy(const struct ast_format_list *list)
999 {
1000         ao2_ref((void *) list, -1);
1001         return NULL;
1002 }
1003
1004 static int build_format_list_array(void)
1005 {
1006         struct ast_format_list *tmp;
1007         size_t arraysize = sizeof(struct ast_format_list) * ao2_container_count(format_list);
1008         int i = 0;
1009         struct ao2_iterator it;
1010
1011         ast_rwlock_wrlock(&format_list_array_lock);
1012         tmp = format_list_array;
1013         if (!(format_list_array = ao2_alloc(arraysize, NULL))) {
1014                 format_list_array = tmp;
1015                 ast_rwlock_unlock(&format_list_array_lock);
1016                 return -1;
1017         }
1018         format_list_array_len = ao2_container_count(format_list);
1019         if (tmp) {
1020                 ao2_ref(tmp, -1);
1021         }
1022
1023         /* walk through the container adding elements to the static array */
1024         it = ao2_iterator_init(format_list, 0);
1025         while ((tmp = ao2_iterator_next(&it)) && (i < format_list_array_len)) {
1026                 memcpy(&format_list_array[i], tmp, sizeof(struct ast_format_list));
1027                 ao2_ref(tmp, -1);
1028                 i++;
1029         }
1030         ao2_iterator_destroy(&it);
1031
1032         ast_rwlock_unlock(&format_list_array_lock);
1033         return 0;
1034 }
1035
1036 static int format_list_init(void)
1037 {
1038         struct ast_format tmpfmt;
1039         if (!(format_list = ao2_container_alloc(1, NULL, list_cmp_cb))) {
1040                 return -1;
1041         }
1042         /* initiate static entries XXX DO NOT CHANGE THIS ORDER! */
1043         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 */
1044         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 */
1045         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 */
1046         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 */
1047         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 */
1048         format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_ADPCM, 0), "adpcm" , 8000, "Dialogic ADPCM", 40, 10, 300, 10, 20, 0, 0);        /*!< codec_adpcm.c */
1049         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 */
1050         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 */
1051         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 */
1052         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 */
1053         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 */
1054         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 */
1055         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 */
1056         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 */
1057         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) */
1058         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 */
1059         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 */
1060         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 */
1061         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 */
1062         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 */
1063         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 */
1064         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 */
1065         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 */
1066         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 */
1067         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 */
1068         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 */
1069         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 */
1070         format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
1071
1072         /* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
1073         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 */
1074         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) */
1075         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) */
1076         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) */
1077         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) */
1078         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) */
1079         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) */
1080         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) */
1081         /* Opus (FIXME: real min is 3/5/10, real max is 120...) */
1082         format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_OPUS, 0), "opus", 48000, "Opus Codec", 10, 20, 60, 20, 20, 0, 0);   /*!< codec_opus.c */
1083         /* VP8 (passthrough) */
1084         format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_VP8, 0), "vp8", 0, "VP8 Video", 0, 0, 0, 0 ,0 ,0, 0);         /*!< Passthrough support, see format_h263.c */
1085
1086         return 0;
1087 }
1088
1089 /*!
1090  * \internal
1091  * \brief Clean up resources on Asterisk shutdown
1092  */
1093 static void format_list_shutdown(void)
1094 {
1095         ast_rwlock_destroy(&format_list_array_lock);
1096         if (format_list) {
1097                 ao2_t_ref(format_list, -1, "Unref format_list container in shutdown");
1098                 format_list = NULL;
1099         }
1100         if (format_list_array) {
1101                 ao2_t_ref(format_list_array, -1, "Unref format_list_array in shutdown");
1102                 format_list_array = NULL;
1103         }
1104 }
1105
1106 int ast_format_list_init(void)
1107 {
1108         if (ast_rwlock_init(&format_list_array_lock)) {
1109                 return -1;
1110         }
1111         if (format_list_init()) {
1112                 goto init_list_cleanup;
1113         }
1114         if (build_format_list_array()) {
1115                 goto init_list_cleanup;
1116         }
1117
1118         ast_register_atexit(format_list_shutdown);
1119         return 0;
1120 init_list_cleanup:
1121
1122         format_list_shutdown();
1123         return -1;
1124 }
1125
1126 /*!
1127  * \internal
1128  * \brief Clean up resources on Asterisk shutdown
1129  */
1130 static void format_attr_shutdown(void)
1131 {
1132         ast_cli_unregister_multiple(my_clis, ARRAY_LEN(my_clis));
1133         if (interfaces) {
1134                 ao2_ref(interfaces, -1);
1135                 interfaces = NULL;
1136         }
1137 }
1138
1139 int ast_format_attr_init(void)
1140 {
1141         interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
1142                 283, interface_hash_cb, interface_cmp_cb);
1143         if (!interfaces) {
1144                 return -1;
1145         }
1146
1147         ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
1148         ast_register_cleanup(format_attr_shutdown);
1149         return 0;
1150 }
1151
1152 static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
1153 {
1154         if (!entry->samplespersecond) {
1155                 ast_log(LOG_WARNING, "Custom CELT format definition '%s' requires sample rate to be defined.\n", entry->name);
1156         }
1157         ast_format_set(&entry->format, AST_FORMAT_CELT, 0);
1158         if (!has_interface(&entry->format)) {
1159                 return -1;
1160         }
1161
1162         snprintf(entry->desc, sizeof(entry->desc), "CELT Custom Format %ukhz", entry->samplespersecond/1000);
1163
1164         ast_format_append(&entry->format,
1165                 CELT_ATTR_KEY_SAMP_RATE, entry->samplespersecond,
1166                 CELT_ATTR_KEY_MAX_BITRATE, maxbitrate,
1167                 CELT_ATTR_KEY_FRAME_SIZE, framesize,
1168                 AST_FORMAT_ATTR_END);
1169
1170         entry->fr_len = 80;
1171         entry->min_ms = 20;
1172         entry->max_ms = 20;
1173         entry->inc_ms = 20;
1174         entry->def_ms = 20;
1175         return 0;
1176 }
1177
1178 static int custom_silk_format(struct ast_format_list *entry, unsigned int maxbitrate, int usedtx, int usefec, int packetloss_percentage)
1179 {
1180         if (!entry->samplespersecond) {
1181                 ast_log(LOG_WARNING, "Custom SILK format definition '%s' requires sample rate to be defined.\n", entry->name);
1182         }
1183         ast_format_set(&entry->format, AST_FORMAT_SILK, 0);
1184
1185         if (!has_interface(&entry->format)) {
1186                 return -1;
1187         }
1188
1189         switch (entry->samplespersecond) {
1190         case 8000:
1191                 ast_copy_string(entry->desc, "SILK Custom Format 8khz", sizeof(entry->desc));
1192                 ast_format_append(&entry->format,
1193                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ,
1194                         AST_FORMAT_ATTR_END);
1195                 break;
1196         case 12000:
1197                 ast_copy_string(entry->desc, "SILK Custom Format 12khz", sizeof(entry->desc));
1198                 ast_format_append(&entry->format,
1199                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ,
1200                         AST_FORMAT_ATTR_END);
1201                 break;
1202         case 16000:
1203                 ast_copy_string(entry->desc, "SILK Custom Format 16khz", sizeof(entry->desc));
1204                 ast_format_append(&entry->format,
1205                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ,
1206                         AST_FORMAT_ATTR_END);
1207                 break;
1208         case 24000:
1209                 ast_copy_string(entry->desc, "SILK Custom Format 24khz", sizeof(entry->desc));
1210                 ast_format_append(&entry->format,
1211                         SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ,
1212                         AST_FORMAT_ATTR_END);
1213                 break;
1214         default:
1215                 ast_log(LOG_WARNING, "Custom SILK format definition '%s' can not support sample rate %u\n", entry->name, entry->samplespersecond);
1216                 return -1;
1217         }
1218         ast_format_append(&entry->format,
1219                         SILK_ATTR_KEY_MAX_BITRATE, maxbitrate,
1220                         SILK_ATTR_KEY_DTX, usedtx ? 1 : 0,
1221                         SILK_ATTR_KEY_FEC, usefec ? 1 : 0,
1222                         SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, packetloss_percentage,
1223                         AST_FORMAT_ATTR_END);
1224
1225         entry->fr_len = 80;
1226         entry->min_ms = 20;
1227         entry->max_ms = 20;
1228         entry->inc_ms = 20;
1229         entry->def_ms = 20;
1230         return 0;
1231 }
1232
1233 static int conf_process_format_name(const char *name, enum ast_format_id *id)
1234 {
1235         if (!strcasecmp(name, "silk")) {
1236                 *id = AST_FORMAT_SILK;
1237         } else if (!strcasecmp(name, "celt")) {
1238                 *id = AST_FORMAT_CELT;
1239         } else {
1240                 *id = 0;
1241                 return -1;
1242         }
1243         return 0;
1244 }
1245
1246 static int conf_process_sample_rate(const char *rate, unsigned int *result)
1247 {
1248         if (!strcasecmp(rate, "8000")) {
1249                 *result = 8000;
1250         } else if (!strcasecmp(rate, "12000")) {
1251                 *result = 12000;
1252         } else if (!strcasecmp(rate, "16000")) {
1253                 *result = 16000;
1254         } else if (!strcasecmp(rate, "24000")) {
1255                 *result = 24000;
1256         } else if (!strcasecmp(rate, "32000")) {
1257                 *result = 32000;
1258         } else if (!strcasecmp(rate, "44100")) {
1259                 *result = 44100;
1260         } else if (!strcasecmp(rate, "48000")) {
1261                 *result = 48000;
1262         } else if (!strcasecmp(rate, "96000")) {
1263                 *result = 96000;
1264         } else if (!strcasecmp(rate, "192000")) {
1265                 *result = 192000;
1266         } else {
1267                 *result = 0;
1268                 return -1;
1269         }
1270
1271         return 0;
1272 }
1273 static int load_format_config(void)
1274 {
1275         struct ast_flags config_flags = { 0, };
1276         struct ast_config *cfg = ast_config_load(FORMAT_CONFIG, config_flags);
1277         struct ast_format_list entry;
1278         struct ast_variable *var;
1279         char *cat = NULL;
1280         int add_it = 0;
1281
1282         struct {
1283                 enum ast_format_id id;
1284                 unsigned int maxbitrate;
1285                 unsigned int framesize;
1286                 unsigned int packetloss_percentage;
1287                 int usefec;
1288                 int usedtx;
1289         } settings;
1290
1291         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1292                 return 0;
1293         }
1294
1295         /* remove all custom formats from the AO2 Container. Note, this has no affect on the
1296          * global format list until the list is rebuild.  That is why this is okay to do while
1297          * reloading the config. */
1298         ao2_callback(format_list, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, list_all_custom, NULL);
1299
1300         while ((cat = ast_category_browse(cfg, cat))) {
1301                 memset(&entry, 0, sizeof(entry));
1302                 memset(&settings, 0, sizeof(settings));
1303                 add_it = 0;
1304
1305                 if (!(ast_variable_retrieve(cfg, cat, "type"))) {
1306                         continue;
1307                 }
1308                 ast_copy_string(entry.name, cat, sizeof(entry.name));
1309                 var = ast_variable_browse(cfg, cat);
1310                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1311                         if (!strcasecmp(var->name, "type") && conf_process_format_name(var->value, &settings.id)) {
1312                                 ast_log(LOG_WARNING, "Can not make custom format type for '%s' at line %d of %s\n",
1313                                         var->value, var->lineno, FORMAT_CONFIG);
1314                                 continue;
1315                         } else if (!strcasecmp(var->name, "samprate") && conf_process_sample_rate(var->value, &entry.samplespersecond)) {
1316                                 ast_log(LOG_WARNING, "Sample rate '%s' at line %d of %s is not supported.\n",
1317                                                 var->value, var->lineno, FORMAT_CONFIG);
1318                         } else if (!strcasecmp(var->name, "maxbitrate")) {
1319                                 if (sscanf(var->value, "%30u", &settings.maxbitrate) != 1) {
1320                                         ast_log(LOG_WARNING, "maxbitrate '%s' at line %d of %s is not supported.\n",
1321                                                 var->value, var->lineno, FORMAT_CONFIG);
1322                                 }
1323                         } else if (!strcasecmp(var->name, "framesize")) {
1324                                 if (sscanf(var->value, "%30u", &settings.framesize) != 1) {
1325                                         ast_log(LOG_WARNING, "framesize '%s' at line %d of %s is not supported.\n",
1326                                                 var->value, var->lineno, FORMAT_CONFIG);
1327                                 }
1328                         } else if (!strcasecmp(var->name, "dtx")) {
1329                                 settings.usedtx = ast_true(var->value) ? 1 : 0;
1330                         } else if (!strcasecmp(var->name, "fec")) {
1331                                 settings.usefec = ast_true(var->value) ? 1 : 0;
1332                         } else if (!strcasecmp(var->name, "packetloss_percentage")) {
1333                                 if ((sscanf(var->value, "%30u", &settings.packetloss_percentage) != 1) || (settings.packetloss_percentage > 100)) {
1334                                         ast_log(LOG_WARNING, "packetloss_percentage '%s' at line %d of %s is not supported.\n",
1335                                                 var->value, var->lineno, FORMAT_CONFIG);
1336                                 }
1337                         }
1338                 }
1339
1340                 switch (settings.id) {
1341                 case AST_FORMAT_SILK:
1342                         if (!(custom_silk_format(&entry, settings.maxbitrate, settings.usedtx, settings.usefec, settings.packetloss_percentage))) {
1343                                 add_it = 1;
1344                         }
1345                         break;
1346                 case AST_FORMAT_CELT:
1347                         if (!(custom_celt_format(&entry, settings.maxbitrate, settings.framesize))) {
1348                                 add_it = 1;
1349                         }
1350                         break;
1351                 default:
1352                         ast_log(LOG_WARNING, "Can not create custom format %s\n", entry.name);
1353                 }
1354
1355                 if (add_it) {
1356                         format_list_add_custom(&entry);
1357                 }
1358         }
1359         ast_config_destroy(cfg);
1360         build_format_list_array();
1361         return 0;
1362 }
1363
1364 int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interface)
1365 {
1366         int x;
1367         size_t f_len;
1368         const struct ast_format_list *f_list;
1369         struct interface_ao2_wrapper *wrapper;
1370         struct interface_ao2_wrapper tmp_wrapper = {
1371                 .id = interface->id,
1372         };
1373
1374         /*
1375          * Grab the write lock before checking for duplicates in
1376          * anticipation of adding a new interface and to prevent a
1377          * duplicate from sneaking in between the check and add.
1378          */
1379         ao2_wrlock(interfaces);
1380
1381         /* check for duplicates first*/
1382         if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
1383                 ao2_unlock(interfaces);
1384                 ast_log(LOG_WARNING, "Can not register attribute interface for format id %u, interface already exists.\n", interface->id);
1385                 ao2_ref(wrapper, -1);
1386                 return -1;
1387         }
1388
1389         wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
1390         if (!wrapper) {
1391                 ao2_unlock(interfaces);
1392                 return -1;
1393         }
1394
1395         wrapper->interface = interface;
1396         wrapper->id = interface->id;
1397
1398         /* The write lock is already held. */
1399         ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
1400         ao2_unlock(interfaces);
1401
1402         ao2_ref(wrapper, -1);
1403
1404         /* This will find all custom formats in codecs.conf for this new registered interface */
1405         load_format_config();
1406
1407         /* update the RTP engine to all custom formats created for this interface */
1408         f_list = ast_format_list_get(&f_len);
1409         for (x = 0; x < f_len; x++) {
1410                 if (f_list[x].format.id == tmp_wrapper.id) {
1411                         ast_rtp_engine_load_format(&f_list[x].format);
1412                 }
1413         }
1414         f_list = ast_format_list_destroy(f_list);
1415         return 0;
1416 }
1417
1418 int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *interface)
1419 {
1420         int x;
1421         size_t f_len;
1422         const struct ast_format_list *f_list;
1423         struct interface_ao2_wrapper *wrapper;
1424         struct interface_ao2_wrapper tmp_wrapper = {
1425                 .id = interface->id,
1426         };
1427
1428         if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
1429                 return -1;
1430         }
1431
1432         ao2_wrlock(wrapper);
1433         wrapper->interface = NULL;
1434         ao2_unlock(wrapper);
1435
1436         ao2_ref(wrapper, -1);
1437
1438         /* update the RTP engine to remove all custom formats created for this interface */
1439         f_list = ast_format_list_get(&f_len);
1440         for (x = 0; x < f_len; x++) {
1441                 if (f_list[x].format.id == tmp_wrapper.id) {
1442                         ast_rtp_engine_unload_format(&f_list[x].format);
1443                 }
1444         }
1445
1446         /* This will remove all custom formats previously created for this interface */
1447         load_format_config();
1448         f_list = ast_format_list_destroy(f_list);
1449         return 0;
1450 }