diff options
Diffstat (limited to 'main/bridge.c')
-rw-r--r-- | main/bridge.c | 146 |
1 files changed, 107 insertions, 39 deletions
diff --git a/main/bridge.c b/main/bridge.c index 462676ca8..926004bc9 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -1825,6 +1825,32 @@ static void bridge_channel_change_bridge(struct ast_bridge_channel *bridge_chann ao2_ref(old_bridge, -1); } +static void bridge_channel_moving(struct ast_bridge_channel *bridge_channel, struct ast_bridge *src, struct ast_bridge *dst) +{ + struct ast_bridge_features *features = bridge_channel->features; + struct ast_bridge_hook *hook; + struct ao2_iterator iter; + + /* Run any moving hooks. */ + iter = ao2_iterator_init(features->other_hooks, 0); + for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) { + int remove_me; + ast_bridge_move_indicate_callback move_cb; + + if (hook->type != AST_BRIDGE_HOOK_TYPE_MOVE) { + continue; + } + move_cb = (ast_bridge_move_indicate_callback) hook->callback; + remove_me = move_cb(bridge_channel, hook->hook_pvt, src, dst); + if (remove_me) { + ast_debug(1, "Move detection hook %p is being removed from %p(%s)\n", + hook, bridge_channel, ast_channel_name(bridge_channel->chan)); + ao2_unlink(features->other_hooks, hook); + } + } + ao2_iterator_destroy(&iter); +} + void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick, unsigned int optimized) { @@ -1873,6 +1899,8 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg continue; } + bridge_channel_moving(bridge_channel, bridge_channel->bridge, dst_bridge); + /* Point to new bridge.*/ bridge_channel_change_bridge(bridge_channel, dst_bridge); @@ -2122,6 +2150,8 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri ao2_ref(orig_bridge, +1);/* Keep a ref in case the push fails. */ bridge_channel_change_bridge(bridge_channel, dst_bridge); + bridge_channel_moving(bridge_channel, orig_bridge, dst_bridge); + if (bridge_channel_internal_push(bridge_channel)) { /* Try to put the channel back into the original bridge. */ ast_bridge_features_remove(bridge_channel->features, @@ -3089,6 +3119,18 @@ int ast_bridge_talk_detector_hook(struct ast_bridge_features *features, AST_BRIDGE_HOOK_TYPE_TALK); } +int ast_bridge_move_hook(struct ast_bridge_features *features, + ast_bridge_move_indicate_callback callback, + void *hook_pvt, + ast_bridge_hook_pvt_destructor destructor, + enum ast_bridge_hook_remove_flags remove_flags) +{ + ast_bridge_hook_callback hook_cb = (ast_bridge_hook_callback) callback; + + return bridge_other_hook(features, hook_cb, hook_pvt, destructor, remove_flags, + AST_BRIDGE_HOOK_TYPE_MOVE); +} + int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, @@ -3828,14 +3870,55 @@ struct stasis_attended_transfer_publish_data { struct ast_bridge_channel_pair to_transferee; /* The bridge between the transferer and transfer target, and the transferer channel in this bridge */ struct ast_bridge_channel_pair to_transfer_target; + /* The Local;1 that will replace the transferee bridge transferer channel */ + struct ast_channel *replace_channel; + /* The transferee channel. NULL if there is no transferee channel or if multiple parties are transferred */ + struct ast_channel *transferee_channel; + /* The transfer target channel. NULL if there is no transfer target channel or if multiple parties are transferred */ + struct ast_channel *target_channel; }; +/*! + * \internal + * \brief Get the transferee channel + * + * This is only applicable to cases where a transfer is occurring on a + * two-party bridge. The channels container passed in is expected to only + * contain two channels, the transferer and the transferee. The transferer + * channel is passed in as a parameter to ensure we don't return it as + * the transferee channel. + * + * \param channels A two-channel container containing the transferer and transferee + * \param transferer The party that is transfering the call + * \return The party that is being transferred + */ +static struct ast_channel *get_transferee(struct ao2_container *channels, struct ast_channel *transferer) +{ + struct ao2_iterator channel_iter; + struct ast_channel *transferee; + + for (channel_iter = ao2_iterator_init(channels, 0); + (transferee = ao2_iterator_next(&channel_iter)); + ao2_cleanup(transferee)) { + if (transferee != transferer) { + break; + } + } + + ao2_iterator_destroy(&channel_iter); + return transferee; +} + + static void stasis_publish_data_cleanup(struct stasis_attended_transfer_publish_data *publication) { ast_channel_unref(publication->to_transferee.channel); ast_channel_unref(publication->to_transfer_target.channel); + ast_channel_cleanup(publication->transferee_channel); + ast_channel_cleanup(publication->target_channel); ao2_cleanup(publication->to_transferee.bridge); ao2_cleanup(publication->to_transfer_target.bridge); + ao2_cleanup(publication->replace_channel); } /*! @@ -3865,6 +3948,9 @@ static void stasis_publish_data_init(struct ast_channel *to_transferee, ao2_ref(to_target_bridge, +1); publication->to_transfer_target.bridge = to_target_bridge; } + + publication->transferee_channel = ast_bridge_peer(to_transferee_bridge, to_transferee); + publication->target_channel = ast_bridge_peer(to_target_bridge, to_transfer_target); } /* @@ -3878,7 +3964,8 @@ static void publish_attended_transfer_bridge_merge(struct stasis_attended_transf struct ast_bridge *final_bridge) { ast_bridge_publish_attended_transfer_bridge_merge(1, AST_BRIDGE_TRANSFER_SUCCESS, - &publication->to_transferee, &publication->to_transfer_target, final_bridge); + &publication->to_transferee, &publication->to_transfer_target, final_bridge, + publication->transferee_channel, publication->target_channel); } /* @@ -3892,7 +3979,9 @@ static void publish_attended_transfer_app(struct stasis_attended_transfer_publis const char *app) { ast_bridge_publish_attended_transfer_app(1, AST_BRIDGE_TRANSFER_SUCCESS, - &publication->to_transferee, &publication->to_transfer_target, app); + &publication->to_transferee, &publication->to_transfer_target, + publication->replace_channel, app, + publication->transferee_channel, publication->target_channel); } /* @@ -3909,7 +3998,8 @@ static void publish_attended_transfer_link(struct stasis_attended_transfer_publi struct ast_channel *locals[2] = { local_channel1, local_channel2 }; ast_bridge_publish_attended_transfer_link(1, AST_BRIDGE_TRANSFER_SUCCESS, - &publication->to_transferee, &publication->to_transfer_target, locals); + &publication->to_transferee, &publication->to_transfer_target, locals, + publication->transferee_channel, publication->target_channel); } /* @@ -3923,7 +4013,8 @@ static void publish_attended_transfer_fail(struct stasis_attended_transfer_publi enum ast_transfer_result result) { ast_bridge_publish_attended_transfer_fail(1, result, &publication->to_transferee, - &publication->to_transfer_target); + &publication->to_transfer_target, publication->transferee_channel, + publication->target_channel); } /*! @@ -3987,9 +4078,12 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha return AST_BRIDGE_TRANSFER_FAIL; } + /* Get a ref for use later since this one is being stolen */ + ao2_ref(local_chan, +1); if (ast_bridge_impart(bridge1, local_chan, chan1, NULL, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { ast_hangup(local_chan); + ao2_cleanup(local_chan); return AST_BRIDGE_TRANSFER_FAIL; } @@ -4005,40 +4099,12 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha publish_attended_transfer_link(publication, local_chan, local_chan2); } else { + publication->replace_channel = ao2_bump(local_chan); publish_attended_transfer_app(publication, app); } - return AST_BRIDGE_TRANSFER_SUCCESS; -} -/*! - * \internal - * \brief Get the transferee channel - * - * This is only applicable to cases where a transfer is occurring on a - * two-party bridge. The channels container passed in is expected to only - * contain two channels, the transferer and the transferee. The transferer - * channel is passed in as a parameter to ensure we don't return it as - * the transferee channel. - * - * \param channels A two-channel container containing the transferer and transferee - * \param transferer The party that is transfering the call - * \return The party that is being transferred - */ -static struct ast_channel *get_transferee(struct ao2_container *channels, struct ast_channel *transferer) -{ - struct ao2_iterator channel_iter; - struct ast_channel *transferee; - - for (channel_iter = ao2_iterator_init(channels, 0); - (transferee = ao2_iterator_next(&channel_iter)); - ao2_cleanup(transferee)) { - if (transferee != transferer) { - break; - } - } - - ao2_iterator_destroy(&channel_iter); - return transferee; + ao2_cleanup(local_chan); + return AST_BRIDGE_TRANSFER_SUCCESS; } static enum ast_transfer_result try_parking(struct ast_channel *transferer, @@ -4142,7 +4208,7 @@ static struct ast_bridge *acquire_bridge(struct ast_channel *chan) static void publish_blind_transfer(int is_external, enum ast_transfer_result result, struct ast_channel *transferer, struct ast_bridge *bridge, - const char *context, const char *exten) + const char *context, const char *exten, struct ast_channel *transferee_channel) { struct ast_bridge_channel_pair pair; pair.channel = transferer; @@ -4150,7 +4216,7 @@ static void publish_blind_transfer(int is_external, enum ast_transfer_result res if (bridge) { ast_bridge_lock(bridge); } - ast_bridge_publish_blind_transfer(is_external, result, &pair, context, exten); + ast_bridge_publish_blind_transfer(is_external, result, &pair, context, exten, transferee_channel); if (bridge) { ast_bridge_unlock(bridge); } @@ -4174,6 +4240,9 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external, transfer_result = AST_BRIDGE_TRANSFER_INVALID; goto publish; } + + transferee = ast_bridge_peer(bridge, transferer); + ast_channel_lock(transferer); bridge_channel = ast_channel_get_bridge_channel(transferer); ast_channel_unlock(transferer); @@ -4235,7 +4304,6 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external, /* Reaching this portion means that we're dealing with a two-party bridge */ - transferee = get_transferee(channels, transferer); if (!transferee) { transfer_result = AST_BRIDGE_TRANSFER_FAIL; goto publish; @@ -4251,7 +4319,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external, transfer_result = AST_BRIDGE_TRANSFER_SUCCESS; publish: - publish_blind_transfer(is_external, transfer_result, transferer, bridge, context, exten); + publish_blind_transfer(is_external, transfer_result, transferer, bridge, context, exten, transferee); return transfer_result; } |