summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_dahdi.c2
-rw-r--r--channels/chan_mgcp.c2
-rw-r--r--channels/chan_sip.c4
-rw-r--r--channels/sig_analog.c2
-rw-r--r--include/asterisk/bridge.h18
-rw-r--r--include/asterisk/parking.h12
-rw-r--r--main/bridge.c28
-rw-r--r--main/bridge_basic.c4
-rw-r--r--main/parking.c8
-rw-r--r--res/parking/parking_applications.c2
-rw-r--r--res/parking/parking_bridge_features.c88
-rw-r--r--res/res_pjsip_refer.c28
12 files changed, 158 insertions, 40 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index b4c8ec366..71e5831e0 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -9741,7 +9741,7 @@ static void *analog_ss_thread(void *data)
bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
if (bridge_channel) {
- if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+ if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
/*
* Swap things around between the three-way and real call so we
* can hear where the channel got parked.
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 1955edaea..2d0afe29d 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -3167,7 +3167,7 @@ static void *mgcp_ss(void *data)
ast_channel_lock(chan);
bridge_channel = ast_channel_get_bridge_channel(chan);
ast_channel_unlock(chan);
- if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf)) {
+ if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf, NULL, NULL)) {
ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
}
break;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index a9a13790c..6c49236ce 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -26081,10 +26081,10 @@ struct blind_transfer_cb_data {
* \param user_data A blind_transfer_cb_data struct
* \param transfer_type Unused
*/
-static void blind_transfer_cb(struct ast_channel *chan, void *user_data,
+static void blind_transfer_cb(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
enum ast_transfer_type transfer_type)
{
- struct blind_transfer_cb_data *cb_data = user_data;
+ struct blind_transfer_cb_data *cb_data = user_data_wrapper->data;
pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
pbx_builtin_setvar_helper(chan, "SIPTRANSFER_REFERER", cb_data->referred_by);
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 21b832164..9957074d1 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -2259,7 +2259,7 @@ static void *__analog_ss_thread(void *data)
bridge_channel = ast_channel_get_bridge_channel(p->subs[ANALOG_SUB_THREEWAY].owner);
ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
if (bridge_channel) {
- if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+ if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
/*
* Swap things around between the three-way and real call so we
* can hear where the channel got parked.
diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h
index 8768fe1be..d23d4b5bc 100644
--- a/include/asterisk/bridge.h
+++ b/include/asterisk/bridge.h
@@ -904,6 +904,22 @@ enum ast_transfer_type {
};
/*!
+ * \brief AO2 object that wraps data for transfer_channel_cb
+ */
+struct transfer_channel_data {
+ void *data; /*! Data to be used by the transfer_channel_cb -- note that this
+ * pointer is going to be pointing to something on the stack, so
+ * it must not be used at any point after returning from the
+ * transfer_channel_cb. */
+ int completed; /*! Initially 0, This will be set to 1 by either the transfer
+ * code or by transfer code hooks (e.g. parking) when the
+ * transfer is completed and any remaining actions have taken
+ * place (e.g. parking announcements). It will never be reset
+ * to 0. This is used for deferring progress for channel
+ * drivers that support deferred progress. */
+};
+
+/*!
* \brief Callback function type called during blind transfers
*
* A caller of ast_bridge_transfer_blind() may wish to set data on
@@ -914,7 +930,7 @@ enum ast_transfer_type {
* \param user_data User-provided data needed in the callback
* \param transfer_type The type of transfer being completed
*/
-typedef void (*transfer_channel_cb)(struct ast_channel *chan, void *user_data,
+typedef void (*transfer_channel_cb)(struct ast_channel *chan, struct transfer_channel_data *user_data,
enum ast_transfer_type transfer_type);
/*!
diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h
index 8b2b4b409..a8832cdb8 100644
--- a/include/asterisk/parking.h
+++ b/include/asterisk/parking.h
@@ -24,6 +24,7 @@
*/
#include "asterisk/stringfields.h"
+#include "asterisk/bridge.h"
/*!
* \brief The default parking application that Asterisk expects.
@@ -163,6 +164,8 @@ struct ast_parking_bridge_feature_fn_table {
* \param parker The \ref bridge_channel object that is initiating the parking
* \param context The context to blind transfer to
* \param exten The extension to blind transfer to
+ * \param parked_channel_cb Execute the following function on the the channel that gets parked
+ * \param parked_channel_data Data for the parked_channel_cb
*
* \note If the bridge \ref parker is in has more than one other occupant, the entire
* bridge will be parked using a Local channel
@@ -172,7 +175,8 @@ struct ast_parking_bridge_feature_fn_table {
* \retval 0 on success
* \retval non-zero on error
*/
- int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context, const char *exten);
+ int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context,
+ const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);
/*!
* \brief Perform a direct park on a channel in a bridge.
@@ -224,6 +228,9 @@ int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t
* \param parker The \ref bridge_channel object that is initiating the parking
* \param context The context to blind transfer to
* \param exten The extension to blind transfer to
+ * \param exten The extension to blind transfer to
+ * \param parked_channel_cb Execute the following function on the the channel that gets parked
+ * \param parked_channel_data Data for the parked_channel_cb
*
* \note If the bridge \ref parker is in has more than one other occupant, the entire
* bridge will be parked using a Local channel
@@ -233,7 +240,8 @@ int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t
* \retval 0 on success
* \retval non-zero on error
*/
-int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten);
+int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context,
+ const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);
/*!
* \brief Perform a direct park on a channel in a bridge.
diff --git a/main/bridge.c b/main/bridge.c
index 6fdf0d554..fa4e3c699 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -3718,7 +3718,7 @@ struct ast_channel *ast_bridge_peer(struct ast_bridge *bridge, struct ast_channe
*/
static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transferer,
struct ast_bridge *bridge, const char *exten, const char *context,
- transfer_channel_cb new_channel_cb, void *user_data)
+ transfer_channel_cb new_channel_cb, struct transfer_channel_data *user_data_wrapper)
{
struct ast_channel *local;
char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
@@ -3734,7 +3734,7 @@ static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transf
pbx_builtin_setvar_helper(local, BLINDTRANSFER, ast_channel_name(transferer));
if (new_channel_cb) {
- new_channel_cb(local, user_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
+ new_channel_cb(local, user_data_wrapper, AST_BRIDGE_TRANSFER_MULTI_PARTY);
}
if (ast_call(local, chan_name, 0)) {
@@ -3968,7 +3968,9 @@ static struct ast_channel *get_transferee(struct ao2_container *channels, struct
return transferee;
}
-static enum ast_transfer_result try_parking(struct ast_channel *transferer, const char *context, const char *exten)
+static enum ast_transfer_result try_parking(struct ast_channel *transferer,
+ const char *context, const char *exten, transfer_channel_cb new_channel_cb,
+ struct transfer_channel_data *user_data_wrapper)
{
RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
@@ -3985,7 +3987,7 @@ static enum ast_transfer_result try_parking(struct ast_channel *transferer, cons
}
if (ast_parking_blind_transfer_park(transferer_bridge_channel,
- context, exten)) {
+ context, exten, new_channel_cb, user_data_wrapper)) {
return AST_BRIDGE_TRANSFER_FAIL;
}
@@ -4089,6 +4091,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel *, transferee, NULL, ast_channel_cleanup);
+ RAII_VAR(struct transfer_channel_data *, user_data_wrapper, NULL, ao2_cleanup);
int do_bridge_transfer;
int transfer_prohibited;
enum ast_transfer_result transfer_result;
@@ -4106,14 +4109,25 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
goto publish;
}
+ user_data_wrapper = ao2_alloc(sizeof(*user_data_wrapper), NULL);
+ if (!user_data_wrapper) {
+ transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+ goto publish;
+ }
+
+ user_data_wrapper->data = user_data;
+
/* Take off hold if they are on hold. */
ast_bridge_channel_write_unhold(bridge_channel);
- transfer_result = try_parking(transferer, context, exten);
+ transfer_result = try_parking(transferer, context, exten, new_channel_cb, user_data_wrapper);
if (transfer_result == AST_BRIDGE_TRANSFER_SUCCESS) {
goto publish;
}
+ /* Since parking didn't take control of the user_data_wrapper, we are just going to raise the completed flag now. */
+ user_data_wrapper->completed = 1;
+
{
SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
@@ -4142,7 +4156,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
if (do_bridge_transfer) {
transfer_result = blind_transfer_bridge(transferer, bridge, exten, context,
- new_channel_cb, user_data);
+ new_channel_cb, user_data_wrapper);
goto publish;
}
@@ -4155,7 +4169,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
}
if (bridge_channel_internal_queue_blind_transfer(transferee, exten, context,
- new_channel_cb, user_data)) {
+ new_channel_cb, user_data_wrapper)) {
transfer_result = AST_BRIDGE_TRANSFER_FAIL;
goto publish;
}
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index a5827f2ad..cee56b1b5 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -3145,10 +3145,10 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
return 0;
}
-static void blind_transfer_cb(struct ast_channel *new_channel, void *user_data,
+static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_channel_data *user_data_wrapper,
enum ast_transfer_type transfer_type)
{
- struct ast_channel *transferer_channel = user_data;
+ struct ast_channel *transferer_channel = user_data_wrapper->data;
if (transfer_type == AST_BRIDGE_TRANSFER_MULTI_PARTY) {
copy_caller_data(new_channel, transferer_channel);
diff --git a/main/parking.c b/main/parking.c
index db274a3ff..f7f1dfb5c 100644
--- a/main/parking.c
+++ b/main/parking.c
@@ -142,7 +142,9 @@ int ast_parking_park_bridge_channel(struct ast_bridge_channel *parkee, const cha
return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
}
-int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten)
+int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
+ const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
+ struct transfer_channel_data *parked_channel_data)
{
RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
ao2_global_obj_ref(parking_provider), ao2_cleanup);
@@ -153,10 +155,10 @@ int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const cha
if (table->module_info) {
SCOPED_MODULE_USE(table->module_info->self);
- return table->parking_blind_transfer_park(parker, context, exten);
+ return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
}
- return table->parking_blind_transfer_park(parker, context, exten);
+ return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
}
int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c
index 3d2eecd29..5500e3316 100644
--- a/res/parking/parking_applications.c
+++ b/res/parking/parking_applications.c
@@ -516,6 +516,7 @@ static int park_app_exec(struct ast_channel *chan, const char *data)
if (!silence_announcements && !transferer) {
ast_stream_and_wait(chan, "pbx-parkingfailed", "");
}
+ publish_parked_call_failure(chan);
return 0;
}
@@ -523,6 +524,7 @@ static int park_app_exec(struct ast_channel *chan, const char *data)
res = ast_bridge_features_init(&chan_features);
if (res) {
ast_bridge_features_cleanup(&chan_features);
+ publish_parked_call_failure(chan);
return -1;
}
diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c
index f9295ccc3..8f563f7cf 100644
--- a/res/parking/parking_bridge_features.c
+++ b/res/parking/parking_bridge_features.c
@@ -49,6 +49,7 @@ struct parked_subscription_datastore {
};
struct parked_subscription_data {
+ struct transfer_channel_data *transfer_data;
char *parkee_uuid;
int hangup_after:1;
char parker_uuid[0];
@@ -89,7 +90,7 @@ static void parker_parked_call_message_response(struct ast_parked_call_payload *
const char *parkee_to_act_on = data->parkee_uuid;
char saynum_buf[16];
struct ast_channel_snapshot *parkee_snapshot = message->parkee;
- RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
@@ -113,22 +114,35 @@ static void parker_parked_call_message_response(struct ast_parked_call_payload *
return;
}
+ /* This subscription callback will block for the duration of the announcement if
+ * parked_subscription_data is tracking a transfer_channel_data struct. */
if (message->event_type == PARKED_CALL) {
/* queue the saynum on the bridge channel and hangup */
snprintf(saynum_buf, sizeof(saynum_buf), "%d %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);
- }
-
- if (message->event_type == PARKED_CALL_FAILED) {
- ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
- wipe_subscription_datastore(bridge_channel->chan);
+ if (!data->transfer_data) {
+ ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
+ } else {
+ ast_bridge_channel_queue_playfile_sync(bridge_channel, say_parking_space, saynum_buf, NULL);
+ data->transfer_data->completed = 1;
+ }
+ wipe_subscription_datastore(parker);
+ } else if (message->event_type == PARKED_CALL_FAILED) {
+ if (!data->transfer_data) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
+ } else {
+ ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
+ data->transfer_data->completed = 1;
+ }
+ wipe_subscription_datastore(parker);
}
}
static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
{
if (stasis_subscription_final_message(sub, message)) {
+ struct parked_subscription_data *ps_data = data;
+ ao2_cleanup(ps_data->transfer_data);
+ ps_data->transfer_data = NULL;
ast_free(data);
return;
}
@@ -139,7 +153,8 @@ static void parker_update_cb(void *data, struct stasis_subscription *sub, struct
}
}
-int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
+static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
+ struct transfer_channel_data *parked_channel_data)
{
struct ast_datastore *datastore;
struct parked_subscription_datastore *parked_datastore;
@@ -167,6 +182,11 @@ int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid
return -1;
}
+ if (parked_channel_data) {
+ subscription_data->transfer_data = parked_channel_data;
+ ao2_ref(parked_channel_data, +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);
@@ -185,13 +205,18 @@ int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid
return 0;
}
+int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
+{
+ return create_parked_subscription_full(chan, parkee_uuid, hangup_after, NULL);
+}
+
/*!
* \internal
* \brief Helper function that creates an outgoing channel and returns it immediately. This function is nearly
* identical to the dial_transfer function in bridge_basic.c, however it doesn't swap the
* local channel and the channel that instigated the park.
*/
-static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten)
+static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
{
char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
struct ast_channel *parkee;
@@ -220,7 +245,11 @@ 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), 1);
+ if (create_parked_subscription_full(parker, ast_channel_uniqueid(parkee_side_2), 1, parked_channel_data)) {
+ ast_channel_unref(parkee_side_2);
+ ast_hangup(parkee);
+ return NULL;
+ }
ast_bridge_set_transfer_variables(parkee_side_2, ast_channel_name(parker), 0);
@@ -272,14 +301,21 @@ static int parking_is_exten_park(const char *context, const char *exten)
* \param bridge_channel The bridge_channel representing the channel performing the park
* \param context The context to blind transfer to
* \param exten The extension to blind transfer to
+ * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge
+ * \param parked_channel_data Data for the parked_channel_cb
*
* \retval 0 on success
* \retval non-zero on error
*/
static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel,
- const char *context, const char *exten)
+ const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
+ struct transfer_channel_data *parked_channel_data)
{
RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup);
+
+ struct ast_exten *e;
+ struct pbx_find_info find_info = { .stacklen = 0 };
int peer_count;
if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
@@ -299,6 +335,8 @@ static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel
if (peer_count == 2) {
other = ast_bridge_channel_peer(bridge_channel);
ao2_ref(other, +1);
+ other_chan = other->chan;
+ ast_channel_ref(other_chan);
}
ast_bridge_unlock(bridge_channel->bridge);
@@ -313,34 +351,48 @@ static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel
if (peer_count > 2) {
struct ast_channel *transfer_chan = NULL;
- transfer_chan = park_local_transfer(bridge_channel->chan, context, exten);
+ transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data);
if (!transfer_chan) {
return -1;
}
+ ast_channel_ref(transfer_chan);
+
+ if (parked_channel_cb) {
+ parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
+ }
if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
ast_hangup(transfer_chan);
+ ast_channel_unref(transfer_chan);
return -1;
}
+
+ ast_channel_unref(transfer_chan);
+
return 0;
}
/* Subscribe to park messages with the other channel entering */
- if (create_parked_subscription(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1)) {
+ if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
return -1;
}
+ if (parked_channel_cb) {
+ parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
+ }
+
+ e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);
+
/* Write the park frame with the intended recipient and other data out to the bridge. */
ast_bridge_channel_write_park(bridge_channel,
- ast_channel_uniqueid(other->chan),
+ ast_channel_uniqueid(other_chan),
ast_channel_uniqueid(bridge_channel->chan),
- NULL);
+ e ? ast_get_extension_app_data(e) : NULL);
return 0;
}
-
/*!
* \internal
* \since 12.0.0
@@ -444,7 +496,7 @@ static int parking_park_call(struct ast_bridge_channel *parker, char *exten, siz
if (exten) {
ast_copy_string(exten, lot->cfg->parkext, length);
}
- return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext);
+ return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
}
static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index e6855ae47..20e3012b1 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -55,6 +55,8 @@ struct refer_progress {
struct ast_taskprocessor *serializer;
/*! \brief Stasis subscription for bridge events */
struct stasis_subscription *bridge_sub;
+ /*! \brief Reference to transfer_channel_data related to the refer */
+ struct transfer_channel_data *transfer_data;
/*! \brief Uniqueid of transferee channel */
char *transferee;
};
@@ -165,6 +167,12 @@ static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
return;
}
+ if (!progress->transfer_data->completed) {
+ /* We can't act on this message because the transfer_channel_data doesn't show that
+ * the transfer is ready to progress */
+ return;
+ }
+
/* OMG the transferee is joining a bridge. His call got answered! */
notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
if (notification) {
@@ -186,6 +194,11 @@ static struct ast_frame *refer_progress_framehook(struct ast_channel *chan, stru
return f;
}
+ /* If the completed flag hasn't been raised, skip this pass. */
+ if (!progress->transfer_data->completed) {
+ return f;
+ }
+
/* Determine the state of the REFER based on the control frames (or voice frames) passing */
if (f->frametype == AST_FRAME_VOICE && !progress->subclass) {
/* Media is passing without progress, this means the call has been answered */
@@ -240,6 +253,10 @@ static void refer_progress_framehook_destroy(void *data)
ao2_cleanup(notification);
}
+ if (progress->bridge_sub) {
+ progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
+ }
+
ao2_cleanup(progress);
}
@@ -296,6 +313,8 @@ static void refer_progress_destroy(void *obj)
progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
}
+ ao2_cleanup(progress->transfer_data);
+
ast_free(progress->transferee);
ast_taskprocessor_unreference(progress->serializer);
}
@@ -472,9 +491,10 @@ struct refer_blind {
};
/*! \brief Blind transfer callback function */
-static void refer_blind_callback(struct ast_channel *chan, void *user_data, enum ast_transfer_type transfer_type)
+static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
+ enum ast_transfer_type transfer_type)
{
- struct refer_blind *refer = user_data;
+ struct refer_blind *refer = user_data_wrapper->data;
pjsip_generic_string_hdr *referred_by;
static const pj_str_t str_referred_by = { "Referred-By", 11 };
@@ -503,6 +523,10 @@ static void refer_blind_callback(struct ast_channel *chan, void *user_data, enum
}
}
+ /* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
+ ao2_ref(user_data_wrapper, +1);
+ refer->progress->transfer_data = user_data_wrapper;
+
/* We need to bump the reference count up on the progress structure since it is in the frame hook now */
ao2_ref(refer->progress, +1);