[svn-commits] rmudgett: branch rmudgett/bridge_phase r381344 - in /team/rmudgett/bridge_pha...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Tue Feb 12 20:14:48 CST 2013
Author: rmudgett
Date: Tue Feb 12 20:14:44 2013
New Revision: 381344
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381344
Log:
Worked out semantics for an after bridge goto location channel property.
* Make Dial, Queue, Bridge F() option setup an after bridge goto location.
Next up need to make bridging code self manage the bridge and do some
testing.
Modified:
team/rmudgett/bridge_phase/apps/app_dial.c
team/rmudgett/bridge_phase/apps/app_queue.c
team/rmudgett/bridge_phase/funcs/func_channel.c
team/rmudgett/bridge_phase/include/asterisk/bridging.h
team/rmudgett/bridge_phase/main/bridging.c
team/rmudgett/bridge_phase/main/features.c
Modified: team/rmudgett/bridge_phase/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_dial.c?view=diff&rev=381344&r1=381343&r2=381344
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_dial.c (original)
+++ team/rmudgett/bridge_phase/apps/app_dial.c Tue Feb 12 20:14:44 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))
@@ -3042,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/rmudgett/bridge_phase/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/apps/app_queue.c?view=diff&rev=381344&r1=381343&r2=381344
==============================================================================
--- team/rmudgett/bridge_phase/apps/app_queue.c (original)
+++ team/rmudgett/bridge_phase/apps/app_queue.c Tue Feb 12 20:14:44 2013
@@ -105,6 +105,7 @@
#include "asterisk/callerid.h"
#include "asterisk/cel.h"
#include "asterisk/data.h"
+#include "asterisk/bridging.h"
/* Define, to debug reference counts on queues, without debugging reference counts on queue members */
/* #define REF_DEBUG_ONLY_QUEUES */
@@ -4921,6 +4922,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,
@@ -4984,6 +4986,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;
@@ -5038,6 +5041,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
@@ -5050,6 +5054,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
*/
@@ -5104,6 +5109,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]);
}
}
@@ -5137,7 +5171,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 */
@@ -5443,11 +5477,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. */
@@ -5601,11 +5630,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);
}
@@ -5887,9 +5913,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
@@ -5924,26 +5951,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/rmudgett/bridge_phase/funcs/func_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/funcs/func_channel.c?view=diff&rev=381344&r1=381343&r2=381344
==============================================================================
--- team/rmudgett/bridge_phase/funcs/func_channel.c (original)
+++ team/rmudgett/bridge_phase/funcs/func_channel.c Tue Feb 12 20:14:44 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/rmudgett/bridge_phase/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/bridging.h?view=diff&rev=381344&r1=381343&r2=381344
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/bridging.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/bridging.h Tue Feb 12 20:14:44 2013
@@ -640,6 +640,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/rmudgett/bridge_phase/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/bridging.c?view=diff&rev=381344&r1=381343&r2=381344
==============================================================================
--- team/rmudgett/bridge_phase/main/bridging.c (original)
+++ team/rmudgett/bridge_phase/main/bridging.c Tue Feb 12 20:14:44 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"
@@ -1503,6 +1504,286 @@
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));
+ exten = ast_strdupa(ast_channel_exten(chan));
+ priority = ast_channel_priority(chan);
+
+ /* Set current dialplan position to default dialplan position */
+ ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
+ after_bridge->priority);
+
+ /* Then perform the goto */
+ goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
+ if (goto_failed) {
+ /* Restore original dialplan location. */
+ ast_channel_context_set(chan, context);
+ ast_channel_exten_set(chan, exten);
+ ast_channel_priority_set(chan, priority);
+ }
+ } else {
+ /* Option F() for Bridge(), Dial(), and Queue() */
+ goto_failed = ast_goto_if_exists(chan, after_bridge->context,
+ after_bridge->exten, after_bridge->priority + 1);
+ }
+ if (!goto_failed) {
+ ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
+ ast_channel_context(chan),
+ ast_channel_exten(chan),
+ ast_channel_priority(chan));
+ }
+ }
+
+ /* Discard after bridge goto datastore. */
+ ast_datastore_free(datastore);
+
+ return goto_failed;
+}
+
+void ast_after_bridge_goto_run(struct ast_channel *chan)
+{
+ int goto_failed;
+
+ goto_failed = ast_after_bridge_goto_setup(chan);
+ if (goto_failed || ast_pbx_run(chan)) {
+ ast_hangup(chan);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Set after bridge goto location of channel.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup after bridge goto location.
+ * \param run_h_exten TRUE if the h exten should be run.
+ * \param specific TRUE if the context/exten/priority is exactly specified.
+ * \param context Context to goto after bridge.
+ * \param exten Exten to goto after bridge. (Could be NULL if run_h_exten)
+ * \param priority Priority to goto after bridge.
+ * \param parseable_goto User specified goto string. (Could be NULL)
+ *
+ * \details Add a channel datastore to setup the goto location
+ * when the channel leaves the bridge and run a PBX from there.
+ *
+ * If run_h_exten then execute the h exten found in the given context.
+ * Else if specific then goto the given context/exten/priority.
+ * Else 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
+ */
+static void __after_bridge_set_goto(struct ast_channel *chan, int run_h_exten, int specific, const char *context, const char *exten, int priority, const char *parseable_goto)
+{
+ struct ast_datastore *datastore;
+ struct after_bridge_goto_ds *after_bridge;
+
+ /* Sanity checks. */
+ ast_assert(chan != NULL);
+ if (!chan) {
+ return;
+ }
+ if (run_h_exten) {
+ ast_assert(run_h_exten && context);
+ if (!context) {
+ return;
+ }
+ } else {
+ ast_assert(context && exten && 0 < priority);
+ if (!context || !exten || priority < 1) {
+ return;
+ }
+ }
+
+ /* Create a new datastore. */
+ datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
+ if (!datastore) {
+ return;
+ }
+ after_bridge = ast_calloc(1, sizeof(*after_bridge));
+ if (!after_bridge) {
+ ast_datastore_free(datastore);
+ return;
+ }
+
+ /* Initialize it. */
+ after_bridge->parseable_goto = ast_strdup(parseable_goto);
+ after_bridge->context = ast_strdup(context);
+ after_bridge->exten = ast_strdup(exten);
+ after_bridge->priority = priority;
+ after_bridge->run_h_exten = run_h_exten ? 1 : 0;
+ after_bridge->specific = specific ? 1 : 0;
+ datastore->data = after_bridge;
+ if ((parseable_goto && !after_bridge->parseable_goto)
+ || (context && !after_bridge->context)
+ || (exten && !after_bridge->exten)) {
+ ast_datastore_free(datastore);
+ return;
+ }
+
+ /* Put it on the channel replacing any existing one. */
+ ast_channel_lock(chan);
+ ast_after_bridge_goto_discard(chan);
+ ast_channel_datastore_add(chan, datastore);
+ ast_channel_unlock(chan);
+}
+
+void ast_after_bridge_set_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
+{
+ __after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
+}
+
+void ast_after_bridge_set_h(struct ast_channel *chan, const char *context)
+{
+ __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
+}
+
+void ast_after_bridge_set_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
+{
+ char *p_goto;
+
+ if (!ast_strlen_zero(parseable_goto)) {
+ p_goto = ast_strdupa(parseable_goto);
+ ast_replace_subargument_delimiter(p_goto);
+ } else {
+ p_goto = NULL;
+ }
+ __after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);
+}
+
enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
struct ast_channel *chan,
struct ast_channel *swap,
@@ -1519,7 +1800,8 @@
ao2_ref(bridge, -1);
}
if (!bridge_channel) {
- return AST_BRIDGE_CHANNEL_STATE_HANGUP;
+ state = AST_BRIDGE_CHANNEL_STATE_HANGUP;
+ goto join_exit;
}
if (tech_args) {
bridge_channel->tech_args = *tech_args;
@@ -1540,6 +1822,15 @@
bridge_channel->features = NULL;
ao2_ref(bridge_channel, -1);
+
+join_exit:;
+ if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)
+ && !ast_after_bridge_goto_setup(chan)) {
+ /* Claim the after bridge goto is an async goto destination. */
+ ast_channel_lock(chan);
+ ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
+ ast_channel_unlock(chan);
+ }
return state;
}
@@ -1558,6 +1849,8 @@
bridge_channel->swap = NULL;
ast_bridge_features_destroy(bridge_channel->features);
bridge_channel->features = NULL;
+
+ ast_after_bridge_goto_discard(bridge_channel->chan);
return NULL;
}
@@ -1585,9 +1878,6 @@
ao2_ref(bridge_channel, -1);
-/* BUGBUG need to run a PBX on this channel or hangup. */
-/* BUGBUG need to start the PBX at the appropriate location. */
-/* BUGBUG need to determine where to execute in the dialplan. */
switch (state) {
case AST_BRIDGE_CHANNEL_STATE_DEPART:
case AST_BRIDGE_CHANNEL_STATE_DEPART_END:
@@ -1598,10 +1888,10 @@
case AST_BRIDGE_CHANNEL_STATE_HANGUP:
case AST_BRIDGE_CHANNEL_STATE_END:
default:
- ast_hangup(chan);
break;
}
+ ast_after_bridge_goto_run(chan);
return NULL;
}
@@ -1625,9 +1915,15 @@
/* Actually create the thread that will handle the channel */
if (independent) {
+ /* Independently imparted channels cannot have a PBX. */
+ ast_assert(!ast_channel_pbx(chan));
+
res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
bridge_channel_ind_thread, bridge_channel);
} else {
+ /* Imparted channels to be departed should not have a PBX either. */
+ ast_assert(!ast_channel_pbx(chan));
+
res = ast_pthread_create(&bridge_channel->thread, NULL,
bridge_channel_depart_thread, bridge_channel);
}
Modified: team/rmudgett/bridge_phase/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/features.c?view=diff&rev=381344&r1=381343&r2=381344
==============================================================================
--- team/rmudgett/bridge_phase/main/features.c (original)
+++ team/rmudgett/bridge_phase/main/features.c Tue Feb 12 20:14:44 2013
@@ -1142,18 +1142,16 @@
ast_channel_data_set(tobj->peer, "(Empty)");
}
-/* BUGBUG If tobj->return_to_pbx need to setup datastore where peer is going to execute on bridge completion. */
+ if (tobj->return_to_pbx) {
+ ast_after_bridge_set_goto(tobj->chan, ast_channel_context(tobj->chan),
+ ast_channel_exten(tobj->chan), ast_channel_priority(tobj->chan));
+ ast_after_bridge_set_goto(tobj->peer, ast_channel_context(tobj->peer),
+ ast_channel_exten(tobj->peer), ast_channel_priority(tobj->peer));
+ }
+
ast_bridge_call(tobj->chan, tobj->peer, &tobj->bconfig);
- if (tobj->return_to_pbx && !ast_check_hangup(tobj->chan)) {
- ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan));
- if (ast_pbx_run(tobj->chan)) {
- ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", ast_channel_name(tobj->chan));
- ast_hangup(tobj->chan);
- }
- } else {
- ast_hangup(tobj->chan);
- }
+ ast_after_bridge_goto_run(tobj->chan);
ast_free(tobj);
@@ -7759,12 +7757,17 @@
*/
static int bridge_exec(struct ast_channel *chan, const char *data)
{
- struct ast_channel *current_dest_chan, *final_dest_chan, *chans[2];
+ struct ast_channel *current_dest_chan;
+ struct ast_channel *final_dest_chan;
+ struct ast_channel *chans[2];
char *tmp_data = NULL;
struct ast_flags opts = { 0, };
struct ast_bridge_config bconfig = { { 0, }, };
char *opt_args[OPT_ARG_ARRAY_SIZE];
struct timeval calldurationlimit = { 0, };
+ const char *context;
+ const char *extension;
+ int priority;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(dest_chan);
@@ -7923,56 +7926,28 @@
if (ast_test_flag(&opts, OPT_CALLER_PARK))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
-/* BUGBUG need to determine where peer is going to execute on bridge completion. */
+ /* Setup after bridge goto location. */
+ 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(final_dest_chan, context, extension, priority,
+ opt_args[OPT_ARG_CALLEE_GO_ON]);
+ } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
+ ast_channel_lock(final_dest_chan);
+ context = ast_strdupa(ast_channel_context(final_dest_chan));
+ extension = ast_strdupa(ast_channel_exten(final_dest_chan));
+ priority = ast_channel_priority(final_dest_chan);
+ ast_channel_unlock(final_dest_chan);
+ ast_after_bridge_set_goto(final_dest_chan, context, extension, priority);
+ }
+
ast_bridge_call(chan, final_dest_chan, &bconfig);
/* The bridge has ended, set BRIDGERESULT to SUCCESS. */
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
-
- /* If the other channel has not been hung up, return it to the PBX */
- if (!ast_check_hangup(final_dest_chan)) {
- if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
- char *caller_context;
- char *caller_extension;
- int caller_priority;
- int goto_opt;
-
- ast_channel_lock(chan);
- caller_context = ast_strdupa(ast_channel_context(chan));
- caller_extension = ast_strdupa(ast_channel_exten(chan));
- caller_priority = ast_channel_priority(chan);
- ast_channel_unlock(chan);
-
- if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
- /* Set current dialplan position to bridger dialplan position */
- goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority)
- /* Then perform the goto */
- || ast_parseable_goto(final_dest_chan, opt_args[OPT_ARG_CALLEE_GO_ON]);
- } else { /* F() */
- goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority + 1);
- }
- if (goto_opt || ast_pbx_start(final_dest_chan)) {
- ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
- }
- } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
- ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
- ast_channel_context(final_dest_chan), ast_channel_exten(final_dest_chan),
- ast_channel_priority(final_dest_chan), ast_channel_name(final_dest_chan));
-
- if (ast_pbx_start(final_dest_chan)) {
- ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan));
- ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
- } else {
- ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan));
- }
- } else {
- ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
- }
- } else {
- ast_debug(1, "chan %s was hungup\n", ast_channel_name(final_dest_chan));
- ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
- }
done:
ast_free((char *) bconfig.warning_sound);
ast_free((char *) bconfig.end_sound);
More information about the svn-commits
mailing list