Asterisk - The Open Source Telephony Project  18.5.0
res_format_attr_silk.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2011, Digium, Inc.
5  *
6  * David Vossel <[email protected]>
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 <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include <ctype.h> /* for tolower */
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 MAX, MIN */
39 
40 /*!
41  * \brief SILK attribute structure.
42  *
43  * \note The only attribute that affects compatibility here is the sample rate.
44  */
45 struct silk_attr {
46  unsigned int maxbitrate;
47  unsigned int dtx;
48  unsigned int fec;
49  unsigned int packetloss_percentage;
50 };
51 
52 static void silk_destroy(struct ast_format *format)
53 {
54  struct silk_attr *attr = ast_format_get_attribute_data(format);
55 
56  ast_free(attr);
57 }
58 
59 static void attr_init(struct silk_attr *attr)
60 {
61  memset(attr, 0, sizeof(*attr));
62 }
63 
64 static int silk_clone(const struct ast_format *src, struct ast_format *dst)
65 {
66  struct silk_attr *original = ast_format_get_attribute_data(src);
67  struct silk_attr *attr = ast_malloc(sizeof(*attr));
68 
69  if (!attr) {
70  return -1;
71  }
72 
73  if (original) {
74  *attr = *original;
75  } else {
76  attr_init(attr);
77  }
78 
80 
81  return 0;
82 }
83 
84 static struct ast_format *silk_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
85 {
86  char *attribs = ast_strdupa(attributes), *attrib;
87  struct ast_format *cloned;
88  struct silk_attr *attr;
89  unsigned int val;
90 
91  cloned = ast_format_clone(format);
92  if (!cloned) {
93  return NULL;
94  }
95  attr = ast_format_get_attribute_data(cloned);
96 
97  /* lower-case everything, so we are case-insensitive */
98  for (attrib = attribs; *attrib; ++attrib) {
99  *attrib = tolower(*attrib);
100  } /* based on channels/chan_sip.c:process_a_sdp_image() */
101 
102  if (sscanf(attribs, "maxaveragebitrate=%30u", &val) == 1) {
103  attr->maxbitrate = val;
104  }
105  if (sscanf(attribs, "usedtx=%30u", &val) == 1) {
106  attr->dtx = val;
107  }
108  if (sscanf(attribs, "useinbandfec=%30u", &val) == 1) {
109  attr->fec = val;
110  }
111 
112  return cloned;
113 }
114 
115 static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
116 {
117  struct silk_attr *attr = ast_format_get_attribute_data(format);
118 
119  if (!attr) {
120  return;
121  }
122 
123  if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) {
124  ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate);
125  }
126 
127  if (attr->dtx) {
128  ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx);
129  }
130  if (attr->fec) {
131  ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec);
132  }
133 }
134 
135 static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2)
136 {
137  if (ast_format_get_sample_rate(format1) == ast_format_get_sample_rate(format2)) {
138  return AST_FORMAT_CMP_EQUAL;
139  }
140 
142 }
143 
144 static struct ast_format *silk_getjoint(const struct ast_format *format1, const struct ast_format *format2)
145 {
146  struct silk_attr *attr1 = ast_format_get_attribute_data(format1);
147  struct silk_attr *attr2 = ast_format_get_attribute_data(format2);
148  struct ast_format *jointformat;
149  struct silk_attr *attr_res;
150 
151  if (ast_format_get_sample_rate(format1) != ast_format_get_sample_rate(format2)) {
152  return NULL;
153  }
154 
155  jointformat = ast_format_clone(format1);
156  if (!jointformat) {
157  return NULL;
158  }
159  attr_res = ast_format_get_attribute_data(jointformat);
160 
161  if (!attr1 || !attr2) {
162  attr_init(attr_res);
163  } else {
164  /* Take the lowest max bitrate */
165  attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate);
166 
167  /* Only do dtx if both sides want it. DTX is a trade off between
168  * computational complexity and bandwidth. */
169  attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0;
170 
171  /* Only do FEC if both sides want it. If a peer specifically requests not
172  * to receive with FEC, it may be a waste of bandwidth. */
173  attr_res->fec = attr1->fec && attr2->fec ? 1 : 0;
174 
175  /* Use the maximum packetloss percentage between the two attributes. This affects how
176  * much redundancy is used in the FEC. */
178  }
179 
180  return jointformat;
181 }
182 
183 static struct ast_format *silk_set(const struct ast_format *format, const char *name, const char *value)
184 {
185  struct ast_format *cloned;
186  struct silk_attr *attr;
187  unsigned int val;
188 
189  if (sscanf(value, "%30u", &val) != 1) {
190  ast_log(LOG_WARNING, "Unknown value '%s' for attribute type '%s'\n",
191  value, name);
192  return NULL;
193  }
194 
195  cloned = ast_format_clone(format);
196  if (!cloned) {
197  return NULL;
198  }
199  attr = ast_format_get_attribute_data(cloned);
200 
201  if (!strcasecmp(name, "max_bitrate")) {
202  attr->maxbitrate = val;
203  } else if (!strcasecmp(name, "dtx")) {
204  attr->dtx = val;
205  } else if (!strcasecmp(name, "fec")) {
206  attr->fec = val;
207  } else if (!strcasecmp(name, "packetloss_percentage")) {
208  attr->packetloss_percentage = val;
209  } else {
210  ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
211  }
212 
213  return cloned;
214 }
215 
216 static const void *silk_get(const struct ast_format *format, const char *name)
217 {
218  struct silk_attr *attr = ast_format_get_attribute_data(format);
219  unsigned int *val;
220 
221  if (!strcasecmp(name, "max_bitrate")) {
222  val = &attr->maxbitrate;
223  } else if (!strcasecmp(name, "dtx")) {
224  val = &attr->dtx;
225  } else if (!strcasecmp(name, "fec")) {
226  val = &attr->fec;
227  } else if (!strcasecmp(name, "packetloss_percentage")) {
228  val = &attr->packetloss_percentage;
229  } else {
230  ast_log(LOG_WARNING, "unknown attribute type %s\n", name);
231  return NULL;
232  }
233 
234  return val;
235 }
236 
239  .format_clone = silk_clone,
240  .format_cmp = silk_cmp,
241  .format_get_joint = silk_getjoint,
242  .format_attribute_set = silk_set,
243  .format_attribute_get = silk_get,
244  .format_parse_sdp_fmtp = silk_parse_sdp_fmtp,
245  .format_generate_sdp_fmtp = silk_generate_sdp_fmtp,
246 };
247 
248 static int load_module(void)
249 {
250  if (ast_format_interface_register("silk", &silk_interface)) {
252  }
253 
255 }
256 
257 static int unload_module(void)
258 {
259  return 0;
260 }
261 
262 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SILK Format Attribute Module",
263  .support_level = AST_MODULE_SUPPORT_CORE,
264  .load = load_module,
265  .unload = unload_module,
266  .load_pri = AST_MODPRI_CHANNEL_DEPEND,
267 );
Asterisk main include file. File version handling, generic pbx functions.
Optional format interface to extend format operations.
Definition: format.h:44
static struct ast_format_interface silk_interface
String manipulation functions.
Definition: ast_expr2.c:325
static int unload_module(void)
#define LOG_WARNING
Definition: logger.h:274
static int silk_clone(const struct ast_format *src, struct ast_format *dst)
Definition of a media format.
Definition: format.c:43
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:1091
SILK attribute structure.
void * ast_format_get_attribute_data(const struct ast_format *format)
Get the attribute data on a format.
Definition: format.c:125
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
Utility functions.
Media Format API.
static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2)
#define MIN(a, b)
Definition: utils.h:226
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 packetloss_percentage
static struct ast_format * silk_getjoint(const struct ast_format *format1, const struct ast_format *format2)
#define ast_log
Definition: astobj2.c:42
#define MAX(a, b)
Definition: utils.h:228
void(*const format_destroy)(struct ast_format *format)
Callback for when the format is destroyed, used to release attribute resources.
Definition: format.h:50
static struct ast_format * silk_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
ast_format_cmp_res
Format comparison results.
Definition: format.h:34
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static void silk_destroy(struct ast_format *format)
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
static struct ast_format * silk_set(const struct ast_format *format, const char *name, const char *value)
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static void attr_init(struct silk_attr *attr)
#define ast_format_interface_register(codec, interface)
Register a format interface for use with the provided codec.
Definition: format.h:273
unsigned int fec
unsigned int maxbitrate
unsigned int dtx
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
static int load_module(void)
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Support for logging to various files, console and syslog Configuration in file logger.conf.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data)
Set the attribute data on a format.
Definition: format.c:130
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
static const void * silk_get(const struct ast_format *format, const char *name)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static snd_pcm_format_t format
Definition: chan_alsa.c:102
static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)