Asterisk - The Open Source Telephony Project  18.5.0
codec.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Digium, Inc.
5  *
6  * Joshua Colp <[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 /*! \file
20  *
21  * \brief Codecs API
22  *
23  * \author Joshua Colp <[email protected]>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 #include "asterisk/logger.h"
33 #include "asterisk/codec.h"
34 #include "asterisk/format.h"
35 #include "asterisk/frame.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/strings.h"
38 #include "asterisk/module.h"
39 #include "asterisk/cli.h"
40 
41 /*! \brief Number of buckets to use for codecs (should be prime for performance reasons) */
42 #define CODEC_BUCKETS 53
43 
44 /*! \brief Current identifier value for newly registered codec */
45 static int codec_id = 1;
46 
47 /*! \brief Registered codecs */
48 static struct ao2_container *codecs;
49 
50 /*!
51  * \internal
52  * \brief Internal codec structure
53  *
54  * External codecs won't know about the format_name field so the public
55  * ast_codec structure has to leave it out. This structure will be used
56  * for the internal codecs.
57  *
58  */
60  /*! \brief Public codec structure. Must remain first. */
62  /*! \brief A format name for a default sane format using this codec */
63  const char *format_name;
64 };
65 
66 /*!
67  * \internal
68  * \brief Internal function for registration with format name
69  *
70  * This function is only used by codec.c and codec_builtin.c and
71  * will be removed in Asterisk 14
72  */
73 int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name,
74  struct ast_module *mod);
75 
77 
78 static int codec_cmp(void *obj, void *arg, int flags)
79 {
80  const struct ast_codec *left = obj;
81  const struct ast_codec *right = arg;
82  const char *right_key = arg;
83  int cmp;
84 
85  switch (flags & OBJ_SEARCH_MASK) {
86  case OBJ_SEARCH_OBJECT:
87  right_key = right->name;
88  cmp = strcmp(left->name, right_key);
89 
90  if (right->type != AST_MEDIA_TYPE_UNKNOWN) {
91  cmp |= (right->type != left->type);
92  }
93 
94  /* BUGBUG: this will allow a match on a codec by name only.
95  * This is particularly useful when executed by the CLI; if
96  * that is not needed in translate.c, this can be removed.
97  */
98  if (right->sample_rate) {
99  cmp |= (right->sample_rate != left->sample_rate);
100  }
101  break;
102  case OBJ_SEARCH_KEY:
103  cmp = strcmp(left->name, right_key);
104  break;
106  cmp = strncmp(left->name, right_key, strlen(right_key));
107  break;
108  default:
109  ast_assert(0);
110  cmp = 0;
111  break;
112  }
113  if (cmp) {
114  return 0;
115  }
116 
117  return CMP_MATCH;
118 }
119 
120 static char *show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
121 {
122  struct ao2_iterator i;
123  struct internal_ast_codec *codec;
124 
125  switch (cmd) {
126  case CLI_INIT:
127  e->command = "core show codecs [audio|video|image|text]";
128  e->usage =
129  "Usage: core show codecs [audio|video|image|text]\n"
130  " Displays codec mapping\n";
131  return NULL;
132  case CLI_GENERATE:
133  return NULL;
134  }
135 
136  if ((a->argc < 3) || (a->argc > 4)) {
137  return CLI_SHOWUSAGE;
138  }
139 
140  if (!ast_opt_dont_warn) {
141  ast_cli(a->fd, "Disclaimer: this command is for informational purposes only.\n"
142  "\tIt does not indicate anything about your configuration.\n");
143  }
144 
145  ast_cli(a->fd, "%8s %-5s %-12s %-16s %s\n","ID","TYPE","NAME","FORMAT","DESCRIPTION");
146  ast_cli(a->fd, "------------------------------------------------------------------------------------------------\n");
147 
148  ao2_rdlock(codecs);
150 
151  for (; (codec = ao2_iterator_next(&i)); ao2_ref(codec, -1)) {
152  if (a->argc == 4) {
153  if (!strcasecmp(a->argv[3], "audio")) {
154  if (codec->external.type != AST_MEDIA_TYPE_AUDIO) {
155  continue;
156  }
157  } else if (!strcasecmp(a->argv[3], "video")) {
158  if (codec->external.type != AST_MEDIA_TYPE_VIDEO) {
159  continue;
160  }
161  } else if (!strcasecmp(a->argv[3], "image")) {
162  if (codec->external.type != AST_MEDIA_TYPE_IMAGE) {
163  continue;
164  }
165  } else if (!strcasecmp(a->argv[3], "text")) {
166  if (codec->external.type != AST_MEDIA_TYPE_TEXT) {
167  continue;
168  }
169  } else {
170  continue;
171  }
172  }
173 
174  ast_cli(a->fd, "%8u %-5s %-12s %-16s (%s)\n",
175  codec->external.id,
177  codec->external.name,
178  S_OR(codec->format_name, "no cached format"),
179  codec->external.description);
180  }
181 
183  ao2_unlock(codecs);
184 
185  return CLI_SUCCESS;
186 }
187 
188 /*! \brief Callback function for getting a codec based on unique identifier */
189 static int codec_id_cmp(void *obj, void *arg, int flags)
190 {
191  struct ast_codec *codec = obj;
192  int *id = arg;
193 
194  return (codec->id == *id) ? CMP_MATCH | CMP_STOP : 0;
195 }
196 
197 static char *show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
198 {
199  int type_punned_codec;
200  struct internal_ast_codec *codec;
201 
202  switch (cmd) {
203  case CLI_INIT:
204  e->command = "core show codec";
205  e->usage =
206  "Usage: core show codec <number>\n"
207  " Displays codec mapping\n";
208  return NULL;
209  case CLI_GENERATE:
210  return NULL;
211  }
212 
213  if (a->argc != 4) {
214  return CLI_SHOWUSAGE;
215  }
216 
217  if (sscanf(a->argv[3], "%30d", &type_punned_codec) != 1) {
218  return CLI_SHOWUSAGE;
219  }
220 
221  codec = ao2_callback(codecs, 0, codec_id_cmp, &type_punned_codec);
222  if (!codec) {
223  ast_cli(a->fd, "Codec %d not found\n", type_punned_codec);
224  return CLI_SUCCESS;
225  }
226 
227  ast_cli(a->fd, "%11u %s (%s)\n", (unsigned int) codec->external.id, codec->external.description,
228  S_OR(codec->format_name, "no format"));
229 
230  ao2_ref(codec, -1);
231 
232  return CLI_SUCCESS;
233 }
234 
235 /* Builtin Asterisk CLI-commands for debugging */
236 static struct ast_cli_entry codec_cli[] = {
237  AST_CLI_DEFINE(show_codecs, "Displays a list of registered codecs"),
238  AST_CLI_DEFINE(show_codec, "Shows a specific codec"),
239 };
240 
241 /*! \brief Function called when the process is shutting down */
242 static void codec_shutdown(void)
243 {
244  ast_cli_unregister_multiple(codec_cli, ARRAY_LEN(codec_cli));
245  ao2_cleanup(codecs);
246  codecs = NULL;
247 }
248 
249 int ast_codec_init(void)
250 {
252  ast_codec_hash_fn, NULL, codec_cmp);
253  if (!codecs) {
254  return -1;
255  }
256 
257  ast_cli_register_multiple(codec_cli, ARRAY_LEN(codec_cli));
259 
260  return 0;
261 }
262 
263 static void codec_dtor(void *obj)
264 {
265  struct ast_codec *codec;
266 
267  codec = obj;
268 
269  ast_module_unref(codec->mod);
270 }
271 
272 int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod)
273 {
274  return __ast_codec_register_with_format(codec, NULL, mod);
275 }
276 
277 int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name, struct ast_module *mod)
278 {
279  SCOPED_AO2WRLOCK(lock, codecs);
280  struct internal_ast_codec *codec_new;
281 
282  /* Some types have specific requirements */
283  if (codec->type == AST_MEDIA_TYPE_UNKNOWN) {
284  ast_log(LOG_ERROR, "A media type must be specified for codec '%s'\n", codec->name);
285  return -1;
286  } else if (codec->type == AST_MEDIA_TYPE_AUDIO) {
287  if (!codec->sample_rate) {
288  ast_log(LOG_ERROR, "A sample rate must be specified for codec '%s' of type '%s'\n",
289  codec->name, ast_codec_media_type2str(codec->type));
290  return -1;
291  }
292  }
293 
294  codec_new = ao2_find(codecs, codec, OBJ_SEARCH_OBJECT | OBJ_NOLOCK);
295  if (codec_new) {
296  ast_log(LOG_ERROR, "A codec with name '%s' of type '%s' and sample rate '%u' is already registered\n",
297  codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate);
298  ao2_ref(codec_new, -1);
299  return -1;
300  }
301 
302  codec_new = ao2_t_alloc_options(sizeof(*codec_new), codec_dtor,
304  if (!codec_new) {
305  ast_log(LOG_ERROR, "Could not allocate a codec with name '%s' of type '%s' and sample rate '%u'\n",
306  codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate);
307  return -1;
308  }
309  codec_new->external = *codec;
310  codec_new->format_name = format_name;
311  codec_new->external.id = codec_id++;
312 
313  ao2_link_flags(codecs, codec_new, OBJ_NOLOCK);
314 
315  /* Once registered a codec can not be unregistered, and the module must persist until shutdown */
317 
318  ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n",
319  ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->external.id);
320 
321  ao2_ref(codec_new, -1);
322 
323  return 0;
324 }
325 
326 struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate)
327 {
328  struct ast_codec codec = {
329  .name = name,
330  .type = type,
331  .sample_rate = sample_rate,
332  };
333 
334  return ao2_find(codecs, &codec, OBJ_SEARCH_OBJECT);
335 }
336 
338 {
339  return ao2_callback(codecs, 0, codec_id_cmp, &id);
340 }
341 
343 {
344  return codec_id;
345 }
346 
348 {
349  switch (type) {
351  return "audio";
353  return "video";
355  return "image";
356  case AST_MEDIA_TYPE_TEXT:
357  return "text";
358  default:
359  return "<unknown>";
360  }
361 }
362 
363 enum ast_media_type ast_media_type_from_str(const char *media_type_str)
364 {
365  if (!strcasecmp(media_type_str, "audio")) {
366  return AST_MEDIA_TYPE_AUDIO;
367  } else if (!strcasecmp(media_type_str, "video")) {
368  return AST_MEDIA_TYPE_VIDEO;
369  } else if (!strcasecmp(media_type_str, "image")) {
370  return AST_MEDIA_TYPE_IMAGE;
371  } else if (!strcasecmp(media_type_str, "text")) {
372  return AST_MEDIA_TYPE_TEXT;
373  } else {
374  return AST_MEDIA_TYPE_UNKNOWN;
375  }
376 }
377 
378 unsigned int ast_codec_samples_count(struct ast_frame *frame)
379 {
380  struct ast_codec *codec;
381  unsigned int samples = 0;
382 
383  if ((frame->frametype != AST_FRAME_VOICE) &&
384  (frame->frametype != AST_FRAME_VIDEO) &&
385  (frame->frametype != AST_FRAME_IMAGE)) {
386  return 0;
387  }
388 
389  codec = ast_format_get_codec(frame->subclass.format);
390 
391  if (codec->samples_count) {
392  samples = codec->samples_count(frame);
393  if ((int) samples < 0) {
394  ast_log(LOG_WARNING, "Codec %s returned invalid number of samples.\n",
396  samples = 0;
397  }
398  } else {
399  ast_log(LOG_WARNING, "Unable to calculate samples for codec %s\n",
401  }
402 
403  ao2_ref(codec, -1);
404  return samples;
405 }
406 
407 unsigned int ast_codec_determine_length(const struct ast_codec *codec, unsigned int samples)
408 {
409  if (!codec->get_length) {
410  return 0;
411  }
412 
413  return codec->get_length(samples);
414 }
static const char type[]
Definition: chan_ooh323.c:109
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
const char * name
Name for this codec.
Definition: codec.h:46
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:347
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
struct ast_codec * ast_format_get_codec(const struct ast_format *format)
Get the codec associated with a format.
Definition: format.c:324
String manipulation functions.
#define AO2_STRING_FIELD_HASH_FN(stype, field)
Creates a hash function for a structure string field.
Definition: astobj2.h:2055
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
unsigned int id
Internal unique identifier for this codec, set at registration time (starts at 1) ...
Definition: codec.h:44
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
enum ast_media_type ast_media_type_from_str(const char *media_type_str)
Conversion function to take a media string and convert it to a media type.
Definition: codec.c:363
static struct ast_cli_entry codec_cli[]
Definition: codec.c:236
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
struct ast_codec external
Public codec structure. Must remain first.
Definition: codec.c:61
Definition: cli.h:152
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
Codec API.
int __ast_codec_register(struct ast_codec *codec, struct ast_module *mod)
This function is used to register a codec with the Asterisk core. Registering allows it to be passed ...
Definition: codec.c:272
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_assert(a)
Definition: utils.h:695
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
struct ast_codec * ast_codec_get_by_id(int id)
Retrieve a codec given the unique identifier.
Definition: codec.c:337
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:404
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
struct ast_module * mod
The module that registered this codec.
Definition: codec.h:82
#define ast_verb(level,...)
Definition: logger.h:463
static void codec_dtor(void *obj)
Definition: codec.c:263
#define SCOPED_AO2WRLOCK(varname, obj)
scoped lock specialization for ao2 write locks.
Definition: lock.h:612
struct ast_frame_subclass subclass
Media Format API.
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
unsigned int ast_codec_samples_count(struct ast_frame *frame)
Get the number of samples contained within a frame.
Definition: codec.c:378
static int codec_id_cmp(void *obj, void *arg, int flags)
Callback function for getting a codec based on unique identifier.
Definition: codec.c:189
#define ast_opt_dont_warn
Definition: options.h:125
#define ast_log
Definition: astobj2.c:42
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
const int fd
Definition: cli.h:159
static struct ao2_container * codecs
Registered codecs.
Definition: codec.c:48
ast_mutex_t lock
Definition: app_meetme.c:1091
Asterisk internal frame definitions.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int ast_codec_get_max(void)
Retrieve the current maximum identifier for codec iteration.
Definition: codec.c:342
const char *const * argv
Definition: cli.h:161
unsigned int ast_codec_determine_length(const struct ast_codec *codec, unsigned int samples)
Get the length of media (in milliseconds) given a number of samples.
Definition: codec.c:407
int ast_codec_init(void)
Initialize codec support within the core.
Definition: codec.c:249
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
const char * description
Brief description.
Definition: codec.h:48
int __ast_codec_register_with_format(struct ast_codec *codec, const char *format_name, struct ast_module *mod)
Definition: codec.c:277
static void codec_shutdown(void)
Function called when the process is shutting down.
Definition: codec.c:242
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
#define ao2_rdlock(a)
Definition: astobj2.h:719
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
int(* get_length)(unsigned int samples)
Retrieve the length of media from number of samples.
Definition: codec.h:76
static const char name[]
Definition: cdr_mysql.c:74
char * command
Definition: cli.h:186
static int codec_id
Current identifier value for newly registered codec.
Definition: codec.c:45
struct ast_codec * ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate)
Retrieve a codec given a name, type, and sample rate.
Definition: codec.c:326
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
const char * format_name
A format name for a default sane format using this codec.
Definition: codec.c:63
unsigned int sample_rate
Sample rate (number of samples carried in a second)
Definition: codec.h:52
static int codec_cmp(void *obj, void *arg, int flags)
Definition: codec.c:78
Support for logging to various files, console and syslog Configuration in file logger.conf.
const char * usage
Definition: cli.h:177
#define CODEC_BUCKETS
Number of buckets to use for codecs (should be prime for performance reasons)
Definition: codec.c:42
#define CLI_SUCCESS
Definition: cli.h:44
Assume that the ao2_container is already locked.
Definition: astobj2.h:1872
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Standard Command Line Interface.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static char * show_codecs(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: codec.c:120
int(* samples_count)(struct ast_frame *frame)
Retrieve the number of samples in a frame.
Definition: codec.h:68
Data structure associated with a single frame of data.
enum ast_media_type type
Type of media this codec contains.
Definition: codec.h:50
ast_media_type
Types of media.
Definition: codec.h:30
enum ast_frame_type frametype
Generic container type.
Search option field mask.
Definition: astobj2.h:1076
struct ast_format * format
Asterisk module definitions.
static char * show_codec(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: codec.c:197
Represents a media codec within Asterisk.
Definition: codec.h:42
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static struct test_val a