[svn-commits] mmichelson: branch mmichelson/atxfer_features r392971 - /team/mmichelson/atxf...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Jun 26 14:02:41 CDT 2013


Author: mmichelson
Date: Wed Jun 26 14:02:39 2013
New Revision: 392971

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392971
Log:
Add pull method for atxfer bridges.

This way, we can detect if the transfer target or the transferee
has hung up. With this in place, I tested the following scenarios:

1) Transfer target hangs up while ringing
2) Transfer target hangs up during consultation
3) Transferee hangs up during target ringing

I have not tested what happens when a transferee hangs up during
consultation because I'm not 100% sure how I'm going to handle it.


Modified:
    team/mmichelson/atxfer_features/main/bridging_basic.c

Modified: team/mmichelson/atxfer_features/main/bridging_basic.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/atxfer_features/main/bridging_basic.c?view=diff&rev=392971&r1=392970&r2=392971
==============================================================================
--- team/mmichelson/atxfer_features/main/bridging_basic.c (original)
+++ team/mmichelson/atxfer_features/main/bridging_basic.c Wed Jun 26 14:02:39 2013
@@ -164,6 +164,19 @@
 	}
 
 	return ast_bridge_base_v_table.push(self, bridge_channel, swap);
+}
+
+static void bridge_basic_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+{
+	struct bridge_basic_personality *personality = self->personality;
+
+	ast_assert(personality != NULL);
+
+	if (personality->v_table->pull) {
+		personality->v_table->pull(self, bridge_channel);
+	}
+
+	ast_bridge_base_v_table.pull(self, bridge_channel);
 }
 
 static void bridge_basic_destroy(struct ast_bridge *self)
@@ -638,6 +651,10 @@
 	case STIMULUS_TRANSFERER_ANSWER:
 		ast_assert(0);
 	case STIMULUS_TRANSFEREE_HANGUP:
+		/* We soft hangup the transferer to prevent him from sitting in
+		 * a bridge by himself after the transfer fails
+		 */
+		ast_softhangup(props->transferer, AST_SOFTHANGUP_EXPLICIT);
 		return TRANSFER_FAIL;
 	case STIMULUS_DTMF_ATXFER_COMPLETE:
 	case STIMULUS_TRANSFERER_HANGUP:
@@ -669,8 +686,7 @@
 
 static int resume_enter(struct attended_transfer_properties *props)
 {
-	ast_bridge_basic_change_personality_normal(props->transferee_bridge);
-	return ast_bridge_destroy(props->target_bridge);
+	return 0;
 }
 
 static int threeway_enter(struct attended_transfer_properties *props)
@@ -762,6 +778,10 @@
 	case STIMULUS_TRANSFERER_ANSWER:
 		ast_assert(0);
 	case STIMULUS_TRANSFEREE_HANGUP:
+		/* We soft hangup the transferer to prevent him from sitting in
+		 * a bridge by himself after the transfer fails
+		 */
+		ast_softhangup(props->transferer, AST_SOFTHANGUP_EXPLICIT);
 		return TRANSFER_FAIL;
 	case STIMULUS_TRANSFERER_HANGUP:
 	case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -1069,6 +1089,44 @@
 	return 0;
 }
 
+static void bridge_personality_atxfer_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
+{
+	struct bridge_basic_personality *personality = self->personality;
+	struct attended_transfer_properties *props = personality->pvt;
+
+	if (self->num_channels > 1) {
+		return;
+	}
+
+	if (self->num_channels == 1) {
+		RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
+
+		ast_channel_lock(props->transferer);
+		transferer_bridge_channel = ast_channel_get_bridge_channel(props->transferer);
+		ast_channel_unlock(props->transferer);
+
+		if (!transferer_bridge_channel) {
+			return;
+		}
+
+		if (AST_LIST_FIRST(&self->channels) != transferer_bridge_channel) {
+			return;
+		}
+	}
+
+	/* Reaching this point means that either
+	 * 1) The bridge has no channels in it
+	 * 2) The bridge has one channel, and it's the transferer
+	 * In either case, it indicates that the non-transferer parties
+	 * are no longer in the bridge.
+	 */
+	if (self == props->transferee_bridge) {
+		stimulate_attended_transfer(props, STIMULUS_TRANSFEREE_HANGUP);
+	} else {
+		stimulate_attended_transfer(props, STIMULUS_TARGET_HANGUP);
+	}
+}
+
 static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfer_properties *props)
 {
 	RAII_VAR(struct stimulus_list *, list, NULL, ast_free_ptr);
@@ -1338,6 +1396,7 @@
 
 void ast_bridge_basic_change_personality_normal(struct ast_bridge *bridge)
 {
+	struct ast_bridge_channel *bridge_channel;
 	struct bridge_basic_personality *personality;
 	SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
 
@@ -1350,6 +1409,11 @@
 	ast_clear_flag(&bridge->feature_flags, AST_FLAGS_ALL);
 	ast_set_flag(&bridge->feature_flags, NORMAL_FLAGS);
 	remove_hooks_on_personality_change(bridge);
+
+	AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+		ast_bridge_hangup_hook(bridge_channel->features, basic_hangup_hook, NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+		ast_bridge_channel_setup_features(bridge_channel);
+	};
 }
 
 void ast_bridge_basic_change_personality_atxfer(struct ast_bridge *bridge,
@@ -1388,6 +1452,7 @@
 	ast_bridge_basic_v_table = ast_bridge_base_v_table;
 	ast_bridge_basic_v_table.name = "basic";
 	ast_bridge_basic_v_table.push = bridge_basic_push;
+	ast_bridge_basic_v_table.pull = bridge_basic_pull;
 	ast_bridge_basic_v_table.destroy = bridge_basic_destroy;
 
 	personality_normal_v_table = ast_bridge_base_v_table;
@@ -1397,6 +1462,7 @@
 	personality_atxfer_v_table = ast_bridge_base_v_table;
 	personality_atxfer_v_table.name = "attended transfer";
 	personality_atxfer_v_table.push = bridge_personality_atxfer_push;
+	personality_atxfer_v_table.pull = bridge_personality_atxfer_pull;
 
 	ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
 }




More information about the svn-commits mailing list