[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