Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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 <markster@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/*! \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 */
35#include "asterisk/file.h"
36#include "asterisk/cli.h"
37#include "asterisk/module.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 */
49static 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
96static 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
104static 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
138static 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 */
144static 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
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 */
193static 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 */
270static 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
275static int unload_module(void)
276{
278
279 return 0;
280}
281
282static int load_module(void)
283{
284 int res;
285
287 if (res) {
289 }
290
292}
293
294/*! \brief Callback to process an individual language directory or subdirectory */
295static 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
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,
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_log
Definition: astobj2.c:42
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 ao2_iterator_next(iter)
Definition: astobj2.h:1911
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
static char language[MAX_LANGUAGE]
Definition: chan_iax2.c:324
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2756
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Generic File Format Support. Should be included by clients of the file handling routines....
Media Format API.
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
Format Capabilities API.
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
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
static const char name[]
Definition: format_mp3.c:68
#define LOG_ERROR
Asterisk locking-related definitions:
Media file format and description indexing engine.
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
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
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
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
struct ast_media_index * ast_media_index_create(const char *base_dir)
Creates a new media index.
Definition: media_index.c:162
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
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_APP_DEPEND
Definition: module.h:328
@ 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
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
#define NULL
Definition: resample.c:96
struct ast_media_index * ast_sounds_get_index(void)
Get the sounds index.
Definition: sounds.c:308
static int show_sounds_cb(void *obj, void *arg, int flags)
Definition: sounds.c:96
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
static struct ao2_container * get_languages(void)
Get the languages in which sound files are available.
Definition: sounds.c:49
static int sound_sorter(const void *obj_left, const void *obj_right, int flags)
Definition: sounds.c:138
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
static int show_sound_info_cb(void *obj, void *arg, void *data, int flags)
Definition: sounds.c:104
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
static int load_module(void)
Definition: sounds.c:282
static struct ast_cli_entry cli_sounds[]
Struct for registering CLI commands.
Definition: sounds.c:270
static int unload_module(void)
Definition: sounds.c:275
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
#define LANGUAGE_BUCKETS
The number of buckets to be used for storing language-keyed objects.
Definition: sounds.c:46
Sound file format and description indexer.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1365
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:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
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:1113
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:205
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Definition of a media format.
Definition: format.c:43
struct ao2_container * index
Definition: media_index.c:149
Support for dynamic strings.
Definition: strings.h:623
static struct test_val a
Utility functions.
#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:941
#define ARRAY_LEN(a)
Definition: utils.h:666