[asterisk-commits] jrose: branch jrose/bridge_projects r385495 - in /team/jrose/bridge_projects:...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Apr 12 10:36:10 CDT 2013


Author: jrose
Date: Fri Apr 12 10:36:06 2013
New Revision: 385495

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=385495
Log:
Some files didn't get added when I updated for automerge yesterday. Ouch. Hopefully they haven't changed in the meantime.

Added:
    team/jrose/bridge_projects/include/asterisk/stasis_bridging.h   (with props)
    team/jrose/bridge_projects/main/manager_bridging.c   (with props)
    team/jrose/bridge_projects/main/stasis_bridging.c   (with props)

Added: team/jrose/bridge_projects/include/asterisk/stasis_bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/stasis_bridging.h?view=auto&rev=385495
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/stasis_bridging.h (added)
+++ team/jrose/bridge_projects/include/asterisk/stasis_bridging.h Fri Apr 12 10:36:06 2013
@@ -1,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#ifndef _STASIS_BRIDGING_H
+#define _STASIS_BRIDGING_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "asterisk/stringfields.h"
+#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+
+/*!
+ * \brief Structure that contains a snapshot of information about a bridge
+ */
+struct ast_bridge_snapshot {
+	AST_DECLARE_STRING_FIELDS(
+		/*! Immutable bridge UUID. */
+		AST_STRING_FIELD(uniqueid);
+		/*! Bridge technology that is handling the bridge */
+		AST_STRING_FIELD(technology);
+	);
+	/*! AO2 container of bare channel uniqueid strings participating in the bridge.
+	 * Allocated from ast_str_container_alloc() */
+	struct ao2_container *channels;
+	/*! Bridge flags to tweak behavior */
+	struct ast_flags feature_flags;
+	/*! Number of channels participating in the bridge */
+	unsigned int num_channels;
+	/*! Number of active channels in the bridge. */
+	unsigned int num_active;
+};
+
+/*!
+ * \since 12
+ * \brief Generate a snapshot of the bridge state. This is an ao2 object, so
+ * ao2_cleanup() to deallocate.
+ *
+ * \param bridge The bridge from which to generate a snapshot
+ *
+ * \retval AO2 refcounted snapshot on success
+ * \retval NULL on error
+ */
+struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge);
+
+/*!
+ * \since 12
+ * \brief Message type for \ref ast_bridge_snapshot.
+ *
+ * \retval Message type for \ref ast_bridge_snapshot.
+ */
+struct stasis_message_type *ast_bridge_snapshot_type(void);
+
+/*!
+ * \since 12
+ * \brief A topic which publishes the events for a particular bridge.
+ *
+ * If the given \a bridge is \c NULL, ast_bridge_topic_all() is returned.
+ *
+ * \param bridge Bridge for which to get a topic or \c NULL.
+ *
+ * \retval Topic for bridge's events.
+ * \retval ast_bridge_topic_all() if \a bridge is \c NULL.
+ */
+struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge);
+
+/*!
+ * \since 12
+ * \brief A topic which publishes the events for all bridges.
+ * \retval Topic for all bridge events.
+ */
+struct stasis_topic *ast_bridge_topic_all(void);
+
+/*!
+ * \since 12
+ * \brief A caching topic which caches \ref ast_bridge_snapshot messages from
+ * ast_bridge_events_all(void).
+ *
+ * \retval Caching topic for all bridge events.
+ */
+struct stasis_caching_topic *ast_bridge_topic_all_cached(void);
+
+/*!
+ * \since 12
+ * \brief Publish the state of a bridge
+ *
+ * \param bridge The bridge for which to publish state
+ */
+void ast_bridge_publish_state(struct ast_bridge *bridge);
+
+/*! \brief Message representing the merge of two bridges */
+struct ast_bridge_merge_message {
+	struct ast_bridge_snapshot *from;	/*!< Bridge from which channels will be removed during the merge */
+	struct ast_bridge_snapshot *to;		/*!< Bridge to which channels will be added during the merge */
+};
+
+/*!
+ * \since 12
+ * \brief Message type for \ref ast_bridge_merge_message.
+ *
+ * \retval Message type for \ref ast_bridge_merge_message.
+ */
+struct stasis_message_type *ast_bridge_merge_message_type(void);
+
+/*!
+ * \since 12
+ * \brief Publish a bridge merge
+ *
+ * \param to The bridge to which channels are being added
+ * \param from The bridge from which channels are being removed
+ */
+void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from);
+
+/*!
+ * \since 12
+ * \brief Blob of data associated with a bridge.
+ *
+ * The \c blob is actually a JSON object of structured data. It has a "type" field
+ * which contains the type string describing this blob.
+ */
+struct ast_bridge_blob {
+	/*! Bridge blob is associated with (or NULL for global/all bridges) */
+	struct ast_bridge_snapshot *bridge;
+	/*! Channel blob is associated with (may be NULL for some messages) */
+	struct ast_channel_snapshot *channel;
+	/*! JSON blob of data */
+	struct ast_json *blob;
+};
+
+/*!
+ * \since 12
+ * \brief Message type for \ref ast_bridge_blob messages.
+ *
+ * \retval Message type for \ref ast_bridge_blob messages.
+ */
+struct stasis_message_type *ast_bridge_blob_type(void);
+
+/*!
+ * \since 12
+ * \brief Creates a \ref ast_bridge_blob message.
+ *
+ * The \a blob JSON object requires a \c "type" field describing the blob. It
+ * should also be treated as immutable and not modified after it is put into the
+ * message.
+ *
+ * \param bridge Channel blob is associated with, or NULL for global/all bridges.
+ * \param blob JSON object representing the data.
+ * \return \ref ast_bridge_blob message.
+ * \return \c NULL on error
+ */
+struct stasis_message *ast_bridge_blob_create(struct ast_bridge *bridge,
+					struct ast_channel *chan,
+					struct ast_json *blob);
+
+/*!
+ * \since 12
+ * \brief Extracts the type field from a \ref ast_bridge_blob.
+ *
+ * Returned \c char* is still owned by \a obj
+ *
+ * \param obj Channel blob object.
+ *
+ * \retval Type field value from the blob.
+ * \retval \c NULL on error.
+ */
+const char *ast_bridge_blob_json_type(struct ast_bridge_blob *obj);
+
+/*!
+ * \since 12
+ * \brief Publish a bridge channel enter event
+ *
+ * \param bridge The bridge a channel entered
+ * \param chan The channel that entered the bridge
+ */
+void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*!
+ * \since 12
+ * \brief Publish a bridge channel leave event
+ *
+ * \param bridge The bridge a channel left
+ * \param chan The channel that left the bridge
+ */
+void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan);
+
+/*!
+ * \brief Dispose of the stasis bridging topics and message types
+ */
+void ast_stasis_bridging_shutdown(void);
+
+/*!
+ * \brief Initialize the stasis bridging topic and message types
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int ast_stasis_bridging_init(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif	/* _STASIS_BRIDGING_H */

Propchange: team/jrose/bridge_projects/include/asterisk/stasis_bridging.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/jrose/bridge_projects/include/asterisk/stasis_bridging.h
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: team/jrose/bridge_projects/include/asterisk/stasis_bridging.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/jrose/bridge_projects/main/manager_bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/manager_bridging.c?view=auto&rev=385495
==============================================================================
--- team/jrose/bridge_projects/main/manager_bridging.c (added)
+++ team/jrose/bridge_projects/main/manager_bridging.c Fri Apr 12 10:36:06 2013
@@ -1,0 +1,461 @@
+/*
+ * 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.
+ */
+
+/*! \file
+ *
+ * \brief The Asterisk Management Interface - AMI (bridge event handling)
+ *
+ * \author Kinsey Moore <kmoore at digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/stasis_bridging.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/manager.h"
+#include "asterisk/stasis_message_router.h"
+
+/*! \brief Message router for cached bridge state snapshot updates */
+static struct stasis_message_router *bridge_state_router;
+
+/*** DOCUMENTATION
+	<managerEvent language="en_US" name="BridgeCreate">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a bridge is created.</synopsis>
+			<syntax>
+				<parameter name="BridgeUniqueid">
+				</parameter>
+				<parameter name="BridgeType">
+					<para>The type of bridge</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="BridgeDestroy">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a bridge is destroyed.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="BridgeEnter">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a channel enters a bridge.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+				<parameter name="Uniqueid">
+					<para>The uniqueid of the channel entering the bridge</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<managerEvent language="en_US" name="BridgeLeave">
+		<managerEventInstance class="EVENT_FLAG_CALL">
+			<synopsis>Raised when a channel leaves a bridge.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+				<parameter name="Uniqueid">
+					<para>The uniqueid of the channel leaving the bridge</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	</managerEvent>
+	<manager name="BridgeList" language="en_US">
+		<synopsis>
+			Get a list of bridges in the system.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="BridgeType">
+				<para>Optional type for filtering the resulting list of bridges.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Returns a list of bridges, optionally filtering on a bridge type.</para>
+		</description>
+	</manager>
+	<manager name="BridgeInfo" language="en_US">
+		<synopsis>
+			Get information about a bridge.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="BridgeUniqueid" required="true">
+				<para>The unique ID of the bridge about which to retreive information.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Returns detailed information about a bridge and the channels in it.</para>
+		</description>
+	</manager>
+ ***/
+
+/*!
+ * \brief Generate the AMI message body from a bridge snapshot
+ * \internal
+ *
+ * \param snapshot the bridge snapshot for which to generate an AMI message
+ *                 body
+ *
+ * \retval NULL on error
+ * \retval ast_str* on success (must be ast_freed by caller)
+ */
+static struct ast_str *manager_build_bridge_state_string(
+	const struct ast_bridge_snapshot *snapshot,
+	const char *suffix)
+{
+	struct ast_str *out = ast_str_create(128);
+	int res = 0;
+	if (!out) {
+		return NULL;
+	}
+	res = ast_str_set(&out, 0,
+		"BridgeUniqueid%s: %s\r\n"
+		"BridgeType%s: %s\r\n",
+		suffix, snapshot->uniqueid,
+		suffix, snapshot->technology);
+
+	if (!res) {
+		return NULL;
+	}
+
+	return out;
+}
+
+/*! \brief Typedef for callbacks that get called on channel snapshot updates */
+typedef struct ast_manager_event_blob *(*bridge_snapshot_monitor)(
+	struct ast_bridge_snapshot *old_snapshot,
+	struct ast_bridge_snapshot *new_snapshot);
+
+/*! \brief Handle bridge creation */
+static struct ast_manager_event_blob *bridge_create(
+	struct ast_bridge_snapshot *old_snapshot,
+	struct ast_bridge_snapshot *new_snapshot)
+{
+	if (!new_snapshot || old_snapshot) {
+		return NULL;
+	}
+
+	return ast_manager_event_blob_create(
+		EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
+}
+
+/*! \brief Handle bridge destruction */
+static struct ast_manager_event_blob *bridge_destroy(
+	struct ast_bridge_snapshot *old_snapshot,
+	struct ast_bridge_snapshot *new_snapshot)
+{
+	if (new_snapshot || !old_snapshot) {
+		return NULL;
+	}
+
+	return ast_manager_event_blob_create(
+		EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
+}
+
+
+bridge_snapshot_monitor bridge_monitors[] = {
+	bridge_create,
+	bridge_destroy,
+};
+
+static void bridge_snapshot_update(void *data, struct stasis_subscription *sub,
+				    struct stasis_topic *topic,
+				    struct stasis_message *message)
+{
+	RAII_VAR(struct ast_str *, bridge_event_string, NULL, ast_free);
+	struct stasis_cache_update *update;
+	struct ast_bridge_snapshot *old_snapshot;
+	struct ast_bridge_snapshot *new_snapshot;
+	size_t i;
+
+	update = stasis_message_data(message);
+
+	if (ast_bridge_snapshot_type() != update->type) {
+		return;
+	}
+
+	old_snapshot = stasis_message_data(update->old_snapshot);
+	new_snapshot = stasis_message_data(update->new_snapshot);
+
+	for (i = 0; i < ARRAY_LEN(bridge_monitors); ++i) {
+		RAII_VAR(struct ast_manager_event_blob *, event, NULL, ao2_cleanup);
+
+		event = bridge_monitors[i](old_snapshot, new_snapshot);
+		if (!event) {
+			continue;
+		}
+
+		/* If we haven't already, build the channel event string */
+		if (!bridge_event_string) {
+			bridge_event_string =
+				manager_build_bridge_state_string(
+					new_snapshot ? new_snapshot : old_snapshot, "");
+			if (!bridge_event_string) {
+				return;
+			}
+		}
+
+		manager_event(event->event_flags, event->manager_event, "%s%s",
+			ast_str_buffer(bridge_event_string),
+			event->extra_fields);
+	}
+}
+
+static void bridge_merge_cb(void *data, struct stasis_subscription *sub,
+				    struct stasis_topic *topic,
+				    struct stasis_message *message)
+{
+	struct ast_bridge_merge_message *merge_msg = stasis_message_data(message);
+	RAII_VAR(struct ast_str *, to_text, NULL, ast_free);
+	RAII_VAR(struct ast_str *, from_text, NULL, ast_free);
+
+	ast_assert(merge_msg->to != NULL);
+	ast_assert(merge_msg->from != NULL);
+
+	to_text = manager_build_bridge_state_string(merge_msg->to, "");
+	from_text = manager_build_bridge_state_string(merge_msg->from, "From");
+
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when two bridges are merged.</synopsis>
+			<syntax>
+				<xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+				<parameter name="BridgeUniqueidFrom">
+					<para>The uniqueid of the bridge being dissolved in the merge</para>
+				</parameter>
+				<parameter name="BridgeTypeFrom">
+					<para>The type of bridge that is being dissolved in the merge</para>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "BridgeMerge",
+		"%s"
+		"%s",
+		ast_str_buffer(to_text),
+		ast_str_buffer(from_text));
+}
+
+static void bridge_blob_cb(void *data, struct stasis_subscription *sub,
+				    struct stasis_topic *topic,
+				    struct stasis_message *message)
+{
+	struct ast_bridge_blob *blob = stasis_message_data(message);
+	const char *type = ast_bridge_blob_json_type(blob);
+	RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
+	char *event;
+
+	if (!strcmp("leave", type)) {
+		event = "BridgeLeave";
+	} else if (!strcmp("enter", type)) {
+		event = "BridgeEnter";
+	} else {
+		return;
+	}
+
+	bridge_text = manager_build_bridge_state_string(blob->bridge, "");
+
+	manager_event(EVENT_FLAG_CALL, event,
+		"%s"
+		"Uniqueid: %s\r\n",
+		ast_str_buffer(bridge_text),
+		blob->channel->uniqueid);
+}
+
+static int filter_bridge_type_cb(void *obj, void *arg, int flags)
+{
+	char *bridge_type = arg;
+	struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
+	/* unlink all the snapshots that do not match the bridge type */
+	return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;
+}
+
+static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
+{
+	struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
+	struct mansession *s = arg;
+	char *id_text = data;
+	RAII_VAR(struct ast_str *, bridge_info, manager_build_bridge_state_string(snapshot, ""), ast_free);
+
+	astman_append(s,
+		"Event: BridgeListItem\r\n"
+		"%s"
+		"%s"
+		"\r\n",
+		ast_str_buffer(bridge_info),
+		id_text);
+	return 0;
+}
+
+static int manager_bridges_list(struct mansession *s, const struct message *m)
+{
+	const char *id = astman_get_header(m, "ActionID");
+	const char *type_filter = astman_get_header(m, "BridgeType");
+	RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
+	RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
+
+	if (!id_text) {
+		astman_send_error(s, m, "Internal error");
+		return -1;
+	}
+
+	if (!ast_strlen_zero(id)) {
+		ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
+	}
+
+	bridges = stasis_cache_dump(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type());
+	if (!bridges) {
+		astman_send_error(s, m, "Internal error");
+		return -1;
+	}
+
+	if (!ast_strlen_zero(type_filter)) {
+		char *type_filter_dup = ast_strdupa(type_filter);
+		ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, filter_bridge_type_cb, type_filter_dup);
+	}
+
+	ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, ast_str_buffer(id_text));
+
+	astman_append(s,
+		"Event: BridgeListComplete\r\n"
+		"%s"
+		"\r\n",
+		ast_str_buffer(id_text));
+
+	return 0;
+}
+
+static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
+{
+	char *uniqueid = obj;
+	struct mansession *s = arg;
+	char *id_text = data;
+
+	astman_append(s,
+		"Event: BridgeInfoChannel\r\n"
+		"Uniqueid: %s\r\n"
+		"%s"
+		"\r\n",
+		uniqueid,
+		id_text);
+	return 0;
+}
+
+static int manager_bridge_info(struct mansession *s, const struct message *m)
+{
+	const char *id = astman_get_header(m, "ActionID");
+	const char *bridge_uniqueid = astman_get_header(m, "BridgeUniqueid");
+	RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
+	struct ast_bridge_snapshot *snapshot;
+
+	if (!id_text) {
+		astman_send_error(s, m, "Internal error");
+		return -1;
+	}
+
+	if (!ast_strlen_zero(bridge_uniqueid)) {
+		astman_send_error(s, m, "BridgeUniqueid must be provided");
+		return -1;
+	}
+
+	if (!ast_strlen_zero(id)) {
+		ast_str_set(&id_text, 0, "ActionID: %s\r\n", id);
+	}
+
+	msg = stasis_cache_get(ast_bridge_topic_all_cached(), ast_bridge_snapshot_type(), bridge_uniqueid);
+	if (!msg) {
+		astman_send_error(s, m, "Specified BridgeUniqueid not found");
+		return -1;
+	}
+
+	snapshot = stasis_message_data(msg);
+	bridge_info = manager_build_bridge_state_string(snapshot, "");
+
+	ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, ast_str_buffer(id_text));
+
+	astman_append(s,
+		"Event: BridgeInfoComplete\r\n"
+		"%s"
+		"%s"
+		"\r\n",
+		ast_str_buffer(bridge_info),
+		ast_str_buffer(id_text));
+
+	return 0;
+}
+
+static void manager_bridging_shutdown(void)
+{
+	stasis_message_router_unsubscribe(bridge_state_router);
+	bridge_state_router = NULL;
+	ast_manager_unregister("BridgeList");
+	ast_manager_unregister("BridgeInfo");
+}
+
+int manager_bridging_init(void)
+{
+	int ret = 0;
+
+	if (bridge_state_router) {
+		/* Already initialized */
+		return 0;
+	}
+
+	ast_register_atexit(manager_bridging_shutdown);
+
+	bridge_state_router = stasis_message_router_create(
+		stasis_caching_get_topic(ast_bridge_topic_all_cached()));
+
+	if (!bridge_state_router) {
+		return -1;
+	}
+
+	ret |= stasis_message_router_add(bridge_state_router,
+					 stasis_cache_update_type(),
+					 bridge_snapshot_update,
+					 NULL);
+
+	ret |= stasis_message_router_add(bridge_state_router,
+					 ast_bridge_merge_message_type(),
+					 bridge_merge_cb,
+					 NULL);
+
+	ret |= stasis_message_router_add(bridge_state_router,
+					 ast_bridge_blob_type(),
+					 bridge_blob_cb,
+					 NULL);
+
+	ret |= ast_manager_register_xml_core("BridgeList", 0, manager_bridges_list);
+	ret |= ast_manager_register_xml_core("BridgeInfo", 0, manager_bridge_info);
+
+	/* If somehow we failed to add any routes, just shut down the whole
+	 * thing and fail it.
+	 */
+	if (ret) {
+		manager_bridging_shutdown();
+		return -1;
+	}
+
+	return 0;
+}

Propchange: team/jrose/bridge_projects/main/manager_bridging.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/jrose/bridge_projects/main/manager_bridging.c
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: team/jrose/bridge_projects/main/manager_bridging.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/jrose/bridge_projects/main/stasis_bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/stasis_bridging.c?view=auto&rev=385495
==============================================================================
--- team/jrose/bridge_projects/main/stasis_bridging.c (added)
+++ team/jrose/bridge_projects/main/stasis_bridging.c Fri Apr 12 10:36:06 2013
@@ -1,0 +1,356 @@
+/*
+ * 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.
+ */
+
+/*! \file
+ *
+ * \brief Stasis Messages and Data Types for Bridge Objects
+ *
+ * \author Kinsey Moore <kmoore at digium.com>
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/stasis.h"
+#include "asterisk/channel.h"
+#include "asterisk/stasis_bridging.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
+
+#define SNAPSHOT_CHANNELS_BUCKETS 13
+
+/*! \brief Message type for bridge snapshot messages */
+static struct stasis_message_type *bridge_snapshot_type;
+
+/*! \brief Message type for bridge blob messages */
+static struct stasis_message_type *bridge_blob_type;
+
+/*! \brief Message type for bridge merge messages */
+static struct stasis_message_type *bridge_merge_message_type;
+
+/*! \brief Aggregate topic for bridge messages */
+static struct stasis_topic *bridge_topic_all;
+
+/*! \brief Caching aggregate topic for bridge snapshots */
+static struct stasis_caching_topic *bridge_topic_all_cached;
+
+/*! \brief Topic pool for individual bridge topics */
+static struct stasis_topic_pool *bridge_topic_pool;
+
+/*! \brief Destructor for bridge snapshots */
+static void bridge_snapshot_dtor(void *obj)
+{
+	struct ast_bridge_snapshot *snapshot = obj;
+	ast_string_field_free_memory(snapshot);
+	ao2_cleanup(snapshot->channels);
+	snapshot->channels = NULL;
+}
+
+struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge)
+{
+	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
+	struct ast_bridge_channel *bridge_channel;
+
+	snapshot = ao2_alloc(sizeof(*snapshot), bridge_snapshot_dtor);
+	if (!snapshot || ast_string_field_init(snapshot, 128)) {
+		return NULL;
+	}
+
+	snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
+	if (!snapshot->channels) {
+		return NULL;
+	}
+
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+		if (ast_str_container_add(snapshot->channels,
+				ast_channel_uniqueid(bridge_channel->chan))) {
+			return NULL;
+		}
+	}
+
+	ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
+	ast_string_field_set(snapshot, technology, bridge->technology->name);
+
+	snapshot->feature_flags = bridge->feature_flags;
+	snapshot->num_channels = bridge->num_channels;
+	snapshot->num_active = bridge->num_active;
+
+	ao2_ref(snapshot, +1);
+	return snapshot;
+}
+
+struct stasis_message_type *ast_bridge_snapshot_type(void)
+{
+	return bridge_snapshot_type;
+}
+
+struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
+{
+	struct stasis_topic *bridge_topic = stasis_topic_pool_get_topic(bridge_topic_pool, bridge->uniqueid);
+	if (!bridge_topic) {
+		return ast_bridge_topic_all();
+	}
+	return bridge_topic;
+}
+
+struct stasis_topic *ast_bridge_topic_all(void)
+{
+	return bridge_topic_all;
+}
+
+struct stasis_caching_topic *ast_bridge_topic_all_cached(void)
+{
+	return bridge_topic_all_cached;
+}
+
+void ast_bridge_publish_state(struct ast_bridge *bridge)
+{
+	RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	ast_assert(bridge != NULL);
+
+	snapshot = ast_bridge_snapshot_create(bridge);
+	if (!snapshot) {
+		return;
+	}
+
+	msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic(bridge), msg);
+}
+
+struct stasis_message_type *ast_bridge_merge_message_type(void)
+{
+	return bridge_merge_message_type;
+}
+
+/*! \brief Destructor for bridge merge messages */
+static void bridge_merge_message_dtor(void *obj)
+{
+	struct ast_bridge_merge_message *msg = obj;
+
+	ao2_cleanup(msg->to);
+	msg->to = NULL;
+	ao2_cleanup(msg->from);
+	msg->from = NULL;
+}
+
+/*! \brief Bridge merge message creation helper */
+static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
+{
+	RAII_VAR(struct ast_bridge_merge_message *, msg, NULL, ao2_cleanup);
+
+	msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
+	if (!msg) {
+		return NULL;
+	}
+
+	msg->to = ast_bridge_snapshot_create(to);
+	if (!msg->to) {
+		return NULL;
+	}
+
+	msg->from = ast_bridge_snapshot_create(from);
+	if (!msg->from) {
+		return NULL;
+	}
+
+	ao2_ref(msg, +1);
+	return msg;
+}
+
+void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
+{
+	RAII_VAR(struct ast_bridge_merge_message *, merge_msg, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	ast_assert(to != NULL);
+	ast_assert(from != NULL);
+
+	merge_msg = bridge_merge_message_create(to, from);
+	if (!merge_msg) {
+		return;
+	}
+
+	msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic_all(), msg);
+}
+
+struct stasis_message_type *ast_bridge_blob_type(void)
+{
+	return bridge_blob_type;
+}
+
+static void bridge_blob_dtor(void *obj)
+{
+	struct ast_bridge_blob *event = obj;
+	ao2_cleanup(event->bridge);
+	event->bridge = NULL;
+	ao2_cleanup(event->channel);
+	event->channel = NULL;
+	ast_json_unref(event->blob);
+	event->blob = NULL;
+}
+
+struct stasis_message *ast_bridge_blob_create(struct ast_bridge *bridge,
+					struct ast_channel *chan,
+					struct ast_json *blob)
+{
+	RAII_VAR(struct ast_bridge_blob *, obj, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	struct ast_json *type;
+
+	ast_assert(blob != NULL);
+
+	type = ast_json_object_get(blob, "type");
+	if (type == NULL) {
+		ast_log(LOG_ERROR, "Invalid ast_bridge_blob; missing type field\n");
+		return NULL;
+	}
+
+	obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
+	if (!obj) {
+		return NULL;
+	}
+
+	if (bridge) {
+		obj->bridge = ast_bridge_snapshot_create(bridge);
+		if (obj->bridge == NULL) {
+			return NULL;
+		}
+	}
+
+	if (chan) {
+		obj->channel = ast_channel_snapshot_create(chan);
+		if (obj->channel == NULL) {
+			return NULL;
+		}
+	}
+
+	obj->blob = ast_json_ref(blob);
+
+	msg = stasis_message_create(ast_bridge_blob_type(), obj);
+	if (!msg) {
+		return NULL;
+	}
+
+	ao2_ref(msg, +1);
+	return msg;
+}
+
+const char *ast_bridge_blob_json_type(struct ast_bridge_blob *obj)
+{
+	if (obj == NULL) {
+		return NULL;
+	}
+
+	return ast_json_string_get(ast_json_object_get(obj->blob, "type"));
+}
+
+void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, enter_json, NULL, ast_json_unref);
+
+	ast_bridge_publish_state(bridge);
+
+	enter_json = ast_json_pack("{s: s}",
+			"type", "enter");
+
+	msg = ast_bridge_blob_create(bridge, chan, enter_json);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic(bridge), msg);
+}
+
+void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
+{
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_json *, leave_json, NULL, ast_json_unref);
+
+	ast_bridge_publish_state(bridge);
+
+	leave_json = ast_json_pack("{s: s}",
+			"type", "leave");
+
+	msg = ast_bridge_blob_create(bridge, chan, leave_json);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_bridge_topic(bridge), msg);
+}
+
+void ast_stasis_bridging_shutdown(void)
+{
+	ao2_cleanup(bridge_snapshot_type);
+	bridge_snapshot_type = NULL;
+	ao2_cleanup(bridge_blob_type);
+	bridge_blob_type = NULL;
+	ao2_cleanup(bridge_merge_message_type);
+	bridge_merge_message_type = NULL;
+	ao2_cleanup(bridge_topic_all);
+	bridge_topic_all = NULL;
+	bridge_topic_all_cached = stasis_caching_unsubscribe(bridge_topic_all_cached);
+	ao2_cleanup(bridge_topic_pool);
+	bridge_topic_pool = NULL;
+}
+
+/*! \brief snapshot ID getter for caching topic */
+static const char *bridge_snapshot_get_id(struct stasis_message *msg)
+{
+	struct ast_bridge_snapshot *snapshot;
+	if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {
+		return NULL;
+	}
+	snapshot = stasis_message_data(msg);
+	return snapshot->uniqueid;
+}
+
+int ast_stasis_bridging_init(void)
+{
+	bridge_snapshot_type = stasis_message_type_create("ast_bridge_snapshot");
+	bridge_blob_type = stasis_message_type_create("ast_bridge_blob");
+	bridge_merge_message_type = stasis_message_type_create("ast_bridge_merge_message");
+	bridge_topic_all = stasis_topic_create("ast_bridge_topic_all");
+	bridge_topic_all_cached = stasis_caching_topic_create(bridge_topic_all, bridge_snapshot_get_id);
+	bridge_topic_pool = stasis_topic_pool_create(bridge_topic_all);
+	return !bridge_snapshot_type
+		|| !bridge_blob_type
+		|| !bridge_merge_message_type
+		|| !bridge_topic_all
+		|| !bridge_topic_all_cached
+		|| !bridge_topic_pool ? -1 : 0;
+}

Propchange: team/jrose/bridge_projects/main/stasis_bridging.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/jrose/bridge_projects/main/stasis_bridging.c
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: team/jrose/bridge_projects/main/stasis_bridging.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list