[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