Merge "app_confbridge: Attended transfer event fixup" into 16

This commit is contained in:
Friendly Automation 2019-06-21 11:24:11 -05:00 committed by Gerrit Code Review
commit a464847a1b
5 changed files with 254 additions and 0 deletions

View File

@ -587,6 +587,43 @@ static void send_conf_stasis(struct confbridge_conference *conference, struct as
}
}
static void send_conf_stasis_snapshots(struct confbridge_conference *conference,
struct ast_channel_snapshot *chan_snapshot, struct stasis_message_type *type,
struct ast_json *extras)
{
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
RAII_VAR(struct ast_bridge_snapshot *, bridge_snapshot, NULL, ao2_cleanup);
json_object = ast_json_pack("{s: s}",
"conference", conference->name);
if (!json_object) {
return;
}
if (extras) {
ast_json_object_update(json_object, extras);
}
ast_bridge_lock(conference->bridge);
bridge_snapshot = ast_bridge_snapshot_create(conference->bridge);
ast_bridge_unlock(conference->bridge);
if (!bridge_snapshot) {
return;
}
msg = ast_bridge_blob_create_from_snapshots(type,
bridge_snapshot,
chan_snapshot,
json_object);
if (!msg) {
return;
}
stasis_publish(ast_bridge_topic(conference->bridge), msg);
}
static void send_conf_start_event(struct confbridge_conference *conference)
{
send_conf_stasis(conference, NULL, confbridge_start_type(), NULL, 0);
@ -1479,6 +1516,126 @@ static int push_announcer(struct confbridge_conference *conference)
return 0;
}
static void confbridge_unlock_and_unref(void *obj)
{
struct confbridge_conference *conference = obj;
if (!obj) {
return;
}
ao2_unlock(conference);
ao2_ref(conference, -1);
}
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg)
{
struct ast_channel_snapshot *old_snapshot;
struct ast_channel_snapshot *new_snapshot;
char *confbr_name = NULL;
char *comma;
RAII_VAR(struct confbridge_conference *, conference, NULL, confbridge_unlock_and_unref);
struct confbridge_user *user = NULL;
int found_user = 0;
struct ast_json *json_object;
if (msg->to_transferee.channel_snapshot
&& strcmp(msg->to_transferee.channel_snapshot->appl, "ConfBridge") == 0
&& msg->target) {
/* We're transferring a bridge to an extension */
old_snapshot = msg->to_transferee.channel_snapshot;
new_snapshot = msg->target;
} else if (msg->to_transfer_target.channel_snapshot
&& strcmp(msg->to_transfer_target.channel_snapshot->appl, "ConfBridge") == 0
&& msg->transferee) {
/* We're transferring a call to a bridge */
old_snapshot = msg->to_transfer_target.channel_snapshot;
new_snapshot = msg->transferee;
} else {
ast_log(LOG_ERROR, "Could not determine proper channels\n");
return;
}
/*
* old_snapshot->data should have the original parameters passed to
* the ConfBridge app:
* conference[,bridge_profile[,user_profile[,menu]]]
* We'll use "conference" to look up the bridge.
*
* We _could_ use old_snapshot->bridgeid to get the bridge but
* that would involve locking the conference_bridges container
* and iterating over it looking for a matching bridge.
*/
if (ast_strlen_zero(old_snapshot->data)) {
ast_log(LOG_ERROR, "Channel '%s' didn't have app data set\n", old_snapshot->name);
return;
}
confbr_name = ast_strdupa(old_snapshot->data);
comma = strchr(confbr_name, ',');
if (comma) {
*comma = '\0';
}
ast_debug(1, "Confbr: %s Leaving: %s Joining: %s\n", confbr_name, old_snapshot->name, new_snapshot->name);
conference = ao2_find(conference_bridges, confbr_name, OBJ_SEARCH_KEY);
if (!conference) {
ast_log(LOG_ERROR, "Conference bridge '%s' not found\n", confbr_name);
return;
}
ao2_lock(conference);
/*
* We need to grab the user profile for the departing user in order to
* properly format the join/leave messages.
*/
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
if (strcasecmp(ast_channel_name(user->chan), old_snapshot->name) == 0) {
found_user = 1;
break;
}
}
/*
* If we didn't find the user in the active list, try the waiting list.
*/
if (!found_user && conference->waitingusers) {
AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
if (strcasecmp(ast_channel_name(user->chan), old_snapshot->name) == 0) {
found_user = 1;
break;
}
}
}
if (!found_user) {
ast_log(LOG_ERROR, "Unable to find user profile for channel '%s' in bridge '%s'\n",
old_snapshot->name, confbr_name);
return;
}
/*
* We're going to use the existing user profile to create the messages.
*/
json_object = ast_json_pack("{s: b}",
"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
);
if (!json_object) {
return;
}
send_conf_stasis_snapshots(conference, old_snapshot, confbridge_leave_type(), json_object);
ast_json_unref(json_object);
json_object = ast_json_pack("{s: b, s: b}",
"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN),
"muted", user->muted);
if (!json_object) {
return;
}
send_conf_stasis_snapshots(conference, new_snapshot, confbridge_join_type(), json_object);
ast_json_unref(json_object);
}
/*!
* \brief Join a conference bridge
*

View File

@ -621,6 +621,26 @@ static void confbridge_join_cb(void *data, struct stasis_subscription *sub,
ast_free(extra_text);
}
static void confbridge_atxfer_cb(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
{
struct ast_attended_transfer_message *msg = stasis_message_data(message);
if (msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
return;
}
/*
* This callback will get called for ALL attended transfers
* so we need to make sure this transfer belongs to
* a conference bridge before trying to handle it.
*/
if (msg->dest_type == AST_ATTENDED_TRANSFER_DEST_APP
&& strcmp(msg->dest.app, "ConfBridge") == 0) {
confbridge_handle_atxfer(msg);
}
}
static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
{
@ -739,6 +759,13 @@ int manager_confbridge_init(void)
manager_confbridge_shutdown();
return -1;
}
if (stasis_message_router_add(bridge_state_router,
ast_attended_transfer_type(),
confbridge_atxfer_cb,
NULL)) {
manager_confbridge_shutdown();
return -1;
}
if (stasis_message_router_add(bridge_state_router,
confbridge_leave_type(),
confbridge_leave_cb,

View File

@ -28,6 +28,7 @@
#include "asterisk/channel.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_features.h"
#include "asterisk/stasis_bridges.h"
#include "conf_state.h"
/*! Maximum length of a conference bridge name */
@ -714,4 +715,14 @@ struct confbridge_conference *conf_find_bridge(const char *conference_name);
void conf_send_event_to_participants(struct confbridge_conference *conference,
struct ast_channel *chan, struct stasis_message *msg);
/*!
* \brief Create join/leave events for attended transfers
* \since 13.28
* \since 16.5
*
* \param msg The attended transfer stasis message
*
*/
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg);
#endif

View File

@ -228,6 +228,29 @@ struct stasis_message *ast_bridge_blob_create(struct stasis_message_type *type,
struct ast_channel *chan,
struct ast_json *blob);
/*!
* \since 13.28
* \since 16.5
* \brief Creates a \ref ast_bridge_blob message from snapshots.
*
* The \a blob JSON object requires a \c "type" field describing the blob. It
* should also be treated as immutable and not modified after it is put into the
* message.
*
* \pre bridge is locked.
* \pre No channels are locked.
*
* \param bridge_snapshot Bridge snapshot
* \param channel_snapshot Channel snapshot
* \param blob JSON object representing the data.
* \return \ref ast_bridge_blob message.
* \return \c NULL on error
*/
struct stasis_message *ast_bridge_blob_create_from_snapshots(struct stasis_message_type *type,
struct ast_bridge_snapshot *bridge_snapshot,
struct ast_channel_snapshot *chan_snapshot,
struct ast_json *blob);
/*!
* \since 12
* \brief Publish a bridge channel enter event

View File

@ -485,6 +485,42 @@ struct stasis_message *ast_bridge_blob_create(
return msg;
}
struct stasis_message *ast_bridge_blob_create_from_snapshots(
struct stasis_message_type *message_type,
struct ast_bridge_snapshot *bridge_snapshot,
struct ast_channel_snapshot *chan_snapshot,
struct ast_json *blob)
{
struct ast_bridge_blob *obj;
struct stasis_message *msg;
if (!message_type) {
return NULL;
}
obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
if (!obj) {
return NULL;
}
if (bridge_snapshot) {
obj->bridge = ao2_bump(bridge_snapshot);
}
if (chan_snapshot) {
obj->channel = ao2_bump(chan_snapshot);
}
if (blob) {
obj->blob = ast_json_ref(blob);
}
msg = stasis_message_create(message_type, obj);
ao2_ref(obj, -1);
return msg;
}
void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
struct ast_channel *swap)
{