[svn-commits] kmoore: branch kmoore/stasis-http_sounds r387262 - in /team/kmoore/stasis-htt...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed May 1 17:00:17 CDT 2013


Author: kmoore
Date: Wed May  1 17:00:15 2013
New Revision: 387262

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387262
Log:
Add sound indexing and tweak JSON as necessary

It was discovered during the course of working on this that the JSON
model currently set for sounds needed some tweaking to reflect reality
a bit better, so now it will contain a list of language/format pairs to
describe which formats and languages are available on the system.

This includes indexing of all sounds in formats registered to asterisk
and sound descriptions in any languages where the descriptions are
present. Currently, only English descriptions will be provided in
responses to Stasis-HTTP queries.

Modified:
    team/kmoore/stasis-http_sounds/include/asterisk/astobj2.h
    team/kmoore/stasis-http_sounds/include/asterisk/file.h
    team/kmoore/stasis-http_sounds/main/astobj2.c
    team/kmoore/stasis-http_sounds/main/file.c
    team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.c
    team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.h
    team/kmoore/stasis-http_sounds/rest-api/api-docs/sounds.json

Modified: team/kmoore/stasis-http_sounds/include/asterisk/astobj2.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/include/asterisk/astobj2.h?view=diff&rev=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/include/asterisk/astobj2.h (original)
+++ team/kmoore/stasis-http_sounds/include/asterisk/astobj2.h Wed May  1 17:00:15 2013
@@ -1883,4 +1883,55 @@
 #define ao2_cleanup(obj) __ao2_cleanup(obj)
 #endif
 void ao2_iterator_cleanup(struct ao2_iterator *iter);
+
+
+/* XXX TODO BUGBUG and all the other things...
+ * These functions should eventually be moved elsewhere, but the utils folder
+ * won't compile with them in strings.h
+ */
+
+/*!
+ * \since 12
+ * \brief Allocates a hash container for bare strings
+ *
+ * \param buckets The number of buckets to use for the hash container
+ *
+ * \retval AO2 container for strings
+ * \retval NULL if allocation failed
+ */
+#define ast_str_container_alloc(buckets) ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_MUTEX, buckets)
+
+/*!
+ * \since 12
+ * \brief Allocates a hash container for bare strings
+ *
+ * \param opts Options to be provided to the container
+ * \param buckets The number of buckets to use for the hash container
+ *
+ * \retval AO2 container for strings
+ * \retval NULL if allocation failed
+ */
+struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets);
+
+/*!
+ * \since 12
+ * \brief Adds a string to a string container allocated by ast_str_container_alloc
+ *
+ * \param str_container The container to which to add a string
+ * \param add The string to add to the container
+ *
+ * \retval zero on success
+ * \retval non-zero if the operation failed
+ */
+int ast_str_container_add(struct ao2_container *str_container, const char *add);
+
+/*!
+ * \since 12
+ * \brief Removes a string from a string container allocated by ast_str_container_alloc
+ *
+ * \param str_container The container from which to remove a string
+ * \param remove The string to remove from the container
+ */
+void ast_str_container_remove(struct ao2_container *str_container, const char *remove);
+
 #endif /* _ASTERISK_ASTOBJ2_H */

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=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/include/asterisk/file.h (original)
+++ team/kmoore/stasis-http_sounds/include/asterisk/file.h Wed May  1 17:00:15 2013
@@ -376,6 +376,17 @@
  */
 char *ast_format_str_reduce(char *fmts);
 
+/*!
+ * \brief Get the description for a sound from the text file included with english sounds
+ *
+ * \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 pointer to the description (does not need to be ast_freed)
+ */
+const char *ast_sounds_get_description(const char *filename, const char *lang);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/kmoore/stasis-http_sounds/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/main/astobj2.c?view=diff&rev=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/main/astobj2.c (original)
+++ team/kmoore/stasis-http_sounds/main/astobj2.c Wed May  1 17:00:15 2013
@@ -5780,3 +5780,41 @@
 
 	return 0;
 }
+
+/* XXX TODO BUGBUG and all the other things...
+ * These functions should eventually be moved elsewhere, but the utils folder
+ * won't compile with them in strings.h
+ */
+static int str_hash(const void *obj, const int flags)
+{
+	return ast_str_hash(obj);
+}
+
+static int str_cmp(void *lhs, void *rhs, int flags)
+{
+	return strcmp(lhs, rhs) ? 0 : CMP_MATCH;
+}
+
+struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets)
+{
+	return ao2_container_alloc_options(opts, buckets, str_hash, str_cmp);
+}
+
+int ast_str_container_add(struct ao2_container *str_container, const char *add)
+{
+	RAII_VAR(char *, ao2_add, ao2_alloc(strlen(add) + 1, NULL), ao2_cleanup);
+
+	if (!ao2_add) {
+		return -1;
+	}
+
+	/* safe strcpy */
+	strcpy(ao2_add, add);
+	ao2_link(str_container, ao2_add);
+	return 0;
+}
+
+void ast_str_container_remove(struct ao2_container *str_container, const char *remove)
+{
+	ao2_find(str_container, remove, OBJ_KEY | OBJ_NODATA | OBJ_UNLINK);
+}

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=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/main/file.c (original)
+++ team/kmoore/stasis-http_sounds/main/file.c Wed May  1 17:00:15 2013
@@ -51,6 +51,8 @@
 #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.
@@ -65,6 +67,110 @@
 int ast_language_is_prefix = 1;
 
 static AST_RWLIST_HEAD_STATIC(formats, ast_format_def);
+
+#define SOUND_VARIANT_BUCKETS 13
+
+#define LANGUAGE_DIR_BUCKETS 13
+
+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)
 {
@@ -1636,6 +1742,22 @@
 	return orig;
 }
 
+const char *ast_sounds_get_description(const char *filename, const char *lang)
+{
+	RAII_VAR(struct sound_info *, info, ao2_find(sounds_index, filename, OBJ_KEY), ao2_cleanup);
+	RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+	if (!info || !lang) {
+		return NULL;
+	}
+
+	variant = ao2_find(info->variant_list, lang, OBJ_KEY);
+	if (!variant) {
+		return NULL;
+	}
+
+	return variant->description;
+}
+
 static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 #define FORMAT "%-10s %-10s %-20s\n"
@@ -1672,17 +1794,387 @@
 #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)
+{
+	struct ast_format_def *f;
+	AST_RWLIST_TRAVERSE(&formats, f, list) {
+		if (exts_compare(f->exts, file_ext)) {
+			return &f->format;
+		}
+	}
+
+	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)
+{
+	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) {
+		/* 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) {
+		/* 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;
+}
+
+/*! \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), 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;
+		RAII_VAR(struct sound_variant *, variant, NULL, ao2_cleanup);
+		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))) {
+				variant = get_variant(file_id_persist, lang);
+				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);
+			ast_str_set(&cumulative_description, 0, "%s", description);
+		}
+	}
+
+	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_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;

Modified: team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.c?view=diff&rev=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.c (original)
+++ team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.c Wed May  1 17:00:15 2013
@@ -28,12 +28,47 @@
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "resource_sounds.h"
+#include "asterisk/file.h"
+
+static struct ast_json *create_sound_blob(const char *filename)
+{
+	RAII_VAR(struct ast_json *, sound, NULL, ast_json_unref);
+	const char *description;
+	struct ast_json *format_lang_list;
+
+	description = ast_sounds_get_description(filename, "en");
+	if (!description) {
+		return NULL;
+	}
+
+	sound = ast_json_pack("{s: s, s: s, s: []}",
+		"id", filename,
+		"text", description,
+		"formats");
+	if (!sound) {
+		return NULL;
+	}
+
+	format_lang_list = ast_json_object_get(sound, "formats");
+	if (!format_lang_list) {
+		return NULL;
+	}
+
+	return ast_json_ref(sound);
+}
 
 void stasis_http_get_sounds(struct ast_variable *headers, struct ast_get_sounds_args *args, struct stasis_http_response *response)
 {
 	ast_log(LOG_ERROR, "TODO: stasis_http_get_sounds\n");
 }
+
 void stasis_http_get_stored_sound(struct ast_variable *headers, struct ast_get_stored_sound_args *args, struct stasis_http_response *response)
 {
-	ast_log(LOG_ERROR, "TODO: stasis_http_get_stored_sound\n");
+	RAII_VAR(struct ast_json *, sound_blob, create_sound_blob(args->sound_id), ast_json_unref);
+	if (sound_blob) {
+		stasis_http_response_ok(response, sound_blob);
+		return;
+	}
+
+	stasis_http_response_error(response, 404, "Not Found", "Channel not found");
 }

Modified: team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.h?view=diff&rev=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.h (original)
+++ team/kmoore/stasis-http_sounds/res/stasis_http/resource_sounds.h Wed May  1 17:00:15 2013
@@ -70,10 +70,12 @@
  * JSON models
  *
  * Sound
- * - lang: string (required)
  * - text: string 
  * - id: string (required)
- * - formats: List[string] (required)
+ * - formats: List[FormatLangPair] (required)
+ * FormatLangPair
+ * - lang: string (required)
+ * - format: string (required)
  */
 
 #endif /* _ASTERISK_RESOURCE_SOUNDS_H */

Modified: team/kmoore/stasis-http_sounds/rest-api/api-docs/sounds.json
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/stasis-http_sounds/rest-api/api-docs/sounds.json?view=diff&rev=387262&r1=387261&r2=387262
==============================================================================
--- team/kmoore/stasis-http_sounds/rest-api/api-docs/sounds.json (original)
+++ team/kmoore/stasis-http_sounds/rest-api/api-docs/sounds.json Wed May  1 17:00:15 2013
@@ -58,6 +58,19 @@
 		}
 	],
 	"models": {
+		"FormatLangPair": {
+			"id": "FormatLangPair",
+			"properties": {
+				"lang": {
+					"required": true,
+					"type": "string"
+				},
+				"format": {
+					"required": true,
+					"type": "string"
+				}
+			}
+		},
 		"Sound": {
 			"id": "Sound",
 			"properties": {
@@ -71,13 +84,10 @@
 					"description": "Text description of the sound, usually the words spoken.",
 					"type": "string"
 				},
-				"lang": {
-					"required": true,
-					"type": "string"
-				},
 				"formats": {
 					"required": true,
-					"type": "List[string]"
+					"description": "The formats and languages in which this sound is available.",
+					"type": "List[FormatLangPair]"
 				}
 			}
 		}




More information about the svn-commits mailing list