CI: Various updates to buildAsterisk.sh
[asterisk/asterisk.git] / main / format.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Media Format API
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/logger.h"
33 #include "asterisk/codec.h"
34 #include "asterisk/format.h"
35 #include "asterisk/astobj2.h"
36 #include "asterisk/strings.h"
37 #include "asterisk/module.h"
38
39 /*! \brief Number of buckets to use for format interfaces (should be prime for performance reasons) */
40 #define FORMAT_INTERFACE_BUCKETS 53
41
42 /*! \brief Definition of a media format */
43 struct ast_format {
44         /*! Name of the format */
45         const char *name;
46         /*! \brief Pointer to the codec in use for this format */
47         struct ast_codec *codec;
48         /*! \brief Attribute specific data, implementation specific */
49         void *attribute_data;
50         /*! \brief Pointer to the optional format interface */
51         const struct ast_format_interface *interface;
52         /*! \brief The number if audio channels used, if more than one an interleaved format is required */
53         unsigned int channel_count;
54 };
55
56 /*! \brief Structure used when registering a format interface */
57 struct format_interface {
58         /*! \brief Pointer to the format interface itself */
59         const struct ast_format_interface *interface;
60         /*! \brief Name of the codec the interface is for */
61         char codec[0];
62 };
63
64 /*! \brief Container for registered format interfaces */
65 static struct ao2_container *interfaces;
66
67 AO2_STRING_FIELD_HASH_FN(format_interface, codec)
68 AO2_STRING_FIELD_CMP_FN(format_interface, codec)
69
70 /*! \brief Function called when the process is shutting down */
71 static void format_shutdown(void)
72 {
73         ao2_cleanup(interfaces);
74         interfaces = NULL;
75 }
76
77 int ast_format_init(void)
78 {
79         interfaces = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0,
80                 FORMAT_INTERFACE_BUCKETS, format_interface_hash_fn, NULL, format_interface_cmp_fn);
81         if (!interfaces) {
82                 return -1;
83         }
84
85         ast_register_cleanup(format_shutdown);
86
87         return 0;
88 }
89
90 int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod)
91 {
92         SCOPED_AO2WRLOCK(lock, interfaces);
93         struct format_interface *format_interface;
94
95         if (!interface->format_clone || !interface->format_destroy) {
96                 ast_log(LOG_ERROR, "Format interface for codec '%s' does not implement required callbacks\n", codec);
97                 return -1;
98         }
99
100         format_interface = ao2_find(interfaces, codec, OBJ_SEARCH_KEY | OBJ_NOLOCK);
101         if (format_interface) {
102                 ast_log(LOG_ERROR, "A format interface is already present for codec '%s'\n", codec);
103                 ao2_ref(format_interface, -1);
104                 return -1;
105         }
106
107         format_interface = ao2_alloc_options(sizeof(*format_interface) + strlen(codec) + 1,
108                 NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
109         if (!format_interface) {
110                 return -1;
111         }
112         format_interface->interface = interface;
113         strcpy(format_interface->codec, codec); /* Safe */
114
115         /* Once registered a format interface cannot be unregistered. */
116         ast_module_shutdown_ref(mod);
117         ao2_link_flags(interfaces, format_interface, OBJ_NOLOCK);
118         ao2_ref(format_interface, -1);
119
120         ast_verb(2, "Registered format interface for codec '%s'\n", codec);
121
122         return 0;
123 }
124
125 void *ast_format_get_attribute_data(const struct ast_format *format)
126 {
127         return format->attribute_data;
128 }
129
130 void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data)
131 {
132         format->attribute_data = attribute_data;
133 }
134
135 unsigned int ast_format_get_channel_count(const struct ast_format *format)
136 {
137         return format->channel_count;
138 }
139
140 void ast_format_set_channel_count(struct ast_format *format, unsigned int channel_count)
141 {
142         format->channel_count = channel_count;
143 }
144
145 /*! \brief Destructor for media formats */
146 static void format_destroy(void *obj)
147 {
148         struct ast_format *format = obj;
149
150         if (format->interface) {
151                 format->interface->format_destroy(format);
152         }
153
154         ao2_cleanup(format->codec);
155 }
156
157 struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec)
158 {
159         struct ast_format *format;
160         struct format_interface *format_interface;
161
162         format = ao2_t_alloc_options(sizeof(*format), format_destroy,
163                 AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""));
164         if (!format) {
165                 return NULL;
166         }
167         format->name = format_name;
168         format->codec = ao2_bump(codec);
169         format->channel_count = 1;
170
171         format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY);
172         if (format_interface) {
173                 format->interface = format_interface->interface;
174                 ao2_ref(format_interface, -1);
175         }
176
177         return format;
178 }
179
180 struct ast_format *ast_format_clone(const struct ast_format *format)
181 {
182         struct ast_format *cloned = ast_format_create_named(format->name, format->codec);
183
184         if (!cloned) {
185                 return NULL;
186         }
187
188         if (cloned->interface && cloned->interface->format_clone(format, cloned)) {
189                 ao2_ref(cloned, -1);
190                 return NULL;
191         }
192
193         return cloned;
194 }
195
196 struct ast_format *ast_format_create(struct ast_codec *codec)
197 {
198         return ast_format_create_named(codec->name, codec);
199 }
200
201 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
202 {
203         const struct ast_format_interface *interface;
204
205         if (format1 == NULL || format2 == NULL) {
206                 return AST_FORMAT_CMP_NOT_EQUAL;
207         }
208
209         if (format1 == format2) {
210                 return AST_FORMAT_CMP_EQUAL;
211         }
212
213         if (format1->codec != format2->codec) {
214                 return AST_FORMAT_CMP_NOT_EQUAL;
215         }
216
217         interface = format1->interface ? format1->interface : format2->interface;
218
219         if (interface && interface->format_cmp) {
220                 return interface->format_cmp(format1, format2);
221         }
222
223         return AST_FORMAT_CMP_EQUAL;
224 }
225
226 struct ast_format *ast_format_joint(const struct ast_format *format1, const struct ast_format *format2)
227 {
228         const struct ast_format_interface *interface;
229
230         if (format1->codec != format2->codec) {
231                 return NULL;
232         }
233
234         /* If the two formats are the same structure OR if the codec is the same and no attributes
235          * exist we can immediately return a format with reference count bumped up, since they are
236          * the same.
237          */
238         if ((ast_format_cmp(format1, format2) == AST_FORMAT_CMP_EQUAL && !format1->attribute_data && !format2->attribute_data)) {
239                 return ao2_bump((struct ast_format*)format1);
240         }
241
242         interface = format1->interface ? format1->interface : format2->interface;
243
244         /* If there is attribute data on either there has to be an interface */
245         return interface->format_get_joint(format1, format2);
246 }
247
248 struct ast_format *ast_format_attribute_set(const struct ast_format *format, const char *name, const char *value)
249 {
250         const struct ast_format_interface *interface = format->interface;
251
252         if (!interface) {
253                 struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
254                 if (format_interface) {
255                         interface = format_interface->interface;
256                         ao2_ref(format_interface, -1);
257                 }
258         }
259
260         if (!interface || !interface->format_attribute_set) {
261                 return ao2_bump((struct ast_format*)format);
262         }
263
264         return interface->format_attribute_set(format, name, value);
265 }
266
267 const void *ast_format_attribute_get(const struct ast_format *format, const char *name)
268 {
269         const struct ast_format_interface *interface = format->interface;
270
271         if (!interface) {
272                 struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
273                 if (format_interface) {
274                         interface = format_interface->interface;
275                         ao2_ref(format_interface, -1);
276                 }
277         }
278
279         if (!interface || !interface->format_attribute_get) {
280                 return NULL;
281         }
282
283         return interface->format_attribute_get(format, name);
284 }
285
286 struct ast_format *ast_format_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
287 {
288         const struct ast_format_interface *interface = format->interface;
289
290         if (!interface) {
291                 struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
292                 if (format_interface) {
293                         interface = format_interface->interface;
294                         ao2_ref(format_interface, -1);
295                 }
296         }
297
298         if (!interface || !interface->format_parse_sdp_fmtp) {
299                 return ao2_bump((struct ast_format*)format);
300         }
301
302         return interface->format_parse_sdp_fmtp(format, attributes);
303 }
304
305 void ast_format_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
306 {
307         const struct ast_format_interface *interface = format->interface;
308
309         if (!interface) {
310                 struct format_interface *format_interface = ao2_find(interfaces, format->codec->name, OBJ_SEARCH_KEY);
311                 if (format_interface) {
312                         interface = format_interface->interface;
313                         ao2_ref(format_interface, -1);
314                 }
315         }
316
317         if (!interface || !interface->format_generate_sdp_fmtp) {
318                 return;
319         }
320
321         interface->format_generate_sdp_fmtp(format, payload, str);
322 }
323
324 struct ast_codec *ast_format_get_codec(const struct ast_format *format)
325 {
326         return ao2_bump(format->codec);
327 }
328
329 unsigned int ast_format_get_codec_id(const struct ast_format *format)
330 {
331         return format->codec->id;
332 }
333
334 const char *ast_format_get_name(const struct ast_format *format)
335 {
336         return format->name;
337 }
338
339 const char *ast_format_get_codec_name(const struct ast_format *format)
340 {
341         return format->codec->name;
342 }
343
344 int ast_format_can_be_smoothed(const struct ast_format *format)
345 {
346         return format->codec->smooth;
347 }
348
349 int ast_format_get_smoother_flags(const struct ast_format *format)
350 {
351         return format->codec->smoother_flags;
352 }
353
354 enum ast_media_type ast_format_get_type(const struct ast_format *format)
355 {
356         return format->codec->type;
357 }
358
359 unsigned int ast_format_get_default_ms(const struct ast_format *format)
360 {
361         return format->codec->default_ms;
362 }
363
364 unsigned int ast_format_get_minimum_ms(const struct ast_format *format)
365 {
366         return format->codec->minimum_ms;
367 }
368
369 unsigned int ast_format_get_maximum_ms(const struct ast_format *format)
370 {
371         return format->codec->maximum_ms;
372 }
373
374 unsigned int ast_format_get_minimum_bytes(const struct ast_format *format)
375 {
376         return format->codec->minimum_bytes;
377 }
378
379 unsigned int ast_format_get_sample_rate(const struct ast_format *format)
380 {
381         return format->codec->sample_rate ?: 8000;
382 }
383
384 unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples)
385 {
386         return ast_codec_determine_length(format->codec, samples);
387 }