[asterisk-commits] kmoore: branch kmoore/stasis-http_sounds r387631 - in /team/kmoore/stasis-htt...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat May 4 10:58:01 CDT 2013
Author: kmoore
Date: Sat May 4 10:57:59 2013
New Revision: 387631
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387631
Log:
Move sounds indexing into a resource module
Pull changes out of file.c/file.h into main/sounds.c for the function
registry and res/res_sounds.c for the actual implementation of the
sounds indexer. Unfortuately it has to be done this way since exporting
global symbols from res_sounds would cause it to be loaded too early to
utilize loaded formats for extension identification.
Added:
team/kmoore/stasis-http_sounds/include/asterisk/sounds.h (with props)
team/kmoore/stasis-http_sounds/main/sounds.c (with props)
team/kmoore/stasis-http_sounds/res/res_sounds.c (with props)
Modified:
team/kmoore/stasis-http_sounds/include/asterisk/file.h
team/kmoore/stasis-http_sounds/main/file.c
team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.c
Modified: team/kmoore/stasis-http_sounds/include/asterisk/file.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/include/asterisk/file.h?view=diff&rev=387631&r1=387630&r2=387631
==============================================================================
--- team/kmoore/stasis-http_sounds/include/asterisk/file.h (original)
+++ team/kmoore/stasis-http_sounds/include/asterisk/file.h Sat May 4 10:57:59 2013
@@ -377,36 +377,14 @@
char *ast_format_str_reduce(char *fmts);
/*!
- * \brief Get the description for a sound
- *
- * \param filename Name of the file for which to get the description
- * \param lang Language for which to get the description
+ * \brief Get the ast_format associated with the given file extension
+ *
+ * \param file_ext The file extension for which to find the format
*
* \retval NULL if not found
- * \return a copy of the description (must be ast_freed)
- */
-char *ast_sounds_get_description(const char *filename, const char *lang);
-
-/*!
- * \brief Get the ast_format_cap for a sound
- *
- * \param filename Name of the file for which to get the description
- * \param lang Language for which to get the description
- *
- * \retval NULL if not found
- * \return a copy of the format capabilities (must be destroyed)
- */
-struct ast_format_cap *ast_sounds_get_format_cap(const char *filename, const char *lang);
-
-/*!
- * \brief Get the languages in which a sound is available
- *
- * \param filename Name of the file for which to get available languages
- *
- * \retval NULL if not found
- * \return an ast_str_container filled with language strings
- */
-struct ao2_container *ast_sounds_get_languages(const char *filename);
+ * \retval A pointer to the ast_format associated with this file extension
+ */
+const struct ast_format *ast_get_format_for_file_ext(const char *file_ext);
#if defined(__cplusplus) || defined(c_plusplus)
}
Added: team/kmoore/stasis-http_sounds/include/asterisk/sounds.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/include/asterisk/sounds.h?view=auto&rev=387631
==============================================================================
--- team/kmoore/stasis-http_sounds/include/asterisk/sounds.h (added)
+++ team/kmoore/stasis-http_sounds/include/asterisk/sounds.h Sat May 4 10:57:59 2013
@@ -1,0 +1,141 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Kinsey Moore <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Sound file format and description indexer.
+ */
+
+#ifndef _ASTERISK_SOUNDS_H
+#define _ASTERISK_SOUNDS_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+struct ast_format_cap;
+
+/*! \brief Interface for sound indexers to use when registering themselves */
+struct ast_sounds_indexer {
+ /*!
+ * \brief Get the description for a sound
+ *
+ * \param filename Name of the file for which to get the description
+ * \param lang Language for which to get the description
+ *
+ * \retval NULL if not found
+ * \return a copy of the description (must be ast_freed)
+ */
+ char *(*get_description)(const char *filename, const char *lang);
+
+ /*!
+ * \brief Get the ast_format_cap for a sound
+ *
+ * \param filename Name of the file for which to get the description
+ * \param lang Language for which to get the description
+ *
+ * \retval NULL if not found
+ * \return a copy of the format capabilities (must be destroyed)
+ */
+ struct ast_format_cap *(*get_format_cap)(const char *filename, const char *lang);
+
+ /*!
+ * \brief Get the languages in which a sound is available
+ *
+ * \param filename Name of the file for which to get available languages
+ *
+ * \retval NULL if not found
+ * \return an ast_str_container filled with language strings
+ */
+ struct ao2_container *(*get_languages)(const char *filename);
+
+ /*!
+ * \brief Reload the sounds index
+ *
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+ int (*reindex)(void);
+};
+
+/*!
+ * \brief Register callbacks for a sound indexer
+ *
+ * \param indexer Struct containing necessary callback functions
+ */
+void ast_sounds_indexer_register(struct ast_sounds_indexer *indexer);
+
+/*!
+ * \brief Unregister callbacks for a sound indexer
+ *
+ * \param indexer The struct that was used to register the functions
+ */
+void ast_sounds_indexer_unregister(struct ast_sounds_indexer *indexer);
+
+/*!
+ * \brief Determine whether a sounds indexer is registered
+ *
+ * \retval zero if not registered
+ * \retval non-zero if registered
+ */
+int ast_sounds_indexer_registered(void);
+
+/*!
+ * \brief Get the description for a sound
+ *
+ * \param filename Name of the file for which to get the description
+ * \param lang Language for which to get the description
+ *
+ * \retval NULL if not found
+ * \return a copy of the description (must be ast_freed)
+ */
+char *ast_sounds_get_description(const char *filename, const char *lang);
+
+/*!
+ * \brief Get the ast_format_cap for a sound
+ *
+ * \param filename Name of the file for which to get the description
+ * \param lang Language for which to get the description
+ *
+ * \retval NULL if not found
+ * \return a copy of the format capabilities (must be destroyed)
+ */
+struct ast_format_cap *ast_sounds_get_format_cap(const char *filename, const char *lang);
+
+/*!
+ * \brief Get the languages in which a sound is available
+ *
+ * \param filename Name of the file for which to get available languages
+ *
+ * \retval NULL if not found
+ * \return an ast_str_container filled with language strings
+ */
+struct ao2_container *ast_sounds_get_languages(const char *filename);
+
+/*!
+ * \brief Reload the sounds index
+ *
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_sounds_reindex(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_SOUNDS_H */
Propchange: team/kmoore/stasis-http_sounds/include/asterisk/sounds.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/kmoore/stasis-http_sounds/include/asterisk/sounds.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/kmoore/stasis-http_sounds/include/asterisk/sounds.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/kmoore/stasis-http_sounds/main/file.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/main/file.c?view=diff&rev=387631&r1=387630&r2=387631
==============================================================================
--- team/kmoore/stasis-http_sounds/main/file.c (original)
+++ team/kmoore/stasis-http_sounds/main/file.c Sat May 4 10:57:59 2013
@@ -51,8 +51,6 @@
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
#include "asterisk/test.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/format_cap.h"
/*! \brief
* The following variable controls the layout of localized sound files.
@@ -67,110 +65,6 @@
int ast_language_is_prefix = 1;
static AST_RWLIST_HEAD_STATIC(formats, ast_format_def);
-
-#define SOUND_VARIANT_BUCKETS 7
-
-#define LANGUAGE_DIR_BUCKETS 7
-
-static struct ao2_container *sounds_index;
-
-/*! \brief Structure to hold a list of the format variations for a sound file in a specific language */
-struct sound_variant {
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(language); /*!< The language this sound is available in */
- AST_STRING_FIELD(description); /*!< The description of the sound */
- );
- struct ast_format_cap *formats; /*!< The formats this sound is available in for this language */
-};
-
-static void sound_variant_destroy(void *obj)
-{
- struct sound_variant *variant = obj;
-
- ast_string_field_free_memory(variant);
- variant->formats = ast_format_cap_destroy(variant->formats);
-}
-
-static struct sound_variant *sound_variant_alloc(const char *language)
-{
- RAII_VAR(struct sound_variant *, variant, ao2_alloc(sizeof(*variant), sound_variant_destroy), ao2_cleanup);
-
- if (ast_string_field_init(variant, 8)) {
- return NULL;
- }
-
- variant->formats = ast_format_cap_alloc();
- if (!variant->formats) {
- return NULL;
- }
-
- ast_string_field_set(variant, language, language);
-
- ao2_ref(variant, 1);
- return variant;
-}
-
-static int sound_variant_hash(const void *obj, const int flags)
-{
- const char *language = (flags & OBJ_KEY) ? obj : ((struct sound_variant*) obj)->language;
- return ast_str_case_hash(language);
-}
-
-static int sound_variant_cmp(void *obj, void *arg, int flags)
-{
- struct sound_variant *opt1 = obj, *opt2 = arg;
- const char *language = (flags & OBJ_KEY) ? arg : opt2->language;
- return strcasecmp(opt1->language, language) ? 0 : CMP_MATCH | CMP_STOP;
-}
-
-/*! \brief Structure to hold information about a sound file */
-struct sound_info {
- AST_DECLARE_STRING_FIELDS(
- AST_STRING_FIELD(name); /*!< The name of the sound */
- );
- struct ao2_container *variant_list; /*!< The list of (language, format) tuples for which this sound is available */
-};
-
-static void sound_info_destroy(void *obj)
-{
- struct sound_info *info = obj;
-
- ast_string_field_free_memory(info);
- ao2_cleanup(info->variant_list);
- info->variant_list = NULL;
-}
-
-static struct sound_info *sound_info_alloc(const char *name)
-{
- RAII_VAR(struct sound_info *, info, ao2_alloc(sizeof(*info), sound_info_destroy), ao2_cleanup);
-
- if (ast_string_field_init(info, 128)) {
- return NULL;
- }
-
- info->variant_list = ao2_container_alloc(SOUND_VARIANT_BUCKETS, sound_variant_hash, sound_variant_cmp);
- if (!info->variant_list) {
- return NULL;
- }
-
- ast_string_field_set(info, name, name);
-
- ao2_ref(info, 1);
- return info;
-}
-
-static int sound_info_hash(const void *obj, const int flags)
-{
- const char *name = (flags & OBJ_KEY) ? obj : ((struct sound_info*) obj)->name;
- return ast_str_case_hash(name);
-}
-
-static int sound_info_cmp(void *obj, void *arg, int flags)
-{
- struct sound_info *opt1 = obj, *opt2 = arg;
- const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
- return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
-}
int __ast_format_def_register(const struct ast_format_def *f, struct ast_module *mod)
{
@@ -1778,10 +1672,10 @@
#undef FORMAT2
}
-/*! \brief Get the ast_format associated with the given file extension */
-static const struct ast_format *get_format_for_file_ext(const char *file_ext)
+const struct ast_format *ast_get_format_for_file_ext(const char *file_ext)
{
struct ast_format_def *f;
+ SCOPED_RDLOCK(lock, &formats.lock);
AST_RWLIST_TRAVERSE(&formats, f, list) {
if (exts_compare(f->exts, file_ext)) {
return &f->format;
@@ -1791,455 +1685,17 @@
return NULL;
}
-/*! \brief Get the languages that sound files are available in */
-static struct ao2_container *get_languages(void)
-{
- RAII_VAR(struct ao2_container *, lang_dirs, NULL, ao2_cleanup);
- struct dirent* dent;
- DIR* srcdir;
- RAII_VAR(struct ast_str *, sounds_dir, ast_str_create(64), ast_free);
-
- lang_dirs = ast_str_container_alloc(LANGUAGE_DIR_BUCKETS);
- if (!sounds_dir || !lang_dirs) {
- return NULL;
- }
-
- ast_str_set(&sounds_dir, 0, "%s/sounds", ast_config_AST_DATA_DIR);
-
- srcdir = opendir(ast_str_buffer(sounds_dir));
-
- if (srcdir == NULL) {
- ast_log(LOG_ERROR, "Failed to open %s\n", ast_str_buffer(sounds_dir));
- return NULL;
- }
-
- while((dent = readdir(srcdir)) != NULL) {
- struct stat st;
-
- if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
- continue;
- }
-
- if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
- ast_log(LOG_ERROR, "Failed to stat %s\n", dent->d_name);
- continue;
- }
-
- if (S_ISDIR(st.st_mode)) {
- ast_str_container_add(lang_dirs, dent->d_name);
- }
- }
-
- closedir(srcdir);
- ao2_ref(lang_dirs, +1);
- return lang_dirs;
-}
-
-/*! \brief Find or create the appropriate sound_variant and any necessary structures */
-static struct sound_variant *get_variant(const char *filename, const char *lang, int no_alloc)
-{
- RAII_VAR(struct sound_info *, info, NULL, ao2_cleanup);
- RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
-
- info = ao2_find(sounds_index, filename, OBJ_KEY);
- if (!info) {
- if (no_alloc) {
- return NULL;
- }
- /* This is the first time the index has seen this filename,
- * allocate and link */
- info = sound_info_alloc(filename);
- if (!info) {
- return NULL;
- }
-
- ao2_link(sounds_index, info);
- }
-
- variant = ao2_find(info->variant_list, lang, OBJ_KEY);
- if (!variant) {
- if (no_alloc) {
- return NULL;
- }
- /* This is the first time the index has seen this language for
- * this filename, allocate and link */
- variant = sound_variant_alloc(lang);
- if (!variant) {
- return NULL;
- }
-
- ao2_link(info->variant_list, variant);
- }
-
- ao2_ref(variant, +1);
- return variant;
-}
-
-char *ast_sounds_get_description(const char *filename, const char *lang)
-{
- RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
- if (!filename || !lang) {
- return NULL;
- }
-
- variant = get_variant(filename, lang, 1);
- if (!variant) {
- return NULL;
- }
-
- return ast_strdup(variant->description);
-}
-
-struct ast_format_cap *ast_sounds_get_format_cap(const char *filename, const char *lang)
-{
- RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
- if (!filename || !lang) {
- return NULL;
- }
-
- variant = get_variant(filename, lang, 1);
- if (!variant) {
- return NULL;
- }
-
- return ast_format_cap_dup(variant->formats);
-}
-
-static int add_language_cb(void *obj, void *arg, int flags)
-{
- struct sound_variant *variant = obj;
- struct ao2_container *languages = arg;
- ast_str_container_add(languages, variant->language);
- return 0;
-}
-
-struct ao2_container *ast_sounds_get_languages(const char *filename)
-{
- RAII_VAR(struct sound_info *, info, NULL, ao2_cleanup);
- RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
- if (!filename) {
- return NULL;
- }
-
- languages = ast_str_container_alloc(LANGUAGE_DIR_BUCKETS);
- if (!languages) {
- return NULL;
- }
-
- info = ao2_find(sounds_index, filename, OBJ_KEY);
- if (!info) {
- return NULL;
- }
-
- ao2_callback(info->variant_list, OBJ_NODATA, add_language_cb, languages);
-
- ao2_ref(languages, +1);
- return languages;
-}
-
-/*! \brief Update an index with new format/language information */
-static int update_file_format_info(const char *filename, const char *lang, const struct ast_format *file_format)
-{
- RAII_VAR(struct sound_variant *, variant, get_variant(filename, lang, 0), ao2_cleanup);
- if (!variant) {
- return -1;
- }
-
- ast_format_cap_add(variant->formats, file_format);
- return 0;
-}
-
-/*! \brief Process a sound file into the index */
-static int process_sound_file(const char *lang, const char *subdir, const char *filename_stripped, const char *ext)
-{
- const struct ast_format *file_format;
- const char *file_identifier = filename_stripped;
- RAII_VAR(struct ast_str *, file_id_str, NULL, ast_free);
- /* Lock must be held while file_format is in use (the remainder of this scope) */
- SCOPED_RDLOCK(lock, &formats.lock);
-
- file_format = get_format_for_file_ext(ext);
- if (!file_format) {
- /* extension not registered */
- return 0;
- }
-
- /* handle updating the file information */
- if (subdir) {
- file_id_str = ast_str_create(64);
- if (!file_id_str) {
- return -1;
- }
-
- ast_str_set(&file_id_str, 0, "%s/%s", subdir, filename_stripped);
- file_identifier = ast_str_buffer(file_id_str);
- }
-
- if (update_file_format_info(file_identifier, lang, file_format)) {
- return -1;
- }
- return 0;
-}
-
-/*!
- * \brief Process a sounds description text file
- *
- * This currently processes core-sounds-*.txt and extra-sounds-*.txt, but will
- * process others if available.
- */
-static int process_description_file(const char *lang, const char *filename)
-{
- RAII_VAR(struct ast_str *, description_file_path, ast_str_create(64), ast_free);
- RAII_VAR(struct ast_str *, cumulative_description, ast_str_create(64), ast_free);
- char *file_id_persist = NULL;
- int res = 0;
- FILE *f = NULL;
-#if defined(LOW_MEMORY)
- char buf[256];
-#else
- char buf[2048];
-#endif
-
- if (!description_file_path || !cumulative_description) {
- return -1;
- }
-
- ast_str_set(&description_file_path, 0, "%s/sounds/%s/%s", ast_config_AST_DATA_DIR, lang, filename);
- f = fopen(ast_str_buffer(description_file_path), "r");
- if (!f) {
- ast_log(LOG_WARNING, "Could not open sound description file '%s'\n", ast_str_buffer(description_file_path));
- return -1;
- }
-
- while (!feof(f)) {
- char *file_identifier, *description;
- if (!fgets(buf, sizeof(buf), f)) {
- continue;
- }
-
- /* Skip lines that are too long */
- if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
- ast_log(LOG_WARNING, "Line too long, skipping. It begins with: %.32s...\n", buf);
- while (fgets(buf, sizeof(buf), f)) {
- if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
- break;
- }
- }
- continue;
- }
-
- if (buf[0] == ';') {
- /* ignore comments */
- continue;
- }
-
- ast_trim_blanks(buf);
- description = buf;
- file_identifier = strsep(&description, ":");
- if (!description) {
- /* no ':' means this is a continuation */
- if (file_id_persist) {
- ast_str_append(&cumulative_description, 0, "\n%s", file_identifier);
- }
- continue;
- } else {
- /* if there's text in cumulative_description, archive it and start anew */
- if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
- RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
- variant = get_variant(file_id_persist, lang, 0);
- if (!variant) {
- res = -1;
- break;
- }
-
- ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
-
- ast_str_reset(cumulative_description);
- ast_free(file_id_persist);
- file_id_persist = NULL;
- }
-
- file_id_persist = strdup(file_identifier);
- description = ast_skip_blanks(description);
- ast_str_set(&cumulative_description, 0, "%s", description);
- }
- }
-
- /* handle the last one */
- if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
- RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
- variant = get_variant(file_id_persist, lang, 0);
- if (variant) {
- ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
- ast_free(file_id_persist);
- } else {
- res = -1;
- }
- }
-
- fclose(f);
- return res;
-}
-
-/*! \brief process an individual file listing */
-static int process_file(const char *lang, const char *subdir, const char *filename)
-{
- RAII_VAR(char *, filename_stripped, ast_strdup(filename), ast_free);
- char *ext;
-
- if (!filename_stripped) {
- return -1;
- }
-
- ext = strrchr(filename_stripped, '.');
- if (!ext) {
- /* file has no extension */
- return 0;
- }
-
- *ext++ = '\0';
- if (!strcmp(ext, "txt")) {
- if (!subdir && process_description_file(lang, filename)) {
- return -1;
- }
- } else {
- if (process_sound_file(lang, subdir, filename_stripped, ext)) {
- return -1;
- }
- }
- return 0;
-}
-
-/*! \brief Callback to process an individual language directory or subdirectory */
-static int update_index_cb(void *obj, void *arg, int flags)
-{
- char *lang = obj;
- char *subdir = arg;
- struct dirent* dent;
- DIR* srcdir;
- RAII_VAR(struct ast_str *, sounds_lang_dir, ast_str_create(64), ast_free);
- int res = 0;
-
- if (!sounds_lang_dir) {
- return 0;
- }
-
- if (subdir) {
- ast_str_set(&sounds_lang_dir, 0, "%s/sounds/%s/%s", ast_config_AST_DATA_DIR, lang, subdir);
- } else {
- ast_str_set(&sounds_lang_dir, 0, "%s/sounds/%s", ast_config_AST_DATA_DIR, lang);
- }
-
- srcdir = opendir(ast_str_buffer(sounds_lang_dir));
- if (srcdir == NULL) {
- ast_log(LOG_ERROR, "Failed to open %s\n", ast_str_buffer(sounds_lang_dir));
- return -1;
- }
-
- while((dent = readdir(srcdir)) != NULL) {
- struct stat st;
-
- if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
- continue;
- }
-
- if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
- ast_log(LOG_ERROR, "Failed to stat %s\n", dent->d_name);
- res = -1;
- break;
- }
-
- if (S_ISDIR(st.st_mode)) {
- /* only recurse one level */
- if (!subdir) {
- update_index_cb(lang, dent->d_name, 0);
- } else {
- ast_log(LOG_ERROR, "Not recursing again on lang %s subdir %s, subsubdir %s\n", lang, subdir, dent->d_name);
- }
- continue;
- }
-
- if (!S_ISREG(st.st_mode)) {
- continue;
- }
-
- if (process_file(lang, subdir, dent->d_name)) {
- res = -1;
- break;
- }
- }
-
- closedir(srcdir);
- return res;
-}
-
-/*! \brief Reindex sounds and sound descriptions */
-static int index_sounds(void)
-{
- RAII_VAR(struct ao2_container *, languages, get_languages(), ao2_cleanup);
-
- if (sounds_index || !languages) {
- return -1;
- }
-
- sounds_index = ao2_container_alloc(SOUND_VARIANT_BUCKETS, sound_info_hash, sound_info_cmp);
- if (!sounds_index) {
- return -1;
- }
-
- ao2_callback(languages, OBJ_NODATA, update_index_cb, NULL);
- return 0;
-}
-
-/*! \brief Free the current sounds index */
-static void drop_sound_index(void)
-{
- ao2_cleanup(sounds_index);
- sounds_index = NULL;
-}
-
-static char *handle_cli_sounds_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- switch (cmd) {
- case CLI_INIT:
- e->command = "sounds reload";
- e->usage =
- "Usage: sounds reload\n"
- " Reloads the index of sound files and their descriptions.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-
- if (a->argc != 2) {
- return CLI_SHOWUSAGE;
- }
-
- drop_sound_index();
- if (index_sounds()) {
- ast_cli(a->fd, "Sound re-indexing failed.\n");
- return CLI_FAILURE;
- }
-
- ast_cli(a->fd, "Sound files re-indexed.\n");
- return CLI_SUCCESS;
-}
-
static struct ast_cli_entry cli_file[] = {
AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats"),
- AST_CLI_DEFINE(handle_cli_sounds_reload, "Reloads sounds index"),
};
static void file_shutdown(void)
{
ast_cli_unregister_multiple(cli_file, ARRAY_LEN(cli_file));
- drop_sound_index();
}
int ast_file_init(void)
{
- sounds_index = NULL;
- index_sounds();
ast_cli_register_multiple(cli_file, ARRAY_LEN(cli_file));
ast_register_atexit(file_shutdown);
return 0;
Added: team/kmoore/stasis-http_sounds/main/sounds.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/main/sounds.c?view=auto&rev=387631
==============================================================================
--- team/kmoore/stasis-http_sounds/main/sounds.c (added)
+++ team/kmoore/stasis-http_sounds/main/sounds.c Sat May 4 10:57:59 2013
@@ -1,0 +1,81 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Kinsey Moore <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Sound file format and description indexer.
+ */
+
+#include "asterisk.h"
+#include "asterisk/sounds.h"
+
+/*! \brief Holder for the registered indexer interface */
+static struct ast_sounds_indexer *sounds_indexer = NULL;
+
+void ast_sounds_indexer_register(struct ast_sounds_indexer *indexer)
+{
+ sounds_indexer = indexer;
+}
+
+void ast_sounds_indexer_unregister(struct ast_sounds_indexer *indexer)
+{
+ if (indexer == sounds_indexer) {
+ indexer = NULL;
+ }
+}
+
+int ast_sounds_indexer_registered(void)
+{
+ return sounds_indexer ? 1 : 0;
+}
+
+char *ast_sounds_get_description(const char *filename, const char *lang)
+{
+ if (sounds_indexer && sounds_indexer->get_description) {
+ return sounds_indexer->get_description(filename, lang);
+ }
+
+ return NULL;
+}
+
+struct ast_format_cap *ast_sounds_get_format_cap(const char *filename, const char *lang)
+{
+ if (sounds_indexer && sounds_indexer->get_format_cap) {
+ return sounds_indexer->get_format_cap(filename, lang);
+ }
+
+ return NULL;
+}
+
+struct ao2_container *ast_sounds_get_languages(const char *filename)
+{
+ if (sounds_indexer && sounds_indexer->get_languages) {
+ return sounds_indexer->get_languages(filename);
+ }
+
+ return NULL;
+}
+
+int ast_sounds_reindex(void)
+{
+ if (sounds_indexer && sounds_indexer->reindex) {
+ return sounds_indexer->reindex();
+ }
+
+ return -1;
+}
+
Propchange: team/kmoore/stasis-http_sounds/main/sounds.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/kmoore/stasis-http_sounds/main/sounds.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/kmoore/stasis-http_sounds/main/sounds.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/kmoore/stasis-http_sounds/res/res_sounds.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/res/res_sounds.c?view=auto&rev=387631
==============================================================================
--- team/kmoore/stasis-http_sounds/res/res_sounds.c (added)
+++ team/kmoore/stasis-http_sounds/res/res_sounds.c Sat May 4 10:57:59 2013
@@ -1,0 +1,625 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Kinsey Moore <kmoore at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
+#include "asterisk/sounds.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/module.h"
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#define SOUND_VARIANT_BUCKETS 7
+
+#define LANGUAGE_DIR_BUCKETS 7
+
+static struct ao2_container *sounds_index;
+
+/*! \brief Structure to hold a list of the format variations for a sound file in a specific language */
+struct sound_variant {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(language); /*!< The language this sound is available in */
+ AST_STRING_FIELD(description); /*!< The description of the sound */
+ );
+ struct ast_format_cap *formats; /*!< The formats this sound is available in for this language */
+};
+
+static void sound_variant_destroy(void *obj)
+{
+ struct sound_variant *variant = obj;
+
+ ast_string_field_free_memory(variant);
+ variant->formats = ast_format_cap_destroy(variant->formats);
+}
+
+static struct sound_variant *sound_variant_alloc(const char *language)
+{
+ RAII_VAR(struct sound_variant *, variant, ao2_alloc(sizeof(*variant), sound_variant_destroy), ao2_cleanup);
+
+ if (ast_string_field_init(variant, 8)) {
+ return NULL;
+ }
+
+ variant->formats = ast_format_cap_alloc();
+ if (!variant->formats) {
+ return NULL;
+ }
+
+ ast_string_field_set(variant, language, language);
+
+ ao2_ref(variant, 1);
+ return variant;
+}
+
+static int sound_variant_hash(const void *obj, const int flags)
+{
+ const char *language = (flags & OBJ_KEY) ? obj : ((struct sound_variant*) obj)->language;
+ return ast_str_case_hash(language);
+}
+
+static int sound_variant_cmp(void *obj, void *arg, int flags)
+{
+ struct sound_variant *opt1 = obj, *opt2 = arg;
+ const char *language = (flags & OBJ_KEY) ? arg : opt2->language;
+ return strcasecmp(opt1->language, language) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+/*! \brief Structure to hold information about a sound file */
+struct sound_info {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name); /*!< The name of the sound */
+ );
+ struct ao2_container *variant_list; /*!< The list of (language, format) tuples for which this sound is available */
+};
+
+static void sound_info_destroy(void *obj)
+{
+ struct sound_info *info = obj;
+
+ ast_string_field_free_memory(info);
+ ao2_cleanup(info->variant_list);
+ info->variant_list = NULL;
+}
+
+static struct sound_info *sound_info_alloc(const char *name)
+{
+ RAII_VAR(struct sound_info *, info, ao2_alloc(sizeof(*info), sound_info_destroy), ao2_cleanup);
+
+ if (ast_string_field_init(info, 128)) {
+ return NULL;
+ }
+
+ info->variant_list = ao2_container_alloc(SOUND_VARIANT_BUCKETS, sound_variant_hash, sound_variant_cmp);
+ if (!info->variant_list) {
+ return NULL;
+ }
+
+ ast_string_field_set(info, name, name);
+
+ ao2_ref(info, 1);
+ return info;
+}
+
+static int sound_info_hash(const void *obj, const int flags)
+{
+ const char *name = (flags & OBJ_KEY) ? obj : ((struct sound_info*) obj)->name;
+ return ast_str_case_hash(name);
+}
+
+static int sound_info_cmp(void *obj, void *arg, int flags)
+{
+ struct sound_info *opt1 = obj, *opt2 = arg;
+ const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
+ return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+/*! \brief Get the languages that sound files are available in */
+static struct ao2_container *get_languages(void)
+{
+ RAII_VAR(struct ao2_container *, lang_dirs, NULL, ao2_cleanup);
+ struct dirent* dent;
+ DIR* srcdir;
+ RAII_VAR(struct ast_str *, sounds_dir, ast_str_create(64), ast_free);
+
+ lang_dirs = ast_str_container_alloc(LANGUAGE_DIR_BUCKETS);
+ if (!sounds_dir || !lang_dirs) {
+ return NULL;
+ }
+
+ ast_str_set(&sounds_dir, 0, "%s/sounds", ast_config_AST_DATA_DIR);
+
+ srcdir = opendir(ast_str_buffer(sounds_dir));
+
+ if (srcdir == NULL) {
+ ast_log(LOG_ERROR, "Failed to open %s\n", ast_str_buffer(sounds_dir));
+ return NULL;
+ }
+
+ while((dent = readdir(srcdir)) != NULL) {
+ struct stat st;
+
+ if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
+ continue;
+ }
+
+ if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) {
+ ast_log(LOG_ERROR, "Failed to stat %s\n", dent->d_name);
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ ast_str_container_add(lang_dirs, dent->d_name);
+ }
+ }
+
+ closedir(srcdir);
+ ao2_ref(lang_dirs, +1);
+ return lang_dirs;
+}
+
+/*! \brief Find or create the appropriate sound_variant and any necessary structures */
+static struct sound_variant *get_variant(const char *filename, const char *lang, int no_alloc)
+{
+ RAII_VAR(struct sound_info *, info, NULL, ao2_cleanup);
+ RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+
+ info = ao2_find(sounds_index, filename, OBJ_KEY);
+ if (!info) {
+ if (no_alloc) {
+ return NULL;
+ }
+ /* This is the first time the index has seen this filename,
+ * allocate and link */
+ info = sound_info_alloc(filename);
+ if (!info) {
+ return NULL;
+ }
+
+ ao2_link(sounds_index, info);
+ }
+
+ variant = ao2_find(info->variant_list, lang, OBJ_KEY);
+ if (!variant) {
+ if (no_alloc) {
+ return NULL;
+ }
+ /* This is the first time the index has seen this language for
+ * this filename, allocate and link */
+ variant = sound_variant_alloc(lang);
+ if (!variant) {
+ return NULL;
+ }
+
+ ao2_link(info->variant_list, variant);
+ }
+
+ ao2_ref(variant, +1);
+ return variant;
+}
+
+static char *sounds_get_description(const char *filename, const char *lang)
+{
+ RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+ if (!filename || !lang) {
+ return NULL;
+ }
+
+ variant = get_variant(filename, lang, 1);
+ if (!variant) {
+ return NULL;
+ }
+
+ return ast_strdup(variant->description);
+}
+
+static struct ast_format_cap *sounds_get_format_cap(const char *filename, const char *lang)
+{
+ RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+ if (!filename || !lang) {
+ return NULL;
+ }
+
+ variant = get_variant(filename, lang, 1);
+ if (!variant) {
+ return NULL;
+ }
+
+ return ast_format_cap_dup(variant->formats);
+}
+
+static int add_language_cb(void *obj, void *arg, int flags)
+{
+ struct sound_variant *variant = obj;
+ struct ao2_container *languages = arg;
+ ast_str_container_add(languages, variant->language);
+ return 0;
+}
+
+static struct ao2_container *sounds_get_languages(const char *filename)
+{
+ RAII_VAR(struct sound_info *, info, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
+ if (!filename) {
+ return NULL;
+ }
+
+ languages = ast_str_container_alloc(LANGUAGE_DIR_BUCKETS);
+ if (!languages) {
+ return NULL;
+ }
+
+ info = ao2_find(sounds_index, filename, OBJ_KEY);
+ if (!info) {
+ return NULL;
+ }
+
+ ao2_callback(info->variant_list, OBJ_NODATA, add_language_cb, languages);
+
+ ao2_ref(languages, +1);
+ return languages;
+}
+
+/*! \brief Update an index with new format/language information */
+static int update_file_format_info(const char *filename, const char *lang, const struct ast_format *file_format)
+{
+ RAII_VAR(struct sound_variant *, variant, get_variant(filename, lang, 0), ao2_cleanup);
+ if (!variant) {
+ return -1;
+ }
+
+ ast_format_cap_add(variant->formats, file_format);
+ return 0;
+}
+
+/*! \brief Process a sound file into the index */
+static int process_sound_file(const char *lang, const char *subdir, const char *filename_stripped, const char *ext)
+{
+ const struct ast_format *file_format;
+ const char *file_identifier = filename_stripped;
+ RAII_VAR(struct ast_str *, file_id_str, NULL, ast_free);
+
+ file_format = ast_get_format_for_file_ext(ext);
+ if (!file_format) {
+ /* extension not registered */
+ return 0;
+ }
+
+ /* handle updating the file information */
+ if (subdir) {
+ file_id_str = ast_str_create(64);
+ if (!file_id_str) {
+ return -1;
+ }
+
+ ast_str_set(&file_id_str, 0, "%s/%s", subdir, filename_stripped);
+ file_identifier = ast_str_buffer(file_id_str);
+ }
+
+ if (update_file_format_info(file_identifier, lang, file_format)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * \brief Process a sounds description text file
+ *
+ * This currently processes core-sounds-*.txt and extra-sounds-*.txt, but will
+ * process others if available.
+ */
+static int process_description_file(const char *lang, const char *filename)
+{
+ RAII_VAR(struct ast_str *, description_file_path, ast_str_create(64), ast_free);
+ RAII_VAR(struct ast_str *, cumulative_description, ast_str_create(64), ast_free);
+ char *file_id_persist = NULL;
+ int res = 0;
+ FILE *f = NULL;
+#if defined(LOW_MEMORY)
+ char buf[256];
+#else
+ char buf[2048];
+#endif
+
+ if (!description_file_path || !cumulative_description) {
+ return -1;
+ }
+
+ ast_str_set(&description_file_path, 0, "%s/sounds/%s/%s", ast_config_AST_DATA_DIR, lang, filename);
+ f = fopen(ast_str_buffer(description_file_path), "r");
+ if (!f) {
+ ast_log(LOG_WARNING, "Could not open sound description file '%s'\n", ast_str_buffer(description_file_path));
+ return -1;
+ }
+
+ while (!feof(f)) {
+ char *file_identifier, *description;
+ if (!fgets(buf, sizeof(buf), f)) {
+ continue;
+ }
+
+ /* Skip lines that are too long */
+ if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
+ ast_log(LOG_WARNING, "Line too long, skipping. It begins with: %.32s...\n", buf);
+ while (fgets(buf, sizeof(buf), f)) {
+ if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (buf[0] == ';') {
+ /* ignore comments */
+ continue;
+ }
+
+ ast_trim_blanks(buf);
+ description = buf;
+ file_identifier = strsep(&description, ":");
+ if (!description) {
+ /* no ':' means this is a continuation */
+ if (file_id_persist) {
+ ast_str_append(&cumulative_description, 0, "\n%s", file_identifier);
+ }
+ continue;
+ } else {
+ /* if there's text in cumulative_description, archive it and start anew */
+ if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
+ RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+ variant = get_variant(file_id_persist, lang, 0);
+ if (!variant) {
+ res = -1;
+ break;
+ }
+
+ ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
+
+ ast_str_reset(cumulative_description);
+ ast_free(file_id_persist);
+ file_id_persist = NULL;
+ }
+
+ file_id_persist = strdup(file_identifier);
+ description = ast_skip_blanks(description);
+ ast_str_set(&cumulative_description, 0, "%s", description);
+ }
+ }
+
+ /* handle the last one */
+ if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
+ RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+ variant = get_variant(file_id_persist, lang, 0);
+ if (variant) {
+ ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
+ ast_free(file_id_persist);
+ } else {
+ res = -1;
+ }
+ }
+
+ fclose(f);
+ return res;
+}
+
+/*! \brief process an individual file listing */
+static int process_file(const char *lang, const char *subdir, const char *filename)
+{
+ RAII_VAR(char *, filename_stripped, ast_strdup(filename), ast_free);
+ char *ext;
+
+ if (!filename_stripped) {
+ return -1;
+ }
+
+ ext = strrchr(filename_stripped, '.');
+ if (!ext) {
+ /* file has no extension */
+ return 0;
+ }
+
+ *ext++ = '\0';
+ if (!strcmp(ext, "txt")) {
+ if (!subdir && process_description_file(lang, filename)) {
+ return -1;
+ }
+ } else {
+ if (process_sound_file(lang, subdir, filename_stripped, ext)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*! \brief Callback to process an individual language directory or subdirectory */
+static int update_index_cb(void *obj, void *arg, int flags)
+{
+ char *lang = obj;
+ char *subdir = arg;
+ struct dirent* dent;
+ DIR* srcdir;
+ RAII_VAR(struct ast_str *, sounds_lang_dir, ast_str_create(64), ast_free);
+ int res = 0;
+
+ if (!sounds_lang_dir) {
+ return 0;
+ }
+
+ if (subdir) {
[... 187 lines stripped ...]
More information about the asterisk-commits
mailing list