[asterisk-commits] file: branch file/media r167060 - in /team/file/media: include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Dec 31 17:03:43 CST 2008


Author: file
Date: Wed Dec 31 17:03:42 2008
New Revision: 167060

URL: http://svn.digium.com/view/asterisk?view=rev&rev=167060
Log:
Add some stuff I've been poking at for a bit. This includes the media format structures themselves plus configuring, reloading, and displaying of them.

Modified:
    team/file/media/include/asterisk/media.h
    team/file/media/main/asterisk.c
    team/file/media/main/media.c

Modified: team/file/media/include/asterisk/media.h
URL: http://svn.digium.com/view/asterisk/team/file/media/include/asterisk/media.h?view=diff&rev=167060&r1=167059&r2=167060
==============================================================================
--- team/file/media/include/asterisk/media.h (original)
+++ team/file/media/include/asterisk/media.h Wed Dec 31 17:03:42 2008
@@ -18,6 +18,13 @@
 
 /*! \file
  * \brief Media Format and Negotiation API
+ * \author Joshua Colp <jcolp at digium.com>
+ * \ref AstMediaFormats
+ */
+
+/*!
+ * \page AstMediaFormats Media Format and Negotiation API
+ *
  */
 
 #ifndef _ASTERISK_MEDIA_H
@@ -27,6 +34,70 @@
 extern "C" {
 #endif
 
+/*! \brief Types of media formats that we support */
+enum ast_media_format_type {
+	AST_MEDIA_FORMAT_AUDIO = 0,       /*!< Media format is for an audio based format */
+	AST_MEDIA_FORMAT_VIDEO,           /*!< Media format is for a video based format */
+	AST_MEDIA_FORMAT_IMAGE,           /*!< Media format is for an image based format */
+	AST_MEDIA_FORMAT_IMAGE_STREAM,    /*!< Media format is for an image stream (like T.38) based format */
+	AST_MEDIA_FORMAT_TEXT,            /*!< Media format is for a text based format */
+	AST_MEDIA_FORMAT_TELEPHONE_EVENT, /*!< Media format is for a DTMF based format */
+};
+
+/*!
+ * \brief Structure that represents audio specific media format information
+ */
+struct ast_media_format_audio {
+	unsigned int sample_rate;        /*!< Sample rate of the format */
+	unsigned int frame_size;         /*!< Default frame size */
+	unsigned int maximum_frame_size; /*!< Maximum allowed frame size */
+	unsigned int minimum_frame_size; /*!< Minimum allowed frame size */
+};
+
+/*!
+ * \brief Structure that represents video specific media format information
+ */
+struct ast_media_format_video {
+	unsigned int maximum_bandwidth; /*!< Maximum allowed bandwidth */
+	unsigned int maximum_bitrate;   /*!< Maximum allowed bitrate */
+};
+
+/*!
+ * \brief Structure that represents telephone event specific media format information
+ */
+struct ast_media_format_telephone_event {
+	unsigned int sample_rate; /*!< Sample rate of the format */
+};
+
+/*!
+ * \brief Structure that represents a known media format
+ */
+struct ast_media_format {
+	char name[32];                                   /*!< Unique name to identify this media format */
+	char codec[32];                                  /*!< Name of the codec this media format belongs to */
+	enum ast_media_format_type type;                 /*!< Type of media format */
+	unsigned int channels;                           /*!< Number of channels this media format has */
+	struct ast_variable *format_specific_attributes; /*!< Format specific attributes */
+	union {
+		struct ast_media_format_audio audio;                     /*!< Audio specific information */
+		struct ast_media_format_video video;                     /*!< Video specific information */
+		struct ast_media_format_telephone_event telephone_event; /*!< Telephone event specific information */
+	};
+};
+
+/*! \brief Initialize core parts for media formats
+ *
+ * Example usage:
+ *
+ * \code
+ * ast_media_load();
+ * \endcode
+ *
+ * This initializes internal data structures that are used to hold known media formats
+ * and registers CLI commands which can be used to examine the media formats themselves.
+ */
+void ast_media_load(void);
+	
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/file/media/main/asterisk.c
URL: http://svn.digium.com/view/asterisk/team/file/media/main/asterisk.c?view=diff&rev=167060&r1=167059&r2=167060
==============================================================================
--- team/file/media/main/asterisk.c (original)
+++ team/file/media/main/asterisk.c Wed Dec 31 17:03:42 2008
@@ -129,6 +129,7 @@
 #include "asterisk/dsp.h"
 #include "asterisk/buildinfo.h"
 #include "asterisk/xmldoc.h"
+#include "asterisk/media.h"
 
 #include "asterisk/doxyref.h"		/* Doxygen documentation */
 
@@ -3483,6 +3484,8 @@
 		exit(1);
 	}
 
+	ast_media_load();
+
 #ifdef AST_XML_DOCS
 	/* Load XML documentation. */
 	ast_xmldoc_load_documentation();

Modified: team/file/media/main/media.c
URL: http://svn.digium.com/view/asterisk/team/file/media/main/media.c?view=diff&rev=167060&r1=167059&r2=167060
==============================================================================
--- team/file/media/main/media.c (original)
+++ team/file/media/main/media.c Wed Dec 31 17:03:42 2008
@@ -28,3 +28,399 @@
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/media.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/cli.h"
+#include "asterisk/config.h"
+
+/* We have to provide a module name for configuration parser reasons */
+#define AST_MODULE "media"
+
+/* Number of buckets to use for media formats */
+#define MAX_MEDIA_FORMATS_BUCKETS 53
+
+/* Configuration file for user defined media formats */
+static const char config_file[] = "media_formats.conf";
+
+/*! \brief Container that holds known media formats */
+static struct ao2_container *media_formats;
+
+/*! \brief Hashing function used for media formats */
+static int media_format_hash_cb(const void *obj, const int flags)
+{
+	const struct ast_media_format *media_format = obj;
+	return ast_str_hash(media_format->name);
+}
+
+/*! \brief Comparison function used for media formats */
+static int media_format_cmp_cb(void *obj, void *arg, int flags)
+{
+	const struct ast_media_format *format0 = obj, *format1 = arg;
+	return !strcasecmp(format0->name, format1->name) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+/*! \brief Destroy function used for media formats */
+static void media_format_destroy_cb(void *obj)
+{
+	struct ast_media_format *media_format = obj;
+
+	if (media_format->format_specific_attributes) {
+		ast_variables_destroy(media_format->format_specific_attributes);
+		media_format->format_specific_attributes = NULL;
+	}
+
+	return;
+}
+
+/*! \brief Conversion function which takes a media format enum and turns it into a string */
+static const char *media_format_type_enum2str(enum ast_media_format_type type)
+{
+	switch (type) {
+	case AST_MEDIA_FORMAT_AUDIO:
+		return "Audio";
+	case AST_MEDIA_FORMAT_VIDEO:
+		return "Video";
+	case AST_MEDIA_FORMAT_IMAGE:
+		return "Image";
+	case AST_MEDIA_FORMAT_IMAGE_STREAM:
+		return "Image Stream";
+	case AST_MEDIA_FORMAT_TEXT:
+		return "Text";
+	case AST_MEDIA_FORMAT_TELEPHONE_EVENT:
+		return "Telephone Event";
+	}
+
+	return "Unknown";
+}
+
+/*! \brief Function which populates a media format with audio specific information */
+static int media_format_populate_audio(struct ast_media_format *media_format, struct ast_variable *v)
+{
+	for (; v; v = v->next) {
+		CV_START(v->name, v->value);
+		CV_F("sample_rate", media_format->audio.sample_rate = atoi(__val));
+		CV_F("frame_size", media_format->audio.frame_size = atoi(__val));
+		CV_F("maximum_frame_size", media_format->audio.maximum_frame_size = atoi(__val));
+		CV_F("minimum_frame_size", media_format->audio.minimum_frame_size = atoi(__val));
+		CV_END;
+	}
+
+	if (!media_format->audio.sample_rate || !media_format->audio.frame_size) {
+		ast_log(LOG_ERROR, "Audio media format '%s' did not pass configuration check.\n", media_format->name);
+		return -1;
+	}
+
+	if (!media_format->audio.maximum_frame_size) {
+		media_format->audio.maximum_frame_size = media_format->audio.frame_size;
+	}
+
+	if (!media_format->audio.minimum_frame_size) {
+		media_format->audio.minimum_frame_size = media_format->audio.frame_size;
+	}
+
+	if (VERBOSITY_ATLEAST(2)) {
+		ast_verbose(VERBOSE_PREFIX_3 "Configured audio media format '%s' with codec '%s', sample rate '%d', and frame size '%d'\n", 
+			    media_format->name, media_format->codec, media_format->audio.sample_rate, media_format->audio.frame_size);
+	}
+
+	return 0;
+}
+
+/*! \brief Function which populates a media format with video specific information */
+static int media_format_populate_video(struct ast_media_format *media_format, struct ast_variable *v)
+{
+	for (; v; v = v->next) {
+		CV_START(v->name, v->value);
+		CV_F("maximum_bandwidth", media_format->video.maximum_bandwidth = atoi(__val));
+		CV_F("maximum_bitrate", media_format->video.maximum_bitrate = atoi(__val));
+		CV_END;
+	}
+
+	if (VERBOSITY_ATLEAST(2)) {
+		ast_verbose(VERBOSE_PREFIX_3 "Configured video media format '%s'\n", media_format->name);
+	}
+
+	return 0;
+}
+
+/*! \brief Function which populates a media format with image specific information */
+static int media_format_populate_image(struct ast_media_format *media_format, struct ast_variable *v)
+{
+	if (VERBOSITY_ATLEAST(2)) {
+		ast_verbose(VERBOSE_PREFIX_3 "Configured image media format '%s'\n", media_format->name);
+	}
+
+	return 0;
+}
+
+/*! \brief Function which populates a media format with image stream specific information */
+static int media_format_populate_image_stream(struct ast_media_format *media_format, struct ast_variable *v)
+{
+	if (VERBOSITY_ATLEAST(2)) {
+		ast_verbose(VERBOSE_PREFIX_3 "Configured image stream media format '%s'\n", media_format->name);
+	}
+
+	return 0;
+}
+
+/*! \brief Function which populates a media format with text specific information */
+static int media_format_populate_text(struct ast_media_format *media_format, struct ast_variable *v)
+{
+	if (VERBOSITY_ATLEAST(2)) {
+		ast_verbose(VERBOSE_PREFIX_3 "Configured text media format '%s'\n", media_format->name);
+	}
+
+	return 0;
+}
+
+/*! \brief Function which populates a media format with telephony event specific information */
+static int media_format_populate_telephone_event(struct ast_media_format *media_format, struct ast_variable *v)
+{
+	for (; v; v = v->next) {
+		CV_START(v->name, v->value);
+		CV_F("sample_rate", media_format->telephone_event.sample_rate = atoi(__val));
+		CV_END;
+	}
+
+	if (!media_format->telephone_event.sample_rate) {
+		ast_log(LOG_ERROR, "Telephone event media format '%s' did not pass configuration check.\n",
+			media_format->name);
+		return -1;
+	}
+
+	if (VERBOSITY_ATLEAST(2)) {
+		ast_verbose(VERBOSE_PREFIX_3 "Configured telephone event media format '%s' with sample rate '%d'\n",
+			    media_format->name, media_format->telephone_event.sample_rate);
+	}
+
+	return 0;
+}
+
+/*! \brief Function which creates the core of a media format */
+static void media_format_create(const char *name, enum ast_media_format_type type, struct ast_variable *v)
+{
+	struct ast_media_format *media_format;
+	struct ast_variable *var = v;
+	int res = 0;
+
+	if (!(media_format = ao2_alloc(sizeof(*media_format), media_format_destroy_cb))) {
+		return;
+	}
+
+	media_format->type = type;
+	ast_copy_string(media_format->name, name, sizeof(media_format->name));
+
+	/* Take care of common configuration parameters */
+	for (; var; var = var->next) {
+		CV_START(var->name, var->value);
+		CV_STR("codec", media_format->codec);
+		CV_UINT("channels", media_format->channels);
+		CV_END;
+	}
+
+	/* For type specific ones pass it off to the respective handler */
+	switch (type) {
+	case AST_MEDIA_FORMAT_AUDIO:
+		res = media_format_populate_audio(media_format, v);
+		break;
+	case AST_MEDIA_FORMAT_VIDEO:
+		res = media_format_populate_video(media_format, v);
+		break;
+	case AST_MEDIA_FORMAT_IMAGE:
+		res = media_format_populate_image(media_format, v);
+		break;
+	case AST_MEDIA_FORMAT_IMAGE_STREAM:
+		res = media_format_populate_image_stream(media_format, v);
+		break;
+	case AST_MEDIA_FORMAT_TEXT:
+		res = media_format_populate_text(media_format, v);
+		break;
+	case AST_MEDIA_FORMAT_TELEPHONE_EVENT:
+		res = media_format_populate_telephone_event(media_format, v);
+		break;
+	}
+	
+	if (!res) {
+		ao2_link(media_formats, media_format);
+	}
+
+	ao2_ref(media_format, -1);
+
+	return;
+}
+
+/*! \brief Function used for unlinking all the media formats */
+static int media_format_unlinker(void *obj, void *arg, int flags)
+{
+	return CMP_MATCH;
+}
+
+/*! \brief Function which parses and configures user defined media formats */
+static int load_config(int reload)
+{
+	struct ast_config *cfg = NULL;
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	const char *name = NULL;
+
+	if (!(cfg = ast_config_load(config_file, config_flags))) {
+		ast_log(LOG_ERROR, "Defined media formats file '%s' not found\n", config_file);
+		return -1;
+	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+		return 0;
+	}
+
+	ao2_lock(media_formats);
+
+	/* For reloads we actually want to drop all of the existing media formats since they may change */
+	if (reload) {
+		ao2_callback(media_formats, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE , media_format_unlinker, NULL);
+
+		if (VERBOSITY_ATLEAST(1)) {
+			ast_verbose(VERBOSE_PREFIX_2 "Removed existing media formats\n");
+		}
+	}
+
+	while ((name = ast_category_browse(cfg, name))) {
+		const char *type = ast_variable_retrieve(cfg, name, "type");
+
+		if (!strcasecmp(type, "audio")) {
+			media_format_create(name, AST_MEDIA_FORMAT_AUDIO, ast_variable_browse(cfg, name));
+		} else if (!strcasecmp(type, "video")) {
+			media_format_create(name, AST_MEDIA_FORMAT_VIDEO, ast_variable_browse(cfg, name));
+		} else if (!strcasecmp(type, "image")) {
+			media_format_create(name, AST_MEDIA_FORMAT_IMAGE, ast_variable_browse(cfg, name));
+		} else if (!strcasecmp(type, "image_stream")) {
+			media_format_create(name, AST_MEDIA_FORMAT_IMAGE_STREAM, ast_variable_browse(cfg, name));
+		} else if (!strcasecmp(type, "text")) {
+			media_format_create(name, AST_MEDIA_FORMAT_TEXT, ast_variable_browse(cfg, name));
+		} else if (!strcasecmp(type, "telephone_event")) {
+			media_format_create(name, AST_MEDIA_FORMAT_TELEPHONE_EVENT, ast_variable_browse(cfg, name));
+		} else {
+			ast_log(LOG_ERROR, "Unknown media format type '%s'\n", type);
+		}
+	}
+
+	ao2_unlock(media_formats);
+
+	if (VERBOSITY_ATLEAST(1)) {
+		ast_verbose(VERBOSE_PREFIX_2 "%d media formats configured\n", ao2_container_count(media_formats));
+	}
+
+	ast_config_destroy(cfg);
+
+	return 0;
+}
+
+/*! \brief CLI command to show all media formats */
+static char *media_show_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT "%-32.32s %-16.16s %-32.32s %-12.12s\n"
+#define FORMAT2 "%-32.32s %-16.16s %-32.32s %-12d\n"	
+	struct ao2_iterator i;
+	struct ast_media_format *media_format;
+	
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media show formats";
+		e->usage =
+			"Usage: media show formats\n"
+			"       Displays information about known media formats.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	ast_cli(a->fd, FORMAT, "Name", "Type", "Codec", "Channels");
+	
+	i = ao2_iterator_init(media_formats, 0);
+
+	while ((media_format = ao2_iterator_next(&i))) {
+		ast_cli(a->fd, FORMAT2, media_format->name, media_format_type_enum2str(media_format->type),
+			ast_strlen_zero(media_format->codec) ? "None" : media_format->codec,
+			media_format->channels);
+		ao2_ref(media_format, -1);
+	}
+
+	ast_cli(a->fd, "%d media formats configured\n", ao2_container_count(media_formats));
+	
+	return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
+/*! \brief CLI command to show a specific media format */
+static char *media_show_format(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ast_media_format *media_format, tmp_media_format;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media show format";
+		e->usage =
+			"Usage: media show format <format name>\n"
+			"       Displays information about a specific media format.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != e->args + 1) {
+		return CLI_SHOWUSAGE;
+	}
+
+	ast_copy_string(tmp_media_format.name, a->argv[a->argc - 1], sizeof(tmp_media_format.name));
+
+	if (!(media_format = ao2_find(media_formats, &tmp_media_format, OBJ_POINTER))) {
+		ast_cli(a->fd, "Could not find a media format named '%s'\n", a->argv[a->argc - 1]);
+		return CLI_FAILURE;
+	}
+
+	ast_cli(a->fd, "--- General Information ---\n");
+	ast_cli(a->fd, "Name: %s\n", media_format->name);
+	ast_cli(a->fd, "Codec: %s\n", media_format->codec);
+	ast_cli(a->fd, "Channels: %d\n", media_format->channels);
+	
+	ao2_ref(media_format, -1);
+	
+	return CLI_SUCCESS;
+}
+
+/*! \brief CLI command to reload user defined media formats */
+static char *media_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media reload";
+		e->usage =
+			"Usage: media reload\n"
+			"       Reloads user defined media formats.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	ast_cli(a->fd, "%s\n", load_config(1) ? "Failed to reload defined media formats." : "Defined media formats reloaded.");
+
+	return CLI_SUCCESS;
+}
+
+/*! \brief CLI commands to interact with media formats */
+static struct ast_cli_entry cli_media_formats[] = {
+	AST_CLI_DEFINE(media_show_formats, "Show known media formats"),
+	AST_CLI_DEFINE(media_show_format, "Show details about a specific media format"),
+	AST_CLI_DEFINE(media_reload, "Reload user defined media formats"),
+};
+
+void ast_media_load(void)
+{
+	if (!(media_formats = ao2_container_alloc(MAX_MEDIA_FORMATS_BUCKETS, media_format_hash_cb, media_format_cmp_cb))) {
+		return;
+	}
+
+	/* Load all defined media formats */
+	load_config(0);
+
+	/* Finally register the CLI commands that display them and allow the user to reload the user defined ones */
+	ast_cli_register_multiple(cli_media_formats, sizeof(cli_media_formats) / sizeof(struct ast_cli_entry));
+
+	return;
+}




More information about the asterisk-commits mailing list