[asterisk-commits] mmichelson: branch mmichelson/more_transfer r387857 - /team/mmichelson/more_t...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue May 7 15:24:12 CDT 2013
Author: mmichelson
Date: Tue May 7 15:24:10 2013
New Revision: 387857
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=387857
Log:
Get the Bridge application working properly.
This took a bit of work to be able to pull off properly, but
the big change is that ast_bridge_call() has some code factored
out that the Bridge application also uses.
Modified:
team/mmichelson/more_transfer/main/features.c
Modified: team/mmichelson/more_transfer/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/more_transfer/main/features.c?view=diff&rev=387857&r1=387856&r2=387857
==============================================================================
--- team/mmichelson/more_transfer/main/features.c (original)
+++ team/mmichelson/more_transfer/main/features.c Tue May 7 15:24:10 2013
@@ -4606,24 +4606,10 @@
}
}
-/*!
- * \brief bridge the call and set CDR
- *
- * \param chan The bridge considers this channel the caller.
- * \param peer The bridge considers this channel the callee.
- * \param config Configuration for this bridge.
- *
- * Set start time, check for two channels,check if monitor on
- * check for feature activation, create new CDR
- * \retval res on success.
- * \retval -1 on failure to bridge.
- */
-int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config,
+ struct ast_bridge_features *chan_features, struct ast_bridge_features *peer_features)
{
int res;
- struct ast_bridge *bridge;
- struct ast_bridge_features chan_features;
- struct ast_bridge_features *peer_features;
/* BUGBUG these channel vars may need to be made dynamic so they update when transfers happen. */
pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
@@ -4656,7 +4642,6 @@
/* Answer if need be */
if (ast_channel_state(chan) != AST_STATE_UP) {
if (ast_raw_answer(chan, 1)) {
- bridge_failed_peer_goto(chan, peer);
return -1;
}
}
@@ -4685,10 +4670,69 @@
ast_channel_lock(peer);
res |= ast_bridge_features_ds_set(peer, &config->features_callee);
ast_channel_unlock(peer);
+
if (res) {
- bridge_failed_peer_goto(chan, peer);
return -1;
}
+
+ if (config->timelimit) {
+ struct ast_bridge_features_limits call_duration_limits_chan;
+ struct ast_bridge_features_limits call_duration_limits_peer;
+ int abandon_call = 0; /* TRUE if set limits fails so we can abandon the call. */
+
+ if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
+ ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
+
+ return -1;
+ }
+
+ if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
+ ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
+ ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+
+ return -1;
+ }
+
+ bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
+
+ if (ast_bridge_features_set_limits(chan_features, &call_duration_limits_chan, 0)) {
+ abandon_call = 1;
+ }
+ if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer, 0)) {
+ abandon_call = 1;
+ }
+
+ /* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
+ ast_bridge_features_limits_destroy(&call_duration_limits_chan);
+ ast_bridge_features_limits_destroy(&call_duration_limits_peer);
+
+ if (abandon_call) {
+ ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief bridge the call and set CDR
+ *
+ * \param chan The bridge considers this channel the caller.
+ * \param peer The bridge considers this channel the callee.
+ * \param config Configuration for this bridge.
+ *
+ * Set start time, check for two channels,check if monitor on
+ * check for feature activation, create new CDR
+ * \retval res on success.
+ * \retval -1 on failure to bridge.
+ */
+int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+{
+ int res;
+ struct ast_bridge *bridge;
+ struct ast_bridge_features chan_features;
+ struct ast_bridge_features *peer_features;
/* Setup features. */
res = ast_bridge_features_init(&chan_features);
@@ -4700,50 +4744,11 @@
return -1;
}
- if (config->timelimit) {
- struct ast_bridge_features_limits call_duration_limits_chan;
- struct ast_bridge_features_limits call_duration_limits_peer;
- int abandon_call = 0; /* TRUE if set limits fails so we can abandon the call. */
-
- if (ast_bridge_features_limits_construct(&call_duration_limits_chan)) {
- ast_log(LOG_ERROR, "Could not construct caller duration limits. Bridge canceled.\n");
-
- ast_bridge_features_destroy(peer_features);
- ast_bridge_features_cleanup(&chan_features);
- bridge_failed_peer_goto(chan, peer);
- return -1;
- }
-
- if (ast_bridge_features_limits_construct(&call_duration_limits_peer)) {
- ast_log(LOG_ERROR, "Could not construct callee duration limits. Bridge canceled.\n");
- ast_bridge_features_limits_destroy(&call_duration_limits_chan);
-
- ast_bridge_features_destroy(peer_features);
- ast_bridge_features_cleanup(&chan_features);
- bridge_failed_peer_goto(chan, peer);
- return -1;
- }
-
- bridge_config_set_limits(config, &call_duration_limits_chan, &call_duration_limits_peer);
-
- if (ast_bridge_features_set_limits(&chan_features, &call_duration_limits_chan, 0)) {
- abandon_call = 1;
- }
- if (ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer, 0)) {
- abandon_call = 1;
- }
-
- /* At this point we are done with the limits structs since they have been copied to the individual feature sets. */
- ast_bridge_features_limits_destroy(&call_duration_limits_chan);
- ast_bridge_features_limits_destroy(&call_duration_limits_peer);
-
- if (abandon_call) {
- ast_log(LOG_ERROR, "Could not set duration limits on one or more sides of the call. Bridge canceled.\n");
- ast_bridge_features_destroy(peer_features);
- ast_bridge_features_cleanup(&chan_features);
- bridge_failed_peer_goto(chan, peer);
- return -1;
- }
+ if (pre_bridge_setup(chan, peer, config, &chan_features, peer_features)) {
+ ast_bridge_features_destroy(peer_features);
+ ast_bridge_features_cleanup(&chan_features);
+ bridge_failed_peer_goto(chan, peer);
+ return -1;
}
/* Create bridge */
@@ -7132,48 +7137,8 @@
return CLI_SUCCESS;
}
-/*!
- * \brief Actual bridge
- * \param chan
- * \param tmpchan
- *
- * Stop hold music, lock both channels, masq channels,
- * after bridge return channel to next priority.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
-{
- const char *context;
- const char *exten;
- int priority;
-
- ast_moh_stop(chan);
- ast_channel_lock_both(chan, tmpchan);
- context = ast_strdupa(ast_channel_context(chan));
- exten = ast_strdupa(ast_channel_exten(chan));
- priority = ast_channel_priority(chan);
- ast_setstate(tmpchan, ast_channel_state(chan));
- ast_format_copy(ast_channel_readformat(tmpchan), ast_channel_readformat(chan));
- ast_format_copy(ast_channel_writeformat(tmpchan), ast_channel_writeformat(chan));
- ast_channel_unlock(chan);
- ast_channel_unlock(tmpchan);
-
- /* Masquerade setup and execution must be done without any channel locks held */
- if (ast_channel_masquerade(tmpchan, chan)) {
- return -1;
- }
- ast_do_masquerade(tmpchan);
-
- /* when returning from bridge, the channel will continue at the next priority */
- ast_explicit_goto(tmpchan, context, exten, priority + 1);
-
- return 0;
-}
-
static int add_to_bridge(struct ast_bridge *bridge, struct ast_channel *chan,
- char buf[], size_t size, int play_tone)
+ struct ast_bridge_features *features, int play_tone)
{
RAII_VAR(struct ast_bridge *, chan_bridge, NULL, ao2_cleanup);
struct ast_channel *bridge_chan;
@@ -7185,6 +7150,13 @@
if (chan_bridge) {
/* XXX Is there a way to play the tone to chan before moving it? A
* bridge action on the channel's bridge_channel perhaps?
+ */
+ /* XXX ast_bridge_move() does not take an ast_bridge_features
+ * parameter. I could presumably get the channel's bridge_channel
+ * and substitute the features directly onto the bridge_channel.
+ * However, because of inconsistencies with allocation of features,
+ * I can't know whether I need to free the old bridge features or
+ * if attempting to free the bridge features will cause a crash.
*/
return ast_bridge_move(bridge, chan_bridge, chan, NULL, 1);
}
@@ -7194,7 +7166,7 @@
*/
bridge_chan = ast_channel_yank(chan);
if (!bridge_chan) {
- snprintf(buf, size, "Could not gain control of channel %s\n", ast_channel_name(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) {
@@ -7207,8 +7179,8 @@
ast_channel_name(bridge_chan));
}
}
- if (ast_bridge_impart(bridge, bridge_chan, NULL, NULL, 1)) {
- snprintf(buf, size, "Could not add %s to the bridge\n", ast_channel_name(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;
}
return 0;
@@ -7264,12 +7236,14 @@
return 0;
}
- if (add_to_bridge(bridge, chana, buf, sizeof(buf), ast_true(playtone))) {
+ if (add_to_bridge(bridge, chana, NULL, ast_true(playtone))) {
+ snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", channela);
astman_send_error(s, m, buf);
return 0;
}
- if (add_to_bridge(bridge, chanb, buf, sizeof(buf), ast_true(playtone))) {
+ if (add_to_bridge(bridge, chanb, NULL, ast_true(playtone))) {
+ snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", channelb);
astman_send_error(s, m, buf);
return 0;
}
@@ -7995,8 +7969,7 @@
*/
static int bridge_exec(struct ast_channel *chan, const char *data)
{
- struct ast_channel *current_dest_chan;
- struct ast_channel *final_dest_chan;
+ RAII_VAR(struct ast_channel *, current_dest_chan, NULL, ao2_cleanup);
struct ast_channel *chans[2];
char *tmp_data = NULL;
struct ast_flags opts = { 0, };
@@ -8006,6 +7979,9 @@
const char *context;
const char *extension;
int priority;
+ struct ast_bridge_features chan_features;
+ struct ast_bridge_features *peer_features;
+ struct ast_bridge *bridge;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(dest_chan);
@@ -8057,20 +8033,6 @@
return 0;
}
- /* try to allocate a place holder where current_dest_chan will be placed */
- if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
- NULL, NULL, ast_channel_linkedid(current_dest_chan), 0, "Bridge/%s", ast_channel_name(current_dest_chan)))) {
- ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
- ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
- "Response: Failed\r\n"
- "Reason: Cannot create placeholder channel\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
- pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
- ast_channel_unref(current_dest_chan);
- return 0;
- }
-
if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
&& !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
&& ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
@@ -8079,48 +8041,13 @@
"Reason: Cannot setup bridge time limit\r\n"
"Channel1: %s\r\n"
"Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
- ast_hangup(final_dest_chan);
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
current_dest_chan = ast_channel_unref(current_dest_chan);
goto done;
}
- if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
- ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
- "Response: Failed\r\n"
- "Reason: Cannot masquerade channels\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", ast_channel_name(chan), args.dest_chan);
- ast_hangup(final_dest_chan);
- pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
- current_dest_chan = ast_channel_unref(current_dest_chan);
- goto done;
- }
-
- /* answer the channel if needed */
- if (ast_channel_state(final_dest_chan) != AST_STATE_UP) {
- ast_answer(final_dest_chan);
- }
-
- chans[0] = current_dest_chan;
- chans[1] = final_dest_chan;
-
- /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
- /* try to make compatible, send error if we fail */
- if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
- ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
- ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
- "Response: Failed\r\n"
- "Reason: Could not make channels compatible for bridge\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
-
- bridge_failed_peer_goto(chan, final_dest_chan);
-
- pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
- current_dest_chan = ast_channel_unref(current_dest_chan);
- goto done;
- }
+ chans[0] = chan;
+ chans[1] = current_dest_chan;
/* Report that the bridge will be successfull */
/*** DOCUMENTATION
@@ -8134,17 +8061,7 @@
ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
"Response: Success\r\n"
"Channel1: %s\r\n"
- "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
-
- current_dest_chan = ast_channel_unref(current_dest_chan);
-
- /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */
- if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
- if (!ast_streamfile(final_dest_chan, xfersound, ast_channel_language(final_dest_chan))) {
- if (ast_waitstream(final_dest_chan, "") < 0)
- ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", ast_channel_name(final_dest_chan));
- }
- }
+ "Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(current_dest_chan));
if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
@@ -8170,18 +8087,40 @@
extension = ast_strdupa(ast_channel_exten(chan));
priority = ast_channel_priority(chan);
ast_channel_unlock(chan);
- ast_after_bridge_set_go_on(final_dest_chan, context, extension, priority,
+ ast_after_bridge_set_go_on(current_dest_chan, context, extension, priority,
opt_args[OPT_ARG_CALLEE_GO_ON]);
} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
- ast_channel_lock(final_dest_chan);
- context = ast_strdupa(ast_channel_context(final_dest_chan));
- extension = ast_strdupa(ast_channel_exten(final_dest_chan));
- priority = ast_channel_priority(final_dest_chan);
- ast_channel_unlock(final_dest_chan);
- ast_after_bridge_set_goto(final_dest_chan, context, extension, priority);
- }
-
- ast_bridge_call(chan, final_dest_chan, &bconfig);
+ ast_channel_lock(current_dest_chan);
+ context = ast_strdupa(ast_channel_context(current_dest_chan));
+ extension = ast_strdupa(ast_channel_exten(current_dest_chan));
+ priority = ast_channel_priority(current_dest_chan);
+ ast_channel_unlock(current_dest_chan);
+ ast_after_bridge_set_goto(current_dest_chan, context, extension, priority);
+ }
+
+ if (ast_bridge_features_init(&chan_features)) {
+ goto done;
+ }
+
+ peer_features = ast_bridge_features_new();
+ if (!peer_features) {
+ ast_bridge_features_cleanup(&chan_features);
+ goto done;
+ }
+
+ if (pre_bridge_setup(chan, current_dest_chan, &bconfig, &chan_features, peer_features)) {
+ ast_bridge_features_destroy(peer_features);
+ ast_bridge_features_cleanup(&chan_features);
+ goto done;
+ }
+
+ bridge = ast_bridge_basic_new();
+
+ add_to_bridge(bridge, current_dest_chan, peer_features, ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE));
+
+ ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 1);
+
+ ast_bridge_features_cleanup(&chan_features);
/* The bridge has ended, set BRIDGERESULT to SUCCESS. */
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
More information about the asterisk-commits
mailing list