app_queue: Handle the caller being redirected out of a queue bridge

A caller can leave the Queue() application after being bridged with a
member in a few ways:

  * Caller or member hangup
  * Caller is transferred somewhere else (blind or atx)
  * Caller is externally redirected elsewhere

The first 2 scenarios are currently handled by subscribing to stasis
messages, but the 3rd is not explicitly covered. If a caller is
redirected away from the Queue() application, the member who was last
bridged with that caller will remain in an "In use" state until the
caller hangs up.

This patch adds handling of the caller leaving the queue via
redirection. We monitor the caller-member bridge, and if the caller is
the one that leaves, we treat it the same as we would a caller hangup.

ASTERISK-26400 #close
Reported by: Etienne Lessard

Change-Id: Iba160907770de5a6c9efeffc9df5a13e9ea75334
certified/13.18
Sean Bright 8 years ago
parent 947f1ebf86
commit 163e9e53dc

@ -5901,6 +5901,67 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
}
}
/*!
* \internal
* \brief Handle a stasis bridge leave event.
*
* We track this event to determine if the caller has left the bridge
* as the result of a redirect. Transfers and hangups are handled in
* separate functions.
*
* \param userdata Data pertaining to the particular call in the queue.
* \param sub The stasis subscription on which the message occurred.
* \param msg The stasis message for the bridge leave event
*/
static void handle_bridge_left(void *userdata, struct stasis_subscription *sub,
struct stasis_message *msg)
{
struct queue_stasis_data *queue_data = userdata;
struct ast_bridge_blob *left_blob = stasis_message_data(msg);
struct ast_channel_snapshot *caller_snapshot, *member_snapshot;
ao2_lock(queue_data);
if (queue_data->dying) {
ao2_unlock(queue_data);
return;
}
if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
ao2_unlock(queue_data);
return;
}
/* Correct channel, correct bridge? */
if (strcmp(left_blob->channel->uniqueid, queue_data->caller_uniqueid)
|| strcmp(left_blob->bridge->uniqueid, queue_data->bridge_uniqueid)) {
ao2_unlock(queue_data);
return;
}
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 redirect of queue caller channel %s\n",
caller_snapshot->name);
ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
"COMPLETECALLER", "%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_snapshot, member_snapshot, queue_data->member,
queue_data->holdstart, queue_data->starttime, CALLER);
update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
time(NULL) - queue_data->starttime);
remove_stasis_subscriptions(queue_data);
ao2_cleanup(member_snapshot);
ao2_cleanup(caller_snapshot);
}
/*!
* \brief Handle a blind transfer event
*
@ -6268,6 +6329,8 @@ static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, str
stasis_message_router_add(queue_data->bridge_router, ast_channel_entered_bridge_type(),
handle_bridge_enter, queue_data);
stasis_message_router_add(queue_data->bridge_router, ast_channel_left_bridge_type(),
handle_bridge_left, queue_data);
stasis_message_router_add(queue_data->bridge_router, ast_blind_transfer_type(),
handle_blind_transfer, queue_data);
stasis_message_router_add(queue_data->bridge_router, ast_attended_transfer_type(),

Loading…
Cancel
Save