[asterisk-commits] mmichelson: branch mmichelson/queue_bugbug r395228 - /team/mmichelson/queue_b...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jul 23 18:13:01 CDT 2013
Author: mmichelson
Date: Tue Jul 23 18:12:59 2013
New Revision: 395228
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395228
Log:
Add doxygen and change some variable names.
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=395228&r1=395227&r2=395228
==============================================================================
--- team/mmichelson/queue_bugbug/apps/app_queue.c (original)
+++ team/mmichelson/queue_bugbug/apps/app_queue.c Tue Jul 23 18:12:59 2013
@@ -5162,34 +5162,88 @@
}
}
+/*!
+ * \brief Structure representing relevant data during a local channel optimization
+ *
+ * The reason we care about local channel optimizations is that we want to be able
+ * to accurately report when the caller and queue member have stopped talking to
+ * each other. A local channel optimization can cause it to appear that the conversation
+ * has stopped immediately after it has begun. By tracking that the relevant channels
+ * to monitor have changed due to a local channel optimization, we can give accurate
+ * reports.
+ *
+ * Local channel optimizations for queues are restricted from their normal operation.
+ * Bridges created by queues can only be the destination of local channel optimizations,
+ * not the source. In addition, move-swap local channel optimizations are the only
+ * permitted types of local channel optimization.
+ *
+ * This data is populated when we are told that a local channel optimization begin
+ * is occurring. When we get told the optimization has ended successfully, we then
+ * apply the data here into the queue_stasis_data.
+ */
struct local_optimization {
AST_DECLARE_STRING_FIELDS(
+ /*! The uniqueid of the channel that will be taking the place of the caller or member */
AST_STRING_FIELD(source_chan_uniqueid);
);
+ /*! Indication of whether we think there is a local channel optimization in progress */
int in_progress;
+ /*! The identifier for this local channel optimization */
unsigned int id;
};
+/*!
+ * \brief User data for stasis subscriptions used for queue calls.
+ *
+ * app_queue subscribes to channel and bridge events for all bridged calls.
+ * app_queue cares about the following events:
+ *
+ * \li bridge enter: To determine the unique ID of the bridge created for the call.
+ * \li blind transfer: To send an appropriate agent complete event.
+ * \li attended transfer: To send an appropriate agent complete event.
+ * \li local optimization: To update caller and member unique IDs for the call.
+ * \li hangup: To send an appropriate agent complete event.
+ *
+ * The stasis subscriptions last until we determine that the caller and the member
+ * are no longer bridged with each other.
+ */
struct queue_stasis_data {
AST_DECLARE_STRING_FIELDS(
+ /*! The unique ID of the caller's channel. */
AST_STRING_FIELD(caller_uniqueid);
- AST_STRING_FIELD(agent_uniqueid);
+ /*! The unique ID of the queue member's channel */
+ AST_STRING_FIELD(member_uniqueid);
+ /*! The unique ID of the bridge created by the queue */
AST_STRING_FIELD(bridge_uniqueid);
);
+ /*! The relevant queue */
struct call_queue *queue;
+ /*! The queue member that has answered the call */
struct member *member;
- struct stasis_topic *caller_topic;
+ /*! The time at which the caller entered the queue. Start of the caller's hold time */
time_t holdstart;
+ /*! The time at which the member answered the call. */
time_t starttime;
+ /*! The original position of the caller when he entered the queue */
int caller_pos;
+ /*! Indication if the call was answered within the configured service level of the queue */
int callcompletedinsl;
+ /*! Indicates if the stasis subscriptions are shutting down */
int dying;
+ /*! The stasis subscription for bridge events */
struct stasis_subscription *bridge_sub;
+ /*! The stasis subscription for channel events */
struct stasis_subscription *channel_sub;
+ /*! Local channel optimization details for the caller */
struct local_optimization caller_optimize;
- struct local_optimization agent_optimize;
+ /*! Local channel optimization details for the member */
+ struct local_optimization member_optimize;
};
+/*!
+ * \internal
+ * \brief Free memory for a queue_stasis_data
+ */
static void queue_stasis_data_destructor(void *obj)
{
struct queue_stasis_data *queue_data = obj;
@@ -5197,10 +5251,14 @@
ao2_cleanup(queue_data->member);
ao2_cleanup(queue_data->queue);
ast_string_field_free_memory(&queue_data->caller_optimize);
- ast_string_field_free_memory(&queue_data->agent_optimize);
+ ast_string_field_free_memory(&queue_data->member_optimize);
ast_string_field_free_memory(queue_data);
}
+/*!
+ * \internal
+ * \brief End all stasis subscriptions on a queue_stasis_data
+ */
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
{
SCOPED_AO2LOCK(lock, queue_data);
@@ -5210,6 +5268,10 @@
queue_data->channel_sub = stasis_unsubscribe(queue_data->channel_sub);
}
+/*!
+ * \internal
+ * \brief Allocate a queue_stasis_data and initialize its data.
+ */
static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
struct ast_channel *peer, struct member *mem, time_t holdstart,
time_t starttime, int callcompletedinsl)
@@ -5221,14 +5283,14 @@
return NULL;
}
- if (ast_string_field_init(queue_data, 64) || ast_string_field_init(&queue_data->agent_optimize, 64) ||
+ if (ast_string_field_init(queue_data, 64) || ast_string_field_init(&queue_data->member_optimize, 64) ||
ast_string_field_init(&queue_data->caller_optimize, 64)) {
ao2_cleanup(queue_data);
return NULL;
}
ast_string_field_set(queue_data, caller_uniqueid, ast_channel_uniqueid(qe->chan));
- ast_string_field_set(queue_data, agent_uniqueid, ast_channel_uniqueid(peer));
+ ast_string_field_set(queue_data, member_uniqueid, ast_channel_uniqueid(peer));
queue_data->queue = queue_ref(qe->parent);
queue_data->starttime = starttime;
queue_data->holdstart = holdstart;
@@ -5239,6 +5301,17 @@
return queue_data;
}
+/*!
+ * \internal
+ * \brief Log an attended transfer in the queue log.
+ *
+ * Attended transfer queue log messages vary based on the method by which the
+ * attended transfer was completed.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue.
+ * \param caller The channel snapshot for the caller channel in the queue.
+ * \param atxfer_msg The stasis attended transfer message data.
+ */
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_channel_snapshot *caller,
struct ast_attended_transfer_message *atxfer_msg)
{
@@ -5273,6 +5346,16 @@
(long) time(NULL) - queue_data->starttime, queue_data->caller_pos);
}
+/*!
+ * \internal
+ * \brief Handle a stasis bridge enter event.
+ *
+ * We track this particular event in order to learn what bridge
+ * was created for the queue call.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue.
+ * \param msg The stasis message for the bridge enter event
+ */
static void handle_bridge_enter(struct queue_stasis_data *queue_data,
struct stasis_message *msg)
{
@@ -5290,49 +5373,69 @@
}
}
+/*!
+ * \brief Handle a blind transfer event
+ *
+ * This event is important in order to be able to log the end of the
+ * call to the queue log and to stasis.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue.
+ * \param msg The stasis message for the blind transfer event
+ */
static void handle_blind_transfer(struct queue_stasis_data *queue_data,
struct stasis_message *msg)
{
struct ast_bridge_blob *blind_blob = stasis_message_data(msg);
- RAII_VAR(struct ast_channel_snapshot *, caller, NULL, ao2_cleanup);
- RAII_VAR(struct ast_channel_snapshot *, agent, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
if (ast_json_integer_get(ast_json_object_get(blind_blob->blob, "result")) == AST_BRIDGE_TRANSFER_FAIL) {
return;
}
ao2_lock(queue_data);
+
if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
strcmp(queue_data->bridge_uniqueid, blind_blob->bridge->uniqueid)) {
ao2_unlock(queue_data);
return;
}
- caller = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
- agent = ast_channel_snapshot_get_latest(queue_data->agent_uniqueid);
+ caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
+ member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
ao2_unlock(queue_data);
ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
- ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
+ ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+ "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
ast_json_string_get(ast_json_object_get(blind_blob->blob, "exten")),
ast_json_string_get(ast_json_object_get(blind_blob->blob, "context")),
(long) queue_data->starttime - queue_data->holdstart,
(long) time(NULL) - queue_data->starttime, queue_data->caller_pos);
- send_agent_complete(queue_data->queue->name, caller, agent, queue_data->member,
+ send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
queue_data->holdstart, queue_data->starttime, TRANSFER);
update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
time(NULL) - queue_data->starttime);
remove_stasis_subscriptions(queue_data);
}
+/*!
+ * \brief Handle an attended transfer event
+ *
+ * This event is important in order to be able to log the end of the
+ * call to the queue log and to stasis.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue.
+ * \param msg The stasis message for the attended transfer event
+ */
static void handle_attended_transfer(struct queue_stasis_data *queue_data,
struct stasis_message *msg)
{
struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
- RAII_VAR(struct ast_channel_snapshot *, caller, NULL, ao2_cleanup);
- RAII_VAR(struct ast_channel_snapshot *, agent, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
if (atxfer_msg->result == AST_BRIDGE_TRANSFER_FAIL ||
atxfer_msg->dest_type == AST_ATTENDED_TRANSFER_DEST_THREEWAY) {
@@ -5340,6 +5443,11 @@
}
ao2_lock(queue_data);
+
+ if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
+ ao2_unlock(queue_data);
+ return;
+ }
if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
@@ -5349,22 +5457,29 @@
return;
}
- caller = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
- agent = ast_channel_snapshot_get_latest(queue_data->agent_uniqueid);
+ caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
+ member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
ao2_unlock(queue_data);
ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
- log_attended_transfer(queue_data, caller, atxfer_msg);
-
- send_agent_complete(queue_data->queue->name, caller, agent, queue_data->member,
+ log_attended_transfer(queue_data, caller_snapshot, atxfer_msg);
+
+ send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
queue_data->holdstart, queue_data->starttime, TRANSFER);
update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
time(NULL) - queue_data->starttime);
remove_stasis_subscriptions(queue_data);
}
+/*!
+ * \internal
+ * \brief Callback for all stasis bridge events
+ *
+ * Based on the event and what bridge it is on, the task is farmed out to relevant
+ * subroutines for further processing.
+ */
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub,
struct stasis_topic *topic, struct stasis_message *msg)
{
@@ -5387,7 +5502,18 @@
}
}
-static void handle_local_optimization_begin(struct queue_stasis_data *queue_data, struct stasis_message *msg)
+/*!
+ * \internal
+ * \brief Handler for the beginning of a local channel optimization
+ *
+ * This method gathers data relevant to the local channel optimization and stores
+ * it to be used once the local optimization completes.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue
+ * \param msg The stasis message for the local optimization begin event
+ */
+static void handle_local_optimization_begin(struct queue_stasis_data *queue_data,
+ struct stasis_message *msg)
{
struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
@@ -5396,8 +5522,8 @@
struct local_optimization *optimization;
unsigned int id;
- if (!strcmp(local_one->uniqueid, queue_data->agent_uniqueid)) {
- optimization = &queue_data->agent_optimize;
+ if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+ optimization = &queue_data->member_optimize;
} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
optimization = &queue_data->caller_optimize;
} else {
@@ -5414,6 +5540,18 @@
optimization->in_progress = 1;
}
+/*!
+ * \internal
+ * \brief Handler for the end of a local channel optimization
+ *
+ * This method takes the data gathered during the local channel optimization begin
+ * event and applies it to the queue stasis data appropriately. This generally involves
+ * updating the caller or member unique ID with the channel that is taking the place of
+ * the previous caller or member.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue
+ * \param msg The stasis message for the local optimization end event
+ */
static void handle_local_optimization_end(struct queue_stasis_data *queue_data, struct stasis_message *msg)
{
struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
@@ -5423,8 +5561,8 @@
int is_caller;
unsigned int id;
- if (!strcmp(local_one->uniqueid, queue_data->agent_uniqueid)) {
- optimization = &queue_data->agent_optimize;
+ if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+ optimization = &queue_data->member_optimize;
is_caller = 0;
} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
optimization = &queue_data->caller_optimize;
@@ -5452,18 +5590,29 @@
ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
} else {
ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
- queue_data->agent_uniqueid, optimization->source_chan_uniqueid);
- ast_string_field_set(queue_data, agent_uniqueid, optimization->source_chan_uniqueid);
+ queue_data->member_uniqueid, optimization->source_chan_uniqueid);
+ ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
}
optimization->in_progress = 0;
}
+/*!
+ * \internal
+ * \brief Handler for hangup stasis event
+ *
+ * This is how we determine that the caller or member has hung up and the call
+ * has ended. An appropriate queue log and stasis message are raised in this
+ * callback.
+ *
+ * \param queue_data Data pertaining to the particular call in the queue.
+ * \param msg The stasis message for the hangup event.
+ */
static void handle_hangup(struct queue_stasis_data *queue_data, struct stasis_message *msg)
{
struct ast_channel_blob *channel_blob = stasis_message_data(msg);
- RAII_VAR(struct ast_channel_snapshot *, caller, NULL, ao2_cleanup);
- RAII_VAR(struct ast_channel_snapshot *, agent, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
enum agent_complete_reason reason;
@@ -5471,7 +5620,7 @@
if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
reason = CALLER;
- } else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->agent_uniqueid)) {
+ } else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) {
reason = AGENT;
} else {
ao2_unlock(queue_data);
@@ -5487,26 +5636,33 @@
return;
}
- caller = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
- agent = ast_channel_snapshot_get_latest(queue_data->agent_uniqueid);
+ caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
+ member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
ao2_unlock(queue_data);
- ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "agent",
+ ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
channel_blob->snapshot->name);
- ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername,
+ ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
(long) (queue_data->starttime - queue_data->holdstart),
(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
- send_agent_complete(queue_data->queue->name, caller, agent, queue_data->member,
+ send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
queue_data->holdstart, queue_data->starttime, reason);
update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
time(NULL) - queue_data->starttime);
remove_stasis_subscriptions(queue_data);
}
+/*!
+ * \internal
+ * \brief Callback for all stasis channel events
+ *
+ * Based on the event and the channels involved, the work is farmed out into
+ * subroutines for further processing.
+ */
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub,
struct stasis_topic *topic, struct stasis_message *msg)
{
@@ -5537,6 +5693,23 @@
}
}
+/*!
+ * \internal
+ * \brief Create stasis subscriptions for a particular call in the queue.
+ *
+ * These subscriptions are created once the call has been answered. The subscriptions
+ * are put in place so that call progress may be tracked. Once the call can be determined
+ * to have ended, then messages are logged to the queue log and stasis events are emitted.
+ *
+ * \param qe The queue entry representing the caller
+ * \param peer The channel that has answered the call
+ * \param mem The queue member that answered the call
+ * \param holdstart The time at which the caller entered the queue
+ * \param starttime The time at which the call was answered
+ * \param callcompletedinsl Indicates if the call was answered within the configured service level of the queue.
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem,
time_t holdstart, time_t starttime, int callcompletedinsl)
{
More information about the asterisk-commits
mailing list