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

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Mar 29 11:48:41 CDT 2013


Author: jrose
Date: Fri Mar 29 11:48:37 2013
New Revision: 384328

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=384328
Log:
Progress up to March 29

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/features.c
    team/jrose/bridge_projects/main/manager_channels.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_controller.c
    team/jrose/bridge_projects/res/parking/res_parking.h
    team/jrose/bridge_projects/res/res_parking.c

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=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/bridging.h (original)
+++ team/jrose/bridge_projects/include/asterisk/bridging.h Fri Mar 29 11:48:37 2013
@@ -675,6 +675,22 @@
 int ast_bridge_merge(struct ast_bridge *bridge1, struct ast_bridge *bridge2);
 
 /*!
+ * \brief XXX Hack function for moving a channel from one bridge to another
+ *
+ * \param bridge_src bridge the channel is being moved from
+ * \param bridge_dst bridge the chnanel is being moved to
+ * \param chan Channel being moved
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * \code
+ * ast_bridge_move(old_bridge, new_bridge, chan);
+ * \endcode
+ */
+int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan);
+
+/*!
  * \brief Adjust the bridge merge inhibit request count.
  * \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=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/include/asterisk/parking.h (original)
+++ team/jrose/bridge_projects/include/asterisk/parking.h Fri Mar 29 11:48:37 2013
@@ -52,10 +52,49 @@
 	);
 };
 
-/*! \brief Constructor for parked_call_payload objects */
+/*!
+ * \brief Constructor for parked_call_payload objects
+ * \since 12
+ *
+ * \param event_type What kind of parked call event is happening
+ * \param parkee_snapshot channel snapshot of the parkee
+ * \param parker_snapshot channel snapshot of the parker
+ * \param parkinglot name of the parking lot where the parked call is parked
+ * \param parkingspace what numerical parking space the parked call is parked in
+ * \param timeout how long the parked call can remain at the point this snapshot is created before timing out
+ * \param duration how long the parked call has currently been parked
+ *
+ * \retval NULL if the parked call payload can't be allocated
+ * \retval reference to a newly created parked call payload
+ */
 struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type, struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot, const char *parkinglot, int parkingspace, long int timeout, long int duration);
 
+/*!
+ * \brief initialize parking stasis types
+ * \since 12
+ */
 void ast_parking_stasis_init(void);
+
+/*!
+ * \brief disable parking stasis types
+ * \since 12
+ */
 void ast_parking_stasis_disable(void);
+
+/*!
+ * \brief accessor for the parking stasis topic
+ * \since 12
+ *
+ * \retval NULL if the parking topic hasn't been created or has been disabled
+ * \retval a pointer to the parking topic
+ */
 struct stasis_topic *ast_parking_topic(void);
+
+/*!
+ * \brief accessor for the parked call stasis message type
+ * \since 12
+ *
+ * \retval NULL if the parking topic hasn't been created or has been canceled
+ * \retval a pointer to the parked call message type
+ */
 struct stasis_message_type *ast_parked_call_type(void);

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=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/main/bridging.c (original)
+++ team/jrose/bridge_projects/main/bridging.c Fri Mar 29 11:48:37 2013
@@ -2614,6 +2614,66 @@
 	ast_debug(1, "Merged channels from bridge %p into bridge %p\n", bridge2, bridge1);
 }
 
+static void ast_bridge_move_do(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
+{
+	struct ast_bridge_channel *bridge_channel;
+
+	ast_debug(1, "Moving channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
+
+	AST_LIST_TRAVERSE(&bridge_src->channels, bridge_channel, entry) {
+		if (bridge_channel->chan == chan) {
+			break;
+		}
+	}
+
+	ast_bridge_channel_pull(bridge_channel);
+
+	/* Point to new bridge. */
+	ao2_ref(bridge_dst, +1);
+	ast_bridge_channel_lock(bridge_channel);
+	bridge_channel->bridge = bridge_dst;
+	ast_bridge_channel_unlock(bridge_channel);
+	ao2_ref(bridge_src, -1);
+
+	ast_bridge_channel_push(bridge_channel);
+
+	ast_bridge_reconfigured(bridge_dst);
+	ast_bridge_reconfigured(bridge_src);
+
+	ast_debug(1, "Moved channel %s from bridge %p into bridge %p\n", ast_channel_name(chan), bridge_src, bridge_dst);
+}
+
+int ast_bridge_move(struct ast_bridge *bridge_src, struct ast_bridge *bridge_dst, struct ast_channel *chan)
+{
+	int res = -1;
+
+	/* Deadlock avoidance. */
+	for (;;) {
+		ast_bridge_lock(bridge_src);
+		if (!ast_bridge_trylock(bridge_dst)) {
+			break;
+		}
+		ast_bridge_unlock(bridge_src);
+		sched_yield();
+	}
+
+	if (bridge_src->dissolved || bridge_dst->dissolved) {
+		ast_debug(1, "Can't move from bridge %p into bridge %p, one or both bridges are dissolved.\n",
+			bridge_src, bridge_dst);
+	} else {
+		++bridge_src->inhibit_merge;
+		++bridge_dst->inhibit_merge;
+		ast_bridge_move_do(bridge_src, bridge_dst, chan);
+		--bridge_dst->inhibit_merge;
+		--bridge_src->inhibit_merge;
+		res = 0;
+	}
+
+	ast_bridge_unlock(bridge_dst);
+	ast_bridge_unlock(bridge_src);
+	return res;
+}
+
 int ast_bridge_merge(struct ast_bridge *bridge1, struct ast_bridge *bridge2)
 {
 	int res = -1;

Modified: team/jrose/bridge_projects/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/features.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/main/features.c (original)
+++ team/jrose/bridge_projects/main/features.c Fri Mar 29 11:48:37 2013
@@ -249,40 +249,7 @@
 			</variablelist>
 		</description>
 	</application>
-	<application name="ParkedCall" language="en_US">
-		<synopsis>
-			Retrieve a parked call.
-		</synopsis>
-		<syntax>
-			<parameter name="exten">
-				<para>Parking space extension to retrieve a parked call.
-				If not provided then the first available parked call in the
-				parking lot will be retrieved.</para>
-			</parameter>
-			<parameter name="parking_lot_name">
-				<para>Specify from which parking lot to retrieve a parked call.</para>
-				<para>The parking lot used is selected in the following order:</para>
-				<para>1) parking_lot_name option</para>
-				<para>2) <variable>PARKINGLOT</variable> variable</para>
-				<para>3) <literal>CHANNEL(parkinglot)</literal> function
-				(Possibly preset by the channel driver.)</para>
-				<para>4) Default parking lot.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>Used to retrieve a parked call from a parking lot.</para>
-			<note>
-				<para>Parking lots automatically create and manage dialplan extensions in
-				the parking lot context.  You do not need to explicitly use this
-				application in your dialplan.  Instead, all you should do is include the
-				parking lot context in your dialplan.</para>
-			</note>
-		</description>
-		<see-also>
-			<ref type="application">Park</ref>
-			<ref type="application">ParkAndAnnounce</ref>
-		</see-also>
-	</application>
+
 	<manager name="Park" language="en_US">
 		<synopsis>
 			Park a channel.
@@ -4925,279 +4892,6 @@
 	AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
 END_OPTIONS );
 
-/*! \brief Pickup parked call */
-static int parked_call_exec(struct ast_channel *chan, const char *data)
-{
-	int res;
-	struct ast_channel *peer = NULL;
-	struct parkeduser *pu;
-	struct ast_context *con;
-	char *parse;
-	const char *pl_name;
-	int park = 0;
-	struct ast_bridge_config config;
-	struct ast_parkinglot *parkinglot;
-	AST_DECLARE_APP_ARGS(app_args,
-		AST_APP_ARG(pl_space);	/*!< Parking lot space to retrieve if present. */
-		AST_APP_ARG(pl_name);	/*!< Parking lot name to use if present. */
-		AST_APP_ARG(dummy);		/*!< Place to put any remaining args string. */
-	);
-
-	parse = ast_strdupa(data);
-	AST_STANDARD_APP_ARGS(app_args, parse);
-
-	if (!ast_strlen_zero(app_args.pl_space)) {
-		if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
-			ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
-				app_args.pl_space);
-			park = -1;
-		}
-	}
-
-	if (!ast_strlen_zero(app_args.pl_name)) {
-		pl_name = app_args.pl_name;
-	} else {
-		pl_name = findparkinglotname(chan);
-	}
-	if (ast_strlen_zero(pl_name)) {
-		/* Parking lot is not specified, so use the default parking lot. */
-		parkinglot = parkinglot_addref(default_parkinglot);
-	} else {
-		parkinglot = find_parkinglot(pl_name);
-		if (!parkinglot) {
-			/* It helps to answer the channel if not already up. :) */
-			if (ast_channel_state(chan) != AST_STATE_UP) {
-				ast_answer(chan);
-			}
-			if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
-				ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
-					"pbx-invalidpark", ast_channel_name(chan));
-			}
-			ast_log(LOG_WARNING,
-				"Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
-				ast_channel_name(chan), pl_name);
-			return -1;
-		}
-	}
-
-	AST_LIST_LOCK(&parkinglot->parkings);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
-		if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
-			&& !pu->notquiteyet && !ast_channel_pbx(pu->chan)) {
-			/* The parking space has a call and can be picked up now. */
-			AST_LIST_REMOVE_CURRENT(list);
-			break;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END;
-	if (pu) {
-		struct ast_callid *callid = ast_read_threadstorage_callid();
-
-		/* Found a parked call to pickup. */
-		peer = pu->chan;
-
-		/* We need to map the call id we have from this thread to the channel we found. */
-		if (callid) {
-			ast_channel_callid_set(peer, callid);
-			callid = ast_callid_unref(callid);
-		}
-
-		con = ast_context_find(parkinglot->cfg.parking_con);
-		if (con) {
-			if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
-				ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
-			} else {
-				notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
-			}
-		} else {
-			ast_log(LOG_WARNING, "Whoa, no parking context?\n");
-		}
-
-		ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
-		/*** DOCUMENTATION
-			<managerEventInstance>
-				<synopsis>Raised when a call has been unparked.</synopsis>
-				<syntax>
-					<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Exten'])" />
-					<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" />
-					<xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='From'])" />
-				</syntax>
-				<see-also>
-					<ref type="application">ParkedCall</ref>
-					<ref type="managerEvent">ParkedCall</ref>
-				</see-also>
-			</managerEventInstance>
-		***/
-		ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
-			"Exten: %s\r\n"
-			"Channel: %s\r\n"
-			"Parkinglot: %s\r\n"
-			"From: %s\r\n"
-			"CallerIDNum: %s\r\n"
-			"CallerIDName: %s\r\n"
-			"ConnectedLineNum: %s\r\n"
-			"ConnectedLineName: %s\r\n"
-			"Uniqueid: %s\r\n",
-			pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name,
-			ast_channel_name(chan),
-			S_COR(ast_channel_caller(pu->chan)->id.number.valid, ast_channel_caller(pu->chan)->id.number.str, "<unknown>"),
-			S_COR(ast_channel_caller(pu->chan)->id.name.valid, ast_channel_caller(pu->chan)->id.name.str, "<unknown>"),
-			S_COR(ast_channel_connected(pu->chan)->id.number.valid, ast_channel_connected(pu->chan)->id.number.str, "<unknown>"),
-			S_COR(ast_channel_connected(pu->chan)->id.name.valid, ast_channel_connected(pu->chan)->id.name.str, "<unknown>"),
-			ast_channel_uniqueid(pu->chan)
-			);
-
-		/* Stop entertaining the caller. */
-		switch (pu->hold_method) {
-		case AST_CONTROL_HOLD:
-			ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
-			break;
-		case AST_CONTROL_RINGING:
-			ast_indicate(pu->chan, -1);
-			break;
-		default:
-			break;
-		}
-		pu->hold_method = 0;
-
-		parkinglot_unref(pu->parkinglot);
-		ast_free(pu);
-	}
-	AST_LIST_UNLOCK(&parkinglot->parkings);
-
-	if (peer) {
-		/* Update connected line between retrieving call and parked call. */
-		struct ast_party_connected_line connected;
-
-		ast_party_connected_line_init(&connected);
-
-		/* Send our caller-id to peer. */
-		ast_channel_lock(chan);
-		ast_connected_line_copy_from_caller(&connected, ast_channel_caller(chan));
-		ast_channel_unlock(chan);
-		connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-		if (ast_channel_connected_line_sub(chan, peer, &connected, 0) &&
-			ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
-			ast_channel_update_connected_line(peer, &connected, NULL);
-		}
-
-		/*
-		 * Get caller-id from peer.
-		 *
-		 * Update the retrieving call before it is answered if possible
-		 * for best results.  Some phones do not support updating the
-		 * connected line information after connection.
-		 */
-		ast_channel_lock(peer);
-		ast_connected_line_copy_from_caller(&connected, ast_channel_caller(peer));
-		ast_channel_unlock(peer);
-		connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
-		if (ast_channel_connected_line_sub(peer, chan, &connected, 0) &&
-			ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
-			ast_channel_update_connected_line(chan, &connected, NULL);
-		}
-
-		ast_party_connected_line_free(&connected);
-	}
-
-	/* JK02: it helps to answer the channel if not already up */
-	if (ast_channel_state(chan) != AST_STATE_UP) {
-		ast_answer(chan);
-	}
-
-	if (peer) {
-		struct ast_datastore *features_datastore;
-		struct ast_dial_features *dialfeatures;
-
-		/* Play a courtesy to the source(s) configured to prefix the bridge connecting */
-		if (!ast_strlen_zero(courtesytone)) {
-			static const char msg[] = "courtesy tone";
-
-			switch (parkedplay) {
-			case 0:/* Courtesy tone to pickup chan */
-				res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
-				break;
-			case 1:/* Courtesy tone to parked chan */
-				res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
-				break;
-			case 2:/* Courtesy tone to both chans */
-				res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
-				break;
-			default:
-				res = 0;
-				break;
-			}
-			if (res) {
-				bridge_failed_peer_goto(chan, peer);
-				parkinglot_unref(parkinglot);
-				return -1;
-			}
-		}
-
-		res = ast_channel_make_compatible(chan, peer);
-		if (res < 0) {
-			ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(peer));
-			bridge_failed_peer_goto(chan, peer);
-			parkinglot_unref(parkinglot);
-			return -1;
-		}
-		/* This runs sorta backwards, since we give the incoming channel control, as if it
-		   were the person called. */
-		ast_verb(3, "Channel %s connected to parked call %d\n", ast_channel_name(chan), park);
-
-		pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer));
-		ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
-		memset(&config, 0, sizeof(struct ast_bridge_config));
-
-		/* Get datastore for peer and apply it's features to the callee side of the bridge config */
-		ast_channel_lock(peer);
-		features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
-		if (features_datastore && (dialfeatures = features_datastore->data)) {
-			ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
-				AST_FLAGS_ALL);
-		}
-		ast_channel_unlock(peer);
-
-		if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
-		}
-		if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
-		}
-		if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
-		}
-		if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
-		}
-		if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
-		}
-		if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
-		}
-		if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
-		}
-		if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
-			ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
-		}
-
-		res = ast_bridge_call(chan, peer, &config);
-	} else {
-		if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
-			ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
-				ast_channel_name(chan));
-		}
-		ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n",
-			ast_channel_name(chan), park);
-		res = -1;
-	}
-
-	parkinglot_unref(parkinglot);
-	return res;
-}
-
 /*!
  * \brief Unreference parkinglot object.
  */
@@ -8340,7 +8034,6 @@
 	ast_manager_unregister("Bridge");
 	ast_manager_unregister("Park");
 
-	ast_unregister_application(parkedcall);
 	ast_unregister_application(app_bridge);
 
 	pthread_cancel(parking_thread);
@@ -8365,7 +8058,6 @@
 		return -1;
 	}
 	ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
-	res = ast_register_application2(parkedcall, parked_call_exec, NULL, NULL, NULL);
 	if (!res) {
 		ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park);
 		ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);

Modified: team/jrose/bridge_projects/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/main/manager_channels.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/main/manager_channels.c (original)
+++ team/jrose/bridge_projects/main/manager_channels.c Fri Mar 29 11:48:37 2013
@@ -204,8 +204,8 @@
 	if (snapshot->manager_vars) {
 		struct ast_var_t *var;
 		AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
-			ast_str_append(&out, 0, "ChanVariable(%s): %s=%s\r\n",
-				       snapshot->name,
+			ast_str_append(&out, 0, " ChanVariable(%s)%s: %s=%s\r\n",
+				       snapshot->name, suffix,
 				       var->name, var->value);
 		}
 	}

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=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_applications.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_applications.c Fri Mar 29 11:48:37 2013
@@ -95,6 +95,40 @@
 		</see-also>
 	</application>
 
+	<application name="ParkedCall" language="en_US">
+		<synopsis>
+			Retrieve a parked call.
+		</synopsis>
+		<syntax>
+			<parameter name="parking_lot_name">
+				<para>Specify from which parking lot to retrieve a parked call.</para>
+				<para>The parking lot used is selected in the following order:</para>
+				<para>1) parking_lot_name option</para>
+				<para>2) <variable>PARKINGLOT</variable> variable</para>
+				<para>3) <literal>CHANNEL(parkinglot)</literal> function
+				(Possibly preset by the channel driver.)</para>
+				<para>4) Default parking lot.</para>
+			</parameter>
+			<parameter name="parking_space">
+				<para>Parking space to retrieve a parked call from.
+				If not provided then the first available parked call in the
+				parking lot will be retrieved.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Used to retrieve a parked call from a parking lot.</para>
+			<note>
+				<para>If a parkinglot's parkext option is set, then Parking lots
+				will automatically create and manage dialplan extensions in
+				the parking lot context. If that is the case then you will not
+				need to manage parking extensions yourself, just include the
+				parking context of the parking lot.</para>
+			</note>
+		</description>
+		<see-also>
+			<ref type="application">Park</ref>
+		</see-also>
+	</application>
  ***/
 
 /* Park a call */
@@ -148,6 +182,8 @@
 	int time_limit = -1;
 	char *comeback_override = NULL;
 
+	int res;
+
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(lot_name);
 		AST_APP_ARG(options);
@@ -217,15 +253,36 @@
 	reset_parked_time(pu);
 	ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
 
+	/*
+	 * If the bridge was broken for a hangup that isn't real, then
+	 * don't run the h extension, because the channel isn't really
+	 * hung up.  This should really only happen with
+	 * AST_SOFTHANGUP_ASYNCGOTO.
+	 */
+	res = -1;
+	ast_channel_lock(chan);
+	if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
+		res = 0;
+	}
+	ast_channel_unlock(chan);
+
 	/* At this point the channel is no longer in the bridge. Start breaking things down. */
 	ast_bridge_features_cleanup(&chan_features);
 
-	/* If the parked channel exits without a resolution set, it gave up. Issue a ParkedCallGiveUp message and exit early. */
-	if (pu->resolution == PARK_UNSET) {
+	switch (pu->resolution) {
+	case PARK_UNSET:
+		/* If the parked channel exits without a resolution set, it gave up. Issue a ParkedCallGiveUp message and exit early. */
 		pu->resolution = PARK_ABANDON;
 		publish_parked_call(pu, PARKED_CALL_GIVEUP);
 		unpark_parked_user(pu);
-		return -1;
+		return res;
+	case PARK_ABANDON:
+	case PARK_FORCED:
+	case PARK_ANSWERED:
+		return res;
+	case PARK_TIMEOUT:
+		/* If we timed out, we need to do some fancy stuff when we re-enter the PBX */
+		break;
 	}
 
 	unpark_parked_user(pu);
@@ -246,3 +303,75 @@
 
 	return ast_check_hangup_locked(chan) ? -1 : 0;
 }
+
+int parked_call_app_exec(struct ast_channel *chan, const char *data)
+{
+	RAII_VAR(struct parking_lot_state *, lot, NULL, ao2_cleanup);
+	RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup); /* Parked user being retrieved */
+	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+	int target_space = -1;
+
+	struct ast_bridge *bridge;
+
+	//struct ast_bridge_features chan_features;
+	char *parse;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(lot_name);
+		AST_APP_ARG(parking_space);
+		AST_APP_ARG(other);	/* Any remaining unused arguments */
+	);
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (ast_strlen_zero(args.lot_name)) {
+		lot = channel_find_parking_lot_state(chan);
+	} else {
+		lot = parking_lot_state_find_by_name(args.lot_name);
+	}
+
+	if (!lot) {
+		ast_log(LOG_ERROR, "Could not find the requested parking lot\n");
+		return -1;
+	}
+
+	if (!ast_strlen_zero(args.parking_space)) {
+		if (sscanf(args.parking_space, "%d", &target_space) != 1 || target_space < 0) {
+			ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", args.parking_space);
+			return -1;
+		}
+	}
+
+	bridge = ast_bridge_base_new(
+		AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_MULTIMIX,
+		AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_SMART);
+
+	if (!bridge) {
+		return -1;
+	}
+
+	/* answer the channel if needed */
+	if (ast_channel_state(chan) != AST_STATE_UP) {
+		ast_answer(chan);
+	}
+
+	pu = parking_lot_state_retrieve_parked_user(lot, target_space);
+
+	if (!pu) {
+		ast_stream_and_wait(chan, "pbx-invalidpark", "");
+		return -1;
+	}
+
+	/* Move the parkee into the new bridge */
+	if (ast_bridge_move(lot->parking_bridge, bridge, pu->chan)) {
+		ast_bridge_destroy(bridge);
+		return -1;
+	}
+
+	/* Now we should try to join the new bridge ourselves... */
+	ast_bridge_join(bridge, chan, NULL, /* XXX features go here! */ NULL, NULL, 1);
+
+	return 0;
+}
+

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=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_bridge.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_bridge.c Fri Mar 29 11:48:37 2013
@@ -28,6 +28,12 @@
 #include "res_parking.h"
 #include "asterisk/astobj2.h"
 
+struct ast_bridge_parking
+{
+	struct ast_bridge base;
+	/* private stuff for parking */
+};
+
 /*!
  * \internal
  * \brief ast_bridge parking class destructor
@@ -39,8 +45,10 @@
  *
  * \return Nothing
  */
-static void bridge_parking_destroy(struct ast_bridge *self)
+static void bridge_parking_destroy(struct ast_bridge_parking *self)
 {
+	ast_log(LOG_NOTICE, "destroying bridge\n");
+	ast_bridge_base_v_table.destroy(&self->base);
 }
 
 /*!
@@ -57,7 +65,7 @@
  *
  * \retval TRUE if can push this channel into the bridge.
  */
-static int bridge_parking_can_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+static int bridge_parking_can_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
 {
 	return 1;
 }
@@ -77,7 +85,7 @@
  * \retval 0 on success
  * \retval -1 on failure
  */
-static int bridge_parking_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
 {
 	return 0;
 }
@@ -95,9 +103,9 @@
  *
  * \return Nothing
  */
-static void bridge_parking_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
 {
-	ast_bridge_base_v_table.pull(self, bridge_channel);
+	ast_bridge_base_v_table.pull(&self->base, bridge_channel);
 }
 
 /*!
@@ -113,36 +121,35 @@
  *
  * \return Nothing
  */
-static void bridge_parking_notify_masquerade(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
 {
-	ast_bridge_base_v_table.notify_masquerade(self, bridge_channel);
+	ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
 }
 
 struct ast_bridge_methods ast_bridge_parking_v_table = {
 	.name = "parking",
-	.destroy = bridge_parking_destroy,
-	.can_push = bridge_parking_can_push,
-	.push = bridge_parking_push,
-	.pull = bridge_parking_pull,
-	.notify_masquerade = bridge_parking_notify_masquerade,
+	.destroy = (ast_bridge_destructor_fn) bridge_parking_destroy,
+	.can_push = (ast_bridge_can_push_channel_fn) bridge_parking_can_push,
+	.push = (ast_bridge_push_channel_fn) bridge_parking_push,
+	.pull = (ast_bridge_pull_channel_fn) bridge_parking_pull,
+	.notify_masquerade = (ast_bridge_notify_masquerade_fn) bridge_parking_notify_masquerade,
 };
 
-static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge *self, struct parking_lot_state *bridge_lot)
+static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot_state *bridge_lot)
 {
-	int flags = AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM;
-	uint32_t capabilities = AST_BRIDGE_CAPABILITY_HOLDING;
-	ast_bridge_base_init(self, capabilities, flags);
+	if (!self) {
+		return NULL;
+	}
 
-	/* XXX Use the parking lot state as the bridge private */
-
-	return self;
+	return &self->base;
 }
 
 struct ast_bridge *bridge_parking_new(struct parking_lot_state *bridge_lot)
 {
 	void *bridge;
 
-	bridge = ast_bridge_alloc(sizeof(struct ast_bridge), &ast_bridge_parking_v_table);
+	bridge = ast_bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
+	bridge = ast_bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
 	bridge = ast_bridge_parking_init(bridge, bridge_lot);
 
 	return bridge;

Modified: team/jrose/bridge_projects/res/parking/parking_controller.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/parking/parking_controller.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/parking_controller.c (original)
+++ team/jrose/bridge_projects/res/parking/parking_controller.c Fri Mar 29 11:48:37 2013
@@ -97,15 +97,7 @@
 	user->resolution = PARK_TIMEOUT;
 	ao2_unlock(user);
 
-	ao2_lock(bridge_channel);
-	switch (bridge_channel->state) {
-	case AST_BRIDGE_CHANNEL_STATE_WAIT:
-		ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
-		break;
-	default:
-		break;
-	}
-	ao2_unlock(bridge_channel);
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
 
 	/* Set parking timeout channel variables */
 	snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
@@ -229,9 +221,61 @@
 	return -1;
 }
 
+static int retrieve_parked_user_first(void *obj, void *arg, int flags)
+{
+	return CMP_MATCH;
+}
+
+static int retrieve_parked_user_targeted(void *obj, void *arg, int flags)
+{
+	int *target = arg;
+	struct parked_user *user = obj;
+	if (user->parking_space == *target) {
+		return CMP_MATCH;
+	}
+
+	return 0;
+}
+
+struct parked_user *parking_lot_state_retrieve_parked_user(struct parking_lot_state *lot, int target)
+{
+	RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup);
+
+	if (target < 0) {
+		user = ao2_callback(lot->parked_user_list, 0, retrieve_parked_user_first, NULL);
+	} else {
+		user = ao2_callback(lot->parked_user_list, 0, retrieve_parked_user_targeted, &target);
+	}
+
+	if (!user) {
+		return NULL;
+	}
+
+	ao2_lock(user);
+	if (user->resolution != PARK_UNSET) {
+		/* Abandon  since something else has resolved the parked user before we got to it. */
+		ao2_unlock(user);
+		return NULL;
+	}
+
+	ao2_unlink(lot->parked_user_list, user);
+	user->resolution = PARK_ANSWERED;
+	ao2_unlock(user);
+
+	publish_parked_call(user, PARKED_CALL_UNPARKED);
+
+	parking_lot_state_remove_if_unused(user->lot_state);
+	user->lot_state = NULL;
+
+	/* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */
+	ao2_ref(user, +1);
+	return user;
+}
+
 static void destroy_parked_user(void *obj)
 {
 	struct parked_user *pu = obj;
+	ast_log(LOG_NOTICE, "Destroy parked user\n");
 	ao2_cleanup(pu->parker);
 }
 

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=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/parking/res_parking.h (original)
+++ team/jrose/bridge_projects/res/parking/res_parking.h Fri Mar 29 11:48:37 2013
@@ -193,6 +193,22 @@
 
 /*!
  * \since 12
+ * \brief Determine if there is a parked user in a parking space and pull it from the parking lot if there is.
+ *
+ * \param lot Parking lot being pulled from
+ * \param target If < 0   search for the first occupied space in the parking lot
+ *               If >= 0  Only pull from the indicated target
+ *
+ * \retval NULL if no parked user could be pulled from the requested parking lot at the requested parking space
+ * \retval reference to the requested parked user
+ *
+ * \note The parked user will be removed from parking lot as part of this process
+ * \note Remove this reference with ao2_cleanup once it falls out of scope.
+ */
+struct parked_user *parking_lot_state_retrieve_parked_user(struct parking_lot_state *lot, int target);
+
+/*!
+ * \since 12
  * \brief Set necessary bridge roles on a channel that is about to enter a parking lot
  *
  * \param chan Entering channel
@@ -325,6 +341,18 @@
 
 /*!
  * \since 12
+ * \brief Execution function for the parked call application
+ *
+ * \param chan ast_channel entering the application
+ * \param data arguments to the application
+ *
+ * \retval 0 the application executed in such a way that the channel should proceed in the dial plan
+ * \retval -1 the channel should no longer proceed through the dial plan
+ */
+int parked_call_app_exec(struct ast_channel *chan, const char *data);
+
+/*!
+ * \since 12
  * \brief Register CLI commands
  *
  * \retval 0 if successful

Modified: team/jrose/bridge_projects/res/res_parking.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/bridge_projects/res/res_parking.c?view=diff&rev=384328&r1=384327&r2=384328
==============================================================================
--- team/jrose/bridge_projects/res/res_parking.c (original)
+++ team/jrose/bridge_projects/res/res_parking.c Fri Mar 29 11:48:37 2013
@@ -52,7 +52,7 @@
 						in order to pick up calls parked to these parking spaces.</para></description>
 				</configOption>
 				<configOption name="parkinghints" default="no">
-					<synopsis>If yes, this parking lot will add hints automatically for parking slots.</synopsis>
+					<synopsis>If yes, this parking lot will add hints automatically for parking spaces.</synopsis>
 				</configOption>
 				<configOption name="parkingtime" default="45">
 					<synopsis>Amount of time a call will remain parked before giving up (in seconds).</synopsis>
@@ -155,10 +155,10 @@
 					</description>
 				</configOption>
 				<configOption name="findslot" default="first">
-					<synopsis>Rule to use when trying to figure out which parking slot a call should be parked with.</synopsis>
+					<synopsis>Rule to use when trying to figure out which parking space a call should be parked with.</synopsis>
 					<description>
 						<enumlist>
-							<enum name="first"><para>Always try to place in the lowest available slot in the parking lot</para></enum>
+							<enum name="first"><para>Always try to place in the lowest available space in the parking lot</para></enum>
 							<enum name="next"><para>Track the last parking space used and always attempt to use the one immediately after.
 							</para></enum>
 						</enumlist>
@@ -188,7 +188,7 @@
 #include "asterisk/manager.h"
 
 #define app_park "Park"
-#define app_parkedcall "ParkedCall"
+#define app_parked_call "ParkedCall"
 
 static int parking_lot_state_hash_fn(const void *obj, const int flags)
 {
@@ -202,10 +202,9 @@
 	case OBJ_POINTER:
 		entry = obj;
 		return ast_str_hash(entry->name);
-	}
-
-	/* It should be impossible to reach this point */
-	return 0;
+	default:
+		return 0;
+	}
 }
 
 static int parking_lot_state_cmp_fn(void *obj, void *arg, const int flags)
@@ -219,17 +218,17 @@
 	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
 	case OBJ_KEY:
 		key = arg;
-		return (!strcmp(entry1->name, key)) ? (CMP_MATCH | CMP_STOP) : 0;
+		return (!strcmp(entry1->name, key)) ? CMP_MATCH : 0;
 	case OBJ_PARTIAL_KEY:
 		key = arg;
 		key_size = strlen(key);
-		return (!strncmp(entry1->name, key, key_size)) ? (CMP_MATCH | CMP_STOP) : 0;
+		return (!strncmp(entry1->name, key, key_size)) ? CMP_MATCH : 0;
 	case OBJ_POINTER:
 		entry2 = arg;
-		return (!strcmp(entry1->name, entry2->name)) ? (CMP_MATCH | CMP_STOP) : 0;
-	}
-
-	return CMP_STOP;
+		return (!strcmp(entry1->name, entry2->name)) ? CMP_MATCH : 0;
+	default:
+		return CMP_STOP;
+	}
 }
 
 /*! All parking lots that are currently alive in some fashion can be obtained from here */
@@ -294,10 +293,9 @@
 	case OBJ_POINTER:
 		entry = obj;
 		return ast_str_hash(entry->name);
-	}
-
-	/* It should be impossible to reach this point */
-	return 0;
+	default:
+		return 0;
+	}
 }
 
 static int parking_lot_cfg_cmp_fn(void *obj, void *arg, const int flags)
@@ -311,17 +309,17 @@
 	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
 	case OBJ_KEY:
 		key = arg;
-		return (!strcmp(entry1->name, key)) ? (CMP_MATCH | CMP_STOP) : 0;
+		return (!strcmp(entry1->name, key)) ? CMP_MATCH : 0;
 	case OBJ_PARTIAL_KEY:
 		key = arg;
 		key_size = strlen(key);
-		return (!strncmp(entry1->name, key, key_size)) ? (CMP_MATCH | CMP_STOP) : 0;
+		return (!strncmp(entry1->name, key, key_size)) ? CMP_MATCH : 0;
 	case OBJ_POINTER:
 		entry2 = arg;
-		return (!strcmp(entry1->name, entry2->name)) ? (CMP_MATCH | CMP_STOP) : 0;
-	}
-
-	return CMP_STOP;
+		return (!strcmp(entry1->name, entry2->name)) ? CMP_MATCH : 0;
+	default:
+		return CMP_STOP;
+	}
 }
 
 /*! \brief destructor for parking_config */
@@ -400,7 +398,7 @@
 	int object_space = user->parking_space;
 
 	if (*search_space == object_space) {
-		return CMP_MATCH | CMP_STOP;
+		return CMP_MATCH;
 	}
 	return 0;
 }
@@ -585,6 +583,7 @@
 static void parking_lot_state_destructor(void *obj)
 {
 	struct parking_lot_state *lot = obj;
+	ast_log(LOG_NOTICE, "state destructor");
 	ao2_cleanup(lot->parking_bridge);
 	ao2_cleanup(lot->parked_user_list);
 	ast_string_field_free_memory(lot);
@@ -659,18 +658,17 @@
 
 	ao2_lock(cfg->parking_lot_list);
 
-	iter = ao2_iterator_init(cfg->parking_lot_list, 0);
-	while ((lot_cfg = ao2_iterator_next(&iter))) {
+	for (iter = ao2_iterator_init(cfg->parking_lot_list, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
 		if (lot_cfg->state) {
-			ao2_ref(lot_cfg, -1);
 			continue;
 		}
+
 		lot_cfg->state = parking_lot_state_build_or_update(lot_cfg);
 		if (lot_cfg->state) {
 			lot_cfg->state->has_owner = 1;
 		}
-		ao2_ref(lot_cfg, -1);
-	}
+	}
+
 	ao2_iterator_destroy(&iter);
 
 	ao2_unlock(cfg->parking_lot_list);
@@ -717,6 +715,10 @@
 		goto error;
 	}
 
+	if (ast_register_application_xml(app_parked_call, parked_call_app_exec)) {
+		goto error;
+	}
+
 	if (load_parking_ui()) {
 		goto error;
 	}




More information about the asterisk-commits mailing list