[asterisk-commits] mmichelson: branch mmichelson/queue_bugbug r394391 - /team/mmichelson/queue_b...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jul 15 14:14:39 CDT 2013


Author: mmichelson
Date: Mon Jul 15 14:14:37 2013
New Revision: 394391

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394391
Log:
Commit some progress towards transfer detection.

With this change, I subscribe to stasis messages for bridges
when a caller enters a queue. I detect when the caller enters
the bridge and then hold onto that bridge for future reference
in case it is involved in a blind or attended transfer.

What I don't have in place is the appropriate queue log or stasis
publications when this occurs. That will be coming next. I've started
to modify the send_agent_complete() function but it isn't actually
used anywhere yet.


Modified:
    team/mmichelson/queue_bugbug/apps/app_queue.c

Modified: team/mmichelson/queue_bugbug/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/apps/app_queue.c?view=diff&rev=394391&r1=394390&r2=394391
==============================================================================
--- team/mmichelson/queue_bugbug/apps/app_queue.c (original)
+++ team/mmichelson/queue_bugbug/apps/app_queue.c Mon Jul 15 14:14:37 2013
@@ -110,6 +110,7 @@
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stasis_message_router.h"
 #include "asterisk/bridging.h"
+#include "asterisk/stasis_bridging.h"
 
 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
 /* #define REF_DEBUG_ONLY_QUEUES */
@@ -1908,25 +1909,19 @@
 		"%s", ast_str_buffer(event_string));
 }
 
-static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
+static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, 
+		struct ast_channel_snapshot *caller_snapshot,
+		struct ast_channel_snapshot *agent_snapshot,
+		struct stasis_message_type *type, struct ast_json *blob)
 {
 	RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
 	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *caller_snapshot;
-	struct ast_channel_snapshot *agent_snapshot;
 
 	payload = ast_multi_channel_blob_create(blob);
 	if (!payload) {
 		return;
 	}
 
-	caller_snapshot = ast_channel_snapshot_create(caller);
-	agent_snapshot = ast_channel_snapshot_create(agent);
-
-	if (!caller_snapshot || !agent_snapshot) {
-		return;
-	}
-
 	ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
 	ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
 
@@ -1935,7 +1930,26 @@
 		return;
 	}
 
-	stasis_publish(ast_channel_topic(caller), msg);
+	stasis_publish(topic, msg);
+}
+
+static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent,
+		struct stasis_message_type *type, struct ast_json *blob)
+{
+	struct ast_channel_snapshot *caller_snapshot;
+	struct ast_channel_snapshot *agent_snapshot;
+
+	caller_snapshot = ast_channel_snapshot_create(caller);
+	agent_snapshot = ast_channel_snapshot_create(agent);
+
+	if (!caller_snapshot || !agent_snapshot) {
+		ast_free(caller_snapshot);
+		ast_free(agent_snapshot);
+		return;
+	}
+
+	queue_publish_multi_channel_snapshot_blob(ast_channel_topic(caller), caller_snapshot,
+			agent_snapshot, type, blob);
 }
 
 static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
@@ -5106,9 +5120,11 @@
 
 #if 0	// BUGBUG
 /*! \brief Send out AMI message with member call completion status information */
-static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
-	const struct ast_channel *peer, const struct member *member, time_t callstart,
-	char *vars, size_t vars_len, enum agent_complete_reason rsn)
+static void send_agent_complete(struct stasis_topic *topic, const char *queuename,
+	const struct ast_channel_snapshot *caller,
+	const struct ast_channel_snapshot *peer,
+	const struct member *member, time_t holdstart, time_t callstart,
+	enum agent_complete_reason rsn)
 {
 	const char *reason = NULL;	/* silence dumb compilers */
 	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
@@ -5129,10 +5145,10 @@
 			     "Queue", queuename,
 			     "Interface", member->interface,
 			     "MemberName", member->membername,
-			     "HoldTime", (long)(callstart - qe->start)
+			     "HoldTime", (long)(callstart - holdstart)
 			     "TalkTime", (long)(time(NULL) - callstart)
 			     "Reason", reason);
-	queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_complete_type(), blob);
+	queue_publish_multi_channel_snapshot_blob(topic, chan, peer, queue_agent_complete_type(), blob);
 }
 #endif	// BUGBUG
 
@@ -5244,6 +5260,98 @@
 	return ds;
 }
 #endif	// BUGBUG
+
+struct queue_stasis_data {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(caller_uniqueid);
+		AST_STRING_FIELD(bridge_uniqueid);
+		AST_STRING_FIELD(queue);
+	);
+	struct stasis_topic *caller_topic;
+	time_t starttime;
+	int callcompletedinsl;
+};
+
+static void queue_stasis_data_destructor(void *obj)
+{
+	struct queue_stasis_data *queue_data = obj;
+
+	ast_string_field_free_memory(queue_data);
+}
+
+static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
+		struct member *mem, time_t starttime, int callcompletedinsl)
+{
+	struct queue_stasis_data *queue_data;
+
+	queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
+	if (!queue_data || ast_string_field_init(queue_data, 64)) {
+		return NULL;
+	}
+
+	ast_string_field_set(queue_data, caller_uniqueid, ast_channel_uniqueid(qe->chan));
+	ast_string_field_set(queue_data, queue, qe->parent->name);
+	queue_data->starttime = starttime;
+	queue_data->callcompletedinsl = callcompletedinsl;
+	return queue_data;
+}
+
+static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub,
+		struct stasis_topic *topic, struct stasis_message *msg)
+{
+	struct queue_stasis_data *queue_data = userdata;
+
+	if (stasis_subscription_final_message(sub, msg)) {
+		ao2_cleanup(queue_data);
+	} else if (ast_channel_entered_bridge_type() == stasis_message_type(msg)) {
+		struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
+
+		if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
+			return;
+		}
+
+		if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
+			ast_string_field_set(queue_data, bridge_uniqueid,
+					enter_blob->bridge->uniqueid);
+			ast_log(LOG_NOTICE, "Detected entry into bridge %s\n", queue_data->bridge_uniqueid);
+		}
+	} else if (ast_blind_transfer_type() == stasis_message_type(msg)) {
+		struct ast_bridge_blob *blind_blob = stasis_message_data(msg);
+
+		if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
+				strcmp(queue_data->bridge_uniqueid, blind_blob->bridge->uniqueid)) {
+			return;
+		}
+
+		ast_log(LOG_NOTICE, "Detected blind transfer in queue %s\n", queue_data->queue);
+		stasis_unsubscribe(sub);
+	} else if (ast_attended_transfer_type() == stasis_message_type(msg)) {
+		struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
+
+		if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
+				(strcmp(queue_data->bridge_uniqueid,
+						atxfer_msg->to_transferee.bridge_snapshot->uniqueid) &&
+				 strcmp(queue_data->bridge_uniqueid,
+					 atxfer_msg->to_transfer_target.bridge_snapshot->uniqueid))) {
+			return;
+		}
+
+		ast_log(LOG_NOTICE, "Detected attended transfer in queue %s\n", queue_data->queue);
+		stasis_unsubscribe(sub);
+	}
+}
+
+static int setup_stasis_subs(struct queue_ent *qe, struct member *mem, time_t starttime,
+		int callcompletedinsl)
+{
+	struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, mem, starttime, callcompletedinsl);
+
+	if (!queue_data) {
+		return -1;
+	}
+	stasis_subscribe(ast_bridge_topic_all(), queue_bridge_cb, queue_data);
+	return 0;
+}
 
 struct queue_end_bridge {
 	struct call_queue *q;
@@ -5348,9 +5456,7 @@
 	int x=0;
 	char *announce = NULL;
 	char digit = 0;
-#if 0	// BUGBUG
 	time_t callstart;
-#endif	// BUGBUG
 	time_t now = time(NULL);
 	struct ast_bridge_config bridge_config;
 	char nondataquality = 1;
@@ -5367,9 +5473,7 @@
 	char *p;
 	int forwardsallowed = 1;
 	int block_connected_line = 0;
-#if 0	// BUGBUG
 	int callcompletedinsl;
-#endif	// BUGBUG
 	struct ao2_iterator memi;
 	struct ast_datastore *datastore;
 #if 0	// BUGBUG
@@ -5641,9 +5745,7 @@
 		time(&now);
 		recalc_holdtime(qe, (now - qe->start));
 		ao2_lock(qe->parent);
-#if 0	// BUGBUG
 		callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
-#endif	// BUGBUG
 		ao2_unlock(qe->parent);
 		member = lpeer->member;
 		/* Increment the refcount for this member, since we're going to be using it for awhile in here. */
@@ -5995,10 +6097,11 @@
 			queue_t_ref(qe->parent, "For bridge_config reference");
 		}
 
+		time(&callstart);
 #if 0	// BUGBUG
-		time(&callstart);
 		transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
 #endif	// BUGBUG
+		setup_stasis_subs(qe, member, callstart, callcompletedinsl);
 		bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
 
 /* BUGBUG need to do this queue logging a different way because we cannot reference peer anymore.  Likely needs to be made a subscriber of stasis transfer events. */




More information about the asterisk-commits mailing list