res_resolver_unbound: Fix config documentation.
[asterisk/asterisk.git] / res / res_format_attr_opus.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Lorenzo Miniero <lorenzo@meetecho.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 /*!
20  * \file
21  * \brief Opus format attribute interface
22  *
23  * \author Lorenzo Miniero <lorenzo@meetecho.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_REGISTER_FILE()
33
34 #include "asterisk/module.h"
35 #include "asterisk/format.h"
36 #include "asterisk/logger.h"            /* for ast_log, LOG_WARNING */
37 #include "asterisk/strings.h"           /* for ast_str_append */
38 #include "asterisk/utils.h"             /* for MIN, ast_malloc, ast_free */
39
40 /*!
41  * \brief Opus attribute structure.
42  *
43  * \note http://tools.ietf.org/html/rfc7587#section-6
44  */
45 struct opus_attr {
46         unsigned int maxbitrate;
47         unsigned int maxplayrate;
48         unsigned int unused; /* was minptime, kept for binary compatibility */
49         unsigned int stereo;
50         unsigned int cbr;
51         unsigned int fec;
52         unsigned int dtx;
53         unsigned int spropmaxcapturerate;
54         unsigned int spropstereo;
55 };
56
57 static struct opus_attr default_opus_attr = {
58         .maxplayrate         = 48000,
59         .spropmaxcapturerate = 48000,
60         .maxbitrate          = 510000,
61         .stereo              = 0,
62         .spropstereo         = 0,
63         .cbr                 = 0,
64         .fec                 = 1,
65         .dtx                 = 0,
66 };
67
68 static void opus_destroy(struct ast_format *format)
69 {
70         struct opus_attr *attr = ast_format_get_attribute_data(format);
71
72         ast_free(attr);
73 }
74
75 static int opus_clone(const struct ast_format *src, struct ast_format *dst)
76 {
77         struct opus_attr *original = ast_format_get_attribute_data(src);
78         struct opus_attr *attr = ast_malloc(sizeof(*attr));
79
80         if (!attr) {
81                 return -1;
82         }
83
84         if (original) {
85                 *attr = *original;
86         } else {
87                 *attr = default_opus_attr;
88         }
89
90         ast_format_set_attribute_data(dst, attr);
91
92         return 0;
93 }
94
95 static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
96 {
97         struct ast_format *cloned;
98         struct opus_attr *attr;
99         const char *kvp;
100         unsigned int val;
101
102         cloned = ast_format_clone(format);
103         if (!cloned) {
104                 return NULL;
105         }
106         attr = ast_format_get_attribute_data(cloned);
107
108         if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) {
109                 attr->maxplayrate = val;
110         } else {
111                 attr->maxplayrate = 48000;
112         }
113
114         if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) {
115                 attr->spropmaxcapturerate = val;
116         } else {
117                 attr->spropmaxcapturerate = 48000;
118         }
119
120         if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) {
121                 attr->maxbitrate = val;
122         } else {
123                 attr->maxbitrate = 510000;
124         }
125
126         if (!strncmp(attributes, "stereo=1", 8)) {
127                 attr->stereo = 1;
128         } else if (strstr(attributes, " stereo=1")) {
129                 attr->stereo = 1;
130         } else if (strstr(attributes, ";stereo=1")) {
131                 attr->stereo = 1;
132         } else {
133                 attr->stereo = 0;
134         }
135
136         if (strstr(attributes, "sprop-stereo=1")) {
137                 attr->spropstereo = 1;
138         } else {
139                 attr->spropstereo = 0;
140         }
141
142         if (strstr(attributes, "cbr=1")) {
143                 attr->cbr = 1;
144         } else {
145                 attr->cbr = 0;
146         }
147
148         if (strstr(attributes, "useinbandfec=1")) {
149                 attr->fec = 1;
150         } else {
151                 attr->fec = 0;
152         }
153
154         if (strstr(attributes, "usedtx=1")) {
155                 attr->dtx = 1;
156         } else {
157                 attr->dtx = 0;
158         }
159
160         return cloned;
161 }
162
163 static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
164 {
165         struct opus_attr *attr = ast_format_get_attribute_data(format);
166         int added = 0;
167
168         if (!attr) {
169                 /*
170                  * (Only) cached formats do not have attribute data assigned because
171                  * they were created before this attribute module was registered.
172                  * Therefore, we assume the default attribute values here.
173                  */
174                 attr = &default_opus_attr;
175         }
176
177         if (48000 != attr->maxplayrate) {
178                 if (added) {
179                         ast_str_append(str, 0, ";");
180                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
181                         added = 1;
182                 }
183                 ast_str_append(str, 0, "maxplaybackrate=%u", attr->maxplayrate);
184         }
185
186         if (48000 != attr->spropmaxcapturerate) {
187                 if (added) {
188                         ast_str_append(str, 0, ";");
189                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
190                         added = 1;
191                 }
192                 ast_str_append(str, 0, "sprop-maxcapturerate=%u", attr->spropmaxcapturerate);
193         }
194
195         if (510000 != attr->maxbitrate) {
196                 if (added) {
197                         ast_str_append(str, 0, ";");
198                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
199                         added = 1;
200                 }
201                 ast_str_append(str, 0, "maxaveragebitrate=%u", attr->maxbitrate);
202         }
203
204         if (0 != attr->stereo) {
205                 if (added) {
206                         ast_str_append(str, 0, ";");
207                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
208                         added = 1;
209                 }
210                 ast_str_append(str, 0, "stereo=%u", attr->stereo);
211         }
212
213         if (0 != attr->spropstereo) {
214                 if (added) {
215                         ast_str_append(str, 0, ";");
216                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
217                         added = 1;
218                 }
219                 ast_str_append(str, 0, "sprop-stereo=%u", attr->spropstereo);
220         }
221
222         if (0 != attr->cbr) {
223                 if (added) {
224                         ast_str_append(str, 0, ";");
225                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
226                         added = 1;
227                 }
228                 ast_str_append(str, 0, "cbr=%u", attr->cbr);
229         }
230
231         if (0 != attr->fec) {
232                 if (added) {
233                         ast_str_append(str, 0, ";");
234                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
235                         added = 1;
236                 }
237                 ast_str_append(str, 0, "useinbandfec=%u", attr->fec);
238         }
239
240         if (0 != attr->dtx) {
241                 if (added) {
242                         ast_str_append(str, 0, ";");
243                 } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
244                         added = 1;
245                 }
246                 ast_str_append(str, 0, "usedtx=%u", attr->dtx);
247         }
248
249         if (added) {
250                 ast_str_append(str, 0, "\r\n");
251         }
252 }
253
254 static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
255 {
256         struct opus_attr *attr1 = ast_format_get_attribute_data(format1);
257         struct opus_attr *attr2 = ast_format_get_attribute_data(format2);
258         struct ast_format *jointformat;
259         struct opus_attr *attr_res;
260
261         if (!attr1) {
262                 attr1 = &default_opus_attr;
263         }
264
265         if (!attr2) {
266                 attr2 = &default_opus_attr;
267         }
268
269         jointformat = ast_format_clone(format1);
270         if (!jointformat) {
271                 return NULL;
272         }
273         attr_res = ast_format_get_attribute_data(jointformat);
274
275         attr_res->dtx = attr1->dtx || attr2->dtx ? 1 : 0;
276
277         /* Only do FEC if both sides want it.  If a peer specifically requests not
278          * to receive with FEC, it may be a waste of bandwidth. */
279         attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
280
281         attr_res->cbr = attr1->cbr || attr2->cbr ? 1 : 0;
282         attr_res->spropstereo = attr1->spropstereo || attr2->spropstereo ? 1 : 0;
283
284         /* Only do stereo if both sides want it.  If a peer specifically requests not
285          * to receive stereo signals, it may be a waste of bandwidth. */
286         attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0;
287
288         attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
289         attr_res->spropmaxcapturerate = MIN(attr1->spropmaxcapturerate, attr2->spropmaxcapturerate);
290         attr_res->maxplayrate = MIN(attr1->maxplayrate, attr2->maxplayrate);
291
292         return jointformat;
293 }
294
295 static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value)
296 {
297         struct ast_format *cloned;
298         struct opus_attr *attr;
299         unsigned int val;
300
301         if (sscanf(value, "%30u", &val) != 1) {
302                 ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
303                         value, name);
304                 return NULL;
305         }
306
307         cloned = ast_format_clone(format);
308         if (!cloned) {
309                 return NULL;
310         }
311         attr = ast_format_get_attribute_data(cloned);
312
313         if (!strcasecmp(name, "max_bitrate")) {
314                 attr->maxbitrate = val;
315         } else if (!strcasecmp(name, "max_playrate")) {
316                 attr->maxplayrate = val;
317         } else if (!strcasecmp(name, "minptime")) {
318                 attr->unused = val;
319         } else if (!strcasecmp(name, "stereo")) {
320                 attr->stereo = val;
321         } else if (!strcasecmp(name, "cbr")) {
322                 attr->cbr = val;
323         } else if (!strcasecmp(name, "fec")) {
324                 attr->fec = val;
325         } else if (!strcasecmp(name, "dtx")) {
326                 attr->dtx = val;
327         } else if (!strcasecmp(name, "sprop_capture_rate")) {
328                 attr->spropmaxcapturerate = val;
329         } else if (!strcasecmp(name, "sprop_stereo")) {
330                 attr->spropstereo = val;
331         } else {
332                 ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
333         }
334
335         return cloned;
336 }
337
338 static struct ast_format_interface opus_interface = {
339         .format_destroy = opus_destroy,
340         .format_clone = opus_clone,
341         .format_get_joint = opus_getjoint,
342         .format_attribute_set = opus_set,
343         .format_parse_sdp_fmtp = opus_parse_sdp_fmtp,
344         .format_generate_sdp_fmtp = opus_generate_sdp_fmtp,
345 };
346
347 static int load_module(void)
348 {
349         if (ast_format_interface_register("opus", &opus_interface)) {
350                 return AST_MODULE_LOAD_DECLINE;
351         }
352
353         return AST_MODULE_LOAD_SUCCESS;
354 }
355
356 static int unload_module(void)
357 {
358         return 0;
359 }
360
361 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module",
362         .support_level = AST_MODULE_SUPPORT_CORE,
363         .load = load_module,
364         .unload = unload_module,
365         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
366 );