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 */
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);
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);
}
}
+/*!
+ * \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);
+ }
+}
+
/*!
* \brief Helper method to place a channel in a bridge on hold
*/
{
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:
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);
{
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:
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;
* 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
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);
{
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:
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);
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;
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;
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;
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;
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;
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;