From 854c4c64fe2851312b1e13857dcd18e743e07594 Mon Sep 17 00:00:00 2001 From: Jonathan Rose Date: Tue, 25 Jun 2013 22:28:22 +0000 Subject: 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 --- main/features.c | 214 ++++---------------------------------------------------- 1 file changed, 12 insertions(+), 202 deletions(-) (limited to 'main/features.c') diff --git a/main/features.c b/main/features.c index c26e2deee..2bb8ffd44 100644 --- a/main/features.c +++ b/main/features.c @@ -254,29 +254,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - - - Park a channel. - - - - - Channel name to park. - - - Channel to return to if timeout. - - - Number of milliseconds to wait before callback. - - - Specify in which parking lot to park the channel. - - - - Park a channel. - - Bridge two channels already in the PBX. @@ -4344,87 +4321,6 @@ static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast return CLI_SUCCESS; } -/*! - * \internal - * \brief Add an arbitrary channel to a bridge - * - * The channel that is being added to the bridge can be in any state: unbridged, - * bridged, answered, unanswered, etc. The channel will be added asynchronously, - * meaning that when this function returns once the channel has been added to - * the bridge, not once the channel has been removed from the bridge. - * - * In addition, a tone can optionally be played to the channel once the - * channel is placed into the bridge. - * - * \note When this function returns, there is no guarantee that the channel that - * was passed in is valid any longer. Do not attempt to operate on the channel - * after this function returns. - * - * \param bridge Bridge to which the channel should be added - * \param chan The channel to add to the bridge - * \param features Features for this channel in the bridge - * \param play_tone Indicates if a tone should be played to the channel - * \retval 0 Success - * \retval -1 Failure - */ -static int add_to_bridge(struct ast_bridge *bridge, struct ast_channel *chan, - struct ast_bridge_features *features, int play_tone) -{ - RAII_VAR(struct ast_bridge *, chan_bridge, NULL, ao2_cleanup); - RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup); - struct ast_channel *bridge_chan = NULL; - const char *tone = NULL; - - ast_channel_lock(chan); - chan_bridge = ast_channel_get_bridge(chan); - xfer_cfg = ast_get_chan_features_xfer_config(chan); - if (!xfer_cfg) { - ast_log(LOG_ERROR, "Unable to determine what tone to play to channel.\n"); - } else { - tone = ast_strdupa(xfer_cfg->xfersound); - } - ast_channel_unlock(chan); - - if (chan_bridge) { - if (ast_bridge_move(bridge, chan_bridge, chan, NULL, 1)) { - return -1; - } - } 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(tone)) { - 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, tone, NULL); - } - } - return 0; -} - enum play_tone_action { PLAYTONE_NONE = 0, PLAYTONE_CHANNEL1 = (1 << 0), @@ -4478,6 +4374,8 @@ static int action_bridge(struct mansession *s, const struct message *m) int chanb_priority; struct ast_bridge *bridge; char buf[256]; + RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_a, NULL, ao2_cleanup); + RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_b, NULL, ao2_cleanup); /* make sure valid channels were specified */ if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { @@ -4492,6 +4390,10 @@ static int action_bridge(struct mansession *s, const struct message *m) astman_send_error(s, m, buf); return 0; } + + xfer_cfg_a = ast_get_chan_features_xfer_config(chana); + xfer_cfg_b = ast_get_chan_features_xfer_config(chanb); + ast_channel_lock(chana); chana_name = ast_strdupa(ast_channel_name(chana)); chana_exten = ast_strdupa(ast_channel_exten(chana)); @@ -4525,7 +4427,7 @@ static int action_bridge(struct mansession *s, const struct message *m) } ast_after_bridge_set_go_on(chana, chana_context, chana_exten, chana_priority, NULL); - if (add_to_bridge(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1)) { + 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); @@ -4533,7 +4435,7 @@ static int action_bridge(struct mansession *s, const struct message *m) } ast_after_bridge_set_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL); - if (add_to_bridge(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2)) { + 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); @@ -4571,100 +4473,6 @@ static struct ast_cli_entry cli_features[] = { AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"), }; -/*! - * \brief Create manager event for parked calls - * \param s - * \param m - * - * Get channels involved in park, create event. - * \return Always 0 - * - * \note ADSI is not compatible with this AMI action for the - * same reason ch2 can no longer announce the parking space. - */ -static int manager_park(struct mansession *s, const struct message *m) -{ - const char *channel = astman_get_header(m, "Channel"); - const char *channel2 = astman_get_header(m, "Channel2"); - const char *timeout = astman_get_header(m, "Timeout"); - const char *parkinglotname = astman_get_header(m, "Parkinglot"); - char buf[BUFSIZ]; - int res = 0; - struct ast_channel *ch1, *ch2; - struct ast_park_call_args args = { - /* - * Don't say anything to ch2 since AMI is a third party parking - * a call and we will likely crash if we do. - * - * XXX When the AMI action was originally implemented, the - * parking space was announced to ch2. Unfortunately, grabbing - * the ch2 lock and holding it while the announcement is played - * was not really a good thing to do to begin with since it - * could hold up the system. Also holding the lock is no longer - * possible with a masquerade. - * - * Restoring the announcement to ch2 is not easily doable for - * the following reasons: - * - * 1) The AMI manager is not the thread processing ch2. - * - * 2) ch2 could be the same as ch1, bridged to ch1, or some - * random uninvolved channel. - */ - .flags = AST_PARK_OPT_SILENCE, - }; - - if (ast_strlen_zero(channel)) { - astman_send_error(s, m, "Channel not specified"); - return 0; - } - - if (ast_strlen_zero(channel2)) { - astman_send_error(s, m, "Channel2 not specified"); - return 0; - } - - if (!ast_strlen_zero(timeout)) { - if (sscanf(timeout, "%30d", &args.timeout) != 1) { - astman_send_error(s, m, "Invalid timeout value."); - return 0; - } - } - - if (!(ch1 = ast_channel_get_by_name(channel))) { - snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel); - astman_send_error(s, m, buf); - return 0; - } - - if (!(ch2 = ast_channel_get_by_name(channel2))) { - snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2); - astman_send_error(s, m, buf); - ast_channel_unref(ch1); - return 0; - } - - if (!ast_strlen_zero(parkinglotname)) { - args.parkinglot = find_parkinglot(parkinglotname); - } - - res = masq_park_call(ch1, ch2, &args); - if (!res) { - ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT); - astman_send_ack(s, m, "Park successful"); - } else { - astman_send_error(s, m, "Park failure"); - } - - if (args.parkinglot) { - parkinglot_unref(args.parkinglot); - } - ch1 = ast_channel_unref(ch1); - ch2 = ast_channel_unref(ch2); - - return 0; -} - /*! * The presence of this datastore on the channel indicates that * someone is attemting to pickup or has picked up the channel. @@ -5112,6 +4920,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data) struct ast_bridge_features chan_features; struct ast_bridge_features *peer_features; struct ast_bridge *bridge; + RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup); AST_DECLARE_APP_ARGS(args, AST_APP_ARG(dest_chan); @@ -5251,7 +5060,9 @@ static int bridge_exec(struct ast_channel *chan, const char *data) goto done; } - if (add_to_bridge(bridge, current_dest_chan, peer_features, ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE))) { + xfer_cfg = ast_get_chan_features_xfer_config(current_dest_chan); + + if (ast_bridge_add_channel(bridge, current_dest_chan, peer_features, 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); @@ -5788,7 +5599,6 @@ int ast_features_init(void) return -1; } res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); - res |= ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park); res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge); res |= ast_devstate_prov_add("Park", metermaidstate); -- cgit v1.2.3