[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r386320 - in /team/mjordan/cdrs-of-doom:...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Apr 22 14:45:05 CDT 2013


Author: mjordan
Date: Mon Apr 22 14:45:01 2013
New Revision: 386320

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386320
Log:
More merging over from bridge_construction

Added:
    team/mjordan/cdrs-of-doom/apps/app_bridgewait.c   (with props)
    team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c   (with props)
    team/mjordan/cdrs-of-doom/bridges/bridge_holding.c   (with props)
    team/mjordan/cdrs-of-doom/include/asterisk/bridging_basic.h   (with props)
    team/mjordan/cdrs-of-doom/include/asterisk/stasis_bridging.h   (with props)
    team/mjordan/cdrs-of-doom/include/asterisk/stasis_http.h   (with props)
    team/mjordan/cdrs-of-doom/main/bridging_basic.c   (with props)
    team/mjordan/cdrs-of-doom/main/manager_bridging.c   (with props)
    team/mjordan/cdrs-of-doom/main/stasis_bridging.c   (with props)
Modified:
    team/mjordan/cdrs-of-doom/apps/app_dial.c
    team/mjordan/cdrs-of-doom/apps/app_followme.c
    team/mjordan/cdrs-of-doom/apps/app_queue.c
    team/mjordan/cdrs-of-doom/apps/confbridge/conf_config_parser.c

Added: team/mjordan/cdrs-of-doom/apps/app_bridgewait.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_bridgewait.c?view=auto&rev=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_bridgewait.c (added)
+++ team/mjordan/cdrs-of-doom/apps/app_bridgewait.c Mon Apr 22 14:45:01 2013
@@ -1,0 +1,243 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * Author: Jonathan Rose <jrose at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Application to place the channel into a holding Bridge
+ *
+ * \author Jonathan Rose <jrose at digium.com>
+ *
+ * \ingroup applications
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/features.h"
+#include "asterisk/say.h"
+#include "asterisk/lock.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
+#include "asterisk/bridging.h"
+#include "asterisk/musiconhold.h"
+
+/*** DOCUMENTATION
+	<application name="BridgeWait" language="en_US">
+		<synopsis>
+			Put a call into the holding bridge.
+		</synopsis>
+		<syntax>
+			<parameter name="options">
+				<optionlist>
+					<option name="A">
+						<para>The channel will join the holding bridge as an
+						announcer</para>
+					</option>
+					<option name="m">
+						<argument name="class" required="false" />
+						<para>Play music on hold to the entering channel while it is
+						on hold. If the <emphasis>class</emphasis> is included, then
+						that class of music on hold will take priority over the
+						channel default.</para>
+					</option>
+					<option name="r">
+						<para>Play a ringing tone to the entering channel while it is
+						on hold.</para>
+					</option>
+					<option name="S">
+						<argument name="duration" required="true" />
+						<para>Automatically end the hold and return to the PBX after
+						<emphasis>duration</emphasis> seconds.</para>
+					</option>
+				</optionlist>
+			</parameter>
+		</syntax>
+		<description>
+			<para>This application places the incoming channel into a holding bridge.
+			The channel will then wait in the holding bridge until some
+			event occurs which removes it from the holding bridge.</para>
+		</description>
+	</application>
+ ***/
+/* BUGBUG Add bridge name/id parameter to specify which holding bridge to join (required) */
+/* BUGBUG Add h(moh-class) option to put channel on hold using AST_CONTROL_HOLD/AST_CONTROL_UNHOLD while in bridge */
+/* BUGBUG Add s option to send silence media frames to channel while in bridge (uses a silence generator) */
+/* BUGBUG Add n option to send no media to channel while in bridge (Channel should not be answered yet) */
+/* BUGBUG The channel may or may not be answered with the r option. */
+/* BUGBUG You should not place an announcer into a holding bridge with unanswered channels. */
+/* BUGBUG Not supplying any option flags will assume the m option with the default music class. */
+
+static char *app = "BridgeWait";
+static struct ast_bridge *holding_bridge;
+
+AST_MUTEX_DEFINE_STATIC(bridgewait_lock);
+
+enum bridgewait_flags {
+	MUXFLAG_PLAYMOH = (1 << 0),
+	MUXFLAG_RINGING = (1 << 1),
+	MUXFLAG_TIMEOUT = (1 << 2),
+	MUXFLAG_ANNOUNCER = (1 << 3),
+};
+
+enum bridgewait_args {
+	OPT_ARG_MOHCLASS,
+	OPT_ARG_TIMEOUT,
+	OPT_ARG_ARRAY_SIZE, /* Always the last element of the enum */
+};
+
+AST_APP_OPTIONS(bridgewait_opts, {
+	AST_APP_OPTION('A', MUXFLAG_ANNOUNCER),
+	AST_APP_OPTION('r', MUXFLAG_RINGING),
+	AST_APP_OPTION_ARG('m', MUXFLAG_PLAYMOH, OPT_ARG_MOHCLASS),
+	AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT),
+});
+
+static int apply_option_timeout(struct ast_bridge_features *features, char *duration_arg)
+{
+	struct ast_bridge_features_limits hold_limits;
+
+	if (ast_strlen_zero(duration_arg)) {
+		ast_log(LOG_ERROR, "No duration value provided for the timeout ('S') option.\n");
+		return -1;
+	}
+
+	if (ast_bridge_features_limits_construct(&hold_limits)) {
+		ast_log(LOG_ERROR, "Could not construct duration limits. Bridge canceled.\n");
+		return -1;
+	}
+
+	if (sscanf(duration_arg, "%u", &(hold_limits.duration)) != 1 || hold_limits.duration == 0) {
+		ast_log(LOG_ERROR, "Duration value provided for the timeout ('S') option must be greater than 0\n");
+		ast_bridge_features_limits_destroy(&hold_limits);
+		return -1;
+	}
+
+	/* Limits struct holds time as milliseconds, so muliply 1000x */
+	hold_limits.duration *= 1000;
+	ast_bridge_features_set_limits(features, &hold_limits, 1 /* remove_on_pull */);
+	ast_bridge_features_limits_destroy(&hold_limits);
+
+	return 0;
+}
+
+static void apply_option_moh(struct ast_channel *chan, char *class_arg)
+{
+	ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
+	ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", class_arg);
+}
+
+static void apply_option_ringing(struct ast_channel *chan)
+{
+	ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing");
+}
+
+static int process_options(struct ast_channel *chan, struct ast_flags *flags, char **opts, struct ast_bridge_features *features)
+{
+	if (ast_test_flag(flags, MUXFLAG_TIMEOUT)) {
+		if (apply_option_timeout(features, opts[OPT_ARG_TIMEOUT])) {
+			return -1;
+		}
+	}
+
+	if (ast_test_flag(flags, MUXFLAG_ANNOUNCER)) {
+		/* Announcer specific stuff */
+		ast_channel_add_bridge_role(chan, "announcer");
+	} else {
+		/* Non Announcer specific stuff */
+		ast_channel_add_bridge_role(chan, "holding_participant");
+
+		if (ast_test_flag(flags, MUXFLAG_PLAYMOH)) {
+			apply_option_moh(chan, opts[OPT_ARG_MOHCLASS]);
+		} else if (ast_test_flag(flags, MUXFLAG_RINGING)) {
+			apply_option_ringing(chan);
+		}
+	}
+
+	return 0;
+}
+
+static int bridgewait_exec(struct ast_channel *chan, const char *data)
+{
+	struct ast_bridge_features chan_features;
+	struct ast_flags flags = { 0 };
+	char *parse;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(options);
+		AST_APP_ARG(other);		/* Any remaining unused arguments */
+	);
+
+	ast_mutex_lock(&bridgewait_lock);
+	if (!holding_bridge) {
+		holding_bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
+			AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM);
+	}
+	ast_mutex_unlock(&bridgewait_lock);
+	if (!holding_bridge) {
+		ast_log(LOG_ERROR, "Could not create holding bridge for '%s'.\n", ast_channel_name(chan));
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (ast_bridge_features_init(&chan_features)) {
+		ast_bridge_features_cleanup(&chan_features);
+		return -1;
+	}
+
+	if (args.options) {
+		char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
+		ast_app_parse_options(bridgewait_opts, &flags, opts, args.options);
+		if (process_options(chan, &flags, opts, &chan_features)) {
+			ast_bridge_features_cleanup(&chan_features);
+			return -1;
+		}
+	}
+
+	ast_bridge_join(holding_bridge, chan, NULL, &chan_features, NULL, 0);
+
+	ast_bridge_features_cleanup(&chan_features);
+	return ast_check_hangup_locked(chan) ? -1 : 0;
+}
+
+static int unload_module(void)
+{
+	ao2_cleanup(holding_bridge);
+	holding_bridge = NULL;
+
+	return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+	return ast_register_application_xml(app, bridgewait_exec);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Place the channel into a holding bridge application");

Propchange: team/mjordan/cdrs-of-doom/apps/app_bridgewait.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mjordan/cdrs-of-doom/apps/app_bridgewait.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mjordan/cdrs-of-doom/apps/app_bridgewait.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/mjordan/cdrs-of-doom/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_dial.c?view=diff&rev=386320&r1=386319&r2=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_dial.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_dial.c Mon Apr 22 14:45:01 2013
@@ -67,6 +67,7 @@
 #include "asterisk/ccss.h"
 #include "asterisk/indications.h"
 #include "asterisk/framehook.h"
+#include "asterisk/bridging.h"
 #include "asterisk/stasis_channels.h"
 
 /*** DOCUMENTATION
@@ -711,7 +712,6 @@
 AST_LIST_HEAD_NOLOCK(dial_head, chanlist);
 
 static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode);
-static const char *hangup_cause_to_dial_status(int hangup_cause);
 
 static void chanlist_free(struct chanlist *outgoing)
 {
@@ -1019,6 +1019,22 @@
 	char status[256];
 };
 
+static const char *hangup_cause_to_dial_status(int hangup_cause)
+{
+	switch(hangup_cause) {
+	case AST_CAUSE_BUSY:
+		return "BUSY";
+	case AST_CAUSE_CONGESTION:
+		return "CONGESTION";
+	case AST_CAUSE_NO_ROUTE_DESTINATION:
+	case AST_CAUSE_UNREGISTERED:
+		return "CHANUNAVAIL";
+	case AST_CAUSE_NO_ANSWER:
+	default:
+		return "NOANSWER";
+	}
+}
+
 static void publish_dial_end_event(struct ast_channel *in, struct dial_head *out_chans, struct ast_channel *exception, const char *status)
 {
 	struct chanlist *outgoing;
@@ -1072,7 +1088,6 @@
 				 */
 				*to = -1;
 				strcpy(pa->status, "CONGESTION");
-				ast_channel_publish_dial(in, outgoing->chan, NULL, pa->status);
 				ast_channel_publish_dial(in, outgoing->chan, NULL, pa->status);
 				return NULL;
 			}
@@ -1515,7 +1530,6 @@
 				*to = -1;
 				strcpy(pa->status, "CANCEL");
 				publish_dial_end_event(in, out_chans, NULL, pa->status);
-				publish_dial_end_event(in, out_chans, NULL, pa->status);
 				if (f) {
 					if (f->data.uint32) {
 						ast_channel_hangupcause_set(in, f->data.uint32);
@@ -1555,7 +1569,6 @@
 					ast_verb(3, "User requested call disconnect.\n");
 					*to = 0;
 					strcpy(pa->status, "CANCEL");
-					publish_dial_end_event(in, out_chans, NULL, pa->status);
 					publish_dial_end_event(in, out_chans, NULL, pa->status);
 					ast_frfree(f);
 					if (is_cc_recall) {
@@ -1668,22 +1681,6 @@
 	return peer;
 }
 
-static const char *hangup_cause_to_dial_status(int hangup_cause)
-{
-	switch(hangup_cause) {
-	case AST_CAUSE_BUSY:
-		return "BUSY";
-	case AST_CAUSE_CONGESTION:
-		return "CONGESTION";
-	case AST_CAUSE_NO_ROUTE_DESTINATION:
-	case AST_CAUSE_UNREGISTERED:
-		return "CHANUNAVAIL";
-	case AST_CAUSE_NO_ANSWER:
-	default:
-		return "NOANSWER";
-	}
-}
-
 static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode)
 {
 	struct ast_flags features = { AST_FEATURE_DISCONNECT }; /* only concerned with disconnect feature */
@@ -2002,6 +1999,40 @@
 	}
 
 	return res;
+}
+
+/*!
+ * \internal
+ * \brief Setup the after bridge goto location on the peer.
+ * \since 12.0.0
+ *
+ * \param chan Calling channel for bridge.
+ * \param peer Peer channel for bridge.
+ * \param opts Dialing option flags.
+ * \param opt_args Dialing option argument strings.
+ *
+ * \return Nothing
+ */
+static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags64 *opts, char *opt_args[])
+{
+	const char *context;
+	const char *extension;
+	int priority;
+
+	if (ast_test_flag64(opts, OPT_PEER_H)) {
+		ast_channel_lock(chan);
+		context = ast_strdupa(ast_channel_context(chan));
+		ast_channel_unlock(chan);
+		ast_after_bridge_set_h(peer, context);
+	} else if (ast_test_flag64(opts, OPT_CALLEE_GO_ON)) {
+		ast_channel_lock(chan);
+		context = ast_strdupa(ast_channel_context(chan));
+		extension = ast_strdupa(ast_channel_exten(chan));
+		priority = ast_channel_priority(chan);
+		ast_channel_unlock(chan);
+		ast_after_bridge_set_go_on(peer, context, extension, priority,
+			opt_args[OPT_ARG_CALLEE_GO_ON]);
+	}
 }
 
 static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast_flags64 *peerflags, int *continue_exec)
@@ -2932,6 +2963,14 @@
 		}
 
 		if (res) { /* some error */
+			if (!ast_check_hangup(chan) && ast_check_hangup(peer)) {
+				ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
+			}
+			setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
+			if (ast_after_bridge_goto_setup(peer)
+				|| ast_pbx_start(peer)) {
+				ast_autoservice_chan_hangup_peer(chan, peer);
+			}
 			res = -1;
 		} else {
 			if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER))
@@ -2954,8 +2993,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;
@@ -2987,38 +3024,10 @@
 
 				ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
 			}
+/* BUGBUG bridge needs to set hangup cause on chan when peer breaks the bridge. */
+			setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
 			res = ast_bridge_call(chan, peer, &config);
 		}
-
-		ast_channel_context_set(peer, ast_channel_context(chan));
-
-		if (ast_test_flag64(&opts, OPT_PEER_H)
-			&& ast_exists_extension(peer, ast_channel_context(peer), "h", 1,
-				S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
-			ast_autoservice_start(chan);
-			ast_pbx_h_exten_run(peer, ast_channel_context(peer));
-			ast_autoservice_stop(chan);
-		}
-		if (!ast_check_hangup(peer)) {
-			if (ast_test_flag64(&opts, OPT_CALLEE_GO_ON)) {
-				int goto_res;
-
-				if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
-					ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
-					goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
-				} else { /* F() */
-					goto_res = ast_goto_if_exists(peer, ast_channel_context(chan),
-						ast_channel_exten(chan), ast_channel_priority(chan) + 1);
-				}
-				if (!goto_res && !ast_pbx_start(peer)) {
-					/* The peer is now running its own PBX. */
-					goto out;
-				}
-			}
-		} else if (!ast_check_hangup(chan)) {
-			ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
-		}
-		ast_autoservice_chan_hangup_peer(chan, peer);
 	}
 out:
 	if (moh) {

Modified: team/mjordan/cdrs-of-doom/apps/app_followme.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_followme.c?view=diff&rev=386320&r1=386319&r2=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_followme.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_followme.c Mon Apr 22 14:45:01 2013
@@ -1087,11 +1087,6 @@
 				 * Destoy all new outgoing calls.
 				 */
 				while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
-					ast_channel_lock(tmpuser->ochan);
-					/*if (ast_channel_cdr(tmpuser->ochan)) {
-						ast_cdr_init(ast_channel_cdr(tmpuser->ochan), tmpuser->ochan);
-					}*/
-					ast_channel_unlock(tmpuser->ochan);
 					destroy_calling_node(tmpuser);
 				}
 
@@ -1113,11 +1108,6 @@
 				AST_LIST_REMOVE_CURRENT(entry);
 
 				/* Destroy this failed new outgoing call. */
-				ast_channel_lock(tmpuser->ochan);
-				/*if (ast_channel_cdr(tmpuser->ochan)) {
-					ast_cdr_init(ast_channel_cdr(tmpuser->ochan), tmpuser->ochan);
-				}*/
-				ast_channel_unlock(tmpuser->ochan);
 				destroy_calling_node(tmpuser);
 			}
 		}
@@ -1492,7 +1482,6 @@
 		}
 
 		res = ast_bridge_call(caller, outbound, &config);
-		ast_autoservice_chan_hangup_peer(caller, outbound);
 	}
 
 outrun:

Modified: team/mjordan/cdrs-of-doom/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_queue.c?view=diff&rev=386320&r1=386319&r2=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_queue.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_queue.c Mon Apr 22 14:45:01 2013
@@ -106,6 +106,7 @@
 #include "asterisk/cel.h"
 #include "asterisk/data.h"
 #include "asterisk/term.h"
+#include "asterisk/bridging.h"
 
 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
 /* #define REF_DEBUG_ONLY_QUEUES */
@@ -3624,6 +3625,7 @@
 
 		member_call_pending_clear(tmp->member);
 
+		/* BUGBUG: Set the CDR to busy somehow */
 		/*if (ast_channel_cdr(qe->chan)) {
 			ast_cdr_busy(ast_channel_cdr(qe->chan));
 		}*/
@@ -4132,11 +4134,13 @@
 		if (pos == 1 /* not found */) {
 			if (numlines == (numbusies + numnochan)) {
 				ast_debug(1, "Everyone is busy at this time\n");
+				/* BUGBUG: make the CDR busy */
 				/*if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP) {
 					ast_cdr_busy(ast_channel_cdr(in));
 				}*/
 			} else {
 				ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
+				/* BUGBUG: make the CDR failed */
 				/*if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP) {
 					ast_cdr_failed(ast_channel_cdr(in));
 				}*/
@@ -4359,6 +4363,7 @@
 							break;
 						case AST_CONTROL_BUSY:
 							ast_verb(3, "%s is busy\n", ochan_name);
+							/* BUGBUG: make the CDR busy */
 							/*if (ast_channel_cdr(in)) {
 								ast_cdr_busy(ast_channel_cdr(in));
 							}*/
@@ -4380,6 +4385,7 @@
 							break;
 						case AST_CONTROL_CONGESTION:
 							ast_verb(3, "%s is circuit-busy\n", ochan_name);
+							/* BUGBUG make the CDR congested */
 							/*if (ast_channel_cdr(in)) {
 								ast_cdr_failed(ast_channel_cdr(in));
 							}*/
@@ -4514,6 +4520,7 @@
 				ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
 				*to = 0;
 				ast_frfree(f);
+				/* BUGBUG: No answer */
 				/*if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP) {
 					ast_cdr_noanswer(ast_channel_cdr(in));
 				}*/
@@ -4524,6 +4531,7 @@
 				*to = 0;
 				*digit = f->subclass.integer;
 				ast_frfree(f);
+				/* BUGBUG: No answer */
 				/*if (ast_channel_cdr(in) && ast_channel_state(in) != AST_STATE_UP) {
 					ast_cdr_noanswer(ast_channel_cdr(in));
 				}*/
@@ -4572,6 +4580,7 @@
 			rna(orig, qe, o->interface, o->member->membername, 1);
 		}
 
+		/* BUGBUG: No answer */
 		/*if (ast_channel_cdr(in)
 			&& ast_channel_state(in) != AST_STATE_UP
 			&& (!*to || ast_check_hangup(in))) {
@@ -4887,6 +4896,7 @@
 	TRANSFER
 };
 
+#if 0	// BUGBUG
 /*! \brief Send out AMI message with member call completion status information */
 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
 	const struct ast_channel *peer, const struct member *member, time_t callstart,
@@ -4950,6 +4960,7 @@
 		(long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
 		qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
 }
+#endif	// BUGBUG
 
 struct queue_transfer_ds {
 	struct queue_ent *qe;
@@ -5004,6 +5015,7 @@
 	}
 }
 
+#if 0	// BUGBUG
 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
  *
  * When a caller is atxferred, then the queue_transfer_info datastore
@@ -5016,6 +5028,7 @@
 {
 	return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
 }
+#endif	// BUGBUG
 
 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
  */
@@ -5070,6 +5083,35 @@
 		set_queue_variables(q, chan);
 		/* This unrefs the reference we made in try_calling when we allocated qeb */
 		queue_t_unref(q, "Expire bridge_config reference");
+	}
+}
+
+/*!
+ * \internal
+ * \brief Setup the after bridge goto location on the peer.
+ * \since 12.0.0
+ *
+ * \param chan Calling channel for bridge.
+ * \param peer Peer channel for bridge.
+ * \param opts Dialing option flags.
+ * \param opt_args Dialing option argument strings.
+ *
+ * \return Nothing
+ */
+static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
+{
+	const char *context;
+	const char *extension;
+	int priority;
+
+	if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
+		ast_channel_lock(chan);
+		context = ast_strdupa(ast_channel_context(chan));
+		extension = ast_strdupa(ast_channel_exten(chan));
+		priority = ast_channel_priority(chan);
+		ast_channel_unlock(chan);
+		ast_after_bridge_set_go_on(peer, context, extension, priority,
+			opt_args[OPT_ARG_CALLEE_GO_ON]);
 	}
 }
 
@@ -5103,7 +5145,7 @@
  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
  */
-static int try_calling(struct queue_ent *qe, const struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
+static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
 {
 	struct member *cur;
 	struct callattempt *outgoing = NULL; /* the list of calls we are building */
@@ -5175,9 +5217,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;
 	}
@@ -5405,6 +5444,7 @@
 				if (!o->chan) {
 					continue;
 				}
+				/* BUGBUG: this is terrible */
 				/*if (strcmp(ast_channel_cdr(o->chan)->dstchannel, ast_channel_cdr(qe->chan)->dstchannel) == 0) {
 					ast_set_flag(ast_channel_cdr(o->chan), AST_CDR_FLAG_DISABLE);
 					break;
@@ -5412,11 +5452,6 @@
 			}
 		}
 	} else { /* peer is valid */
-		/* These variables are used with the F option without arguments (callee jumps to next priority after queue) */
-		char *caller_context;
-		char *caller_extension;
-		int caller_priority;
-
 		/* Ah ha!  Someone answered within the desired timeframe.  Of course after this
 		   we will always return with -1 so that it is hung up properly after the
 		   conversation.  */
@@ -5523,6 +5558,7 @@
 			ast_moh_stop(qe->chan);
 		}
 		/* If appropriate, log that we have a destination channel */
+		/* BUGBUG: remove me */
 		/*if (ast_channel_cdr(qe->chan)) {
 			ast_cdr_setdestchan(ast_channel_cdr(qe->chan), ast_channel_name(peer));
 		}*/
@@ -5532,6 +5568,7 @@
 			ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
 			ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
 			record_abandoned(qe);
+			/* BUGBUG: Fail the CDR? */
 			/*ast_cdr_failed(ast_channel_cdr(qe->chan));*/
 			ast_autoservice_chan_hangup_peer(qe->chan, peer);
 			ao2_ref(member, -1);
@@ -5570,11 +5607,8 @@
 		set_queue_variables(qe->parent, qe->chan);
 		set_queue_variables(qe->parent, peer);
 
+		setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
 		ast_channel_lock(qe->chan);
-		/* Copy next destination data for 'F' option (no args) */
-		caller_context = ast_strdupa(ast_channel_context(qe->chan));
-		caller_extension = ast_strdupa(ast_channel_exten(qe->chan));
-		caller_priority = ast_channel_priority(qe->chan);
 		if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
 				monitorfilename = ast_strdupa(monitorfilename);
 		}
@@ -5836,6 +5870,8 @@
 		transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
 		bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
 
+/* BUGBUG need to do this queue logging a different way because we cannot reference peer anymore.  Likely needs to be made a subscriber of stasis transfer events. */
+#if 0	// BUGBUG
 		/* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
 		 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
 		 * the AgentComplete manager event
@@ -5870,26 +5906,10 @@
 			/* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
 			send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
 		}
+#endif	// BUGBUG
 
 		if (transfer_ds) {
 			ast_datastore_free(transfer_ds);
-		}
-
-		if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
-			int goto_res;
-
-			if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
-				ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
-				goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
-			} else { /* F() */
-				goto_res = ast_goto_if_exists(peer, caller_context, caller_extension,
-					caller_priority + 1);
-			}
-			if (goto_res || ast_pbx_start(peer)) {
-				ast_autoservice_chan_hangup_peer(qe->chan, peer);
-			}
-		} else {
-			ast_autoservice_chan_hangup_peer(qe->chan, peer);
 		}
 
 		res = bridge ? bridge : 1;

Modified: team/mjordan/cdrs-of-doom/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/confbridge/conf_config_parser.c?view=diff&rev=386320&r1=386319&r2=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/confbridge/conf_config_parser.c (original)
+++ team/mjordan/cdrs-of-doom/apps/confbridge/conf_config_parser.c Mon Apr 22 14:45:01 2013
@@ -2053,7 +2053,8 @@
 		ao2_ref(menu, +1);
 		pvt->menu = menu;
 
-		ast_bridge_features_hook(&user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
+		ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf, menu_hook_callback,
+			pvt, menu_hook_destroy, 0);
 	}
 
 	ao2_unlock(menu);

Added: team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c?view=auto&rev=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c (added)
+++ team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c Mon Apr 22 14:45:01 2013
@@ -1,0 +1,215 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Jonathan Rose <jrose at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Built in bridging interval features
+ *
+ * \author Jonathan Rose <jrose at digium.com>
+ *
+ * \ingroup bridges
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$REVISION: 381278 $")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/file.h"
+#include "asterisk/app.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/test.h"
+
+#include "asterisk/say.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/musiconhold.h"
+
+static int bridge_features_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	struct ast_bridge_features_limits *limits = hook_pvt;
+
+	if (!ast_strlen_zero(limits->duration_sound)) {
+		ast_stream_and_wait(bridge_channel->chan, limits->duration_sound, AST_DIGIT_NONE);
+	}
+
+	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+
+	ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s", ast_channel_name(bridge_channel->chan));
+	return -1;
+}
+
+static void limits_interval_playback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_bridge_features_limits *limits, const char *file)
+{
+	if (!strcasecmp(file, "timeleft")) {
+		unsigned int remaining = ast_tvdiff_ms(limits->quitting_time, ast_tvnow()) / 1000;
+		unsigned int min;
+		unsigned int sec;
+
+		if (remaining <= 0) {
+			return;
+		}
+
+		if ((remaining / 60) > 1) {
+			min = remaining / 60;
+			sec = remaining % 60;
+		} else {
+			min = 0;
+			sec = remaining;
+		}
+
+		ast_stream_and_wait(bridge_channel->chan, "vm-youhave", AST_DIGIT_NONE);
+		if (min) {
+			ast_say_number(bridge_channel->chan, min, AST_DIGIT_NONE,
+				ast_channel_language(bridge_channel->chan), NULL);
+			ast_stream_and_wait(bridge_channel->chan, "queue-minutes", AST_DIGIT_NONE);
+		}
+		if (sec) {
+			ast_say_number(bridge_channel->chan, sec, AST_DIGIT_NONE,
+				ast_channel_language(bridge_channel->chan), NULL);
+			ast_stream_and_wait(bridge_channel->chan, "queue-seconds", AST_DIGIT_NONE);
+		}
+	} else {
+		ast_stream_and_wait(bridge_channel->chan, file, AST_DIGIT_NONE);
+	}
+
+	/*
+	 * It may be necessary to resume music on hold after we finish
+	 * playing the announcment.
+	 *
+	 * XXX We have no idea what MOH class was in use before playing
+	 * the file.
+	 */
+	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
+		ast_moh_start(bridge_channel->chan, NULL, NULL);
+	}
+}
+
+static int bridge_features_connect_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	struct ast_bridge_features_limits *limits = hook_pvt;
+
+	if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		return -1;
+	}
+
+	limits_interval_playback(bridge, bridge_channel, limits, limits->connect_sound);
+	return -1;
+}
+
+static int bridge_features_warning_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+	struct ast_bridge_features_limits *limits = hook_pvt;
+
+	if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+		/* If we aren't in the wait state, something more important than this warning is happening and we should skip it. */
+		limits_interval_playback(bridge, bridge_channel, limits, limits->warning_sound);
+	}
+
+	return !limits->frequency ? -1 : limits->frequency;
+}
+
+static void copy_bridge_features_limits(struct ast_bridge_features_limits *dst, struct ast_bridge_features_limits *src)
+{
+	dst->duration = src->duration;
+	dst->warning = src->warning;
+	dst->frequency = src->frequency;
+	dst->quitting_time = src->quitting_time;
+
+	ast_string_field_set(dst, duration_sound, src->duration_sound);
+	ast_string_field_set(dst, warning_sound, src->warning_sound);
+	ast_string_field_set(dst, connect_sound, src->connect_sound);
+}
+
+static int bridge_builtin_set_limits(struct ast_bridge_features *features, struct ast_bridge_features_limits *limits, int remove_on_pull)
+{
+	struct ast_bridge_features_limits *feature_limits;
+
+	if (!limits->duration) {
+		return -1;
+	}
+
+	if (features->limits) {
+		ast_log(LOG_ERROR, "Tried to apply limits to a feature set that already has limits.\n");
+		return -1;
+	}
+
+	feature_limits = ast_malloc(sizeof(*feature_limits));
+	if (!feature_limits) {
+		return -1;
+	}
+
+	if (ast_bridge_features_limits_construct(feature_limits)) {
+		return -1;
+	}
+
+	copy_bridge_features_limits(feature_limits, limits);
+	features->limits = feature_limits;
+
+/* BUGBUG feature interval hooks need to be reimplemented to be more stand alone. */
+	if (ast_bridge_interval_hook(features, feature_limits->duration,
+		bridge_features_duration_callback, feature_limits, NULL, remove_on_pull)) {
+		ast_log(LOG_ERROR, "Failed to schedule the duration limiter to the bridge channel.\n");
+		return -1;
+	}
+
+	feature_limits->quitting_time = ast_tvadd(ast_tvnow(), ast_samp2tv(feature_limits->duration, 1000));
+
+	if (!ast_strlen_zero(feature_limits->connect_sound)) {
+		if (ast_bridge_interval_hook(features, 1,
+			bridge_features_connect_callback, feature_limits, NULL, remove_on_pull)) {
+			ast_log(LOG_WARNING, "Failed to schedule connect sound to the bridge channel.\n");
+		}
+	}
+
+	if (feature_limits->warning && feature_limits->warning < feature_limits->duration) {
+		if (ast_bridge_interval_hook(features, feature_limits->duration - feature_limits->warning,
+			bridge_features_warning_callback, feature_limits, NULL, remove_on_pull)) {
+			ast_log(LOG_WARNING, "Failed to schedule warning sound playback to the bridge channel.\n");
+		}
+	}
+
+	return 0;
+}
+
+static int unload_module(void)
+{
+	return 0;
+}
+
+static int load_module(void)
+{
+	ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS, bridge_builtin_set_limits);
+
+	/* Bump up our reference count so we can't be unloaded. */
+	ast_module_ref(ast_module_info->self);
+
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging interval features");

Propchange: team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mjordan/cdrs-of-doom/bridges/bridge_builtin_interval_features.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/mjordan/cdrs-of-doom/bridges/bridge_holding.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/bridges/bridge_holding.c?view=auto&rev=386320
==============================================================================
--- team/mjordan/cdrs-of-doom/bridges/bridge_holding.c (added)
+++ team/mjordan/cdrs-of-doom/bridges/bridge_holding.c Mon Apr 22 14:45:01 2013
@@ -1,0 +1,311 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Jonathan Rose <jrose at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Bridging technology for storing channels in a bridge for
+ *        the purpose of holding, parking, queues, and other such
+ *        states where a channel may need to be in a bridge but not
+ *        actually communicating with anything.
+ *
+ * \author Jonathan Rose <jrose at digium.com>
+ *
+ * \ingroup bridges
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
+#include "asterisk/frame.h"
+#include "asterisk/musiconhold.h"
+
+enum role_flags {
+	HOLDING_ROLE_PARTICIPANT = (1 << 0),
+	HOLDING_ROLE_ANNOUNCER = (1 << 1),
+};
+
+/* BUGBUG Add IDLE_MODE_HOLD option to put channel on hold using AST_CONTROL_HOLD/AST_CONTROL_UNHOLD while in bridge */
+/* BUGBUG Add IDLE_MODE_SILENCE to send silence media frames to channel while in bridge (uses a silence generator) */
+/* BUGBUG A channel without the holding_participant role will assume IDLE_MODE_MOH with the default music class. */
+enum idle_modes {
+	IDLE_MODE_NONE = 0,
+	IDLE_MODE_MOH,
+	IDLE_MODE_RINGING,
+};
+
+/*! \brief Structure which contains per-channel role information */
+struct holding_channel {
+	struct ast_flags holding_roles;
+	enum idle_modes idle_mode;
+};
+
+static void participant_stop_hold_audio(struct ast_bridge_channel *bridge_channel)
+{
+	struct holding_channel *hc = bridge_channel->tech_pvt;
+	if (!hc) {
+		return;
+	}
+
+	switch (hc->idle_mode) {
+	case IDLE_MODE_MOH:
+		ast_moh_stop(bridge_channel->chan);
+		break;
+	case IDLE_MODE_RINGING:
+		ast_indicate(bridge_channel->chan, -1);
+		break;
+	case IDLE_MODE_NONE:
+		break;
+	}
+}
+
+static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
+{
+	struct ast_channel *chan;
+	chan = bridge_channel->chan;
+	participant_stop_hold_audio(bridge_channel);
+	if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) {
+		ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
+	}
+}
+
+/* This should only be called on verified holding_participants. */
+static void participant_start_hold_audio(struct ast_bridge_channel *bridge_channel)
+{
+	struct holding_channel *hc = bridge_channel->tech_pvt;
+	const char *moh_class;
+
+	if (!hc) {
+		return;
+	}
+
+	switch(hc->idle_mode) {
+	case IDLE_MODE_MOH:
+		moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
+		ast_moh_start(bridge_channel->chan, ast_strlen_zero(moh_class) ? NULL : moh_class, NULL);
+		break;
+	case IDLE_MODE_RINGING:
+		ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
+		break;
+	case IDLE_MODE_NONE:
+		break;
+	}
+}
+
+static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
+{
+	struct ast_channel *us = bridge_channel->chan;

[... 1779 lines stripped ...]



More information about the asterisk-commits mailing list