Merge "app_confbridge: Attended transfer event fixup" into 16
This commit is contained in:
commit
a464847a1b
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue