[Asterisk-code-review] app_confbridge: Attended transfer event fixup (...asterisk[16])

George Joseph asteriskteam at digium.com
Tue Jun 11 14:28:42 CDT 2019


George Joseph has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/11452


Change subject: app_confbridge:  Attended transfer event fixup
......................................................................

app_confbridge:  Attended transfer event fixup

When a channel already in a conference bridge is attended transfered
to another extension, or when an exysting call is attended
transferred into a conference bridge, we now generate ConfbridgeJoin
and ConfbridgeLeave events for the entering and departing channels.

Change-Id: Id7709cfbceb26fbcb828b2d0d2a6b2fbeaf028e1
---
M apps/app_confbridge.c
M apps/confbridge/confbridge_manager.c
M apps/confbridge/include/confbridge.h
3 files changed, 153 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/52/11452/1

diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
index 6d141bd..8e2cabf 100644
--- a/apps/app_confbridge.c
+++ b/apps/app_confbridge.c
@@ -1479,6 +1479,122 @@
 	return 0;
 }
 
+void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg)
+{
+	struct ast_channel_snapshot *old_snapshot;
+	struct ast_channel_snapshot *new_snapshot;
+	char *confbr_name = NULL;
+	char *comma;
+	struct confbridge_conference *conference = NULL;
+	struct confbridge_user *user = NULL;
+	struct confbridge_user temp_user = { 0, };
+	struct ast_channel *new_chan = NULL;
+	struct ast_channel *old_chan = NULL;
+	struct user_profile u_profile;
+
+	if (msg->to_transferee.channel_snapshot
+		&& strcmp(msg->to_transferee.channel_snapshot->appl, "ConfBridge") == 0) {
+		/* We're transferring a bridge to an extension */
+		old_snapshot = msg->to_transferee.channel_snapshot;
+		new_snapshot = msg->target;
+	} else if (msg->to_transfer_target.channel_snapshot
+		&& strcmp(msg->to_transfer_target.channel_snapshot->appl, "ConfBridge") == 0) {
+		/* We're transferring a call to a bridge */
+		old_snapshot = msg->to_transfer_target.channel_snapshot;
+		new_snapshot = msg->transferee;
+	} else {
+		ast_log(LOG_ERROR, "Could not determine proper channels\n");
+		return;
+	}
+
+	/*
+	 * old_snapshot->data should have the original parameters passed to
+	 * the ConfBridge app:
+	 * conference[,bridge_profile[,user_profile[,menu]]]
+	 * We'll use "conference" to look up the bridge.
+	 *
+	 * We _could_ use old_snapshot->bridgeid to get the bridge but
+	 * that would involve locking the conference_bridges container
+	 * and iterating over it looking for a matching bridge.
+	 */
+	if (ast_strlen_zero(old_snapshot->data)) {
+		ast_log(LOG_ERROR, "Channel '%s' didn't have app data set\n", old_snapshot->name);
+		return;
+	}
+	confbr_name = ast_strdupa(old_snapshot->data);
+	comma = strchr(confbr_name, ',');
+	if (comma) {
+		*comma = '\0';
+	}
+
+	ast_debug(1, "Confbr: %s  Leaving: %s  Joining: %s\n", confbr_name, old_snapshot->name, new_snapshot->name);
+
+	conference = ao2_find(conference_bridges, confbr_name, OBJ_SEARCH_KEY);
+	if (!conference) {
+		ast_log(LOG_ERROR, "Conference bridge '%s' not found\n", confbr_name);
+		return;
+	}
+	ao2_lock(conference);
+
+	AST_LIST_TRAVERSE(&conference->active_list, user, list) {
+		if (strcasecmp(ast_channel_name(user->chan), old_snapshot->name) == 0) {
+			old_chan = user->chan;
+			u_profile = user->u_profile;
+			break;
+		}
+	}
+
+	if (!old_chan && conference->waitingusers) {
+		AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
+			if (strcasecmp(ast_channel_name(user->chan), old_snapshot->name) == 0) {
+				old_chan = user->chan;
+				u_profile = user->u_profile;
+				break;
+			}
+		}
+	}
+
+	if (!old_chan) {
+		ast_log(LOG_ERROR, "Channel '%s' left before it could be replaced in bridge '%s'\n",
+			old_snapshot->name, confbr_name);
+		ao2_unlock(conference);
+		ao2_ref(conference, -1);
+		return;
+	}
+	ast_channel_ref(old_chan);
+
+	new_chan = ast_channel_get_by_name(new_snapshot->name);
+	if (!new_chan) {
+		ast_log(LOG_ERROR, "Channel '%s' left before it could be joined to bridge '%s'\n",
+			new_snapshot->name, confbr_name);
+		ast_channel_cleanup(old_chan);
+		ao2_unlock(conference);
+		ao2_ref(conference, -1);
+		return;
+	}
+
+	ast_debug(1, "Old chan: %p %s  New chan: %p %s\n", old_chan, ast_channel_name(old_chan),
+		new_chan, ast_channel_name(new_chan));
+
+	/*
+	 * We're going to use the existing user profile to create the messages.
+	 * It and the channel are the only things in the user structure that
+	 * are used by the send event functions.
+	 */
+	temp_user.u_profile = u_profile;
+
+	temp_user.chan = old_chan;
+	send_leave_event(&temp_user, conference);
+	ast_channel_cleanup(old_chan);
+
+	temp_user.chan = new_chan;
+	send_join_event(&temp_user, conference);
+	ast_channel_cleanup(new_chan);
+
+	ao2_unlock(conference);
+	ao2_ref(conference, -1);
+}
+
 /*!
  * \brief Join a conference bridge
  *
diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c
index e88bbc2..35d3f72 100644
--- a/apps/confbridge/confbridge_manager.c
+++ b/apps/confbridge/confbridge_manager.c
@@ -621,6 +621,26 @@
 	ast_free(extra_text);
 }
 
+static void confbridge_atxfer_cb(void *data, struct stasis_subscription *sub,
+	struct stasis_message *message)
+{
+	struct ast_attended_transfer_message *msg = stasis_message_data(message);
+
+	if (msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
+		return;
+	}
+
+	/*
+	 * This callback will get called for ALL attended transfers
+	 * so we need to make sure this transfer belongs to
+	 * a conference bridge before trying to handle it.
+	 */
+	if (msg->dest_type == AST_ATTENDED_TRANSFER_DEST_APP
+		&& strcmp(msg->dest.app, "ConfBridge") == 0) {
+		confbridge_handle_atxfer(msg);
+	}
+}
+
 static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
 	struct stasis_message *message)
 {
@@ -740,6 +760,13 @@
 		return -1;
 	}
 	if (stasis_message_router_add(bridge_state_router,
+			ast_attended_transfer_type(),
+			confbridge_atxfer_cb,
+			NULL)) {
+		manager_confbridge_shutdown();
+		return -1;
+	}
+	if (stasis_message_router_add(bridge_state_router,
 			confbridge_leave_type(),
 			confbridge_leave_cb,
 			NULL)) {
diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
index 237431e..976b8a3 100644
--- a/apps/confbridge/include/confbridge.h
+++ b/apps/confbridge/include/confbridge.h
@@ -28,6 +28,7 @@
 #include "asterisk/channel.h"
 #include "asterisk/bridge.h"
 #include "asterisk/bridge_features.h"
+#include "asterisk/stasis_bridges.h"
 #include "conf_state.h"
 
 /*! Maximum length of a conference bridge name */
@@ -714,4 +715,13 @@
 void conf_send_event_to_participants(struct confbridge_conference *conference,
 	struct ast_channel *chan, struct stasis_message *msg);
 
+/*
+ * \brief Create join/leave events for attended transfers
+ * \since 13.28.0
+ *
+ * \param msg The attended transfer stasis message
+ *
+ */
+void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg);
+
 #endif

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/11452
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 16
Gerrit-Change-Id: Id7709cfbceb26fbcb828b2d0d2a6b2fbeaf028e1
Gerrit-Change-Number: 11452
Gerrit-PatchSet: 1
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190611/cf7314b4/attachment.html>


More information about the asterisk-code-review mailing list