mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
Bridge API: Set a cause code on a channel when it is ejected from a bridge.
The cause code needs to be passed from the disconnecting channel to the bridge peers if the disconnecting channel dissolves the bridge. * Made the call to an app_agent_pool agent disconnect with the busy cause code if the agent does not ack the call in time or hangs up before acking the call. (closes issue ASTERISK-22042) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2772/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397472 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -55,7 +55,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/_private.h"
|
||||
|
||||
#include "asterisk/heap.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/timing.h"
|
||||
@@ -66,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/parking.h"
|
||||
#include "asterisk/core_local.h"
|
||||
#include "asterisk/core_unreal.h"
|
||||
#include "asterisk/causes.h"
|
||||
|
||||
/*! All bridges container. */
|
||||
static struct ao2_container *bridges;
|
||||
@@ -241,22 +241,7 @@ int ast_bridge_queue_action(struct ast_bridge *bridge, struct ast_frame *action)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Dissolve the bridge.
|
||||
* \since 12.0.0
|
||||
*
|
||||
* \param bridge Bridge to eject all channels
|
||||
*
|
||||
* \details
|
||||
* Force out all channels that are not already going out of the
|
||||
* bridge. Any new channels joining will leave immediately.
|
||||
*
|
||||
* \note On entry, bridge is already locked.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
void bridge_dissolve(struct ast_bridge *bridge)
|
||||
void bridge_dissolve(struct ast_bridge *bridge, int cause)
|
||||
{
|
||||
struct ast_bridge_channel *bridge_channel;
|
||||
struct ast_frame action = {
|
||||
@@ -269,11 +254,17 @@ void bridge_dissolve(struct ast_bridge *bridge)
|
||||
}
|
||||
bridge->dissolved = 1;
|
||||
|
||||
ast_debug(1, "Bridge %s: dissolving bridge\n", bridge->uniqueid);
|
||||
if (cause <= 0) {
|
||||
cause = AST_CAUSE_NORMAL_CLEARING;
|
||||
}
|
||||
bridge->cause = cause;
|
||||
|
||||
ast_debug(1, "Bridge %s: dissolving bridge with cause %d(%s)\n",
|
||||
bridge->uniqueid, cause, ast_cause2str(cause));
|
||||
|
||||
/* BUGBUG need a cause code on the bridge for the later ejected channels. */
|
||||
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, cause);
|
||||
}
|
||||
|
||||
/* Must defer dissolving bridge because it is already locked. */
|
||||
@@ -302,7 +293,7 @@ static void bridge_dissolve_check_stolen(struct ast_bridge *bridge, struct ast_b
|
||||
&& ast_test_flag(&bridge_channel->features->feature_flags,
|
||||
AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP)) {
|
||||
/* The stolen channel controlled the bridge it was stolen from. */
|
||||
bridge_dissolve(bridge);
|
||||
bridge_dissolve(bridge, 0);
|
||||
return;
|
||||
}
|
||||
if (bridge->num_channels < 2
|
||||
@@ -311,7 +302,7 @@ static void bridge_dissolve_check_stolen(struct ast_bridge *bridge, struct ast_b
|
||||
* The stolen channel has not left enough channels to keep the
|
||||
* bridge alive. Assume the stolen channel hung up.
|
||||
*/
|
||||
bridge_dissolve(bridge);
|
||||
bridge_dissolve(bridge, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -648,7 +639,7 @@ struct ast_bridge *bridge_register(struct ast_bridge *bridge)
|
||||
bridge->construction_completed = 1;
|
||||
ast_bridge_publish_state(bridge);
|
||||
if (!ao2_link(bridges, bridge)) {
|
||||
ast_bridge_destroy(bridge);
|
||||
ast_bridge_destroy(bridge, 0);
|
||||
bridge = NULL;
|
||||
}
|
||||
}
|
||||
@@ -852,11 +843,11 @@ struct ast_bridge *ast_bridge_base_new(uint32_t capabilities, unsigned int flags
|
||||
return bridge;
|
||||
}
|
||||
|
||||
int ast_bridge_destroy(struct ast_bridge *bridge)
|
||||
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
|
||||
{
|
||||
ast_debug(1, "Bridge %s: telling all channels to leave the party\n", bridge->uniqueid);
|
||||
ast_bridge_lock(bridge);
|
||||
bridge_dissolve(bridge);
|
||||
bridge_dissolve(bridge, cause);
|
||||
ast_bridge_unlock(bridge);
|
||||
|
||||
ao2_ref(bridge, -1);
|
||||
@@ -1366,7 +1357,7 @@ void bridge_reconfigured(struct ast_bridge *bridge, unsigned int colp_update)
|
||||
if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_SMART)
|
||||
&& smart_bridge_operation(bridge)) {
|
||||
/* Smart bridge failed. */
|
||||
bridge_dissolve(bridge);
|
||||
bridge_dissolve(bridge, 0);
|
||||
return;
|
||||
}
|
||||
bridge_complete_join(bridge);
|
||||
@@ -1652,7 +1643,8 @@ int ast_bridge_depart(struct ast_channel *chan)
|
||||
* channel thread.
|
||||
*/
|
||||
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
|
||||
|
||||
/* Wait for the depart thread to die */
|
||||
ast_debug(1, "Waiting for %p(%s) bridge thread to die.\n",
|
||||
@@ -1680,7 +1672,8 @@ int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
|
||||
|
||||
ast_bridge_unlock(bridge);
|
||||
|
||||
@@ -1689,7 +1682,7 @@ int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
|
||||
|
||||
static void kick_it(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
|
||||
{
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
|
||||
}
|
||||
|
||||
int ast_bridge_kick(struct ast_bridge *bridge, struct ast_channel *chan)
|
||||
@@ -1770,7 +1763,8 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
|
||||
if (kick_me) {
|
||||
for (idx = 0; idx < num_kick; ++idx) {
|
||||
if (bridge_channel == kick_me[idx]) {
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1788,7 +1782,8 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
|
||||
bridge_channel_change_bridge(bridge_channel, dst_bridge);
|
||||
|
||||
if (bridge_channel_internal_push(bridge_channel)) {
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
@@ -1802,7 +1797,8 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
|
||||
bridge_channel = kick_me[idx];
|
||||
ast_bridge_channel_lock(bridge_channel);
|
||||
if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
|
||||
ast_bridge_channel_leave_bridge_nolock(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge_nolock(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
|
||||
bridge_channel_internal_pull(bridge_channel);
|
||||
}
|
||||
ast_bridge_channel_unlock(bridge_channel);
|
||||
@@ -2036,10 +2032,12 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
|
||||
bridge_channel_change_bridge(bridge_channel, orig_bridge);
|
||||
|
||||
if (bridge_channel_internal_push(bridge_channel)) {
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
|
||||
}
|
||||
} else {
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
|
||||
}
|
||||
res = -1;
|
||||
}
|
||||
@@ -2452,7 +2450,8 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
|
||||
}
|
||||
other->swap = dst_bridge_channel->chan;
|
||||
if (!bridge_do_move(dst_bridge, other, 1, 1)) {
|
||||
ast_bridge_channel_leave_bridge(src_bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(src_bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
|
||||
res = -1;
|
||||
}
|
||||
if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
|
||||
@@ -4063,7 +4062,8 @@ static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge
|
||||
return AST_BRIDGE_TRANSFER_FAIL;
|
||||
}
|
||||
/* Must kick the source channel out of its bridge. */
|
||||
ast_bridge_channel_leave_bridge(source_bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(source_bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
|
||||
return AST_BRIDGE_TRANSFER_SUCCESS;
|
||||
} else {
|
||||
return AST_BRIDGE_TRANSFER_INVALID;
|
||||
@@ -4619,7 +4619,7 @@ static char *handle_bridge_destroy_specific(struct ast_cli_entry *e, int cmd, st
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "Destroying bridge '%s'\n", a->argv[2]);
|
||||
ast_bridge_destroy(bridge);
|
||||
ast_bridge_destroy(bridge, 0);
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
@@ -299,7 +299,8 @@ static int basic_hangup_hook(struct ast_bridge_channel *bridge_channel, void *ho
|
||||
}
|
||||
if (2 <= bridge_count) {
|
||||
/* Just allow this channel to leave the multi-party bridge. */
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0);
|
||||
}
|
||||
ast_bridge_unlock(bridge_channel->bridge);
|
||||
return 0;
|
||||
@@ -1488,7 +1489,7 @@ static void attended_transfer_properties_shutdown(struct attended_transfer_prope
|
||||
}
|
||||
|
||||
if (props->target_bridge) {
|
||||
ast_bridge_destroy(props->target_bridge);
|
||||
ast_bridge_destroy(props->target_bridge, 0);
|
||||
props->target_bridge = NULL;
|
||||
}
|
||||
|
||||
@@ -2454,7 +2455,7 @@ static enum attended_transfer_state wait_to_recall_exit(struct attended_transfer
|
||||
static int fail_enter(struct attended_transfer_properties *props)
|
||||
{
|
||||
if (props->transferee_bridge) {
|
||||
ast_bridge_destroy(props->transferee_bridge);
|
||||
ast_bridge_destroy(props->transferee_bridge, 0);
|
||||
props->transferee_bridge = NULL;
|
||||
}
|
||||
return 0;
|
||||
|
@@ -53,6 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/features_config.h"
|
||||
#include "asterisk/parking.h"
|
||||
#include "asterisk/causes.h"
|
||||
|
||||
/*!
|
||||
* \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge.
|
||||
@@ -101,13 +102,6 @@ int ast_bridge_channel_notify_talking(struct ast_bridge_channel *bridge_channel,
|
||||
return ast_bridge_channel_queue_frame(bridge_channel, &action);
|
||||
}
|
||||
|
||||
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state)
|
||||
{
|
||||
ast_bridge_channel_lock(bridge_channel);
|
||||
ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state);
|
||||
ast_bridge_channel_unlock(bridge_channel);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Poke the bridge_channel thread
|
||||
@@ -122,9 +116,33 @@ static void bridge_channel_poke(struct ast_bridge_channel *bridge_channel)
|
||||
}
|
||||
}
|
||||
|
||||
void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Set actual cause on channel.
|
||||
* \since 12.0.0
|
||||
*
|
||||
* \param chan Channel to set cause.
|
||||
* \param cause Cause to set on channel.
|
||||
* If cause <= 0 then use cause on channel if cause still <= 0 use AST_CAUSE_NORMAL_CLEARING.
|
||||
*
|
||||
* \return Actual cause set on channel.
|
||||
*/
|
||||
static int channel_set_cause(struct ast_channel *chan, int cause)
|
||||
{
|
||||
ast_channel_lock(chan);
|
||||
if (cause <= 0) {
|
||||
cause = ast_channel_hangupcause(chan);
|
||||
if (cause <= 0) {
|
||||
cause = AST_CAUSE_NORMAL_CLEARING;
|
||||
}
|
||||
}
|
||||
ast_channel_hangupcause_set(chan, cause);
|
||||
ast_channel_unlock(chan);
|
||||
return cause;
|
||||
}
|
||||
|
||||
void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
|
||||
{
|
||||
/* BUGBUG need cause code for the bridge_channel leaving the bridge. */
|
||||
if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
|
||||
return;
|
||||
}
|
||||
@@ -133,12 +151,21 @@ void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_ch
|
||||
bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->state,
|
||||
new_state);
|
||||
|
||||
channel_set_cause(bridge_channel->chan, cause);
|
||||
|
||||
/* Change the state on the bridge channel */
|
||||
bridge_channel->state = new_state;
|
||||
|
||||
bridge_channel_poke(bridge_channel);
|
||||
}
|
||||
|
||||
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
|
||||
{
|
||||
ast_bridge_channel_lock(bridge_channel);
|
||||
ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state, cause);
|
||||
ast_bridge_channel_unlock(bridge_channel);
|
||||
}
|
||||
|
||||
struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
|
||||
{
|
||||
struct ast_bridge *bridge = bridge_channel->bridge;
|
||||
@@ -263,12 +290,19 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch
|
||||
}
|
||||
}
|
||||
|
||||
void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel)
|
||||
void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel, int cause)
|
||||
{
|
||||
struct ast_bridge_features *features = bridge_channel->features;
|
||||
struct ast_bridge_hook *hook;
|
||||
struct ao2_iterator iter;
|
||||
|
||||
ast_bridge_channel_lock(bridge_channel);
|
||||
if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
|
||||
channel_set_cause(bridge_channel->chan, cause);
|
||||
cause = 0;
|
||||
}
|
||||
ast_bridge_channel_unlock(bridge_channel);
|
||||
|
||||
/* Run any hangup hooks. */
|
||||
iter = ao2_iterator_init(features->other_hooks, 0);
|
||||
for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
|
||||
@@ -287,7 +321,7 @@ void ast_bridge_channel_kick(struct ast_bridge_channel *bridge_channel)
|
||||
ao2_iterator_destroy(&iter);
|
||||
|
||||
/* Default hangup action. */
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, cause);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -595,7 +629,7 @@ void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const
|
||||
}
|
||||
if (run_app_helper(bridge_channel->chan, app_name, S_OR(app_args, ""))) {
|
||||
/* Break the bridge if the app returns non-zero. */
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
|
||||
}
|
||||
if (moh_class) {
|
||||
ast_bridge_channel_write_unhold(bridge_channel);
|
||||
@@ -1106,7 +1140,7 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel, co
|
||||
* here if the hook did not already change the state.
|
||||
*/
|
||||
if (bridge_channel->chan && ast_check_hangup_locked(bridge_channel->chan)) {
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, 0);
|
||||
}
|
||||
} else if (features->dtmf_passthrough) {
|
||||
/* Stream any collected DTMF to the other channels. */
|
||||
@@ -1219,7 +1253,7 @@ static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_chan
|
||||
struct blind_transfer_data *blind_data)
|
||||
{
|
||||
ast_async_goto(bridge_channel->chan, blind_data->context, blind_data->exten, 1);
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1235,7 +1269,7 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c
|
||||
chan_target = ast_channel_get_by_name(target_chan_name);
|
||||
if (!chan_target) {
|
||||
/* Dang, it disappeared somehow */
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1252,7 +1286,7 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c
|
||||
/* Release the ref we tried to pass to ast_bridge_set_after_callback(). */
|
||||
ast_channel_unref(chan_target);
|
||||
}
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, AST_CAUSE_NORMAL_CLEARING);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1337,7 +1371,7 @@ static void bridge_channel_dissolve_check(struct ast_bridge_channel *bridge_chan
|
||||
if (!bridge->num_channels
|
||||
&& ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_EMPTY)) {
|
||||
/* Last channel leaving the bridge turns off the lights. */
|
||||
bridge_dissolve(bridge);
|
||||
bridge_dissolve(bridge, ast_channel_hangupcause(bridge_channel->chan));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1348,7 +1382,7 @@ static void bridge_channel_dissolve_check(struct ast_bridge_channel *bridge_chan
|
||||
|| (bridge_channel->features->usable
|
||||
&& ast_test_flag(&bridge_channel->features->feature_flags,
|
||||
AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP))) {
|
||||
bridge_dissolve(bridge);
|
||||
bridge_dissolve(bridge, ast_channel_hangupcause(bridge_channel->chan));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -1357,9 +1391,14 @@ static void bridge_channel_dissolve_check(struct ast_bridge_channel *bridge_chan
|
||||
}
|
||||
|
||||
if (bridge->num_lonely && bridge->num_lonely == bridge->num_channels) {
|
||||
/* This will start a chain reaction where each channel leaving enters this function and causes
|
||||
* the next to leave as long as there aren't non-lonely channels in the bridge. */
|
||||
ast_bridge_channel_leave_bridge(AST_LIST_FIRST(&bridge->channels), BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
/*
|
||||
* This will start a chain reaction where each channel leaving
|
||||
* enters this function and causes the next to leave as long as
|
||||
* there aren't non-lonely channels in the bridge.
|
||||
*/
|
||||
ast_bridge_channel_leave_bridge(AST_LIST_FIRST(&bridge->channels),
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
|
||||
ast_channel_hangupcause(bridge_channel->chan));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1473,7 +1512,7 @@ int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
|
||||
|
||||
ast_bridge_publish_enter(bridge, bridge_channel->chan, swap ? swap->chan : NULL);
|
||||
if (swap) {
|
||||
ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, 0);
|
||||
bridge_channel_internal_pull(swap);
|
||||
}
|
||||
|
||||
@@ -1671,14 +1710,14 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
|
||||
}
|
||||
|
||||
if (!frame) {
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, 0);
|
||||
return;
|
||||
}
|
||||
switch (frame->frametype) {
|
||||
case AST_FRAME_CONTROL:
|
||||
switch (frame->subclass.integer) {
|
||||
case AST_CONTROL_HANGUP:
|
||||
ast_bridge_channel_kick(bridge_channel);
|
||||
ast_bridge_channel_kick(bridge_channel, 0);
|
||||
ast_frfree(frame);
|
||||
return;
|
||||
/* BUGBUG This is where incoming HOLD/UNHOLD memory should register. Write UNHOLD into bridge when this channel is pulled. */
|
||||
@@ -1885,7 +1924,8 @@ int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
|
||||
}
|
||||
|
||||
if (bridge_channel_internal_push(bridge_channel)) {
|
||||
ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
|
||||
ast_bridge_channel_leave_bridge(bridge_channel,
|
||||
BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, bridge_channel->bridge->cause);
|
||||
res = -1;
|
||||
}
|
||||
bridge_reconfigured(bridge_channel->bridge, 1);
|
||||
|
@@ -676,7 +676,7 @@ int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *pee
|
||||
|
||||
/* Put peer into the bridge */
|
||||
if (ast_bridge_impart(bridge, peer, NULL, peer_features, 1)) {
|
||||
ast_bridge_destroy(bridge);
|
||||
ast_bridge_destroy(bridge, 0);
|
||||
ast_bridge_features_cleanup(&chan_features);
|
||||
bridge_failed_peer_goto(chan, peer);
|
||||
return -1;
|
||||
@@ -829,7 +829,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
|
||||
if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) {
|
||||
snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana));
|
||||
astman_send_error(s, m, buf);
|
||||
ast_bridge_destroy(bridge);
|
||||
ast_bridge_destroy(bridge, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -837,7 +837,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
|
||||
if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) {
|
||||
snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb));
|
||||
astman_send_error(s, m, buf);
|
||||
ast_bridge_destroy(bridge);
|
||||
ast_bridge_destroy(bridge, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1125,7 +1125,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
|
||||
ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE), xfer_cfg ? xfer_cfg->xfersound : NULL)) {
|
||||
ast_bridge_features_destroy(peer_features);
|
||||
ast_bridge_features_cleanup(&chan_features);
|
||||
ast_bridge_destroy(bridge);
|
||||
ast_bridge_destroy(bridge, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user