Asterisk - The Open Source Telephony Project GIT-master-7e7a603
res_format_attr_opus.c
Go to the documentation of this file.
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#include <ctype.h>
33
34#include "asterisk/module.h"
35#include "asterisk/format.h"
36#include "asterisk/astobj2.h"
37#include "asterisk/logger.h"
38#include "asterisk/strings.h"
39#include "asterisk/utils.h"
40#include "asterisk/opus.h"
41
42/*!
43 * \brief Opus attribute structure.
44 *
45 * \note http://tools.ietf.org/html/rfc7587#section-6
46 */
47struct opus_attr {
50 int ptime;
51 int stereo;
52 int cbr;
53 int fec;
54 int dtx;
58 /* Note data is expected to be an ao2_object type */
59 void *data;
60};
61
64 .maxplayrate = CODEC_OPUS_DEFAULT_SAMPLE_RATE,
70 .spropmaxcapturerate = CODEC_OPUS_DEFAULT_SAMPLE_RATE,
71 .spropstereo = CODEC_OPUS_DEFAULT_STEREO,
73};
74
75static void opus_destroy(struct ast_format *format)
76{
77 struct opus_attr *attr = ast_format_get_attribute_data(format);
78
79 if (!attr) {
80 return;
81 }
82
83 ao2_cleanup(attr->data);
84 ast_free(attr);
85}
86
87static int opus_clone(const struct ast_format *src, struct ast_format *dst)
88{
89 struct opus_attr *original = ast_format_get_attribute_data(src);
90 struct opus_attr *attr = ast_malloc(sizeof(*attr));
91
92 if (!attr) {
93 return -1;
94 }
95
96 *attr = original ? *original : default_opus_attr;
97 ao2_bump(attr->data);
98
101
102 return 0;
103}
104
105static void sdp_fmtp_get(const char *attributes, const char *name, int *attr)
106{
107 const char *kvp = attributes;
108 int val;
109
110 if (ast_strlen_zero(attributes)) {
111 return;
112 }
113
114 /* This logic goes through each attribute in the fmtp line looking for the
115 * requested named attribute.
116 */
117 while (*kvp) {
118 /* Skip any preceeding blanks as some implementations separate attributes using spaces too */
119 kvp = ast_skip_blanks(kvp);
120
121 /* If we are at the requested attribute get its value and return */
122 if (!strncmp(kvp, name, strlen(name)) && kvp[strlen(name)] == '=') {
123 if (sscanf(kvp, "%*[^=]=%30d", &val) == 1) {
124 *attr = val;
125 break;
126 }
127 }
128
129 /* Move on to the next attribute if possible */
130 kvp = strchr(kvp, ';');
131 if (!kvp) {
132 break;
133 }
134
135 kvp++;
136 }
137}
138
139static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
140{
141 char *attribs = ast_strdupa(attributes), *attrib;
142 struct ast_format *cloned;
143 struct opus_attr *attr;
144
145 cloned = ast_format_clone(format);
146 if (!cloned) {
147 return NULL;
148 }
149
150 attr = ast_format_get_attribute_data(cloned);
151
152 /* lower-case everything, so we are case-insensitive */
153 for (attrib = attribs; *attrib; ++attrib) {
154 *attrib = tolower(*attrib);
155 } /* based on channels/chan_sip.c:process_a_sdp_image() */
156
159 &attr->maxplayrate);
161 &attr->spropmaxcapturerate);
163 sdp_fmtp_get(attribs, CODEC_OPUS_ATTR_PTIME, &attr->ptime);
166 if (attr->stereo) {
168 }
170 sdp_fmtp_get(attribs, CODEC_OPUS_ATTR_CBR, &attr->cbr);
171 sdp_fmtp_get(attribs, CODEC_OPUS_ATTR_FEC, &attr->fec);
172 sdp_fmtp_get(attribs, CODEC_OPUS_ATTR_DTX, &attr->dtx);
173
174 return cloned;
175}
176
177static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
178{
179 struct opus_attr *attr = ast_format_get_attribute_data(format);
180 int base_fmtp_size;
181 int original_size;
182
183 if (!attr) {
184 /*
185 * (Only) cached formats do not have attribute data assigned because
186 * they were created before this attribute module was registered.
187 * Therefore, we assume the default attribute values here.
188 */
189 attr = &default_opus_attr;
190 }
191
192 original_size = ast_str_strlen(*str);
193 base_fmtp_size = ast_str_append(str, 0, "a=fmtp:%u ", payload);
194
196 ast_str_append(str, 0, "%s=%d;",
198 }
199
201 ast_str_append(str, 0, "%s=%d;",
203 }
204
205 if (CODEC_OPUS_DEFAULT_BITRATE != attr->maxbitrate || attr->maxbitrate > 0) {
206 ast_str_append(str, 0, "%s=%d;",
208 }
209
210 if (CODEC_OPUS_DEFAULT_STEREO != attr->stereo) {
211 ast_str_append(str, 0, "%s=%d;",
213 }
214
216 ast_str_append(str, 0, "%s=%d;",
218 }
219
220 if (CODEC_OPUS_DEFAULT_CBR != attr->cbr) {
221 ast_str_append(str, 0, "%s=%d;",
222 CODEC_OPUS_ATTR_CBR, attr->cbr);
223 }
224
225 if (CODEC_OPUS_DEFAULT_FEC!= attr->fec) {
226 ast_str_append(str, 0, "%s=%d;",
227 CODEC_OPUS_ATTR_FEC, attr->fec);
228 }
229
230 if (CODEC_OPUS_DEFAULT_DTX != attr->dtx) {
231 ast_str_append(str, 0, "%s=%d;",
232 CODEC_OPUS_ATTR_DTX, attr->dtx);
233 }
234
235 if (base_fmtp_size == ast_str_strlen(*str) - original_size) {
236 ast_str_truncate(*str, original_size);
237 } else {
238 ast_str_truncate(*str, -1);
239 ast_str_append(str, 0, "\r\n");
240 }
241}
242
243static struct ast_format *opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
244{
245 struct opus_attr *attr1 = ast_format_get_attribute_data(format1);
246 struct opus_attr *attr2 = ast_format_get_attribute_data(format2);
247 struct ast_format *jointformat;
248 struct opus_attr *attr_res;
249
250 if (!attr1) {
251 attr1 = &default_opus_attr;
252 }
253
254 if (!attr2) {
255 attr2 = &default_opus_attr;
256 }
257
258 jointformat = ast_format_clone(format1);
259 if (!jointformat) {
260 return NULL;
261 }
262
263 if (ast_format_get_channel_count(format1) == 2 || ast_format_get_channel_count(format2) == 2) {
264 ast_format_set_channel_count(jointformat, 2);
265 }
266 attr_res = ast_format_get_attribute_data(jointformat);
267
268 attr_res->dtx = attr1->dtx || attr2->dtx ? 1 : 0;
269
270 /* Only do FEC if both sides want it. If a peer specifically requests not
271 * to receive with FEC, it may be a waste of bandwidth. */
272 attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
273
274 attr_res->cbr = attr1->cbr || attr2->cbr ? 1 : 0;
275 attr_res->spropstereo = attr1->spropstereo || attr2->spropstereo ? 1 : 0;
276
277 /* Only do stereo if both sides want it. If a peer specifically requests not
278 * to receive stereo signals, it may be a waste of bandwidth. */
279 attr_res->stereo = attr1->stereo && attr2->stereo ? 1 : 0;
280
281 if (attr1->maxbitrate < 0) {
282 attr_res->maxbitrate = attr2->maxbitrate;
283 } else if (attr2->maxbitrate < 0) {
284 attr_res->maxbitrate = attr1->maxbitrate;
285 } else {
286 attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
287 }
288
290 attr_res->maxplayrate = MIN(attr1->maxplayrate, attr2->maxplayrate);
291
292 return jointformat;
293}
294
295static struct ast_format *opus_set(const struct ast_format *format,
296 const char *name, const char *value)
297{
298 struct ast_format *cloned;
299 struct opus_attr *attr;
300 int val;
301
302 if (!(cloned = ast_format_clone(format))) {
303 return NULL;
304 }
305
306 attr = ast_format_get_attribute_data(cloned);
307
308 if (!strcmp(name, CODEC_OPUS_ATTR_DATA)) {
309 ao2_cleanup(attr->data);
310 attr->data = ao2_bump((void*)value);
311 return cloned;
312 }
313
314 if (sscanf(value, "%30d", &val) != 1) {
315 ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
316 value, name);
317 ao2_ref(cloned, -1);
318 return NULL;
319 }
320
321 if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE)) {
322 attr->maxplayrate = val;
323 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_CODED_AUDIO_BANDWIDTH)) {
324 attr->maxplayrate = val;
325 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE)) {
326 attr->spropmaxcapturerate = val;
327 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PTIME)) {
328 attr->maxptime = val;
329 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_PTIME)) {
330 attr->ptime = val;
331 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE)) {
332 attr->maxbitrate = val;
333 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_STEREO)) {
334 attr->stereo = val;
335 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_STEREO)) {
336 attr->spropstereo = val;
337 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_CBR)) {
338 attr->cbr = val;
339 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_FEC)) {
340 attr->fec = val;
341 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_DTX)) {
342 attr->dtx = val;
343 } else {
344 ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
345 }
346
347 return cloned;
348}
349
350static const void *opus_get(const struct ast_format *format, const char *name)
351{
352 struct opus_attr *attr = ast_format_get_attribute_data(format);
353 int *val = NULL;
354
355 if (!attr) {
356 return NULL;
357 }
358
359 if (!strcasecmp(name, CODEC_OPUS_ATTR_DATA)) {
360 return ao2_bump(attr->data);
361 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE)) {
362 val = &attr->maxplayrate;
363 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE)) {
364 val = &attr->spropmaxcapturerate;
365 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_PTIME)) {
366 val = &attr->maxptime;
367 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_PTIME)) {
368 val = &attr->ptime;
369 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE)) {
370 val = &attr->maxbitrate;
371 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_STEREO)) {
372 val = &attr->stereo;
373 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_SPROP_STEREO)) {
374 val = &attr->spropstereo;
375 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_CBR)) {
376 val = &attr->cbr;
377 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_FEC)) {
378 val = &attr->fec;
379 } else if (!strcasecmp(name, CODEC_OPUS_ATTR_DTX)) {
380 val = &attr->dtx;
381 } else {
382 ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
383 }
384
385 return val;
386}
387
390 .format_clone = opus_clone,
391 .format_get_joint = opus_getjoint,
392 .format_attribute_set = opus_set,
393 .format_parse_sdp_fmtp = opus_parse_sdp_fmtp,
394 .format_generate_sdp_fmtp = opus_generate_sdp_fmtp,
395 .format_attribute_get = opus_get
396};
397
398static int load_module(void)
399{
402 }
403
405}
406
407static int unload_module(void)
408{
409 return 0;
410}
411
413 .support_level = AST_MODULE_SUPPORT_CORE,
414 .load = load_module,
415 .unload = unload_module,
416 .load_pri = AST_MODPRI_REALTIME_DRIVER /* Needs to load before codec_opus */
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Media Format API.
int __ast_format_interface_register(const char *codec, const struct ast_format_interface *interface, struct ast_module *mod)
Register a format interface for use with the provided codec.
Definition: format.c:90
void ast_format_set_channel_count(struct ast_format *format, unsigned int channel_count)
Set the channel count on a format.
Definition: format.c:140
void * ast_format_get_attribute_data(const struct ast_format *format)
Get the attribute data on a format.
Definition: format.c:125
void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data)
Set the attribute data on a format.
Definition: format.c:130
struct ast_format * ast_format_clone(const struct ast_format *format)
Clone an existing media format so it can be modified.
Definition: format.c:180
unsigned int ast_format_get_channel_count(const struct ast_format *format)
Get the channel count on a format.
Definition: format.c:135
static const char name[]
Definition: format_mp3.c:68
Support for logging to various files, console and syslog Configuration in file logger....
#define LOG_WARNING
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_REALTIME_DRIVER
Definition: module.h:323
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Codec opus externals and format attributes.
#define CODEC_OPUS_ATTR_CBR
Decoder prefers a constant (1) vs variable (0) bitrate.
Definition: opus.h:45
#define CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE
Maximum average received bit rate (in bits per second)
Definition: opus.h:39
#define CODEC_OPUS_ATTR_MAX_PLAYBACK_RATE
Maximum sampling rate an endpoint is capable of receiving.
Definition: opus.h:29
#define CODEC_OPUS_DEFAULT_SAMPLE_RATE
Default attribute values.
Definition: opus.h:54
#define CODEC_OPUS_ATTR_MAX_CODED_AUDIO_BANDWIDTH
An alias for maxplaybackrate (used in older versions)
Definition: opus.h:31
#define CODEC_OPUS_ATTR_DTX
Use discontinuous transmission (1) or not (0)
Definition: opus.h:49
#define CODEC_OPUS_DEFAULT_STEREO
Definition: opus.h:62
#define CODEC_OPUS_ATTR_STEREO
Decode stereo (1) vs mono (0)
Definition: opus.h:41
#define CODEC_OPUS_DEFAULT_BITRATE
Definition: opus.h:58
#define CODEC_OPUS_DEFAULT_FEC
Definition: opus.h:60
#define CODEC_OPUS_DEFAULT_DTX
Definition: opus.h:61
#define CODEC_OPUS_DEFAULT_MAX_PTIME
Definition: opus.h:56
#define CODEC_OPUS_DEFAULT_PTIME
Definition: opus.h:57
#define CODEC_OPUS_ATTR_SPROP_STEREO
Likeliness of sender producing stereo (1) vs mono (0)
Definition: opus.h:43
#define CODEC_OPUS_ATTR_SPROP_MAX_CAPTURE_RATE
Maximum sampling rate an endpoint is capable of sending.
Definition: opus.h:33
#define CODEC_OPUS_ATTR_FEC
Use forward error correction (1) or not (0)
Definition: opus.h:47
#define CODEC_OPUS_DEFAULT_CBR
Definition: opus.h:59
#define CODEC_OPUS_ATTR_PTIME
Duration of packet (in milliseconds)
Definition: opus.h:37
#define CODEC_OPUS_ATTR_MAX_PTIME
Maximum duration of packet (in milliseconds)
Definition: opus.h:35
#define CODEC_OPUS_ATTR_DATA
Custom data object.
Definition: opus.h:51
static void opus_destroy(struct ast_format *format)
static void opus_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
static struct ast_format * opus_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
static struct ast_format_interface opus_interface
static struct ast_format * opus_getjoint(const struct ast_format *format1, const struct ast_format *format2)
static struct ast_format * opus_set(const struct ast_format *format, const char *name, const char *value)
static const void * opus_get(const struct ast_format *format, const char *name)
static struct opus_attr default_opus_attr
static int opus_clone(const struct ast_format *src, struct ast_format *dst)
static int load_module(void)
static int unload_module(void)
static void sdp_fmtp_get(const char *attributes, const char *name, int *attr)
#define NULL
Definition: resample.c:96
String manipulation functions.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Optional format interface to extend format operations.
Definition: format.h:44
void(*const format_destroy)(struct ast_format *format)
Callback for when the format is destroyed, used to release attribute resources.
Definition: format.h:50
Definition of a media format.
Definition: format.c:43
struct ast_module * self
Definition: module.h:342
Support for dynamic strings.
Definition: strings.h:623
Opus attribute structure.
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
Utility functions.
#define MIN(a, b)
Definition: utils.h:231