[asterisk-commits] mmichelson: branch mmichelson/atxfer_features r392794 - /team/mmichelson/atxf...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jun 24 18:07:42 CDT 2013


Author: mmichelson
Date: Mon Jun 24 18:07:40 2013
New Revision: 392794

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392794
Log:
Attach a framehook to the transfer target so an answer can be detected.

I also updated some unholding logic to write to the bridge when the transfer
is completed.

With this commit, I can actually perform the most basic of attended transfers
successfully. There are reference leaks present, but the actual call path was
set up properly. Milestone!


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=392794&r1=392793&r2=392794
==============================================================================
--- team/mmichelson/atxfer_features/main/bridging_basic.c (original)
+++ team/mmichelson/atxfer_features/main/bridging_basic.c Mon Jun 24 18:07:40 2013
@@ -344,6 +344,20 @@
 	STIMULUS_DTMF_ATXFER_SWAP,
 };
 
+const char *stimulus_strs[] = {
+	[STIMULUS_NONE] = "None",
+	[STIMULUS_TRANSFEREE_HANGUP] = "Transferee Hangup",
+	[STIMULUS_TRANSFERER_HANGUP] = "Transferer Hangup",
+	[STIMULUS_TARGET_HANGUP] = "Transfer Target Hangup",
+	[STIMULUS_TRANSFERER_ANSWER] = "Transferer Answer",
+	[STIMULUS_TARGET_ANSWER] = "Transfer Target Answer",
+	[STIMULUS_TIMEOUT] = "Timeout",
+	[STIMULUS_DTMF_ATXFER_ABORT] = "DTMF Abort",
+	[STIMULUS_DTMF_ATXFER_COMPLETE] = "DTMF Complete",
+	[STIMULUS_DTMF_ATXFER_THREEWAY] = "DTMF Threeway",
+	[STIMULUS_DTMF_ATXFER_SWAP] = "DTMF Swap",
+};
+
 struct stimulus_list {
 	enum attended_transfer_stimulus stimulus;
 	AST_LIST_ENTRY(stimulus_list) next;
@@ -363,6 +377,7 @@
 	int atxferdropcall;
 	int atxfercallbackretries;
 	int retry_attempts;
+	int target_framehook_id;
 };
 
 static void attended_transfer_properties_destructor(void *obj)
@@ -415,26 +430,38 @@
 {
 	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 
+	if (chan) {
+		ast_channel_lock(chan);
+		bridge_channel = ast_channel_get_bridge_channel(chan);
+		ast_channel_unlock(chan);
+		
+		ast_assert(bridge_channel != NULL);
+
+		ast_bridge_channel_write_hold(bridge_channel, NULL);
+	}
+}
+
+static void unhold(struct ast_channel *chan)
+{
+	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+
 	ast_channel_lock(chan);
 	bridge_channel = ast_channel_get_bridge_channel(chan);
 	ast_channel_unlock(chan);
 	
 	ast_assert(bridge_channel != NULL);
 
-	ast_bridge_channel_write_hold(bridge_channel, NULL);
-}
-
-static void unhold(struct ast_channel *chan)
-{
-	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-
-	ast_channel_lock(chan);
-	bridge_channel = ast_channel_get_bridge_channel(chan);
-	ast_channel_unlock(chan);
-	
-	ast_assert(bridge_channel != NULL);
-
 	ast_bridge_channel_write_unhold(bridge_channel);
+}
+
+static void bridge_unhold(struct ast_bridge *bridge)
+{
+	struct ast_frame unhold = {
+		.frametype = AST_FRAME_CONTROL,
+		.subclass.integer = AST_CONTROL_UNHOLD,
+	};
+
+	ast_bridge_queue_everyone_else(bridge, NULL, &unhold);
 }
 
 static int bridge_move(struct ast_bridge *dest, struct ast_bridge *src, struct ast_channel *channel, struct ast_channel *swap)
@@ -693,11 +720,7 @@
 	 * is no guarantee here that the resulting bridge's technology will be.
 	 */
 	if (props->transferer) {
-		/* XXX Either transferee or transfer target could be on hold depending
-		 * on where the transferer was when the transfer was completed. Need to
-		 * throw an unhold at the bridge and let it take effect where it makes
-		 * sense.
-		 */
+		bridge_unhold(props->transferee_bridge);
 	}
 
 	return 0;
@@ -939,6 +962,26 @@
 	return 0;
 }
 
+static struct ast_frame *transfer_target_framehook_cb(struct ast_channel *chan,
+		struct ast_frame *frame, enum ast_framehook_event event, void *data)
+{
+	struct attended_transfer_properties *props = data;
+
+	if (event == AST_FRAMEHOOK_EVENT_READ &&
+			frame && frame->frametype == AST_FRAME_CONTROL &&
+			frame->subclass.integer == AST_CONTROL_ANSWER) {
+		stimulate_attended_transfer(props, STIMULUS_TARGET_ANSWER);
+	}
+
+	return frame;
+}
+
+static void transfer_target_framehook_destroy_cb(void *data)
+{
+	struct attended_transfer_properties *props = data;
+	ao2_cleanup(props);
+}
+
 static int bridge_personality_atxfer_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
 {
 	const char *abort_dtmf;
@@ -1014,27 +1057,55 @@
 static void *attended_transfer_monitor_thread(void *data)
 {
 	struct attended_transfer_properties *props = data;
+	ast_log(LOG_NOTICE, "ATXFER MONITOR THREAD START\n");
 
 	for (;;) {
 		enum attended_transfer_stimulus stimulus;
 
+		ast_log(LOG_NOTICE, "About to enter state %s\n", state_properties[props->state].state_name);
+
 		if (state_properties[props->state].enter &&
 				state_properties[props->state].enter(props)) {
+			ast_log(LOG_NOTICE, "State enter function returned an error\n");
 			break;
 		}
 
 		if (state_properties[props->state].flags & TRANSFER_STATE_IS_TERMINAL) {
+			ast_log(LOG_NOTICE, "State is a terminal state, so we have left it\n");
 			break;
 		}
 
 		stimulus = wait_for_stimulus(props);
+
+		ast_log(LOG_NOTICE, "Received stimulus %s\n", stimulus_strs[stimulus]);
 		
 		ast_assert(state_properties[props->state].next != NULL);
 
 		props->state = state_properties[props->state].next(props, stimulus);
+
+		ast_log(LOG_NOTICE, "Told to enter state %s next\n", state_properties[props->state].state_name);
 	}
 
 	return NULL;
+}
+
+static int attach_framehook(struct ast_channel *transfer_target, struct attended_transfer_properties *props)
+{
+	struct ast_framehook_interface target_interface = {
+		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
+		.event_cb = transfer_target_framehook_cb,
+		.destroy_cb = transfer_target_framehook_destroy_cb,
+	};
+
+	ao2_ref(props, +1);
+	target_interface.data = props;
+
+	props->target_framehook_id = ast_framehook_attach(transfer_target, &target_interface);
+	if (props->target_framehook_id == -1) {
+		ao2_ref(props, -1);
+		return -1;
+	}
+	return 0;
 }
 
 /* XXX Needs swap option as well */
@@ -1396,6 +1467,8 @@
 		ast_bridge_channel_write_unhold(bridge_channel);
 		return 0;
 	}
+
+	attach_framehook(peer, props);
 
 	ast_bridge_basic_change_personality_atxfer(attended_bridge, props);
 




More information about the asterisk-commits mailing list