Asterisk - The Open Source Telephony Project  18.5.0
sounds.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  * Kinsey Moore <[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  * \brief Sound file format and description index.
21  */
22 
23 #include "asterisk.h"
24 
25 #include <dirent.h>
26 #include <sys/stat.h>
27 
28 #include "asterisk/utils.h"
29 #include "asterisk/lock.h"
30 #include "asterisk/format.h"
31 #include "asterisk/format_cap.h"
32 #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
33 #include "asterisk/media_index.h"
34 #include "asterisk/sounds_index.h"
35 #include "asterisk/file.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/module.h"
39 #include "asterisk/stasis_system.h"
40 
41 /*** MODULEINFO
42  <support_level>core</support_level>
43  ***/
44 
45 /*! \brief The number of buckets to be used for storing language-keyed objects */
46 #define LANGUAGE_BUCKETS 7
47 
48 /*! \brief Get the languages in which sound files are available */
49 static struct ao2_container *get_languages(void)
50 {
51  RAII_VAR(struct ao2_container *, lang_dirs, NULL, ao2_cleanup);
52  struct dirent* dent;
53  DIR* srcdir;
54  RAII_VAR(struct ast_str *, media_dir, ast_str_create(64), ast_free);
55  RAII_VAR(struct ast_str *, variant_dir, ast_str_create(64), ast_free);
56 
58  if (!media_dir || !lang_dirs) {
59  return NULL;
60  }
61 
62  ast_str_set(&media_dir, 0, "%s/sounds", ast_config_AST_DATA_DIR);
63 
64  srcdir = opendir(ast_str_buffer(media_dir));
65 
66  if (srcdir == NULL) {
67  ast_log(LOG_ERROR, "Failed to open %s\n", ast_str_buffer(media_dir));
68  return NULL;
69  }
70 
71  while((dent = readdir(srcdir)) != NULL) {
72  struct stat st;
73 
74  if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
75  continue;
76  }
77 
78  ast_str_reset(variant_dir);
79  ast_str_set(&variant_dir, 0, "%s/%s", ast_str_buffer(media_dir), dent->d_name);
80 
81  if (stat(ast_str_buffer(variant_dir), &st) < 0) {
82  ast_log(LOG_ERROR, "Failed to stat %s\n", ast_str_buffer(variant_dir));
83  continue;
84  }
85 
86  if (S_ISDIR(st.st_mode)) {
87  ast_str_container_add(lang_dirs, dent->d_name);
88  }
89  }
90 
91  closedir(srcdir);
92  ao2_ref(lang_dirs, +1);
93  return lang_dirs;
94 }
95 
96 static int show_sounds_cb(void *obj, void *arg, int flags)
97 {
98  char *name = obj;
99  struct ast_cli_args *a = arg;
100  ast_cli(a->fd, "%s\n", name);
101  return 0;
102 }
103 
104 static int show_sound_info_cb(void *obj, void *arg, void *data, int flags)
105 {
106  char *language = obj;
107  struct ast_cli_args *a = arg;
108  struct ast_format *format;
109  int formats_shown = 0;
110  struct ast_media_index *local_index = data;
111  struct ast_format_cap *cap;
112  const char *description = ast_media_get_description(local_index, a->argv[3], language);
113 
114  ast_cli(a->fd, " Language %s:\n", language);
115  if (!ast_strlen_zero(description)) {
116  ast_cli(a->fd, " Description: %s\n", description);
117  }
118 
119  cap = ast_media_get_format_cap(local_index, a->argv[3], language);
120  if (cap) {
121  int x;
122  for (x = 0; x < ast_format_cap_count(cap); x++) {
123  format = ast_format_cap_get_format(cap, x);
124  ast_cli(a->fd, " Format: %s\n", ast_format_get_name(format));
125  ao2_ref(format, -1);
126  formats_shown = 1;
127  }
128  ao2_ref(cap, -1);
129  }
130 
131  if (!formats_shown) {
132  ast_cli(a->fd, " No Formats Available\n");
133  }
134 
135  return 0;
136 }
137 
138 static int sound_sorter(const void *obj_left, const void *obj_right, int flags)
139 {
140  return strcmp(obj_left, obj_right);
141 }
142 
143 /*! \brief Show a list of sounds available on the system */
144 static char *handle_cli_sounds_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
145 {
146  switch (cmd) {
147  case CLI_INIT:
148  e->command = "core show sounds";
149  e->usage =
150  "Usage: core show sounds\n"
151  " Shows a listing of sound files available on the system.\n";
152  return NULL;
153  case CLI_GENERATE:
154  return NULL;
155  }
156 
157  if (a->argc == 3) {
158  struct ast_media_index *sounds_index = ast_sounds_get_index();
159  struct ao2_container *sound_files;
160  struct ao2_container *sorted;
161 
162  if (!sounds_index) {
163  return CLI_FAILURE;
164  }
165 
166  sound_files = ast_media_get_media(sounds_index);
167  ao2_ref(sounds_index, -1);
168  if (!sound_files) {
169  return CLI_FAILURE;
170  }
171 
173  sound_sorter, NULL);
174  if (!sorted
175  || ao2_container_dup(sorted, sound_files, 0)) {
176  ao2_cleanup(sorted);
177  ao2_cleanup(sound_files);
178  return CLI_FAILURE;
179  }
180 
181  ast_cli(a->fd, "Available audio files:\n");
183  ao2_ref(sorted, -1);
184  ao2_ref(sound_files, -1);
185 
186  return CLI_SUCCESS;
187  }
188 
189  return CLI_SHOWUSAGE;
190 }
191 
192 /*! \brief Show details about a sound available in the system */
193 static char *handle_cli_sound_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
194 {
195  int length;
196  struct ao2_iterator it_sounds;
197  char *filename;
198  struct ast_media_index *sounds_index;
199  struct ao2_container *sound_files;
200 
201  switch (cmd) {
202  case CLI_INIT:
203  e->command = "core show sound";
204  e->usage =
205  "Usage: core show sound [soundid]\n"
206  " Shows information about the specified sound.\n";
207  return NULL;
208  case CLI_GENERATE:
209  if (a->pos != 3) {
210  return NULL;
211  }
212 
213  sounds_index = ast_sounds_get_index();
214  if (!sounds_index) {
215  return NULL;
216  }
217 
218  sound_files = ast_media_get_media(sounds_index);
219  ao2_ref(sounds_index, -1);
220  if (!sound_files) {
221  return NULL;
222  }
223 
224  length = strlen(a->word);
225  it_sounds = ao2_iterator_init(sound_files, 0);
226  while ((filename = ao2_iterator_next(&it_sounds))) {
227  if (!strncasecmp(a->word, filename, length)) {
228  if (ast_cli_completion_add(ast_strdup(filename))) {
229  ao2_ref(filename, -1);
230  break;
231  }
232  }
233  ao2_ref(filename, -1);
234  }
235  ao2_iterator_destroy(&it_sounds);
236  ao2_ref(sound_files, -1);
237 
238  return NULL;
239  }
240 
241  if (a->argc == 4) {
242  struct ao2_container *variants;
243 
244  sounds_index = ast_sounds_get_index_for_file(a->argv[3]);
245  if (!sounds_index) {
246  return NULL;
247  }
248 
249  variants = ast_media_get_variants(sounds_index, a->argv[3]);
250 
251  if (!variants || !ao2_container_count(variants)) {
252  ao2_ref(sounds_index, -1);
253  ao2_cleanup(variants);
254  ast_cli(a->fd, "ERROR: File %s not found in index\n", a->argv[3]);
255  return CLI_FAILURE;
256  }
257 
258  ast_cli(a->fd, "Indexed Information for %s:\n", a->argv[3]);
259  ao2_callback_data(variants, OBJ_MULTIPLE | OBJ_NODATA, show_sound_info_cb, a, sounds_index);
260  ao2_ref(sounds_index, -1);
261  ao2_ref(variants, -1);
262 
263  return CLI_SUCCESS;
264  }
265 
266  return CLI_SHOWUSAGE;
267 }
268 
269 /*! \brief Struct for registering CLI commands */
270 static struct ast_cli_entry cli_sounds[] = {
271  AST_CLI_DEFINE(handle_cli_sounds_show, "Shows available sounds"),
272  AST_CLI_DEFINE(handle_cli_sound_show, "Shows details about a specific sound"),
273 };
274 
275 static int unload_module(void)
276 {
277  ast_cli_unregister_multiple(cli_sounds, ARRAY_LEN(cli_sounds));
278 
279  return 0;
280 }
281 
282 static int load_module(void)
283 {
284  int res;
285 
286  res = ast_cli_register_multiple(cli_sounds, ARRAY_LEN(cli_sounds));
287  if (res) {
289  }
290 
292 }
293 
294 /*! \brief Callback to process an individual language directory or subdirectory */
295 static int update_index_cb(void *obj, void *arg, void *data, int flags)
296 {
297  char *lang = obj;
298  char *filename = data;
299  struct ast_media_index *index = arg;
300 
301  if (ast_media_index_update_for_file(index, lang, filename)) {
302  return CMP_MATCH;
303  }
304 
305  return 0;
306 }
307 
309 {
311 }
312 
313 struct ast_media_index *ast_sounds_get_index_for_file(const char *filename)
314 {
315  struct ast_str *sounds_dir = ast_str_create(64);
316  struct ao2_container *languages;
317  char *failed_index;
318  struct ast_media_index *new_index;
319 
320  if (!sounds_dir) {
321  return NULL;
322  }
323 
324  ast_str_set(&sounds_dir, 0, "%s/sounds", ast_config_AST_DATA_DIR);
325  new_index = ast_media_index_create(ast_str_buffer(sounds_dir));
326  ast_free(sounds_dir);
327  if (!new_index) {
328  return NULL;
329  }
330 
331  languages = get_languages();
332  if (!languages) {
333  ao2_ref(new_index, -1);
334  return NULL;
335  }
336 
337  failed_index = ao2_callback_data(languages, 0, update_index_cb, new_index, (void *)filename);
338  ao2_ref(languages, -1);
339  if (failed_index) {
340  ao2_ref(failed_index, -1);
341  ao2_ref(new_index, -1);
342  new_index = NULL;
343  }
344 
345  return new_index;
346 }
347 
349  .support_level = AST_MODULE_SUPPORT_CORE,
350  .load = load_module,
351  .unload = unload_module,
352  /* Load after the format modules to reduce processing during startup. */
353  .load_pri = AST_MODPRI_APP_DEPEND + 1,
354 );
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static char * handle_cli_sounds_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Show a list of sounds available on the system.
Definition: sounds.c:144
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
const char * ast_media_get_description(struct ast_media_index *index, const char *filename, const char *variant)
Get the description for a media file.
Definition: media_index.c:230
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static int update_index_cb(void *obj, void *arg, void *data, int flags)
Callback to process an individual language directory or subdirectory.
Definition: sounds.c:295
struct ast_media_index * ast_sounds_get_index_for_file(const char *filename)
Get the index for a specific sound file.
Definition: sounds.c:313
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1312
Definition: cli.h:152
Definition of a media format.
Definition: format.c:43
#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.
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition: format_cap.c:395
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
struct ao2_container * ast_media_get_media(struct ast_media_index *index)
Get the a container of all media available on the system.
Definition: media_index.c:307
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static int show_sounds_cb(void *obj, void *arg, int flags)
Definition: sounds.c:96
Utility functions.
Media Format API.
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ast_log
Definition: astobj2.c:42
Asterisk file paths, configured in asterisk.conf.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static int unload_module(void)
Definition: sounds.c:275
const int fd
Definition: cli.h:159
#define LANGUAGE_BUCKETS
The number of buckets to be used for storing language-keyed objects.
Definition: sounds.c:46
static struct ao2_container * get_languages(void)
Get the languages in which sound files are available.
Definition: sounds.c:49
struct ao2_container * ast_media_get_variants(struct ast_media_index *index, const char *filename)
Get the languages in which a media file is available.
Definition: media_index.c:274
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:117
Format Capabilities API.
const char *const * argv
Definition: cli.h:161
int ast_media_index_update_for_file(struct ast_media_index *index, const char *variant, const char *filename)
Update a media index for a specific sound file.
Definition: media_index.c:587
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
static char * handle_cli_sound_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Show details about a sound available in the system.
Definition: sounds.c:193
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Sound file format and description indexer.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1743
static int show_sound_info_cb(void *obj, void *arg, void *data, int flags)
Definition: sounds.c:104
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
struct ast_media_index * ast_media_index_create(const char *base_dir)
Creates a new media index.
Definition: media_index.c:162
#define CLI_FAILURE
Definition: cli.h:46
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static int sound_sorter(const void *obj_left, const void *obj_right, int flags)
Definition: sounds.c:138
const char * word
Definition: cli.h:163
struct ao2_container * index
Definition: media_index.c:149
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
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",)
const char * usage
Definition: cli.h:177
static int load_module(void)
Definition: sounds.c:282
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
#define CLI_SUCCESS
Definition: cli.h:44
struct ast_media_index * ast_sounds_get_index(void)
Get the sounds index.
Definition: sounds.c:308
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.
const int pos
Definition: cli.h:164
Media file format and description indexing engine.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1358
static struct ast_cli_entry cli_sounds[]
Struct for registering CLI commands.
Definition: sounds.c:270
Generic container type.
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition: format_cap.c:400
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2726
#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
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:206
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
struct ast_format_cap * ast_media_get_format_cap(struct ast_media_index *index, const char *filename, const char *variant)
Get the ast_format_cap for a media file.
Definition: media_index.c:245
static struct test_val a