[Asterisk-code-review] bridge basic: don't cache xferfailsound during an attended t... (asterisk[certified/13.1])

Joshua Colp asteriskteam at digium.com
Sat Jan 16 08:29:11 CST 2016


Joshua Colp has submitted this change and it was merged.

Change subject: bridge_basic: don't cache xferfailsound during an attended transfer
......................................................................


bridge_basic: don't cache xferfailsound during an attended transfer

The xferfailsound was read from the channel at the beginning of the transfer,
and that value is "cached" for the duration of the transfer. Therefore, changing
the xferfailsound on the channel using the FEATURE() dialplan function does
nothing once the transfer is under way.

This makes it so the transfer code instead gets the xferfailsound configuration
options from the channel when it is actually going to be used.

This patch also fixes a potential memory leak of the props object as well as
making sure the condition variable gets initialized before being destroyed.

ASTERISK-25696 #close

Change-Id: Ic726b0f54ef588bd9c9c67f4b0e4d787934f85e4
---
M include/asterisk/features_config.h
M main/bridge_basic.c
M main/features_config.c
3 files changed, 92 insertions(+), 18 deletions(-)

Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  Anonymous Coward #1000019: Verified
  Joshua Colp: Looks good to me, approved



diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h
index b15759b..baaff18 100644
--- a/include/asterisk/features_config.h
+++ b/include/asterisk/features_config.h
@@ -102,6 +102,21 @@
 struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan);
 
 /*!
+ * \brief Get the transfer configuration option xferfailsound
+ *
+ * \note The channel should be locked before calling this function.
+ * \note The returned value has to be freed.
+ *
+ * If no channel is provided, then option is pulled from the global
+ * transfer configuration.
+ *
+ * \param chan The channel to get configuration options for
+ * \retval NULL Failed to get configuration
+ * \retval non-NULL The xferfailsound
+ */
+char *ast_get_chan_features_xferfailsound(struct ast_channel *chan);
+
+/*!
  * \brief Configuration relating to call pickup
  */
 struct ast_features_pickup_config {
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index 3bbd173..6b40901 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -1296,8 +1296,6 @@
 		AST_STRING_FIELD(exten);
 		/*! Context of transfer target */
 		AST_STRING_FIELD(context);
-		/*! Sound to play on failure */
-		AST_STRING_FIELD(failsound);
 		/*! Sound to play when transfer completes */
 		AST_STRING_FIELD(xfersound);
 		/*! The channel technology of the transferer channel */
@@ -1421,11 +1419,20 @@
 	struct ast_flags *transferer_features;
 
 	props = ao2_alloc(sizeof(*props), attended_transfer_properties_destructor);
-	if (!props || ast_string_field_init(props, 64)) {
+	if (!props) {
+		ast_log(LOG_ERROR, "Unable to create props - channel %s, context %s\n",
+			ast_channel_name(transferer), context);
 		return NULL;
 	}
 
 	ast_cond_init(&props->cond, NULL);
+
+	if (ast_string_field_init(props, 64)) {
+		ast_log(LOG_ERROR, "Unable to initialize prop fields - channel %s, context %s\n",
+			ast_channel_name(transferer), context);
+		ao2_ref(props, -1);
+		return NULL;
+	}
 
 	props->target_framehook_id = -1;
 	props->transferer = ast_channel_ref(transferer);
@@ -1447,7 +1454,6 @@
 	props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout;
 	props->atxferloopdelay = xfer_cfg->atxferloopdelay;
 	ast_string_field_set(props, context, get_transfer_context(transferer, context));
-	ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
 	ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
 	ao2_ref(xfer_cfg, -1);
 
@@ -1704,6 +1710,44 @@
 	if (bridge_channel) {
 		ast_bridge_channel_queue_playfile(bridge_channel, NULL, sound, NULL);
 		ao2_ref(bridge_channel, -1);
+	}
+}
+
+/*!
+ * \brief Helper method to play a fail sound on a channel in a bridge
+ *
+ * \param chan The channel to play the fail sound to
+ */
+static void play_failsound(struct ast_channel *chan)
+{
+	char *sound;
+
+	ast_channel_lock(chan);
+	sound = ast_get_chan_features_xferfailsound(chan);
+	ast_channel_unlock(chan);
+
+	if (sound) {
+		play_sound(chan, sound);
+		ast_free(sound);
+	}
+}
+
+/*!
+ * \brief Helper method to stream a fail sound on a channel
+ *
+ * \param chan The channel to stream the fail sound to
+ */
+static void stream_failsound(struct ast_channel *chan)
+{
+	char *sound;
+
+	ast_channel_lock(chan);
+	sound = ast_get_chan_features_xferfailsound(chan);
+	ast_channel_unlock(chan);
+
+	if (sound) {
+		ast_stream_and_wait(chan, sound, AST_DIGIT_NONE);
+		ast_free(sound);
 	}
 }
 
@@ -2049,7 +2093,7 @@
 {
 	switch (stimulus) {
 	case STIMULUS_TRANSFEREE_HANGUP:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		publish_transfer_fail(props);
 		return TRANSFER_FAIL;
 	case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -2061,7 +2105,7 @@
 	case STIMULUS_TRANSFER_TARGET_HANGUP:
 	case STIMULUS_TIMEOUT:
 	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		return TRANSFER_REBRIDGE;
 	case STIMULUS_DTMF_ATXFER_THREEWAY:
 		bridge_unhold(props->transferee_bridge);
@@ -2090,7 +2134,7 @@
 {
 	switch (stimulus) {
 	case STIMULUS_TRANSFEREE_HANGUP:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		publish_transfer_fail(props);
 		return TRANSFER_FAIL;
 	case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -2101,7 +2145,7 @@
 	case STIMULUS_TRANSFER_TARGET_HANGUP:
 	case STIMULUS_TIMEOUT:
 	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		return TRANSFER_RESUME;
 	case STIMULUS_DTMF_ATXFER_THREEWAY:
 		return TRANSFER_THREEWAY;
@@ -2163,7 +2207,7 @@
 		 * a sound to the transferer to indicate the transferee is gone.
 		 */
 		bridge_basic_change_personality(props->target_bridge, BRIDGE_BASIC_PERSONALITY_NORMAL, NULL);
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		ast_bridge_merge_inhibit(props->target_bridge, -1);
 		/* These next two lines are here to ensure that our reference to the target bridge
 		 * is cleaned up properly and that the target bridge is not destroyed when the
@@ -2179,7 +2223,7 @@
 		return TRANSFER_COMPLETE;
 	case STIMULUS_TRANSFER_TARGET_HANGUP:
 	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		return TRANSFER_REBRIDGE;
 	case STIMULUS_DTMF_ATXFER_THREEWAY:
 		bridge_unhold(props->transferee_bridge);
@@ -2211,7 +2255,7 @@
 {
 	switch (stimulus) {
 	case STIMULUS_TRANSFEREE_HANGUP:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		publish_transfer_fail(props);
 		return TRANSFER_FAIL;
 	case STIMULUS_TRANSFERER_HANGUP:
@@ -2221,7 +2265,7 @@
 		return TRANSFER_COMPLETE;
 	case STIMULUS_TRANSFER_TARGET_HANGUP:
 	case STIMULUS_DTMF_ATXFER_ABORT:
-		play_sound(props->transferer, props->failsound);
+		play_failsound(props->transferer);
 		return TRANSFER_RESUME;
 	case STIMULUS_DTMF_ATXFER_THREEWAY:
 		bridge_unhold(props->target_bridge);
@@ -3297,7 +3341,7 @@
 	props->transfer_target = dial_transfer(bridge_channel->chan, destination);
 	if (!props->transfer_target) {
 		ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n");
-		ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+		stream_failsound(props->transferer);
 		ast_bridge_channel_write_unhold(bridge_channel);
 		attended_transfer_properties_shutdown(props);
 		return 0;
@@ -3308,7 +3352,7 @@
 	props->target_bridge = ast_bridge_basic_new();
 	if (!props->target_bridge) {
 		ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n");
-		ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+		stream_failsound(props->transferer);
 		ast_bridge_channel_write_unhold(bridge_channel);
 		ast_hangup(props->transfer_target);
 		props->transfer_target = NULL;
@@ -3319,7 +3363,7 @@
 
 	if (attach_framehook(props, props->transfer_target)) {
 		ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n");
-		ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+		stream_failsound(props->transferer);
 		ast_bridge_channel_write_unhold(bridge_channel);
 		ast_hangup(props->transfer_target);
 		props->transfer_target = NULL;
@@ -3334,7 +3378,7 @@
 
 	if (ast_call(props->transfer_target, destination, 0)) {
 		ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n");
-		ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+		stream_failsound(props->transferer);
 		ast_bridge_channel_write_unhold(bridge_channel);
 		ast_hangup(props->transfer_target);
 		props->transfer_target = NULL;
@@ -3350,7 +3394,7 @@
 	if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL,
 		AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
 		ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n");
-		ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+		stream_failsound(props->transferer);
 		ast_bridge_channel_write_unhold(bridge_channel);
 		ast_hangup(props->transfer_target);
 		props->transfer_target = NULL;
@@ -3360,7 +3404,7 @@
 
 	if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) {
 		ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n");
-		ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+		stream_failsound(props->transferer);
 		ast_bridge_channel_write_unhold(bridge_channel);
 		attended_transfer_properties_shutdown(props);
 		return 0;
diff --git a/main/features_config.c b/main/features_config.c
index 9fed53b..9126a86 100644
--- a/main/features_config.c
+++ b/main/features_config.c
@@ -1158,6 +1158,21 @@
 	return cfg->global->xfer;
 }
 
+char *ast_get_chan_features_xferfailsound(struct ast_channel *chan)
+{
+	char *res;
+	struct ast_features_xfer_config *cfg = ast_get_chan_features_xfer_config(chan);
+
+	if (!cfg) {
+		return NULL;
+	}
+
+	res = ast_strdup(cfg->xferfailsound);
+	ao2_ref(cfg, -1);
+
+	return res;
+}
+
 struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan)
 {
 	RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);

-- 
To view, visit https://gerrit.asterisk.org/2016
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic726b0f54ef588bd9c9c67f4b0e4d787934f85e4
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: certified/13.1
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>



More information about the asterisk-code-review mailing list