[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