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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 24 14:39:43 CDT 2013


Author: jrose
Date: Wed Apr 24 14:39:39 2013
New Revision: 386442

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386442
Log:
asynchronous parking for bridge feature park

Modified:
    team/jrose/bridge_projects/include/asterisk/bridging.h
    team/jrose/bridge_projects/include/asterisk/parking.h
    team/jrose/bridge_projects/main/bridging.c
    team/jrose/bridge_projects/main/parking.c
    team/jrose/bridge_projects/res/parking/parking_applications.c
    team/jrose/bridge_projects/res/parking/parking_bridge.c
    team/jrose/bridge_projects/res/parking/parking_bridge_features.c
    team/jrose/bridge_projects/res/parking/parking_manager.c
    team/jrose/bridge_projects/res/parking/res_parking.h

Modified: team/jrose/bridge_projects/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/bridging.h?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging.h Wed Apr 24 14:39:39 2013
@@ -219,6 +219,8 @@
 	AST_BRIDGE_ACTION_TALKING_STOP,
 	/*! Bridge channel is to play the indicated sound file. */
 	AST_BRIDGE_ACTION_PLAY_FILE,
+	/*! Bridge channel is to get parked. */
+	AST_BRIDGE_ACTION_PARK,
 	/*! Bridge channel is to run the indicated application. */
 	AST_BRIDGE_ACTION_RUN_APP,
 
@@ -1139,6 +1141,22 @@
 void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
 
 /*!
+ * \brief Have a bridge channel park a channel in the bridge
+ * \since 12.0.0
+ *
+ * \param bridge_channel Bridge channel performing the parking
+ * \param parkee_uuid Unique id of the channel we want to park
+ * \param parker_uuid Unique id of the channel parking the call
+ * \param app_data string indicating data used for park application (NULL allowed)
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid,
+	const char *parker_uuid, const char *app_data);
+
+/*!
  * \brief Write a bridge action play file frame into the bridge.
  * \since 12.0.0
  *

Modified: team/jrose/bridge_projects/include/asterisk/parking.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/include/asterisk/parking.h?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/parking.h (original)
+++ team/jrose/bridge_projects/include/asterisk/parking.h Wed Apr 24 14:39:39 2013
@@ -36,6 +36,7 @@
 	PARKED_CALL_TIMEOUT,
 	PARKED_CALL_GIVEUP,
 	PARKED_CALL_UNPARKED,
+	PARKED_CALL_FAILED,
 };
 
 /*!
@@ -107,6 +108,20 @@
 struct stasis_message_type *ast_parked_call_type(void);
 
 /*!
+ * \brief invoke an installable park callback to asynchronously park a bridge_channel in a bridge
+ * \since 12
+ *
+ * \param bridge_channel the bridge channel that initiated parking
+ * \parkee_uuid channel id of the channel being parked
+ * \parker_uuid channel id of the channel that initiated parking
+ * \param app_data string of application data that might be applied to parking
+ */
+void ast_bridge_channel_park(struct ast_bridge_channel *bridge_channel,
+	const char *parkee_uuid,
+	const char *parker_uuid,
+	const char *app_data);
+
+/*!
  * \brief install a callback for handling blind transfers to a parking extension
  * \since 12
  *
@@ -136,6 +151,22 @@
 		const char *app_data);
 
 /*!
+ * \brief Install a function for ast_bridge_channel_park
+ * \since 12
+ *
+ * \param bridge_channel_park_func function callback to use for ast_bridge_channel_park
+ */
+void ast_install_bridge_channel_park_func(void (*bridge_channel_park_func)(struct ast_bridge_channel *parkee,
+	const char *parkee_uuid, const char *parker_uuid, const char *app_data));
+
+/*!
+ * \brief Uninstall the ast_bridge_channel_park function callback
+ * \since 12
+ */
+void ast_uninstall_bridge_channel_park_func(void);
+
+
+/*!
  * \brief Determines whether a certain extension is a park application extension or not.
  * \since 12
  *

Modified: team/jrose/bridge_projects/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/bridging.c?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Wed Apr 24 14:39:39 2013
@@ -58,6 +58,7 @@
 #include "asterisk/musiconhold.h"
 #include "asterisk/features.h"
 #include "asterisk/cli.h"
+#include "asterisk/parking.h"
 
 /*! All bridges container. */
 static struct ao2_container *bridges;
@@ -919,6 +920,48 @@
 {
 	payload_helper_playfile(ast_bridge_channel_queue_action_data,
 		bridge_channel, custom_play, playfile, moh_class);
+}
+
+struct bridge_park {
+	int parker_uuid_offset;
+	int app_data_offset;
+	/* buffer used for holding those strings */
+	char parkee_uuid[0];
+};
+
+static void bridge_channel_park(struct ast_bridge_channel *bridge_channel, struct bridge_park *payload)
+{
+	ast_bridge_channel_park(bridge_channel, payload->parkee_uuid, &payload->parkee_uuid[payload->parker_uuid_offset], payload->app_data_offset ? &payload->parkee_uuid[payload->app_data_offset] : NULL);
+}
+
+static void payload_helper_park(ast_bridge_channel_post_action_data post_it,
+	struct ast_bridge_channel *bridge_channel,
+	const char *parkee_uuid,
+	const char *parker_uuid,
+	const char *app_data)
+{
+	struct bridge_park *payload;
+	size_t len_parkee_uuid = strlen(parkee_uuid) + 1;
+	size_t len_parker_uuid = strlen(parker_uuid) + 1;
+	size_t len_app_data = !app_data ? 0 : strlen(app_data) + 1;
+	size_t len_payload = sizeof(*payload) + len_parker_uuid + len_parkee_uuid + len_app_data;
+
+	payload = alloca(len_payload);
+	payload->app_data_offset = len_app_data ? len_parkee_uuid + len_parker_uuid : 0;
+	payload->parker_uuid_offset = len_parkee_uuid;
+	strcpy(payload->parkee_uuid, parkee_uuid);
+	strcpy(&payload->parkee_uuid[payload->parker_uuid_offset], parker_uuid);
+	if (app_data) {
+		strcpy(&payload->parkee_uuid[payload->app_data_offset], app_data);
+	}
+
+	post_it(bridge_channel, AST_BRIDGE_ACTION_PARK, payload, len_payload);
+}
+
+void ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
+{
+	payload_helper_park(ast_bridge_channel_write_action_data,
+		bridge_channel, parkee_uuid, parker_uuid, app_data);
 }
 
 /*!
@@ -2026,6 +2069,13 @@
 		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
 		bridge_channel_unsuspend(bridge_channel);
 		break;
+	case AST_BRIDGE_ACTION_PARK:
+		bridge_channel_suspend(bridge_channel);
+		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+		bridge_channel_park(bridge_channel, action->data.ptr);
+		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+		bridge_channel_unsuspend(bridge_channel);
+		break;
 	case AST_BRIDGE_ACTION_RUN_APP:
 		bridge_channel_suspend(bridge_channel);
 		ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);

Modified: team/jrose/bridge_projects/main/parking.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/parking.c?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/main/parking.c (original)
+++ team/jrose/bridge_projects/main/parking.c Wed Apr 24 14:39:39 2013
@@ -40,9 +40,13 @@
 /*! \brief Topic for parking lots */
 static struct stasis_topic *parking_topic;
 
-/*! \brief Funcion Callback for handling blind transfers to park applications */
+/*! \brief Function Callback for handling blind transfers to park applications */
 static int (*ast_park_blind_xfer_func)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel,
 		const char *app_data) = NULL;
+
+/*! \brief Function Callback for handling a bridge channel trying to park itself */
+static void (*ast_bridge_channel_park_func)(struct ast_bridge_channel *parkee, const char *parkee_uuid,
+		const char *parker_uuid, const char *app_data) = NULL;
 
 void ast_parking_stasis_init(void)
 {
@@ -100,15 +104,20 @@
 	ao2_ref(parkee_snapshot, +1);
 	payload->parkee = parkee_snapshot;
 
-	ao2_ref(parker_snapshot, +1);
-	payload->parker = parker_snapshot;
+	if (parker_snapshot) {
+		ao2_ref(parker_snapshot, +1);
+		payload->parker = parker_snapshot;
+	}
 
 	if (retriever_snapshot) {
 		ao2_ref(retriever_snapshot, +1);
 		payload->retriever = retriever_snapshot;
 	}
 
-	ast_string_field_set(payload, parkinglot, parkinglot);
+	if (parkinglot) {
+		ast_string_field_set(payload, parkinglot, parkinglot);
+	}
+
 	payload->parkingspace = parkingspace;
 	payload->timeout = timeout;
 	payload->duration = duration;
@@ -124,9 +133,20 @@
 	ast_park_blind_xfer_func = park_blind_xfer_func;
 }
 
+void ast_install_bridge_channel_park_func(void (*bridge_channel_park_func)(struct ast_bridge_channel *parkee,
+	const char *parkee_uuid, const char *parker_uuid, const char *app_data))
+{
+	ast_bridge_channel_park_func = bridge_channel_park_func;
+}
+
 void ast_uninstall_park_blind_xfer_func(void)
 {
 	ast_park_blind_xfer_func = NULL;
+}
+
+void ast_uninstall_bridge_channel_park_func(void)
+{
+	ast_bridge_channel_park_func = NULL;
 }
 
 int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel *parker,
@@ -165,3 +185,11 @@
 
 	return exten;
 }
+
+void ast_bridge_channel_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
+{
+	/* Run installable function */
+	if (ast_bridge_channel_park_func) {
+		return ast_bridge_channel_park_func(bridge_channel, parkee_uuid, parker_uuid, app_data);
+	}
+}

Modified: team/jrose/bridge_projects/res/parking/parking_applications.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_applications.c?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_applications.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_applications.c Wed Apr 24 14:39:39 2013
@@ -200,7 +200,9 @@
 		}
 
 		if (ast_test_flag(&flags, MUXFLAG_NOANNOUNCE)) {
-			*disable_announce = 1;
+			if (disable_announce) {
+				*disable_announce = 1;
+			}
 		}
 
 		if (ast_test_flag(&flags, MUXFLAG_RINGING)) {
@@ -219,10 +221,10 @@
 	return 0;
 }
 
-int park_common_setup(struct parking_lot **lot, struct ast_bridge **parking_bridge, struct parked_user **pu,
+int park_common_setup(struct parking_lot **lot, struct ast_bridge **parking_bridge,
+		struct parked_user **pu, int *silence_announcements,
 		struct ast_channel *parker, struct ast_channel *parkee, const char *app_data)
 {
-	int silence_announcements = 0;
 	int use_ringing = 0;
 	int randomize = 0;
 	int time_limit = -1;
@@ -232,7 +234,7 @@
 
 	/* parse the app data if we have it */
 	if (app_data) {
-		park_app_parse_data(app_data, &silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
+		park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
 	}
 
 	lot_name = lot_name_app_arg;
@@ -253,7 +255,6 @@
 
 	if (!*lot) {
 		ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name);
-		ast_stream_and_wait(parker, "pbx-parkingfailed", "");
 		return -1;
 	}
 
@@ -263,21 +264,13 @@
 
 	if (!*parking_bridge) {
 		ast_log(LOG_ERROR, "Could not acquire holding bridge to park into\n");
-		ast_stream_and_wait(parker, "pbx-parkingfailed", "");
 		return -1;
 	}
 
 	*pu = generate_parked_user(*lot, parkee, parker, randomize, time_limit);
 
 	if (!*pu) {
-		ast_log(LOG_ERROR, "Failed to create parked user for channel %s, can not park.\n", ast_channel_name(parkee));
-		ast_stream_and_wait(parker, "pbx-parkingfailed", "");
-		return -1;
-	}
-
-	/* Announce parking space to the parking channel */
-	if (!silence_announcements) {
-		ast_say_digits(parker, (*pu)->parking_space, "", ast_channel_language(parker));
+		return -1;
 	}
 
 	/* Apply relevant bridge roles and such to the parking channel */
@@ -315,6 +308,7 @@
 	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
 	RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+	int silence_announcements = 0;
 
 	struct ast_bridge_features chan_features;
 	int res;
@@ -325,8 +319,15 @@
 	}
 
 	/* Handle all the common aprking setup stuff */
-	if (park_common_setup(&lot, &parking_bridge, &pu, chan, chan, data)) {
-		return -1;
+	if (park_common_setup(&lot, &parking_bridge, &pu, &silence_announcements, chan, chan, data)) {
+		ast_stream_and_wait(chan, "pbx-parkingfailed", "");
+		return -1;
+	}
+
+	/* Announce parking space to the parking channel */
+	/* Need to make this conditional */
+	if (!silence_announcements) {
+		ast_say_digits(chan, pu->parking_space, "", ast_channel_language(chan));
 	}
 
 	/* Initialize bridge features for the channel. */

Modified: team/jrose/bridge_projects/res/parking/parking_bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge.c?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge.c Wed Apr 24 14:39:39 2013
@@ -110,6 +110,7 @@
 		pu = swap->bridge_pvt;
 		if (!pu) {
 			/* This should be impossible since the only way a channel can enter in the first place is if it has a parked user associated with it */
+			publish_parked_call_failure(bridge_channel->chan);
 			return -1;
 		}
 

Modified: team/jrose/bridge_projects/res/parking/parking_bridge_features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_bridge_features.c?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge_features.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge_features.c Wed Apr 24 14:39:39 2013
@@ -35,47 +35,236 @@
 #include "asterisk/bridging_features.h"
 #include "asterisk/features.h"
 #include "asterisk/say.h"
+#include "asterisk/datastore.h"
+#include "asterisk/stasis.h"
+
+struct parked_subscription_datastore {
+	struct stasis_subscription *parked_subscription;
+};
+
+struct parked_subscription_data {
+	const char *parker_uuid;
+	const char *parkee_uuid;
+};
+
+static void parked_subscription_datastore_destroy(void *data)
+{
+	struct parked_subscription_datastore *subscription_data = data;
+
+	stasis_unsubscribe(subscription_data->parked_subscription);
+	subscription_data->parked_subscription = NULL;
+}
+
+static const struct ast_datastore_info parked_subscription_info = {
+	.type = "park subscription",
+	.destroy = parked_subscription_datastore_destroy,
+};
+
+static void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *playfile)
+{
+	int numeric_value;
+
+	if (sscanf(playfile, "%d", &numeric_value) != 1) {
+		/* If say_parking_space is called with a non-numeric string, we have a problem. */
+		ast_assert(0);
+		ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+		return;
+	}
+
+	ast_say_digits(bridge_channel->chan, numeric_value, "", ast_channel_language(bridge_channel->chan));
+
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+}
+
+static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data,
+	struct stasis_subscription *sub)
+{
+	const char *parkee_to_act_on = data->parkee_uuid;
+	char saynum_buf[16];
+	struct ast_channel_snapshot *parkee_snapshot = message->parkee;
+	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+
+	if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
+		return;
+	}
+
+	if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
+		/* We only care about these two event types */
+		return;
+	}
+
+	parker = ast_channel_get_by_name(data->parker_uuid);
+	if (!parker) {
+		return;
+	}
+
+	ast_channel_lock(parker);
+
+	bridge_channel = ast_channel_internal_bridge_channel(parker);
+	if (!bridge_channel) {
+		ast_channel_unlock(parker);
+		return;
+	}
+
+	/* this reference will be freed by RAII_VAR */
+	ao2_ref(bridge_channel, +1);
+	ast_channel_unlock(parker);
+
+	if (message->event_type == PARKED_CALL) {
+		/* queue the saynum on the bridge channel and hangup */
+		snprintf(saynum_buf, sizeof(saynum_buf), "%u", message->parkingspace);
+
+		ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
+
+		/* toss the subscription */
+		stasis_unsubscribe(sub);
+	}
+
+	if (message->event_type == PARKED_CALL_FAILED) {
+		ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
+		stasis_unsubscribe(sub);
+	}
+}
+
+static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
+{
+	if (stasis_message_type(message) == ast_parked_call_type()) {
+		struct ast_parked_call_payload *parked_call_message = stasis_message_data(message);
+		parker_parked_call_message_response(parked_call_message, data, sub);
+	}
+}
+
+static struct parked_subscription_datastore *fetch_parked_subscription_datastore(struct ast_channel *chan)
+{
+	struct ast_datastore *datastore = NULL;
+
+	ast_channel_lock(chan);
+	if (!(datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL))) {
+		ast_channel_unlock(chan);
+		return NULL;
+	}
+	ast_channel_unlock(chan);
+	return datastore->data;
+}
+
+static int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid)
+{
+	struct ast_datastore *datastore = NULL;
+	struct parked_subscription_datastore *parked_datastore;
+	struct parked_subscription_data *subscription_data;
+
+	/* If there is already a subscription, get rid of it. */
+	if ((parked_datastore = fetch_parked_subscription_datastore(chan))) {
+		stasis_unsubscribe(parked_datastore->parked_subscription);
+		parked_datastore->parked_subscription = NULL;
+		goto datastore_exists;
+	}
+
+	if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
+		return -1;
+	}
+
+	if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) {
+		ast_datastore_free(datastore);
+		return -1;
+	}
+
+datastore_exists:
+
+	if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data))))
+	{
+		ast_datastore_free(datastore);
+		ast_free(parked_datastore);
+	}
+
+	subscription_data->parker_uuid = ast_strdup(ast_channel_uniqueid(chan));
+	subscription_data->parkee_uuid = ast_strdup(parkee_uuid);
+
+	if (!(parked_datastore->parked_subscription = stasis_subscribe(ast_parking_topic(), parker_update_cb, subscription_data)))
+
+	/* If the parked_datastore already exists, there is no need to relink it. */
+	if (datastore) {
+		datastore->data = parked_datastore;
+		ast_channel_datastore_add(chan, datastore);
+	}
+
+	return 0;
+}
 
 static int park_feature_helper(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, const char *app_data)
 {
-	struct ast_bridge_channel *other;
-
+	RAII_VAR(struct ast_channel *, other, NULL, ao2_cleanup);
 	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
 	RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
-
-	/* If this is the only channel in this bridge then this feature shouldn't be at all usable. */
-	/* XXX Reaching accross the bridge no good */
-	if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
+	RAII_VAR(struct ao2_container *, bridge_peers, NULL, ao2_cleanup);
+	struct ao2_iterator iter;
+
+	bridge_peers = ast_bridge_peers(bridge);
+
+	if (ao2_container_count(bridge_peers) < 2) {
+		/* Can't do anything with that. */
 		return 0;
 	}
 
-	/* Find the channel we want to park */
-	other = AST_LIST_FIRST(&bridge->channels);
-	if (other == bridge_channel) {
-		other = AST_LIST_LAST(&bridge->channels);
-	}
-
-	ast_channel_lock(other->chan);
-
-	/* Handle all the common parking setup stuff */
-	if (park_common_setup(&lot, &parking_bridge, &pu, bridge_channel->chan, other->chan, app_data)) {
+	if (ao2_container_count(bridge_peers) > 2) {
+		/* XXX Need to do the multiparty bridge park... which is a local channel to the parking lot */
 		return 0;
 	}
 
-	/* Now for the fun part... park it! */
-	if (ast_bridge_move(bridge, parking_bridge, other->chan)) {
+	for (iter = ao2_iterator_init(bridge_peers, 0); (other = ao2_iterator_next(&iter)); ao2_ref(other, -1)) {
+		/* We need the channel that isn't the bridge_channel's channel. */
+		if (strcmp(ast_channel_uniqueid(other), ast_channel_uniqueid(bridge_channel->chan))) {
+			break;
+		}
+	}
+
+	if (!other) {
+		ast_assert(0);
+		return -1;
+	}
+
+	/* Subscribe to park messages with the other channel entering */
+	if (create_parked_subscription(bridge_channel->chan, ast_channel_uniqueid(other))) {
+		return -1;
+	}
+
+	/* Write the park frame with the intended recipient and other data out to the bridge. */
+	ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(other), ast_channel_uniqueid(bridge_channel->chan), app_data);
+
+	return 0;
+}
+
+static void park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
+{
+	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
+	RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
+
+	if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) {
+		/* We aren't the parkee, so ignore this action. */
+		return;
+	}
+
+	parker = ast_channel_get_by_name(uuid_parker);
+
+	if (!parker) {
+		ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
+	}
+
+	/* XXX Most of this can be moved into the push. Doing so will keep all of the publishing of parking events in
+	 * the bridge join/pull functions. Also, silence option is not respected here in park_common_setup */
+	if (park_common_setup(&lot, &parking_bridge, &pu, NULL, parker, bridge_channel->chan, app_data)) {
+		publish_parked_call_failure(bridge_channel->chan);
+		return;
+	}
+
+	if (ast_bridge_move(bridge_channel->bridge, parking_bridge, bridge_channel->chan)) {
 		ast_log(LOG_ERROR, "Failed to move %s into the parking bridge for %s\n",
-			ast_channel_name(other->chan), lot->name);
-		return 0;
-	}
-
-	ast_channel_unlock(other->chan);
-
-	/* The parker parked the call successfully, so it leaves the bridge now. */
-	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
-
-	return 0;
+			ast_channel_name(bridge_channel->chan), lot->name);
+	}
 }
 
 static int feature_park(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
@@ -162,11 +351,13 @@
 {
 	ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_PARKCALL);
 	ast_uninstall_park_blind_xfer_func();
+	ast_uninstall_bridge_channel_park_func();
 }
 
 int load_parking_bridge_features(void)
 {
 	ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park, NULL);
 	ast_install_park_blind_xfer_func(park_feature_helper);
+	ast_install_bridge_channel_park_func(park_bridge_channel);
 	return 0;
 }

Modified: team/jrose/bridge_projects/res/parking/parking_manager.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_manager.c?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_manager.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_manager.c Wed Apr 24 14:39:39 2013
@@ -226,6 +226,19 @@
 /*! \brief subscription to the parking lot topic */
 static struct stasis_subscription *parking_sub;
 
+static struct ast_parked_call_payload *parked_call_payload_from_failure(struct ast_channel *chan)
+{
+	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel_snapshot *, parkee_snapshot, NULL, ao2_cleanup);
+
+	parkee_snapshot = ast_channel_snapshot_create(chan);
+	if (!parkee_snapshot) {
+		return NULL;
+	}
+
+	return ast_parked_call_payload_create(PARKED_CALL_FAILED, parkee_snapshot, NULL, NULL, NULL, 0, 0, 0);
+}
+
 static struct ast_parked_call_payload *parked_call_payload_from_parked_user(struct parked_user *pu, enum ast_parked_call_event_type event_type)
 {
 	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
@@ -266,7 +279,11 @@
 	}
 
 	parkee_string = ast_manager_build_channel_state_string_suffix(payload->parkee, "Parkee");
-	parker_string = ast_manager_build_channel_state_string_suffix(payload->parker, "Parker");
+
+	if (payload->parker) {
+		parker_string = ast_manager_build_channel_state_string_suffix(payload->parker, "Parker");
+	}
+
 	if (payload->retriever) {
 		retriever_string = ast_manager_build_channel_state_string_suffix(payload->retriever, "Retriever");
 	}
@@ -281,7 +298,7 @@
 		"ParkingDuration: %lu\r\n",
 
 		ast_str_buffer(parkee_string),
-		ast_str_buffer(parker_string),
+		parker_string ? ast_str_buffer(parker_string) : "",
 		retriever_string ? ast_str_buffer(retriever_string) : "",
 		payload->parkinglot,
 		payload->parkingspace,
@@ -464,6 +481,24 @@
 	return RESULT_SUCCESS;
 }
 
+void publish_parked_call_failure(struct ast_channel *parkee)
+{
+	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+
+	payload = parked_call_payload_from_failure(parkee);
+	if (!payload) {
+		return;
+	}
+
+	msg = stasis_message_create(ast_parked_call_type(), payload);
+	if (!msg) {
+		return;
+	}
+
+	stasis_publish(ast_parking_topic(), msg);
+}
+
 void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type event_type)
 {
 	RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
@@ -479,9 +514,7 @@
 		return;
 	}
 
-	if (pu->chan) {
-		stasis_publish(ast_parking_topic(), msg);
-	}
+	stasis_publish(ast_parking_topic(), msg);
 }
 
 static void parked_call_message_response(struct ast_parked_call_payload *parked_call)
@@ -502,6 +535,9 @@
 	case PARKED_CALL_UNPARKED:
 		event_type = "UnParkedCall";
 		break;
+	case PARKED_CALL_FAILED:
+		/* PARKED_CALL_FAILED doesn't currently get a message and is used exclusively for bridging */
+		return;
 	}
 
 	parked_call_string = manager_build_parked_call_string(parked_call);

Modified: team/jrose/bridge_projects/res/parking/res_parking.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/res_parking.h?view=diff&rev=386442&r1=386441&r2=386442
==============================================================================
--- team/jrose/bridge_projects/res/parking/res_parking.h (original)
+++ team/jrose/bridge_projects/res/parking/res_parking.h Wed Apr 24 14:39:39 2013
@@ -319,6 +319,14 @@
 
 /*!
  * \since 12
+ * \brief Publish a stasis parked call message for the channel indicating failure to park.
+ *
+ * \param parkee channel belonging to the failed parkee
+ */
+void publish_parked_call_failure(struct ast_channel *parkee);
+
+/*!
+ * \since 12
  * \brief Publish a stasis parked call message for a given parked user
  *
  * \param pu pointer to a parked_user that we are generating the message for
@@ -335,6 +343,7 @@
  *            based on either app_data or channel variables.
  * \param parking_bridge pointer to an ast_bridge struct pointer. Set to the parking lot's parking bridge.
  * \param pu pointer to a parked user struct pointer. Set to the newly generated parked user.
+ * \param silence_announcements pointer to an integer which holds whether announcements should be made or not.
  *
  * \param parker ast_channel struct pointer, the channel that is initiating the parking
  * \param parkee ast_channel struct pointer, the channel that is being parked
@@ -348,7 +357,7 @@
  *       a specific usage example.
  */
 int park_common_setup(struct parking_lot **lot, struct ast_bridge **parking_bridge, struct parked_user **pu,
-		struct ast_channel *parker, struct ast_channel *parkee, const char *app_data);
+		int *silence_announcements, struct ast_channel *parker, struct ast_channel *parkee, const char *app_data);
 
 /*!
  * \since 12




More information about the asterisk-commits mailing list