res_pjsip res_pjsip_mwi: Misc fixes and cleanups.
[asterisk/asterisk.git] / res / res_format_attr_silk.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2011, Digium, Inc.
5  *
6  * David Vossel <dvossel@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 /*!
20  * \file
21  * \brief SILK format attribute interface
22  *
23  * \author David Vossel <dvossel@digium.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
37 /*!
38  * \brief SILK attribute structure.
39  *
40  * \note The only attribute that affects compatibility here is the sample rate.
41  */
42 struct silk_attr {
43         unsigned int maxbitrate;
44         unsigned int dtx;
45         unsigned int fec;
46         unsigned int packetloss_percentage;
47 };
48
49 static void silk_destroy(struct ast_format *format)
50 {
51         struct silk_attr *attr = ast_format_get_attribute_data(format);
52
53         ast_free(attr);
54 }
55
56 static void attr_init(struct silk_attr *attr)
57 {
58         memset(attr, 0, sizeof(*attr));
59 }
60
61 static int silk_clone(const struct ast_format *src, struct ast_format *dst)
62 {
63         struct silk_attr *original = ast_format_get_attribute_data(src);
64         struct silk_attr *attr = ast_malloc(sizeof(*attr));
65
66         if (!attr) {
67                 return -1;
68         }
69
70         if (original) {
71                 *attr = *original;
72         } else {
73                 attr_init(attr);
74         }
75
76         ast_format_set_attribute_data(dst, attr);
77
78         return 0;
79 }
80
81 static struct ast_format *silk_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
82 {
83         struct ast_format *cloned;
84         struct silk_attr *attr;
85         unsigned int val;
86
87         cloned = ast_format_clone(format);
88         if (!cloned) {
89                 return NULL;
90         }
91         attr = ast_format_get_attribute_data(cloned);
92
93         if (sscanf(attributes, "maxaveragebitrate=%30u", &val) == 1) {
94                 attr->maxbitrate = val;
95         }
96         if (sscanf(attributes, "usedtx=%30u", &val) == 1) {
97                 attr->dtx = val;
98         }
99         if (sscanf(attributes, "useinbandfec=%30u", &val) == 1) {
100                 attr->fec = val;
101         }
102
103         return cloned;
104 }
105
106 static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
107 {
108         struct silk_attr *attr = ast_format_get_attribute_data(format);
109
110         if (!attr) {
111                 return;
112         }
113
114         if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) { 
115                 ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate);
116         }
117
118         if (attr->dtx) {
119                 ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx);
120         }
121         if (attr->fec) {
122                 ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec);
123         }
124 }
125
126 static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2)
127 {
128         if (ast_format_get_sample_rate(format1) == ast_format_get_sample_rate(format2)) {
129                 return AST_FORMAT_CMP_EQUAL;
130         }
131
132         return AST_FORMAT_CMP_NOT_EQUAL;
133 }
134
135 static struct ast_format *silk_getjoint(const struct ast_format *format1, const struct ast_format *format2)
136 {
137         struct silk_attr *attr1 = ast_format_get_attribute_data(format1);
138         struct silk_attr *attr2 = ast_format_get_attribute_data(format2);
139         struct ast_format *jointformat;
140         struct silk_attr *attr_res;
141
142         if (ast_format_get_sample_rate(format1) != ast_format_get_sample_rate(format2)) {
143                 return NULL;
144         }
145
146         jointformat = ast_format_clone(format1);
147         if (!jointformat) {
148                 return NULL;
149         }
150         attr_res = ast_format_get_attribute_data(jointformat);
151
152         if (!attr1 || !attr2) {
153                 attr_init(attr_res);
154         } else {
155                 /* Take the lowest max bitrate */
156                 attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
157
158                 /* Only do dtx if both sides want it. DTX is a trade off between
159                  * computational complexity and bandwidth. */
160                 attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
161
162                 /* Only do FEC if both sides want it.  If a peer specifically requests not
163                  * to receive with FEC, it may be a waste of bandwidth. */
164                 attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
165
166                 /* Use the maximum packetloss percentage between the two attributes. This affects how
167                  * much redundancy is used in the FEC. */
168                 attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage);
169         }
170
171         return jointformat;
172 }
173
174 static struct ast_format *silk_set(const struct ast_format *format, const char *name, const char *value)
175 {
176         struct ast_format *cloned;
177         struct silk_attr *attr;
178         unsigned int val;
179
180         if (sscanf(value, "%30u", &val) != 1) {
181                 ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
182                         value, name);
183                 return NULL;
184         }
185
186         cloned = ast_format_clone(format);
187         if (!cloned) {
188                 return NULL;
189         }
190         attr = ast_format_get_attribute_data(cloned);
191
192         if (!strcasecmp(name, "max_bitrate")) {
193                 attr->maxbitrate = val;
194         } else if (!strcasecmp(name, "dtx")) {
195                 attr->dtx = val;
196         } else if (!strcasecmp(name, "fec")) {
197                 attr->fec = val;
198         } else if (!strcasecmp(name, "packetloss_percentage")) {
199                 attr->packetloss_percentage = val;
200         } else {
201                 ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
202         }
203
204         return cloned;
205 }
206
207 static const void *silk_get(const struct ast_format *format, const char *name)
208 {
209         struct silk_attr *attr = ast_format_get_attribute_data(format);
210         unsigned int *val;
211
212         if (!strcasecmp(name, "max_bitrate")) {
213                 val = &attr->maxbitrate;
214         } else if (!strcasecmp(name, "dtx")) {
215                 val = &attr->dtx;
216         } else if (!strcasecmp(name, "fec")) {
217                 val = &attr->fec;
218         } else if (!strcasecmp(name, "packetloss_percentage")) {
219                 val = &attr->packetloss_percentage;
220         } else {
221                 ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
222                 return NULL;
223         }
224
225         return val;
226 }
227
228 static struct ast_format_interface silk_interface = {
229         .format_destroy = silk_destroy,
230         .format_clone = silk_clone,
231         .format_cmp = silk_cmp,
232         .format_get_joint = silk_getjoint,
233         .format_attribute_set = silk_set,
234         .format_attribute_get = silk_get,
235         .format_parse_sdp_fmtp = silk_parse_sdp_fmtp,
236         .format_generate_sdp_fmtp = silk_generate_sdp_fmtp,
237 };
238
239 static int load_module(void)
240 {
241         if (ast_format_interface_register("silk", &silk_interface)) {
242                 return AST_MODULE_LOAD_DECLINE;
243         }
244
245         return AST_MODULE_LOAD_SUCCESS;
246 }
247
248 static int unload_module(void)
249 {
250         return 0;
251 }
252
253 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SILK Format Attribute Module",
254         .support_level = AST_MODULE_SUPPORT_CORE,
255         .load = load_module,
256         .unload = unload_module,
257         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
258 );