[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