res_pjsip: Allow configuration of endpoint identifier query order
[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_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/module.h"
35 #include "asterisk/format.h"
36
37 /*!
38  * \brief Opus attribute structure.
39  *
40  * \note http://tools.ietf.org/html/draft-ietf-payload-rtp-opus-00.
41  */
42 struct opus_attr {
43         unsigned int maxbitrate;                /* Default 64-128 kb/s for FB stereo music */
44         unsigned int maxplayrate                /* Default 48000 */;
45         unsigned int minptime;              /* Default 3, but it's 10 in format.c */
46         unsigned int stereo;                /* Default 0 */
47         unsigned int cbr;                       /* Default 0 */
48         unsigned int fec;                       /* Default 0 */
49         unsigned int dtx;                       /* Default 0 */
50         unsigned int spropmaxcapturerate;       /* Default 48000 */
51         unsigned int spropstereo;               /* Default 0 */
52 };
53
54 static struct opus_attr default_opus_attr = {
55         .fec    = 0,
56         .dtx    = 0,
57         .stereo = 0,
58 };
59
60 static void opus_destroy(struct ast_format *format)
61 {
62         struct opus_attr *attr = ast_format_get_attribute_data(format);
63
64         ast_free(attr);
65 }
66
67 static int opus_clone(const struct ast_format *src, struct ast_format *dst)
68 {
69         struct opus_attr *original = ast_format_get_attribute_data(src);
70         struct opus_attr *attr = ast_calloc(1, sizeof(*attr));
71
72         if (!attr) {
73                 return -1;
74         }
75
76         if (original) {
77                 *attr = *original;
78         }
79
80         ast_format_set_attribute_data(dst, attr);
81
82         return 0;
83 }
84
85 static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
86 {
87         struct ast_format *cloned;
88         struct opus_attr *attr;
89         const char *kvp;
90         unsigned int val;
91
92         cloned = ast_format_clone(format);
93         if (!cloned) {
94                 return NULL;
95         }
96         attr = ast_format_get_attribute_data(cloned);
97
98         if ((kvp = strstr(attributes, "maxplaybackrate")) && sscanf(kvp, "maxplaybackrate=%30u", &val) == 1) {
99                 attr->maxplayrate = val;
100         }
101         if ((kvp = strstr(attributes, "sprop-maxcapturerate")) && sscanf(kvp, "sprop-maxcapturerate=%30u", &val) == 1) {
102                 attr->spropmaxcapturerate = val;
103         }
104         if ((kvp = strstr(attributes, "minptime")) && sscanf(kvp, "minptime=%30u", &val) == 1) {
105                 attr->minptime = val;
106         }
107         if ((kvp = strstr(attributes, "maxaveragebitrate")) && sscanf(kvp, "maxaveragebitrate=%30u", &val) == 1) {
108                 attr->maxbitrate = val;
109         }
110         if ((kvp = strstr(attributes, " stereo")) && sscanf(kvp, " stereo=%30u", &val) == 1) {
111                 attr->stereo = val;
112         }
113         if ((kvp = strstr(attributes, ";stereo")) && sscanf(kvp, ";stereo=%30u", &val) == 1) {
114                 attr->stereo = val;
115         }
116         if ((kvp = strstr(attributes, "sprop-stereo")) && sscanf(kvp, "sprop-stereo=%30u", &val) == 1) {
117                 attr->spropstereo = val;
118         }
119         if ((kvp = strstr(attributes, "cbr")) && sscanf(kvp, "cbr=%30u", &val) == 1) {
120                 attr->cbr = val;
121         }
122         if ((kvp = strstr(attributes, "useinbandfec")) && sscanf(kvp, "useinbandfec=%30u", &val) == 1) {
123                 attr->fec = val;
124         }
125         if ((kvp = strstr(attributes, "usedtx")) && sscanf(kvp, "usedtx=%30u", &val) == 1) {
126                 attr->dtx = val;
127         }
128
129         return cloned;
130 }
131
132 static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
133 {
134         struct opus_attr *attr = ast_format_get_attribute_data(format);
135
136         if (!attr) {
137                 return;
138         }
139
140         /* FIXME should we only generate attributes that were explicitly set? */
141         ast_str_append(str, 0,
142                                 "a=fmtp:%u "
143                                         "maxplaybackrate=%u;"
144                                         "sprop-maxcapturerate=%u;"
145                                         "minptime=%u;"
146                                         "maxaveragebitrate=%u;"
147                                         "stereo=%d;"
148                                         "sprop-stereo=%d;"
149                                         "cbr=%d;"
150                                         "useinbandfec=%d;"
151                                         "usedtx=%d\r\n",
152                         payload,
153                         attr->maxplayrate ? attr->maxplayrate : 48000,  /* maxplaybackrate */
154                         attr->spropmaxcapturerate ? attr->spropmaxcapturerate : 48000,  /* sprop-maxcapturerate */
155                         attr->minptime > 10 ? attr->minptime : 10,      /* minptime */
156                         attr->maxbitrate ? attr->maxbitrate : 20000,    /* maxaveragebitrate */
157                         attr->stereo ? 1 : 0,           /* stereo */
158                         attr->spropstereo ? 1 : 0,              /* sprop-stereo */
159                         attr->cbr ? 1 : 0,              /* cbr */
160                         attr->fec ? 1 : 0,              /* useinbandfec */
161                         attr->dtx ? 1 : 0               /* usedtx */
162         );
163 }
164
165 static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
166 {
167         struct opus_attr *attr1 = ast_format_get_attribute_data(format1);
168         struct opus_attr *attr2 = ast_format_get_attribute_data(format2);
169         struct ast_format *jointformat;
170         struct opus_attr *attr_res;
171
172         if (!attr1) {
173                 attr1 = &default_opus_attr;
174         }
175
176         if (!attr2) {
177                 attr2 = &default_opus_attr;
178         }
179
180         jointformat = ast_format_clone(format1);
181         if (!jointformat) {
182                 return NULL;
183         }
184         attr_res = ast_format_get_attribute_data(jointformat);
185
186         /* Only do dtx if both sides want it. DTX is a trade off between
187          * computational complexity and bandwidth. */
188         attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
189
190         /* Only do FEC if both sides want it.  If a peer specifically requests not
191          * to receive with FEC, it may be a waste of bandwidth. */
192         attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
193
194         /* Only do stereo if both sides want it.  If a peer specifically requests not
195          * to receive stereo signals, it may be a waste of bandwidth. */
196         attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0;
197
198         /* FIXME: do we need to join other attributes as well, e.g., minptime, cbr, etc.? */
199
200         return jointformat;
201 }
202
203 static struct ast_format *opus_set(const struct ast_format *format, const char *name, const char *value)
204 {
205         struct ast_format *cloned;
206         struct opus_attr *attr;
207         unsigned int val;
208
209         if (sscanf(value, "%30u", &val) != 1) {
210                 ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
211                         value, name);
212                 return NULL;
213         }
214
215         cloned = ast_format_clone(format);
216         if (!cloned) {
217                 return NULL;
218         }
219         attr = ast_format_get_attribute_data(cloned);
220
221         if (!strcasecmp(name, "max_bitrate")) {
222                 attr->maxbitrate = val;
223         } else if (!strcasecmp(name, "max_playrate")) {
224                 attr->maxplayrate = val;
225         } else if (!strcasecmp(name, "minptime")) {
226                 attr->minptime = val;
227         } else if (!strcasecmp(name, "stereo")) {
228                 attr->stereo = val;
229         } else if (!strcasecmp(name, "cbr")) {
230                 attr->cbr = val;
231         } else if (!strcasecmp(name, "fec")) {
232                 attr->fec = val;
233         } else if (!strcasecmp(name, "dtx")) {
234                 attr->dtx = val;
235         } else if (!strcasecmp(name, "sprop_capture_rate")) {
236                 attr->spropmaxcapturerate = val;
237         } else if (!strcasecmp(name, "sprop_stereo")) {
238                 attr->spropstereo = val;
239         } else {
240                 ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
241         }
242
243         return cloned;
244 }
245
246 static struct ast_format_interface opus_interface = {
247         .format_destroy = opus_destroy,
248         .format_clone = opus_clone,
249         .format_get_joint = opus_getjoint,
250         .format_attribute_set = opus_set,
251         .format_parse_sdp_fmtp = opus_parse_sdp_fmtp,
252         .format_generate_sdp_fmtp = opus_generate_sdp_fmtp,
253 };
254
255 static int load_module(void)
256 {
257         if (ast_format_interface_register("opus", &opus_interface)) {
258                 return AST_MODULE_LOAD_DECLINE;
259         }
260
261         return AST_MODULE_LOAD_SUCCESS;
262 }
263
264 static int unload_module(void)
265 {
266         return 0;
267 }
268
269 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Opus Format Attribute Module",
270         .support_level = AST_MODULE_SUPPORT_CORE,
271         .load = load_module,
272         .unload = unload_module,
273         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
274 );