[svn-commits] mmichelson: branch mmichelson/queue_bugbug r395228 - /team/mmichelson/queue_b...

SVN commits to the Digium repositories svn-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 svn-commits mailing list