[asterisk-commits] rmudgett: branch group/bridge_construction r381657 - in /team/group/bridge_co...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Feb 18 14:01:03 CST 2013
Author: rmudgett
Date: Mon Feb 18 14:00:59 2013
New Revision: 381657
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381657
Log:
Bridge API enhancements: Refactor callers of ast_bridge_call to use Bridging API model
Merge work accomplishing this from team/rmudgett/bridge_phase.
* Callers of ast_bridge_call() do not access peer after the function
returns.
* A datastore on the channel is used to cause the channel to execute
dialplan at a specified location when the channel leaves the bridge. This
is called an after bridge goto location.
* A bridge can now destroy itself when the last channel leaves the bridge
and there are no external references to the bridge.
* Disolved bridges now no longer allow any more channels to join. These
late commer channels are immediately bounced back out of the bridge.
(closes issue ASTERISK-21051)
Reported by: Matt Jordan
Modified:
team/group/bridge_construction/apps/app_channelredirect.c
team/group/bridge_construction/apps/app_confbridge.c
team/group/bridge_construction/apps/app_dial.c
team/group/bridge_construction/apps/app_followme.c
team/group/bridge_construction/apps/app_queue.c
team/group/bridge_construction/bridges/bridge_builtin_features.c
team/group/bridge_construction/funcs/func_channel.c
team/group/bridge_construction/include/asterisk/bridging.h
team/group/bridge_construction/include/asterisk/bridging_features.h
team/group/bridge_construction/include/asterisk/bridging_technology.h
team/group/bridge_construction/include/asterisk/channel.h
team/group/bridge_construction/main/bridging.c
team/group/bridge_construction/main/channel_internal_api.c
team/group/bridge_construction/main/features.c
team/group/bridge_construction/main/manager.c
team/group/bridge_construction/main/pbx.c
Modified: team/group/bridge_construction/apps/app_channelredirect.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_channelredirect.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/apps/app_channelredirect.c (original)
+++ team/group/bridge_construction/apps/app_channelredirect.c Mon Feb 18 14:00:59 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/group/bridge_construction/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_confbridge.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/apps/app_confbridge.c (original)
+++ team/group/bridge_construction/apps/app_confbridge.c Mon Feb 18 14:00:59 2013
@@ -627,7 +627,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, 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 */
@@ -1751,7 +1751,8 @@
chan,
NULL,
&conference_bridge_user.features,
- &conference_bridge_user.tech_args);
+ &conference_bridge_user.tech_args,
+ 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/group/bridge_construction/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_dial.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/apps/app_dial.c (original)
+++ team/group/bridge_construction/apps/app_dial.c Mon Feb 18 14:00:59 2013
@@ -67,6 +67,7 @@
#include "asterisk/ccss.h"
#include "asterisk/indications.h"
#include "asterisk/framehook.h"
+#include "asterisk/bridging.h"
/*** DOCUMENTATION
<application name="Dial" language="en_US">
@@ -2054,6 +2055,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)
{
int res = -1; /* default: error */
@@ -2989,6 +3024,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))
@@ -3011,8 +3054,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;
@@ -3044,39 +3085,10 @@
ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
}
-/* BUGBUG need to determine where peer is going to execute on bridge completion. */
+/* 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/group/bridge_construction/apps/app_followme.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_followme.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/apps/app_followme.c (original)
+++ team/group/bridge_construction/apps/app_followme.c Mon Feb 18 14:00:59 2013
@@ -1520,7 +1520,6 @@
}
res = ast_bridge_call(caller, outbound, &config);
- ast_autoservice_chan_hangup_peer(caller, outbound);
}
outrun:
Modified: team/group/bridge_construction/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/apps/app_queue.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/apps/app_queue.c (original)
+++ team/group/bridge_construction/apps/app_queue.c Mon Feb 18 14:00:59 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 */
@@ -4922,6 +4923,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,
@@ -4985,6 +4987,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;
@@ -5039,6 +5042,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
@@ -5051,6 +5055,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
*/
@@ -5105,6 +5110,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]);
}
}
@@ -5138,7 +5172,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 */
@@ -5210,9 +5244,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;
}
@@ -5447,11 +5478,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. */
@@ -5605,11 +5631,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);
}
@@ -5891,9 +5914,10 @@
time(&callstart);
transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
-/* BUGBUG need to determine where peer is going to execute on bridge completion. */
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
@@ -5928,26 +5952,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/group/bridge_construction/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_features.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_features.c Mon Feb 18 14:00:59 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);
/* Wait for peer thread to exit bridge and die. */
if (!ast_autoservice_start(bridge_channel->chan)) {
Modified: team/group/bridge_construction/funcs/func_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/funcs/func_channel.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/funcs/func_channel.c (original)
+++ team/group/bridge_construction/funcs/func_channel.c Mon Feb 18 14:00:59 2013
@@ -329,6 +329,11 @@
</function>
***/
+/*
+ * BUGBUG add CHANNEL(after_bridge_goto)=<parseable-goto> Sets an after bridge goto datastore property on the channel.
+ * CHANNEL(after_bridge_goto)=<empty> Deletes any after bridge goto datastore property on the channel.
+ */
+
#define locked_copy_string(chan, dest, source, len) \
do { \
ast_channel_lock(chan); \
Modified: team/group/bridge_construction/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging.h?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Mon Feb 18 14:00:59 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,
@@ -230,12 +230,14 @@
* for bridge technologies that mix audio. When set to 0, the bridge tech must choose a
* default interval for itself. */
unsigned int internal_mixing_interval;
- /*! Bit to indicate that the bridge thread is waiting on channels in the bridge array */
+ /*! TRUE if the bridge thread is waiting on channels in the bridge array */
unsigned int waiting:1;
- /*! Bit to indicate the bridge thread should stop */
+ /*! TRUE if the bridge thread should stop */
unsigned int stop:1;
- /*! Bit to indicate the bridge thread should refresh itself */
+ /*! TRUE if the bridge thread should refresh itself */
unsigned int refresh:1;
+ /*! TRUE if the bridge has been dissolved. Any channel that now tries to join is immediately ejected. */
+ unsigned int dissolved:1;
/*! Bridge flags to tweak behavior */
struct ast_flags feature_flags;
/*! Bridge technology that is handling the bridge */
@@ -352,13 +354,14 @@
* \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 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);
* \endcode
*
* This adds a channel pointed to by the chan pointer to the bridge pointed to by
@@ -376,7 +379,8 @@
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 pass_reference);
/*!
* \brief Impart (non-blocking) a channel onto a bridge
@@ -647,6 +651,100 @@
*/
void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan);
+/*!
+ * \brief Set channel to goto specific location after the bridge.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup after bridge goto location.
+ * \param context Context to goto after bridge.
+ * \param exten Exten to goto after bridge.
+ * \param priority Priority to goto after bridge.
+ *
+ * \details Add a channel datastore to setup the goto location
+ * when the channel leaves the bridge and run a PBX from there.
+ *
+ * \return Nothing
+ */
+void ast_after_bridge_set_goto(struct ast_channel *chan, const char *context, const char *exten, int priority);
+
+/*!
+ * \brief Set channel to run the h exten after the bridge.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup after bridge goto location.
+ * \param context Context to goto after bridge.
+ *
+ * \details Add a channel datastore to setup the goto location
+ * when the channel leaves the bridge and run a PBX from there.
+ *
+ * \return Nothing
+ */
+void ast_after_bridge_set_h(struct ast_channel *chan, const char *context);
+
+/*!
+ * \brief Set channel to go on in the dialplan after the bridge.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup after bridge goto location.
+ * \param context Current context of the caller channel.
+ * \param exten Current exten of the caller channel.
+ * \param priority Current priority of the caller channel
+ * \param parseable_goto User specified goto string from dialplan.
+ *
+ * \details Add a channel datastore to setup the goto location
+ * when the channel leaves the bridge and run a PBX from there.
+ *
+ * If parseable_goto then use the given context/exten/priority
+ * as the relative position for the parseable_goto.
+ * Else goto the given context/exten/priority+1.
+ *
+ * \return Nothing
+ */
+void ast_after_bridge_set_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto);
+
+/*!
+ * \brief Setup any after bridge goto location to begin execution.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup after bridge goto location.
+ *
+ * \details Pull off any after bridge goto location datastore and
+ * setup for dialplan execution there.
+ *
+ * \retval 0 on success. The goto location is set for a PBX to run it.
+ * \retval non-zero on error or no goto location.
+ *
+ * \note If the after bridge goto is set to run an h exten it is
+ * run here immediately.
+ */
+int ast_after_bridge_goto_setup(struct ast_channel *chan);
+
+/*!
+ * \brief Run a PBX on any after bridge goto location.
+ * \since 12.0.0
+ *
+ * \param chan Channel to execute after bridge goto location.
+ *
+ * \details Pull off any after bridge goto location datastore
+ * and run a PBX at that location.
+ *
+ * \note On return, the chan pointer is no longer valid because
+ * the channel has hung up.
+ *
+ * \return Nothing
+ */
+void ast_after_bridge_goto_run(struct ast_channel *chan);
+
+/*!
+ * \brief Discard channel after bridge goto location.
+ * \since 12.0.0
+ *
+ * \param chan Channel to discard after bridge goto location.
+ *
+ * \return Nothing
+ */
+void ast_after_bridge_goto_discard(struct ast_channel *chan);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: team/group/bridge_construction/include/asterisk/bridging_features.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_features.h?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_features.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_features.h Mon Feb 18 14:00:59 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 all participants have this flag set. */
+ AST_BRIDGE_FLAG_LONELY = (1 << 2),
};
/*! \brief Built in DTMF features */
Modified: team/group/bridge_construction/include/asterisk/bridging_technology.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging_technology.h?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging_technology.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging_technology.h Mon Feb 18 14:00:59 2013
@@ -73,7 +73,7 @@
int (*poke)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel);
/*! Formats that the bridge technology supports */
struct ast_format_cap *format_capabilities;
- /*! Bit to indicate whether the bridge technology is currently suspended or not */
+ /*! TRUE if the bridge technology is currently suspended. */
unsigned int suspended:1;
/*! Module this bridge technology belongs to. Is used for reference counting when creating/destroying a bridge. */
struct ast_module *mod;
Modified: team/group/bridge_construction/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/channel.h?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/include/asterisk/channel.h (original)
+++ team/group/bridge_construction/include/asterisk/channel.h Mon Feb 18 14:00:59 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/group/bridge_construction/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging.c?view=diff&rev=381657&r1=381656&r2=381657
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Mon Feb 18 14:00:59 2013
@@ -45,6 +45,7 @@
#include "asterisk/file.h"
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
+#include "asterisk/pbx.h"
#include "asterisk/test.h"
#include "asterisk/heap.h"
@@ -52,6 +53,7 @@
#include "asterisk/timing.h"
#include "asterisk/stringfields.h"
#include "asterisk/musiconhold.h"
+#include "asterisk/features.h"
static AST_RWLIST_HEAD_STATIC(bridge_technologies, ast_bridge_technology);
@@ -137,6 +139,7 @@
void ast_bridge_change_state_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
{
+/* BUGBUG need cause code for the bridge_channel leaving the bridge. */
ast_debug(1, "BUGBUG Setting bridge channel %p state from:%d to:%d\n",
bridge_channel, bridge_channel->state, new_state);
@@ -309,6 +312,9 @@
{
struct ast_bridge_channel *bridge_channel;
+ bridge->dissolved = 1;
+
+/* BUGBUG need a cause code on the bridge for the later ejected channels. */
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
ao2_lock(bridge_channel);
switch (bridge_channel->state) {
@@ -322,7 +328,18 @@
}
}
-/*! \brief Internal function to see whether a bridge should dissolve, and if so do it */
+/*!
+ * \internal
+ * \brief Check if a bridge should dissolve and then do it.
+ * \since 12.0.0
+ *
+ * \param bridge Bridge to check.
+ * \param bridge_channel Channel causing the check.
+ *
+ * \note On entry, bridge is already locked.
+ *
+ * \return Nothing
+ */
static void bridge_check_dissolve(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP)
@@ -550,19 +567,25 @@
}
}
-/*! \brief Bridge thread function */
+/*!
+ * \brief Bridge thread function
+ *
+ * \note The thread does not have its own reference to the
+ * bridge. The bridge ao2 object destructor will stop the
+ * thread if it is running.
+ */
static void *bridge_thread(void *data)
{
struct ast_bridge *bridge = data;
int res = 0;
+ ast_debug(1, "Started bridge thread for %p\n", bridge);
+
ao2_lock(bridge);
if (bridge->callid) {
ast_callid_threadassoc_add(bridge->callid);
}
-
- ast_debug(1, "Started bridge thread for %p\n", bridge);
/* Loop around until we are told to stop */
while (!bridge->stop) {
@@ -574,10 +597,6 @@
/* In case the refresh bit was set simply set it back to off */
bridge->refresh = 0;
-
- ast_debug(1, "Launching bridge thread function %p for bridge %p\n",
- bridge->technology->thread ? bridge->technology->thread : generic_thread_loop,
- bridge);
/*
* Execute the appropriate thread function. If the technology
@@ -597,10 +616,9 @@
}
}
+ ao2_unlock(bridge);
+
ast_debug(1, "Ending bridge thread for %p\n", bridge);
-
- ao2_unlock(bridge);
- ao2_ref(bridge, -1);
return NULL;
}
@@ -647,6 +665,16 @@
/* There should not be any channels left in the bridge. */
ast_assert(AST_LIST_EMPTY(&bridge->channels));
ast_assert(AST_LIST_EMPTY(&bridge->depart_wait));
+
+ ao2_lock(bridge);
+ if (bridge->thread != AST_PTHREADT_NULL) {
+ bridge_stop(bridge);
+ }
+ ao2_unlock(bridge);
+
+ if (bridge->callid) {
+ bridge->callid = ast_callid_unref(bridge->callid);
+ }
/* Pass off the bridge to the technology to destroy if needed */
if (bridge->technology->destroy) {
@@ -746,23 +774,9 @@
int ast_bridge_destroy(struct ast_bridge *bridge)
{
+ ast_debug(1, "Telling all channels in bridge %p to leave the party\n", bridge);
ao2_lock(bridge);
-
- if (bridge->callid) {
-/* BUGBUG the bridge callid needs to be verified. */
- 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. */
- bridge_stop(bridge);
- }
-
- ast_debug(1, "Telling all channels in bridge %p to leave the party\n", bridge);
-
- /* Drop every bridged channel, the last one will cause the bridge thread (if it exists) to exit */
bridge_force_out_all(bridge);
-
ao2_unlock(bridge);
ao2_ref(bridge, -1);
@@ -996,7 +1010,7 @@
ao2_unlock(bridge_channel);
ao2_lock(bridge_channel->bridge);
} else if (bridge_channel->suspended) {
- ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n",
+ ast_debug(1, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n",
bridge_channel, bridge_channel->bridge);
ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
ao2_unlock(bridge_channel);
@@ -1019,7 +1033,8 @@
ao2_unlock(bridge_channel->bridge);
ao2_lock(bridge_channel);
if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
- ast_debug(1, "Going into a single threaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
+ ast_debug(1, "Going into a single threaded signal wait for bridge channel %p of bridge %p\n",
+ bridge_channel, bridge_channel->bridge);
ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
}
ao2_unlock(bridge_channel);
@@ -1345,6 +1360,19 @@
}
}
+ if (bridge_channel->bridge->dissolved) {
+ /* Force out channel trying to join a dissolved bridge. */
+ ao2_lock(bridge_channel);
+ switch (bridge_channel->state) {
+ case AST_BRIDGE_CHANNEL_STATE_WAIT:
+ ast_bridge_change_state_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
+ break;
+ default:
+ break;
+ }
+ ao2_unlock(bridge_channel);
+ }
+
/* Actually execute the respective threading model, and keep our bridge thread alive */
while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
/* Update bridge pointer on channel */
@@ -1361,10 +1389,8 @@
if (bridge_channel->bridge->thread == AST_PTHREADT_NULL
&& (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_THREAD)) {
ast_debug(1, "Starting a bridge thread for bridge %p\n", bridge_channel->bridge);
- ao2_ref(bridge_channel->bridge, +1);
if (ast_pthread_create(&bridge_channel->bridge->thread, NULL, bridge_thread, bridge_channel->bridge)) {
ast_debug(1, "Failed to create a bridge thread for bridge %p, giving it another go.\n", bridge_channel->bridge);
- ao2_ref(bridge_channel->bridge, -1);
continue;
}
}
@@ -1407,8 +1433,6 @@
ao2_unlock(bridge_channel);
}
- ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
-
/* See if we need to dissolve the bridge itself if they hung up */
switch (bridge_channel->state) {
case AST_BRIDGE_CHANNEL_STATE_END:
@@ -1459,6 +1483,25 @@
}
ao2_unlock(bridge_channel);
+/* BUGBUG Revisit in regards to moving channels between bridges and local channel optimization. */
+ /* Complete any partial DTMF digit before exiting the bridge. */
+ if (ast_channel_sending_dtmf_digit(bridge_channel->chan)) {
+ ast_bridge_end_dtmf(bridge_channel->chan,
+ ast_channel_sending_dtmf_digit(bridge_channel->chan),
+ ast_channel_sending_dtmf_tv(bridge_channel->chan), "bridge end");
+ }
+
+ /*
+ * Wait for any dual redirect to complete.
+ *
+ * Must be done while "still in the bridge" for ast_async_goto()
+ * to work right.
+ */
+ while (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT)) {
+ sched_yield();
+ }
+ ast_channel_internal_bridge_set(bridge_channel->chan, NULL);
+
/* Restore original formats of the channel as they came in */
if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &formats[0]) == AST_FORMAT_CMP_NOT_EQUAL) {
ast_debug(1, "Bridge is returning %p to read format %s(%d)\n", bridge_channel, ast_getformatname(&formats[0]), formats[0].id);
@@ -1506,18 +1549,303 @@
return bridge_channel;
}
+struct after_bridge_goto_ds {
+ /*! Goto string that can be parsed by ast_parseable_goto(). */
+ const char *parseable_goto;
+ /*! Specific goto context or default context for parseable_goto. */
+ const char *context;
+ /*! Specific goto exten or default exten for parseable_goto. */
+ const char *exten;
+ /*! Specific goto priority or default priority for parseable_goto. */
+ int priority;
+ /*! TRUE if the peer should run the h exten. */
+ unsigned int run_h_exten:1;
+ /*! Specific goto location */
+ unsigned int specific:1;
+};
+
+/*!
+ * \internal
+ * \brief Destroy the after bridge goto datastore.
+ * \since 12.0.0
+ *
+ * \param data After bridge goto data to destroy.
+ *
+ * \return Nothing
+ */
+static void after_bridge_goto_destroy(void *data)
+{
+ struct after_bridge_goto_ds *after_bridge = data;
+
+ ast_free((char *) after_bridge->parseable_goto);
+ ast_free((char *) after_bridge->context);
+ ast_free((char *) after_bridge->exten);
+}
+
+/*!
+ * \internal
+ * \brief Fixup the after bridge goto datastore.
+ * \since 12.0.0
+ *
+ * \param data After bridge goto data to fixup.
+ * \param old_chan The datastore is moving from this channel.
+ * \param new_chan The datastore is moving to this channel.
+ *
+ * \return Nothing
+ */
+static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+ /* There can be only one. Discard any already on the new channel. */
+ ast_after_bridge_goto_discard(new_chan);
+}
+
+static const struct ast_datastore_info after_bridge_goto_info = {
+ .type = "after-bridge-goto",
+ .destroy = after_bridge_goto_destroy,
+ .chan_fixup = after_bridge_goto_fixup,
+};
+
+/*!
+ * \internal
+ * \brief Remove channel goto location after the bridge and return it.
+ * \since 12.0.0
+ *
+ * \param chan Channel to remove after bridge goto location.
+ *
+ * \retval datastore on success.
+ * \retval NULL on error or not found.
+ */
+static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
+{
+ struct ast_datastore *datastore;
+
+ ast_channel_lock(chan);
+ datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
+ if (datastore && ast_channel_datastore_remove(chan, datastore)) {
+ datastore = NULL;
+ }
+ ast_channel_unlock(chan);
+
+ return datastore;
+}
+
+void ast_after_bridge_goto_discard(struct ast_channel *chan)
+{
+ struct ast_datastore *datastore;
+
+ datastore = after_bridge_goto_remove(chan);
+ if (datastore) {
+ ast_datastore_free(datastore);
+ }
+}
+
+int ast_after_bridge_goto_setup(struct ast_channel *chan)
+{
+ struct ast_datastore *datastore;
+ struct after_bridge_goto_ds *after_bridge;
+ int goto_failed = -1;
+
+ /* Determine if we are going to setup a dialplan location and where. */
+ if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
+ /* An async goto has already setup a location. */
+ ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
+ if (!ast_check_hangup(chan)) {
+ goto_failed = 0;
+ }
+ return goto_failed;
+ }
+
+ /* Get after bridge goto datastore. */
+ datastore = after_bridge_goto_remove(chan);
+ if (!datastore) {
+ return goto_failed;
+ }
+
+ after_bridge = datastore->data;
+ if (after_bridge->run_h_exten) {
+ if (ast_exists_extension(chan, after_bridge->context, "h", 1,
+ S_COR(ast_channel_caller(chan)->id.number.valid,
+ ast_channel_caller(chan)->id.number.str, NULL))) {
+ ast_debug(1, "Running after bridge goto h exten %s,h,1\n",
+ ast_channel_context(chan));
+ ast_pbx_h_exten_run(chan, after_bridge->context);
+ }
+ } else if (!ast_check_hangup(chan)) {
+ if (after_bridge->specific) {
+ goto_failed = ast_explicit_goto(chan, after_bridge->context,
+ after_bridge->exten, after_bridge->priority);
+ } else if (!ast_strlen_zero(after_bridge->parseable_goto)) {
+ char *context;
+ char *exten;
+ int priority;
+
+ /* Option F(x) for Bridge(), Dial(), and Queue() */
+
+ /* Save current dialplan location in case of failure. */
+ context = ast_strdupa(ast_channel_context(chan));
[... 1200 lines stripped ...]
More information about the asterisk-commits
mailing list