diff options
author | Jonathan Rose <jrose@digium.com> | 2013-06-25 22:28:22 +0000 |
---|---|---|
committer | Jonathan Rose <jrose@digium.com> | 2013-06-25 22:28:22 +0000 |
commit | 854c4c64fe2851312b1e13857dcd18e743e07594 (patch) | |
tree | 80d042e06f38f95d4f1fd2adc07658b2cbd46038 /main/bridging.c | |
parent | 5b40420813318e08b9186d41aaf1d1aaff8d61e1 (diff) |
res_parking: Add Parking manager action to the new parking system
(closes issue ASTERISK-21641)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2573/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@392915 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/bridging.c')
-rw-r--r-- | main/bridging.c | 116 |
1 files changed, 102 insertions, 14 deletions
diff --git a/main/bridging.c b/main/bridging.c index 0530424ff..b0c27966a 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -528,45 +528,66 @@ static void bridge_dissolve(struct ast_bridge *bridge) /*! * \internal - * \brief Check if a bridge should dissolve and do it. + * \brief Determine whether a bridge channel leaving the bridge will cause it to dissolve or not. * \since 12.0.0 * - * \param bridge_channel Channel causing the check. + * \param bridge_channel Channel causing the check + * \param bridge The bridge we are concerned with * - * \note On entry, bridge_channel->bridge is already locked. + * \note the bridge should be locked prior to calling this function * - * \return Nothing + * \retval 0 if the channel leaving shouldn't cause the bridge to dissolve + * \retval non-zero if the channel should cause the bridge to dissolve */ -static void bridge_dissolve_check(struct ast_bridge_channel *bridge_channel) +static int bridge_check_will_dissolve(struct ast_bridge_channel *bridge_channel, struct ast_bridge *bridge, int assume_end_state) { - struct ast_bridge *bridge = bridge_channel->bridge; - if (bridge->dissolved) { - return; + /* The bridge is already dissolved. Don't try to dissolve it again. */ + return 0; } 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); - return; + return 1; } - switch (bridge_channel->state) { + switch (assume_end_state ? AST_BRIDGE_CHANNEL_STATE_END : bridge_channel->state) { case AST_BRIDGE_CHANNEL_STATE_END: /* Do we need to dissolve the bridge because this channel hung up? */ if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP) || (bridge_channel->features->usable && ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_DISSOLVE_HANGUP))) { - bridge_dissolve(bridge); - return; + return 1; } + break; default: break; } -/* BUGBUG need to implement AST_BRIDGE_CHANNEL_FLAG_LONELY support here */ + /* BUGBUG need to implement AST_BRIDGE_CHANNEL_FLAG_LONELY support here */ + return 0; +} + +/*! + * \internal + * \brief Check if a bridge should dissolve and do it. + * \since 12.0.0 + * + * \param bridge_channel Channel causing the check. + * + * \note On entry, bridge_channel->bridge is already locked. + * + * \return Nothing + */ +static void bridge_dissolve_check(struct ast_bridge_channel *bridge_channel) +{ + struct ast_bridge *bridge = bridge_channel->bridge; + + if (bridge_check_will_dissolve(bridge_channel, bridge, 0)) { + bridge_dissolve(bridge); + } } /*! @@ -4300,6 +4321,73 @@ int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge return res; } +int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan, + struct ast_bridge_features *features, int play_tone, const char *xfersound) +{ + RAII_VAR(struct ast_bridge *, chan_bridge, NULL, ao2_cleanup); + struct ast_channel *bridge_chan = NULL; + + ast_channel_lock(chan); + chan_bridge = ast_channel_get_bridge(chan); + ast_channel_unlock(chan); + + if (chan_bridge) { + RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup); + int hangup = 0; + + /* Simply moving the channel from the bridge won't perform the dissolve check + * so we need to manually check here to see if we should dissolve after moving. */ + ao2_lock(chan_bridge); + if ((bridge_channel = ast_channel_get_bridge_channel(chan))) { + hangup = bridge_check_will_dissolve(bridge_channel, chan_bridge, 1); + } + + if (ast_bridge_move(bridge, chan_bridge, chan, NULL, 1)) { + ao2_unlock(chan_bridge); + return -1; + } + + if (hangup) { + bridge_dissolve(chan_bridge); + } + ao2_unlock(chan_bridge); + + } else { + /* Slightly less easy case. We need to yank channel A from + * where he currently is and impart him into our bridge. + */ + bridge_chan = ast_channel_yank(chan); + if (!bridge_chan) { + ast_log(LOG_WARNING, "Could not gain control of channel %s\n", ast_channel_name(chan)); + return -1; + } + if (ast_channel_state(bridge_chan) != AST_STATE_UP) { + ast_answer(bridge_chan); + } + if (ast_bridge_impart(bridge, bridge_chan, NULL, features, 1)) { + ast_log(LOG_WARNING, "Could not add %s to the bridge\n", ast_channel_name(chan)); + return -1; + } + } + + if (play_tone && !ast_strlen_zero(xfersound)) { + struct ast_channel *play_chan = bridge_chan ?: chan; + RAII_VAR(struct ast_bridge_channel *, play_bridge_channel, NULL, ao2_cleanup); + + ast_channel_lock(play_chan); + play_bridge_channel = ast_channel_get_bridge_channel(play_chan); + ast_channel_unlock(play_chan); + + if (!play_bridge_channel) { + ast_log(LOG_WARNING, "Unable to play tone for channel %s. Unable to get bridge channel\n", + ast_channel_name(play_chan)); + } else { + ast_bridge_channel_queue_playfile(play_bridge_channel, NULL, xfersound, NULL); + } + } + return 0; +} + struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel) { struct ast_bridge *bridge = bridge_channel->bridge; |