[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