[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