[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r381193 - in /team/rmudgett/bridge_pha...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Feb 11 12:49:40 CST 2013
Author: rmudgett
Date: Mon Feb 11 12:49:36 2013
New Revision: 381193
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381193
Log:
Initial changes to make ast_bridge_call callers not expect peer back.
* Remoevd CDR related code from ast_bridge_call() and associated defines
as a result of ast_bridge_call() doing all this CDR work.
(AST_FLAG_BRIDGE_HANGUP_DONT, AST_FEATURE_NO_H_EXTEN)
* Added new parameters to ast_bridge_join(). join_on_empty and
pass_reference
* Convert bridge_call_thread_launch() to use ast_pthread_create_detached()
instead of inlining it. This also fixes a missing pthread_attr_destroy()
if the thread creation failed. Also changed the thread scheduling to be
the same as other threads instead of SCHED_RR.
* Tweaked set_bridge_features_on_config() to eliminate this_feature.
Modified:
team/rmudgett/bridge_phase/apps/app_channelredirect.c
team/rmudgett/bridge_phase/apps/app_confbridge.c
team/rmudgett/bridge_phase/apps/app_dial.c
team/rmudgett/bridge_phase/apps/app_followme.c
team/rmudgett/bridge_phase/apps/app_queue.c
team/rmudgett/bridge_phase/bridges/bridge_builtin_features.c
team/rmudgett/bridge_phase/include/asterisk/bridging.h
team/rmudgett/bridge_phase/include/asterisk/bridging_features.h
team/rmudgett/bridge_phase/include/asterisk/channel.h
team/rmudgett/bridge_phase/main/bridging.c
team/rmudgett/bridge_phase/main/channel_internal_api.c
team/rmudgett/bridge_phase/main/features.c
team/rmudgett/bridge_phase/main/manager.c
Modified: team/rmudgett/bridge_phase/apps/app_channelredirect.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_channelredirect.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_channelredirect.c (original)
+++ team/rmudgett/bridge_phase/apps/app_channelredirect.c Mon Feb 11 12:49:36 2013
@@ -96,10 +96,6 @@
return 0;
}
- if (ast_channel_pbx(chan2)) {
- ast_set_flag(ast_channel_flags(chan2), AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
- }
-
res = ast_async_parseable_goto(chan2, args.label);
chan2 = ast_channel_unref(chan2);
Modified: team/rmudgett/bridge_phase/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_confbridge.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_confbridge.c (original)
+++ team/rmudgett/bridge_phase/apps/app_confbridge.c Mon Feb 11 12:49:36 2013
@@ -447,7 +447,7 @@
chan = ast_channel_ref(conference_bridge->record_chan);
ast_answer(chan);
pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
- ast_bridge_join(conference_bridge->bridge, chan, NULL, NULL, NULL);
+ ast_bridge_join(conference_bridge->bridge, chan, NULL, NULL, NULL, 1, 0);
ast_hangup(chan); /* This will eat this thread's reference to the channel as well */
/* STOP has been called. Wait for either a START or an EXIT */
@@ -1659,7 +1659,9 @@
chan,
NULL,
&conference_bridge_user.features,
- &conference_bridge_user.tech_args);
+ &conference_bridge_user.tech_args,
+ 1,
+ 0);
send_leave_event(conference_bridge_user.chan, conference_bridge->name);
/* if we're shutting down, don't attempt to do further processing */
Modified: team/rmudgett/bridge_phase/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_dial.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_dial.c (original)
+++ team/rmudgett/bridge_phase/apps/app_dial.c Mon Feb 11 12:49:36 2013
@@ -3011,8 +3011,6 @@
ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
- if (ast_test_flag64(peerflags, OPT_GO_ON))
- ast_set_flag(&(config.features_caller), AST_FEATURE_NO_H_EXTEN);
config.end_bridge_callback = end_bridge_callback;
config.end_bridge_callback_data = chan;
Modified: team/rmudgett/bridge_phase/apps/app_followme.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_followme.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_followme.c (original)
+++ team/rmudgett/bridge_phase/apps/app_followme.c Mon Feb 11 12:49:36 2013
@@ -1520,7 +1520,6 @@
}
res = ast_bridge_call(caller, outbound, &config);
- ast_autoservice_chan_hangup_peer(caller, outbound);
}
outrun:
Modified: team/rmudgett/bridge_phase/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_queue.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_queue.c (original)
+++ team/rmudgett/bridge_phase/apps/app_queue.c Mon Feb 11 12:49:36 2013
@@ -5209,9 +5209,6 @@
if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
}
- if (ast_test_flag(&opts, OPT_GO_ON)) {
- ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
- }
if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
nondataquality = 0;
}
Modified: team/rmudgett/bridge_phase/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/bridges/bridge_builtin_features.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/bridges/bridge_builtin_features.c (original)
+++ team/rmudgett/bridge_phase/bridges/bridge_builtin_features.c Mon Feb 11 12:49:36 2013
@@ -246,7 +246,7 @@
/* BUGBUG we need to wait for Party C (peer) to answer before dumping into the transient B-C bridge. */
/* Create a bridge to use to talk to the person we are calling */
- attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE,
+ attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX,
AST_BRIDGE_FLAG_DISSOLVE_HANGUP);
if (!attended_bridge) {
ast_hangup(peer);
@@ -279,7 +279,7 @@
attended_threeway_transfer, NULL, NULL);
/* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
- attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL);
+ attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL, 0, 0);
/* Wait for peer thread to exit bridge and die. */
if (!ast_autoservice_start(bridge_channel->chan)) {
Modified: team/rmudgett/bridge_phase/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging.h?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging.h Mon Feb 11 12:49:36 2013
@@ -67,12 +67,12 @@
/*! \brief Capabilities for a bridge technology */
enum ast_bridge_capability {
+ /*! Bridge should natively bridge two channels if possible */
+ AST_BRIDGE_CAPABILITY_NATIVE = (1 << 1),
/*! Bridge is only capable of mixing 2 channels */
- AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 1),
+ AST_BRIDGE_CAPABILITY_1TO1MIX = (1 << 2),
/*! Bridge is capable of mixing 2 or more channels */
- AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 2),
- /*! Bridge should natively bridge two channels if possible */
- AST_BRIDGE_CAPABILITY_NATIVE = (1 << 3),
+ AST_BRIDGE_CAPABILITY_MULTIMIX = (1 << 3),
/*! Bridge should run using the multithreaded model */
AST_BRIDGE_CAPABILITY_MULTITHREADED = (1 << 4),
/*! Bridge should run a central bridge thread */
@@ -87,7 +87,7 @@
enum ast_bridge_channel_state {
/*! Waiting for a signal (Channel in the bridge) */
AST_BRIDGE_CHANNEL_STATE_WAIT = 0,
- /*! Bridged channel has ended itself (it has hung up) */
+ /*! Bridged channel was forced out and should be hung up (Bridge may dissolve.) */
AST_BRIDGE_CHANNEL_STATE_END,
/*! Bridged channel was forced out and should be hung up */
AST_BRIDGE_CHANNEL_STATE_HANGUP,
@@ -352,13 +352,15 @@
* \param swap Channel to swap out if swapping
* \param features Bridge features structure
* \param tech_args Optional Bridging tech optimization parameters for this channel.
+ * \param join_on_empty TRUE to join the bridge even if the bridge is empty.
+ * \param pass_reference TRUE if the bridge reference is being passed by the caller.
*
* \retval state that channel exited the bridge with
*
* Example usage:
*
* \code
- * ast_bridge_join(bridge, chan, NULL, NULL);
+ * ast_bridge_join(bridge, chan, NULL, NULL, NULL, 0, 0);
* \endcode
*
* This adds a channel pointed to by the chan pointer to the bridge pointed to by
@@ -376,7 +378,9 @@
struct ast_channel *chan,
struct ast_channel *swap,
struct ast_bridge_features *features,
- struct ast_bridge_tech_optimizations *tech_args);
+ struct ast_bridge_tech_optimizations *tech_args,
+ int join_on_empty,
+ int pass_reference);
/*!
* \brief Impart (non-blocking) a channel onto a bridge
Modified: team/rmudgett/bridge_phase/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging_features.h?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging_features.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging_features.h Mon Feb 11 12:49:36 2013
@@ -30,12 +30,12 @@
/*! \brief Flags used for bridge features */
enum ast_bridge_feature_flags {
- /*! Upon channel hangup the bridge should be ended. */
+ /*! Upon channel hangup all bridge participants should be kicked out. */
AST_BRIDGE_FLAG_DISSOLVE_HANGUP = (1 << 0),
/*! Move between bridging technologies as needed. */
AST_BRIDGE_FLAG_SMART = (1 << 1),
- /*! The bridge ends when the last channel leaves. (There is no external bridge manager.) */
- AST_BRIDGE_FLAG_DISSOLVE_EMPTY = (1 << 2),
+ /*! This channel leaves the bridge if the only other participants have this flag set. */
+ AST_BRIDGE_FLAG_LONELY = (1 << 2),
};
/*! \brief Built in DTMF features */
Modified: team/rmudgett/bridge_phase/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/channel.h?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/channel.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/channel.h Mon Feb 11 12:49:36 2013
@@ -895,10 +895,6 @@
* a message aimed at preventing a subsequent hangup exten being run at the pbx_run
* level */
AST_FLAG_BRIDGE_HANGUP_RUN = (1 << 17),
- /*! This flag indicates that the hangup exten should NOT be run when the
- * bridge terminates, this will allow the hangup in the pbx loop to be run instead.
- * */
- AST_FLAG_BRIDGE_HANGUP_DONT = (1 << 18),
/*! Disable certain workarounds. This reintroduces certain bugs, but allows
* some non-traditional dialplans (like AGI) to continue to function.
*/
@@ -927,7 +923,6 @@
AST_FEATURE_AUTOMON = (1 << 4),
AST_FEATURE_PARKCALL = (1 << 5),
AST_FEATURE_AUTOMIXMON = (1 << 6),
- AST_FEATURE_NO_H_EXTEN = (1 << 7),
AST_FEATURE_WARNING_ACTIVE = (1 << 8),
};
Modified: team/rmudgett/bridge_phase/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/bridging.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/main/bridging.c (original)
+++ team/rmudgett/bridge_phase/main/bridging.c Mon Feb 11 12:49:36 2013
@@ -746,12 +746,12 @@
ao2_lock(bridge);
if (bridge->callid) {
-/* BUGBUG the bridge callid needs to be verified. */
+/* BUGBUG the bridge callid needs to be verified. Move to the bridge destructor. */
bridge->callid = ast_callid_unref(bridge->callid);
}
if (bridge->thread != AST_PTHREADT_NULL) {
-/* BUGBUG this needs to be moved to the last bridge_channel removal code if the bridge flag AST_BRIDGE_FLAG_DISSOLVE_EMPTY. */
+/* BUGBUG this needs to be moved to the bridge ao2 destructor. */
bridge_stop(bridge);
}
@@ -1507,12 +1507,17 @@
struct ast_channel *chan,
struct ast_channel *swap,
struct ast_bridge_features *features,
- struct ast_bridge_tech_optimizations *tech_args)
+ struct ast_bridge_tech_optimizations *tech_args,
+ int join_on_empty,
+ int pass_reference)
{
struct ast_bridge_channel *bridge_channel;
enum ast_bridge_channel_state state;
bridge_channel = bridge_channel_alloc(bridge);
+ if (pass_reference) {
+ ao2_ref(bridge, -1);
+ }
if (!bridge_channel) {
return AST_BRIDGE_CHANNEL_STATE_HANGUP;
}
@@ -1525,6 +1530,7 @@
bridge_channel->swap = swap;
bridge_channel->features = features;
+/* BUGBUG need to deal with join_on_empty */
bridge_channel_join(bridge_channel);
state = bridge_channel->state;
Modified: team/rmudgett/bridge_phase/main/channel_internal_api.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/channel_internal_api.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/main/channel_internal_api.c (original)
+++ team/rmudgett/bridge_phase/main/channel_internal_api.c Mon Feb 11 12:49:36 2013
@@ -263,7 +263,6 @@
ast_data_add_bool(tree, "END_DTMF_ONLY", ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY));
ast_data_add_bool(tree, "MASQ_NOSTREAM", ast_test_flag(ast_channel_flags(chan), AST_FLAG_MASQ_NOSTREAM));
ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN));
- ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT));
ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS));
ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE));
}
Modified: team/rmudgett/bridge_phase/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/features.c?view=diff&rev=381193&r1=381192&r2=381193
==============================================================================
--- team/rmudgett/bridge_phase/main/features.c (original)
+++ team/rmudgett/bridge_phase/main/features.c Mon Feb 11 12:49:36 2013
@@ -1142,65 +1142,42 @@
ast_channel_data_set(tobj->peer, "(Empty)");
}
- ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
-
- if (tobj->return_to_pbx) {
- if (!ast_check_hangup(tobj->peer)) {
- ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", ast_channel_name(tobj->peer));
- if (ast_pbx_start(tobj->peer)) {
- ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", ast_channel_name(tobj->peer));
- ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
- }
- } else {
- ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
- }
- if (!ast_check_hangup(tobj->chan)) {
- ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan));
- if (ast_pbx_start(tobj->chan)) {
- ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan));
- ast_hangup(tobj->chan);
- }
- } else {
+/* BUGBUG If tobj->return_to_pbx need to setup datastore where peer is going to execute on bridge completion. */
+ ast_bridge_call(tobj->chan, tobj->peer, &tobj->bconfig);
+
+ if (tobj->return_to_pbx && !ast_check_hangup(tobj->chan)) {
+ ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan));
+ if (ast_pbx_run(tobj->chan)) {
+ ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan));
ast_hangup(tobj->chan);
}
} else {
ast_hangup(tobj->chan);
+ }
+
+ ast_free(tobj);
+
+ return NULL;
+}
+
+/*!
+ * \brief create thread for the bridging call
+ * \param tobj
+ */
+static void bridge_call_thread_launch(struct ast_bridge_thread_obj *tobj)
+{
+ pthread_t thread;
+
+ /* This needs to be unreffed once it has been associated with the new thread. */
+ tobj->callid = ast_read_threadstorage_callid();
+
+ if (ast_pthread_create_detached(&thread, NULL, bridge_call_thread, tobj)) {
+ ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
+ ast_callid_unref(tobj->callid);
+ ast_hangup(tobj->chan);
ast_hangup(tobj->peer);
- }
-
- ast_free(tobj);
-
- return NULL;
-}
-
-/*!
- * \brief create thread for the parked call
- * \param data
- *
- * Create thread and attributes, call bridge_call_thread
- */
-static void bridge_call_thread_launch(struct ast_bridge_thread_obj *data)
-{
- pthread_t thread;
- pthread_attr_t attr;
- struct sched_param sched;
-
- /* This needs to be unreffed once it has been associated with the new thread. */
- data->callid = ast_read_threadstorage_callid();
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) {
- /* Failed to create thread. Ditch the reference to callid. */
- ast_callid_unref(data->callid);
- ast_hangup(data->chan);
- ast_hangup(data->peer);
- ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
- return;
- }
- pthread_attr_destroy(&attr);
- memset(&sched, 0, sizeof(sched));
- pthread_setschedparam(thread, SCHED_RR, &sched);
+ ast_free(tobj);
+ }
}
/*!
@@ -2591,11 +2568,6 @@
if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
ast_log(LOG_WARNING, "Async goto failed :-(\n");
res = -1;
- } else if (res == AST_FEATURE_RETURN_SUCCESSBREAK) {
- /* Don't let the after-bridge code run the h-exten */
- ast_channel_lock(transferee);
- ast_set_flag(ast_channel_flags(transferee), AST_FLAG_BRIDGE_HANGUP_DONT);
- ast_channel_unlock(transferee);
}
check_goto_on_transfer(transferer);
return res;
@@ -2782,8 +2754,6 @@
ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate);
if (!ast_check_hangup(transferer)) {
- int hangup_dont = 0;
-
/* Transferer (party B) is up */
ast_debug(1, "Actually doing an attended transfer.\n");
@@ -2823,30 +2793,10 @@
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
/*
- * ast_bridge_call clears AST_FLAG_BRIDGE_HANGUP_DONT, but we
- * don't want that to happen here because the transferer is in
- * another bridge already.
- */
- if (ast_test_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT)) {
- hangup_dont = 1;
- }
-
- /*
- * Don't let the after-bridge code run the h-exten. It is the
- * wrong bridge to run the h-exten after.
- */
- ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT);
-
- /*
* Let party B and C talk as long as they want while party A
* languishes in autoservice listening to MOH.
*/
ast_bridge_call(transferer, newchan, &bconfig);
-
- if (hangup_dont) {
- /* Restore the AST_FLAG_BRIDGE_HANGUP_DONT flag */
- ast_set_flag(ast_channel_flags(transferer), AST_FLAG_BRIDGE_HANGUP_DONT);
- }
if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
ast_autoservice_chan_hangup_peer(transferer, newchan);
@@ -4189,20 +4139,6 @@
ast_log(LOG_NOTICE, "===== done ====\n");
}
-/*!
- * \brief return the first unlocked cdr in a possible chain
- */
-static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
-{
- struct ast_cdr *cdr_orig = cdr;
- while (cdr) {
- if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
- return cdr;
- cdr = cdr->next;
- }
- return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
-}
-
static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
{
const char *feature;
@@ -4213,17 +4149,14 @@
for (feature = features; *feature; feature++) {
struct ast_flags *party;
- char this_feature;
if (isupper(*feature)) {
- party = &(config->features_caller);
+ party = &config->features_caller;
} else {
- party = &(config->features_callee);
- }
-
- this_feature = tolower(*feature);
-
- switch (this_feature) {
+ party = &config->features_callee;
+ }
+
+ switch (tolower(*feature)) {
case 't' :
ast_set_flag(party, AST_FEATURE_REDIRECT);
break;
@@ -4241,6 +4174,7 @@
break;
default :
ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
+ break;
}
}
}
@@ -4445,6 +4379,7 @@
}
}
+/* BUGBUG Change callers of ast_bridge_call() to not expect the peer back. */
/*!
* \brief bridge the call and set CDR
*
@@ -4459,20 +4394,7 @@
*/
int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
{
- /* Copy voice back and forth between the two channels. Give the peer
- the ability to transfer calls with '#<extension' syntax. */
- char orig_channame[AST_CHANNEL_NAME];
- char orig_peername[AST_CHANNEL_NAME];
int res;
- int we_disabled_peer_cdr = 0;
- struct ast_cdr *bridge_cdr = NULL;
- struct ast_cdr *chan_cdr = ast_channel_cdr(chan); /* the proper chan cdr, if there are forked cdrs */
- struct ast_cdr *peer_cdr = ast_channel_cdr(peer); /* the proper chan cdr, if there are forked cdrs */
- struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
- struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
- /*! TRUE if h-exten or hangup handlers run. */
- int hangup_run = 0;
-
struct ast_bridge *bridge;
struct ast_bridge_features chan_features;
struct ast_bridge_features *peer_features;
@@ -4481,6 +4403,7 @@
struct ast_bridge_features_limits call_duration_limits_chan = {0};
struct ast_bridge_features_limits call_duration_limits_peer = {0};
+/* 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));
pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
@@ -4491,10 +4414,15 @@
set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
add_features_datastores(chan, peer, config);
- /* This is an interesting case. One example is if a ringing channel gets redirected to
- * an extension that picks up a parked call. This will make sure that the call taken
- * out of parking gets told that the channel it just got bridged to is still ringing. */
- if (ast_channel_state(chan) == AST_STATE_RINGING && ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) {
+ /*
+ * This is an interesting case. One example is if a ringing
+ * channel gets redirected to an extension that picks up a
+ * parked call. This will make sure that the call taken out of
+ * parking gets told that the channel it just got bridged to is
+ * still ringing.
+ */
+ if (ast_channel_state(chan) == AST_STATE_RINGING
+ && ast_channel_visible_indication(peer) != AST_CONTROL_RINGING) {
ast_indicate(peer, AST_CONTROL_RINGING);
}
@@ -4505,6 +4433,7 @@
/* Answer if need be */
if (ast_channel_state(chan) != AST_STATE_UP) {
if (ast_raw_answer(chan, 1)) {
+ ast_autoservice_chan_hangup_peer(chan, peer);
return -1;
}
}
@@ -4515,115 +4444,14 @@
ast_channel_log("Pre-bridge PEER Channel info", peer);
#endif
/* two channels are being marked as linked here */
- ast_channel_set_linkgroup(chan,peer);
-
- /* copy the userfield from the B-leg to A-leg if applicable */
- if (ast_channel_cdr(chan) && ast_channel_cdr(peer) && !ast_strlen_zero(ast_channel_cdr(peer)->userfield)) {
- char tmp[256];
-
- ast_channel_lock(chan);
- if (!ast_strlen_zero(ast_channel_cdr(chan)->userfield)) {
- snprintf(tmp, sizeof(tmp), "%s;%s", ast_channel_cdr(chan)->userfield, ast_channel_cdr(peer)->userfield);
- ast_cdr_appenduserfield(chan, tmp);
- } else {
- ast_cdr_setuserfield(chan, ast_channel_cdr(peer)->userfield);
- }
- ast_channel_unlock(chan);
- /* Don't delete the CDR; just disable it. */
- ast_set_flag(ast_channel_cdr(peer), AST_CDR_FLAG_POST_DISABLED);
- we_disabled_peer_cdr = 1;
- }
- ast_copy_string(orig_channame,ast_channel_name(chan),sizeof(orig_channame));
- ast_copy_string(orig_peername,ast_channel_name(peer),sizeof(orig_peername));
-
- if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
- ast_channel_lock_both(chan, peer);
- if (chan_cdr) {
- ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
- ast_cdr_update(chan);
- bridge_cdr = ast_cdr_dup_unique_swap(chan_cdr);
- /* rip any forked CDR's off of the chan_cdr and attach
- * them to the bridge_cdr instead */
- bridge_cdr->next = chan_cdr->next;
- chan_cdr->next = NULL;
- ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp));
- ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata));
- if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
- ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
- }
- ast_cdr_setaccount(peer, ast_channel_accountcode(chan));
- } else {
- /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
- bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
- ast_copy_string(bridge_cdr->channel, ast_channel_name(chan), sizeof(bridge_cdr->channel));
- ast_copy_string(bridge_cdr->dstchannel, ast_channel_name(peer), sizeof(bridge_cdr->dstchannel));
- ast_copy_string(bridge_cdr->uniqueid, ast_channel_uniqueid(chan), sizeof(bridge_cdr->uniqueid));
- ast_copy_string(bridge_cdr->lastapp, S_OR(ast_channel_appl(chan), ""), sizeof(bridge_cdr->lastapp));
- ast_copy_string(bridge_cdr->lastdata, S_OR(ast_channel_data(chan), ""), sizeof(bridge_cdr->lastdata));
- ast_cdr_setcid(bridge_cdr, chan);
- bridge_cdr->disposition = (ast_channel_state(chan) == AST_STATE_UP) ? AST_CDR_ANSWERED : AST_CDR_NULL;
- bridge_cdr->amaflags = ast_channel_amaflags(chan) ? ast_channel_amaflags(chan) : ast_default_amaflags;
- ast_copy_string(bridge_cdr->accountcode, ast_channel_accountcode(chan), sizeof(bridge_cdr->accountcode));
- /* Destination information */
- ast_copy_string(bridge_cdr->dst, ast_channel_exten(chan), sizeof(bridge_cdr->dst));
- ast_copy_string(bridge_cdr->dcontext, ast_channel_context(chan), sizeof(bridge_cdr->dcontext));
- if (peer_cdr) {
- bridge_cdr->start = peer_cdr->start;
- ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
- } else {
- ast_cdr_start(bridge_cdr);
- }
- }
- ast_channel_unlock(chan);
- ast_channel_unlock(peer);
-
- ast_debug(4, "bridge answer set, chan answer set\n");
- /* peer_cdr->answer will be set when a macro runs on the peer;
- in that case, the bridge answer will be delayed while the
- macro plays on the peer channel. The peer answered the call
- before the macro started playing. To the phone system,
- this is billable time for the call, even tho the caller
- hears nothing but ringing while the macro does its thing. */
-
- /* Another case where the peer cdr's time will be set, is when
- A self-parks by pickup up phone and dialing 700, then B
- picks up A by dialing its parking slot; there may be more
- practical paths that get the same result, tho... in which
- case you get the previous answer time from the Park... which
- is before the bridge's start time, so I added in the
- tvcmp check to the if below */
-
- if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
- ast_cdr_setanswer(bridge_cdr, peer_cdr->answer);
- ast_cdr_setdisposition(bridge_cdr, peer_cdr->disposition);
- if (chan_cdr) {
- ast_cdr_setanswer(chan_cdr, peer_cdr->answer);
- ast_cdr_setdisposition(chan_cdr, peer_cdr->disposition);
- }
- } else {
- ast_cdr_answer(bridge_cdr);
- if (chan_cdr) {
- ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
- }
- }
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
- if (chan_cdr) {
- ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
- }
- if (peer_cdr) {
- ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
- }
- }
- /* the DIALED flag may be set if a dialed channel is transfered
- * and then bridged to another channel. In order for the
- * bridge CDR to be written, the DIALED flag must not be
- * present. */
- ast_clear_flag(bridge_cdr, AST_CDR_FLAG_DIALED);
- }
-
- /* If we are bridging a call, stop worrying about forwarding loops. We presume that if
- * a call is being bridged, that the humans in charge know what they're doing. If they
- * don't, well, what can we do about that? */
+ ast_channel_set_linkgroup(chan, peer);
+
+ /*
+ * If we are bridging a call, stop worrying about forwarding
+ * loops. We presume that if a call is being bridged, that the
+ * humans in charge know what they're doing. If they don't,
+ * well, what can we do about that?
+ */
clear_dialed_interfaces(chan);
clear_dialed_interfaces(peer);
@@ -4635,10 +4463,7 @@
|| setup_bridge_channel_features(&chan_features, &config->features_caller)) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
-
- if (bridge_cdr) {
- ast_cdr_discard(bridge_cdr);
- }
+ ast_autoservice_chan_hangup_peer(chan, peer);
return -1;
}
@@ -4648,38 +4473,27 @@
ast_bridge_features_set_limits(peer_features, &call_duration_limits_peer);
}
- ast_cel_report_event(chan, AST_CEL_BRIDGE_START, NULL, NULL, peer);/* BUGBUG expected to go away. */
-
/* Create bridge */
- bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE,
- AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_DISSOLVE_EMPTY | AST_BRIDGE_FLAG_SMART);
+ bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_MULTIMIX,
+ AST_BRIDGE_FLAG_DISSOLVE_HANGUP | AST_BRIDGE_FLAG_SMART);
if (!bridge) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
-
- ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);/* BUGBUG expected to go away. */
- if (bridge_cdr) {
- ast_cdr_discard(bridge_cdr);
- }
+ ast_autoservice_chan_hangup_peer(chan, peer);
return -1;
}
/* Put peer into the bridge */
-/* BUGBUG imparting the peer this way must be changed. The peer ultimately cannot be returned to the caller. */
- if (ast_bridge_impart(bridge, peer, NULL, peer_features, 0)) {
+ if (ast_bridge_impart(bridge, peer, NULL, peer_features, 1)) {
ast_bridge_destroy(bridge);
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
-
- ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);/* BUGBUG expected to go away. */
- if (bridge_cdr) {
- ast_cdr_discard(bridge_cdr);
- }
+ ast_autoservice_chan_hangup_peer(chan, peer);
return -1;
}
/* Join bridge */
- ast_bridge_join(bridge, chan, NULL, &chan_features, NULL);
+ ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 0, 1);
/*
* If the bridge was broken for a hangup that isn't real, then
@@ -4690,24 +4504,13 @@
res = -1;
ast_channel_lock(chan);
if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
- ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT);
res = 0;
}
ast_channel_unlock(chan);
- /* Wait for peer thread to exit bridge and die. */
- if (!ast_autoservice_start(chan)) {
- ast_bridge_depart(bridge, peer);
- ast_autoservice_stop(chan);
- } else {
- ast_bridge_depart(bridge, peer);
- }
-
- ast_bridge_destroy(bridge);
ast_bridge_features_cleanup(&chan_features);
- ast_cel_report_event(chan, AST_CEL_BRIDGE_END, NULL, NULL, peer);/* BUGBUG expected to go away. */
-
+/* BUGBUG move this to bridge_channel_join before dissolve the bridge check. */
if (ast_channel_sending_dtmf_digit(chan)) {
ast_bridge_end_dtmf(chan, ast_channel_sending_dtmf_digit(chan),
ast_channel_sending_dtmf_tv(chan), "bridge end");
@@ -4717,200 +4520,15 @@
ast_channel_sending_dtmf_tv(peer), "bridge end");
}
+/* BUGBUG move this to bridge_channel_join before dissolve the bridge check. */
/* Wait for any dual redirect to complete. */
while (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
sched_yield();
}
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT)) {
- ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
- if (bridge_cdr) {
- ast_cdr_discard(bridge_cdr);
- /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
- }
- return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
- }
-
- if (config->end_bridge_callback) {
+/* BUGBUG this is used by Dial and FollowMe for CDR information. By Queue for Queue stats like CDRs. */
+ if (res && config->end_bridge_callback) {
config->end_bridge_callback(config->end_bridge_callback_data);
- }
-
- if (!ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
- struct ast_cdr *swapper = NULL;
- char savelastapp[AST_MAX_EXTENSION];
- char savelastdata[AST_MAX_EXTENSION];
- char save_context[AST_MAX_CONTEXT];
- char save_exten[AST_MAX_EXTENSION];
- int save_prio;
-
- ast_channel_lock(chan);
- if (bridge_cdr) {
- /*
- * Swap the bridge_cdr and the chan cdr for a moment, and let
- * the hangup dialplan code operate on it.
- */
- swapper = ast_channel_cdr(chan);
- ast_channel_cdr_set(chan, bridge_cdr);
-
- /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
- ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
- ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
- }
- ast_copy_string(save_context, ast_channel_context(chan), sizeof(save_context));
- ast_copy_string(save_exten, ast_channel_exten(chan), sizeof(save_exten));
- save_prio = ast_channel_priority(chan);
- ast_channel_unlock(chan);
-
- ast_autoservice_start(peer);
- if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
- S_COR(ast_channel_caller(chan)->id.number.valid,
- ast_channel_caller(chan)->id.number.str, NULL))) {
- ast_pbx_h_exten_run(chan, ast_channel_context(chan));
- hangup_run = 1;
- } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
- && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
- S_COR(ast_channel_caller(chan)->id.number.valid,
- ast_channel_caller(chan)->id.number.str, NULL))) {
- ast_pbx_h_exten_run(chan, ast_channel_macrocontext(chan));
- hangup_run = 1;
- }
- if (ast_pbx_hangup_handler_run(chan)) {
- /* Indicate hangup handlers were run. */
- hangup_run = 1;
- }
- ast_autoservice_stop(peer);
-
- ast_channel_lock(chan);
-
- /* swap it back */
- ast_channel_context_set(chan, save_context);
- ast_channel_exten_set(chan, save_exten);
- ast_channel_priority_set(chan, save_prio);
- if (bridge_cdr) {
- if (ast_channel_cdr(chan) == bridge_cdr) {
- ast_channel_cdr_set(chan, swapper);
-
- /* Restore the lastapp/lastdata */
- ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
- ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
- } else {
- bridge_cdr = NULL;
- }
- }
- ast_channel_unlock(chan);
- }
-
- /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
- new_chan_cdr = pick_unlocked_cdr(ast_channel_cdr(chan)); /* the proper chan cdr, if there are forked cdrs */
-
- /*
- * If the channel CDR has been modified during the call, record
- * the changes in the bridge cdr, BUT, if hangup_run, the CDR
- * got swapped so don't overwrite what was done in the
- * h-extension or hangup handlers. What a mess. This is why
- * you never touch CDR code.
- */
- if (new_chan_cdr && bridge_cdr && !hangup_run) {
- ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
- ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
- bridge_cdr->amaflags = new_chan_cdr->amaflags;
- ast_copy_string(bridge_cdr->accountcode, new_chan_cdr->accountcode, sizeof(bridge_cdr->accountcode));
- if (ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED)) {
- ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
- }
- }
-
- /* we can post the bridge CDR at this point */
- if (bridge_cdr) {
- ast_cdr_end(bridge_cdr);
- ast_cdr_detach(bridge_cdr);
- }
-
- /* do a specialized reset on the beginning channel
- CDR's, if they still exist, so as not to mess up
- issues in future bridges;
-
- Here are the rules of the game:
- 1. The chan and peer channel pointers will not change
- during the life of the bridge.
- 2. But, in transfers, the channel names will change.
- between the time the bridge is started, and the
- time the channel ends.
- Usually, when a channel changes names, it will
- also change CDR pointers.
- 3. Usually, only one of the two channels (chan or peer)
- will change names.
- 4. Usually, if a channel changes names during a bridge,
- it is because of a transfer. Usually, in these situations,
- it is normal to see 2 bridges running simultaneously, and
- it is not unusual to see the two channels that change
- swapped between bridges.
- 5. After a bridge occurs, we have 2 or 3 channels' CDRs
- to attend to; if the chan or peer changed names,
- we have the before and after attached CDR's.
- */
-
- if (new_chan_cdr) {
- struct ast_channel *chan_ptr = NULL;
-
- if (strcasecmp(orig_channame, ast_channel_name(chan)) != 0) {
- /* old channel */
- if ((chan_ptr = ast_channel_get_by_name(orig_channame))) {
- ast_channel_lock(chan_ptr);
- if (!ast_bridged_channel(chan_ptr)) {
- struct ast_cdr *cur;
- for (cur = ast_channel_cdr(chan_ptr); cur; cur = cur->next) {
- if (cur == chan_cdr) {
- break;
- }
- }
- if (cur) {
- ast_cdr_specialized_reset(chan_cdr, 0);
- }
- }
- ast_channel_unlock(chan_ptr);
- chan_ptr = ast_channel_unref(chan_ptr);
- }
- /* new channel */
- ast_cdr_specialized_reset(new_chan_cdr, 0);
- } else {
- ast_cdr_specialized_reset(ast_channel_cdr(chan), 0); /* nothing changed, reset the chan cdr */
- }
- }
-
- {
- struct ast_channel *chan_ptr = NULL;
- new_peer_cdr = pick_unlocked_cdr(ast_channel_cdr(peer)); /* the proper chan cdr, if there are forked cdrs */
- if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED))
- ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
- if (strcasecmp(orig_peername, ast_channel_name(peer)) != 0) {
[... 117 lines stripped ...]
More information about the asterisk-commits
mailing list