From 57372e61d23543c70158ba8a0fec40e4848ee44e Mon Sep 17 00:00:00 2001 From: Jonathan Rose <jrose@digium.com> Date: Fri, 2 May 2014 16:06:40 +0000 Subject: [PATCH] Parking: Add 'AnnounceChannel' argument to manager action 'Park' (closes ASTERISK-23397) Reported by: Denis Review: https://reviewboard.asterisk.org/r/3446/ ........ Merged revisions 413196 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@413197 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- CHANGES | 10 ++- res/parking/parking_bridge_features.c | 10 ++- res/parking/parking_manager.c | 116 ++++++++++++++++++++++++-- res/parking/res_parking.h | 13 +++ 4 files changed, 135 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index f8c698fd56..c5e7badf78 100644 --- a/CHANGES +++ b/CHANGES @@ -52,6 +52,15 @@ chan_sip calling information to communicate that the private information should not be relayed to untrusted parties. +res_parking +------------------ + * Manager action 'Park' now takes an additional argument 'AnnounceChannel' + which can be used to announce the parked call's location to an arbitrary + channel in a bridge. If 'Channel' and 'TimeoutChannel' are now the two + parties in a one to one bridge, 'TimeoutChannel' is treated as having + parked 'Channel' like with the Park Call DTMF feature and will receive + announcements prior to being hung up. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 12.1.0 to Asterisk 12.2.0 ------------ ------------------------------------------------------------------------------ @@ -1526,7 +1535,6 @@ sip_to_res_pjsip.py what the script provides will be needed. ------------------------------------------------------------------------------ ->>>>>>> .merge-right.r412746 --- Functionality changes from Asterisk 10 to Asterisk 11 -------------------- ------------------------------------------------------------------------------ diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index e9f814151d..9840b294c0 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -50,6 +50,7 @@ struct parked_subscription_datastore { struct parked_subscription_data { char *parkee_uuid; + int hangup_after:1; char parker_uuid[0]; }; @@ -114,7 +115,7 @@ static void parker_parked_call_message_response(struct ast_parked_call_payload * if (message->event_type == PARKED_CALL) { /* queue the saynum on the bridge channel and hangup */ - snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", 1, message->parkingspace); + snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", data->hangup_after, message->parkingspace); ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL); wipe_subscription_datastore(bridge_channel->chan); } @@ -138,7 +139,7 @@ static void parker_update_cb(void *data, struct stasis_subscription *sub, struct } } -static int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid) +int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after) { struct ast_datastore *datastore; struct parked_subscription_datastore *parked_datastore; @@ -166,6 +167,7 @@ static int create_parked_subscription(struct ast_channel *chan, const char *park return -1; } + subscription_data->hangup_after = hangup_after; subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size; strcpy(subscription_data->parkee_uuid, parkee_uuid); strcpy(subscription_data->parker_uuid, parker_uuid); @@ -218,7 +220,7 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const ast_channel_unlock(parkee); /* We need to have the parker subscribe to the new local channel before hand. */ - create_parked_subscription(parker, ast_channel_uniqueid(parkee_side_2)); + create_parked_subscription(parker, ast_channel_uniqueid(parkee_side_2), 1); ast_bridge_set_transfer_variables(parkee_side_2, ast_channel_name(parker), 0); @@ -325,7 +327,7 @@ static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel } /* Subscribe to park messages with the other channel entering */ - if (create_parked_subscription(bridge_channel->chan, ast_channel_uniqueid(other->chan))) { + if (create_parked_subscription(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1)) { return -1; } diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c index 16e2863698..55ce85a354 100644 --- a/res/parking/parking_manager.c +++ b/res/parking/parking_manager.c @@ -74,11 +74,21 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <para>Channel name to park.</para> </parameter> <parameter name="TimeoutChannel" required="false"> - <para>Channel name to use when constructing the dial string that will be dialed if the parked channel times out.</para> + <para>Channel name to use when constructing the dial string that will be dialed if the parked channel + times out. If <literal>TimeoutChannel</literal> is in a two party bridge with + <literal>Channel</literal>, then <literal>TimeoutChannel</literal> will receive an announcement and be + treated as having parked <literal>Channel</literal> in the same manner as the Park Call DTMF feature. + </para> + </parameter> + <parameter name="AnnounceChannel" required="false"> + <para>If specified, then this channel will receive an announcement when <literal>Channel</literal> + is parked if <literal>AnnounceChannel</literal> is in a state where it can receive announcements + (AnnounceChannel must be bridged). <literal>AnnounceChannel</literal> has no bearing on the actual + state of the parked call.</para> </parameter> <parameter name="Timeout" required="false"> <para>Overrides the timeout of the parking lot for this park action. Specified in milliseconds, but will be converted to - seconds. Use a value of 0 to nullify the timeout. + seconds. Use a value of 0 to disable the timeout. </para> </parameter> <parameter name="Parkinglot" required="false"> @@ -420,17 +430,85 @@ static int manager_parking_lot_list(struct mansession *s, const struct message * return 0; } +static void manager_park_unbridged(struct mansession *s, const struct message *m, + struct ast_channel *chan, const char *parkinglot, int timeout_override) +{ + struct ast_bridge *parking_bridge = park_common_setup(chan, + chan, parkinglot, NULL, 0, 0, timeout_override, 1); + + if (!parking_bridge) { + astman_send_error(s, m, "Park action failed\n"); + return; + } + + if (ast_bridge_add_channel(parking_bridge, chan, NULL, 0, NULL)) { + astman_send_error(s, m, "Park action failed\n"); + ao2_cleanup(parking_bridge); + return; + } + + astman_send_ack(s, m, "Park successful\n"); + ao2_cleanup(parking_bridge); +} + +static void manager_park_bridged(struct mansession *s, const struct message *m, + struct ast_channel *chan, struct ast_channel *parker_chan, + const char *parkinglot, int timeout_override) +{ + struct ast_bridge_channel *bridge_channel; + char *app_data; + + if (timeout_override != -1) { + if (ast_asprintf(&app_data, "%s,t(%d)", parkinglot, timeout_override) == -1) { + astman_send_error(s, m, "Park action failed\n"); + return; + } + } else { + if (ast_asprintf(&app_data, "%s", parkinglot) == -1) { + astman_send_error(s, m, "Park action failed\n"); + return; + } + } + + ast_channel_lock(parker_chan); + bridge_channel = ast_channel_get_bridge_channel(parker_chan); + ast_channel_unlock(parker_chan); + + if (!bridge_channel) { + ast_free(app_data); + astman_send_error(s, m, "Park action failed\n"); + return; + } + + /* Subscribe to park messages for the channel being parked */ + if (create_parked_subscription(parker_chan, ast_channel_uniqueid(chan), 1)) { + ast_free(app_data); + astman_send_error(s, m, "Park action failed\n"); + ao2_cleanup(bridge_channel); + return; + } + + ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(chan), + ast_channel_uniqueid(parker_chan), app_data); + + ast_free(app_data); + + astman_send_ack(s, m, "Park successful\n"); + ao2_cleanup(bridge_channel); +} + static int manager_park(struct mansession *s, const struct message *m) { const char *channel = astman_get_header(m, "Channel"); const char *timeout_channel = S_OR(astman_get_header(m, "TimeoutChannel"), astman_get_header(m, "Channel2")); + const char *announce_channel = astman_get_header(m, "AnnounceChannel"); const char *timeout = astman_get_header(m, "Timeout"); const char *parkinglot = astman_get_header(m, "Parkinglot"); char buf[BUFSIZ]; int timeout_override = -1; + RAII_VAR(struct ast_channel *, parker_chan, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup); - RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup); if (ast_strlen_zero(channel)) { astman_send_error(s, m, "Channel not specified"); @@ -461,17 +539,37 @@ static int manager_park(struct mansession *s, const struct message *m) } ast_channel_unlock(chan); - if (!(parking_bridge = park_common_setup(chan, chan, parkinglot, NULL, 0, 0, timeout_override, 0))) { - astman_send_error(s, m, "Park action failed\n"); + parker_chan = ast_channel_bridge_peer(chan); + if (!parker_chan || strcmp(ast_channel_name(parker_chan), timeout_channel)) { + if (!ast_strlen_zero(announce_channel)) { + struct ast_channel *announce_chan = ast_channel_get_by_name(announce_channel); + if (!announce_channel) { + astman_send_error(s, m, "AnnounceChannel does not exist"); + return 0; + } + + create_parked_subscription(announce_chan, ast_channel_uniqueid(chan), 0); + ast_channel_cleanup(announce_chan); + } + + manager_park_unbridged(s, m, chan, parkinglot, timeout_override); return 0; } - if (ast_bridge_add_channel(parking_bridge, chan, NULL, 0, NULL)) { - astman_send_error(s, m, "Park action failed\n"); - return 0; + if (!ast_strlen_zero(announce_channel) && strcmp(announce_channel, timeout_channel)) { + /* When using an announce_channel in bridge mode, only add the announce channel if it isn't + * the same as the timeout channel (which will play announcements anyway) */ + struct ast_channel *announce_chan = ast_channel_get_by_name(announce_channel); + if (!announce_channel) { + astman_send_error(s, m, "AnnounceChannel does not exist"); + return 0; + } + + create_parked_subscription(announce_chan, ast_channel_uniqueid(chan), 0); + ast_channel_cleanup(announce_chan); } - astman_send_ack(s, m, "Park successful\n"); + manager_park_bridged(s, m, chan, parker_chan, parkinglot, timeout_override); return 0; } diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h index f97e85be9f..3d77e514c4 100644 --- a/res/parking/res_parking.h +++ b/res/parking/res_parking.h @@ -385,6 +385,19 @@ void publish_parked_call_failure(struct ast_channel *parkee); */ void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type event_type); +/*! + * \since 12.3.0 + * \brief Create a parking announcement subscription + * + * \param chan Channel that will receive the announcement + * \param parkee_uuid Unique ID of the channel being parked + * \param hangup_after if non-zero, have the channel hangup after hearing the announcement + * + * \retval 0 on success + * \retval -1 on failure + */ +int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after); + /*! * \since 12.0.0 * \brief Setup a parked call on a parking bridge without needing to parse appdata -- GitLab