Move after bridge callbacks into their own file
authorMatthew Jordan <mjordan@digium.com>
Thu, 25 Jul 2013 02:20:23 +0000 (02:20 +0000)
committerMatthew Jordan <mjordan@digium.com>
Thu, 25 Jul 2013 02:20:23 +0000 (02:20 +0000)
One more major refactoring to go.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395367 65c4cc65-6c06-0410-ace0-fbb531ad65f3

20 files changed:
apps/app_agent_pool.c
apps/app_dial.c
apps/app_queue.c
bridges/bridge_builtin_features.c
bridges/bridge_builtin_interval_features.c
bridges/bridge_softmix.c
funcs/func_channel.c
include/asterisk/bridging.h
include/asterisk/bridging_after.h [new file with mode: 0644]
include/asterisk/bridging_channel.h
include/asterisk/bridging_channel_internal.h
include/asterisk/bridging_features.h
include/asterisk/bridging_internal.h
include/asterisk/bridging_technology.h
main/bridging.c
main/bridging_after.c [new file with mode: 0644]
main/bridging_basic.c
main/bridging_channel.c
main/features.c
res/parking/parking_bridge_features.c

index 956a97e..a9f256e 100644 (file)
@@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/bridging.h"
 #include "asterisk/bridging_internal.h"
 #include "asterisk/bridging_basic.h"
+#include "asterisk/bridging_after.h"
 #include "asterisk/config_options.h"
 #include "asterisk/features_config.h"
 #include "asterisk/astobj2.h"
@@ -1055,7 +1056,7 @@ static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, stru
 
        if (!caller_bridge) {
                /* Reset agent. */
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
                return;
        }
        res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan,
@@ -1063,7 +1064,7 @@ static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, stru
        if (res) {
                /* Reset agent. */
                ast_bridge_destroy(caller_bridge);
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
                return;
        }
        ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_ANSWER, NULL, 0);
@@ -1159,13 +1160,13 @@ static int bridge_agent_hold_heartbeat(struct ast_bridge *bridge, struct ast_bri
 
        if (deferred_logoff) {
                ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username);
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
        } else if (probation_timedout) {
                ast_debug(1, "Agent %s: Login complete.\n", agent->username);
                agent_devstate_changed(agent->username);
        } else if (ack_timedout) {
                ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username);
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
        } else if (wrapup_timedout) {
                ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username);
                agent_devstate_changed(agent->username);
@@ -1175,7 +1176,7 @@ static int bridge_agent_hold_heartbeat(struct ast_bridge *bridge, struct ast_bri
 }
 
 static void agent_after_bridge_cb(struct ast_channel *chan, void *data);
-static void agent_after_bridge_cb_failed(enum ast_after_bridge_cb_reason reason, void *data);
+static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data);
 
 /*!
  * \internal
@@ -1252,7 +1253,7 @@ static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_cha
        }
 
        if (swap) {
-               res = ast_after_bridge_callback_set(chan, agent_after_bridge_cb,
+               res = ast_bridge_set_after_callback(chan, agent_after_bridge_cb,
                        agent_after_bridge_cb_failed, chan);
                if (res) {
                        ast_channel_remove_bridge_role(chan, "holding_participant");
@@ -1270,7 +1271,7 @@ static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_cha
                 * agent will have some slightly different behavior in corner
                 * cases.
                 */
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
                return 0;
        }
 
@@ -1620,7 +1621,7 @@ static void agent_after_bridge_cb(struct ast_channel *chan, void *data)
        ao2_ref(agent, -1);
 }
 
-static void agent_after_bridge_cb_failed(enum ast_after_bridge_cb_reason reason, void *data)
+static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
 {
        struct ast_channel *chan = data;
        struct agent_pvt *agent;
@@ -1631,7 +1632,7 @@ static void agent_after_bridge_cb_failed(enum ast_after_bridge_cb_reason reason,
        }
        ast_log(LOG_WARNING, "Agent %s: Forced logout.  Lost control of %s because: %s\n",
                agent->username, ast_channel_name(chan),
-               ast_after_bridge_cb_reason_string(reason));
+               ast_bridge_after_cb_reason_string(reason));
        agent_lock(agent);
        agent_logout(agent);
        ao2_ref(agent, -1);
@@ -1704,7 +1705,7 @@ static void caller_abort_agent(struct agent_pvt *agent)
        }
 
        /* Kick the agent out of the holding bridge to reset it. */
-       ast_bridge_channel_leave_bridge_nolock(logged, AST_BRIDGE_CHANNEL_STATE_END);
+       ast_bridge_channel_leave_bridge_nolock(logged, BRIDGE_CHANNEL_STATE_END);
        ast_bridge_channel_unlock(logged);
 }
 
@@ -1714,7 +1715,7 @@ static int caller_safety_timeout(struct ast_bridge *bridge, struct ast_bridge_ch
 
        if (agent->state == AGENT_STATE_CALL_PRESENT) {
                ast_verb(3, "Agent '%s' did not respond.  Safety timeout.\n", agent->username);
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
                caller_abort_agent(agent);
        }
 
index 0a43197..6d7c1ab 100644 (file)
@@ -67,6 +67,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/dial.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/bridging.h"
+#include "asterisk/bridging_after.h"
 #include "asterisk/features_config.h"
 
 /*** DOCUMENTATION
@@ -201,7 +202,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <argument name="exten" required="false" />
                                        <argument name="priority" required="true" />
                                        <para>If the call is answered, transfer the calling party to
-                                       the specified <replaceable>priority</replaceable> and the called party to the specified 
+                                       the specified <replaceable>priority</replaceable> and the called party to the specified
                                        <replaceable>priority</replaceable> plus one.</para>
                                        <note>
                                                <para>You cannot use any additional action post answer options in conjunction with this option.</para>
@@ -290,7 +291,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <argument name="arg" multiple="true">
                                                <para>Macro arguments</para>
                                        </argument>
-                                       <para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel 
+                                       <para>Execute the specified <replaceable>macro</replaceable> for the <emphasis>called</emphasis> channel
                                        before connecting to the calling channel. Arguments can be specified to the Macro
                                        using <literal>^</literal> as a delimiter. The macro can set the variable
                                        <variable>MACRO_RESULT</variable> to specify the following actions after the macro is
@@ -332,7 +333,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                                <para>With <replaceable>delete</replaceable> set to <literal>1</literal>, the introduction will
                                                always be deleted.</para>
                                        </argument>
-                                       <para>This option is a modifier for the call screening/privacy mode. (See the 
+                                       <para>This option is a modifier for the call screening/privacy mode. (See the
                                        <literal>p</literal> and <literal>P</literal> options.) It specifies
                                        that no introductions are to be saved in the <directory>priv-callerintros</directory>
                                        directory.</para>
@@ -353,7 +354,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <argument name="mode">
                                                <para>With <replaceable>mode</replaceable> either not specified or set to <literal>1</literal>,
                                                the originator hanging up will cause the phone to ring back immediately.</para>
-                                               <para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator 
+                                               <para>With <replaceable>mode</replaceable> set to <literal>2</literal>, when the operator
                                                flashes the trunk, it will ring their phone back.</para>
                                        </argument>
                                        <para>Enables <emphasis>operator services</emphasis> mode.  This option only
@@ -1071,7 +1072,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                        /* If we are calling a single channel, and not providing ringback or music, */
                        /* then, make them compatible for in-band tone purpose */
                        if (ast_channel_make_compatible(outgoing->chan, in) < 0) {
-                               /* If these channels can not be made compatible, 
+                               /* If these channels can not be made compatible,
                                 * there is no point in continuing.  The bridge
                                 * will just fail if it gets that far.
                                 */
@@ -1765,7 +1766,7 @@ static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
 
                /*! \page DialPrivacy Dial Privacy scripts
                 * \par priv-callee-options script:
-                * \li Dial 1 if you wish this caller to reach you directly in the future, 
+                * \li Dial 1 if you wish this caller to reach you directly in the future,
                 *      and immediately connect to their incoming call.
                 * \li Dial 2 if you wish to send this caller to voicemail now and forevermore.
                 * \li Dial 3 to send this caller to the torture menus, now and forevermore.
@@ -1891,7 +1892,7 @@ static int setup_privacy_args(struct privacy_args *pa,
        } else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
                ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
        }
-       
+
        if (pa->privdb_val == AST_PRIVACY_DENY) {
                ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
                ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status));
@@ -2021,14 +2022,14 @@ static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_ch
                ast_channel_lock(chan);
                context = ast_strdupa(ast_channel_context(chan));
                ast_channel_unlock(chan);
-               ast_after_bridge_set_h(peer, context);
+               ast_bridge_set_after_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,
+               ast_bridge_set_after_go_on(peer, context, extension, priority,
                        opt_args[OPT_ARG_CALLEE_GO_ON]);
        }
 }
@@ -2444,7 +2445,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                        /* We are on the only destination. */
                        ast_rtp_instance_early_bridge_make_compatible(tc, chan);
                }
-               
+
                /* Inherit specially named variables from parent channel */
                ast_channel_inherit_variables(chan, tc);
                ast_channel_datastore_inherit(chan, tc);
@@ -2698,7 +2699,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                /* If appropriate, log that we have a destination channel and set the answer time */
                if (ast_channel_name(peer))
                        pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
-               
+
                ast_channel_lock(peer);
                number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
                if (ast_strlen_zero(number)) {
@@ -2967,7 +2968,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                                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)
+                       if (ast_bridge_setup_after_goto(peer)
                                || ast_pbx_start(peer)) {
                                ast_autoservice_chan_hangup_peer(chan, peer);
                        }
@@ -2997,7 +2998,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                        config.end_bridge_callback = end_bridge_callback;
                        config.end_bridge_callback_data = chan;
                        config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
-                       
+
                        if (moh) {
                                moh = 0;
                                ast_moh_stop(chan);
index 8c5291a..6b89a70 100644 (file)
@@ -109,6 +109,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stasis_message_router.h"
 #include "asterisk/bridging.h"
+#include "asterisk/bridging_after.h"
 
 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
 /* #define REF_DEBUG_ONLY_QUEUES */
@@ -5293,7 +5294,7 @@ static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_ch
                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,
+               ast_bridge_set_after_go_on(peer, context, extension, priority,
                        opt_args[OPT_ARG_CALLEE_GO_ON]);
        }
 }
index 1252240..00c8871 100644 (file)
@@ -483,7 +483,7 @@ static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *
         * bridge_channel to force the channel out of the bridge and the
         * core takes care of the rest.
         */
-       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
        return 0;
 }
 
index 7e5291a..5a02991 100644 (file)
@@ -58,7 +58,7 @@ static int bridge_features_duration_callback(struct ast_bridge *bridge, struct a
                ast_stream_and_wait(bridge_channel->chan, limits->duration_sound, AST_DIGIT_NONE);
        }
 
-       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
 
        ast_test_suite_event_notify("BRIDGE_TIMELIMIT", "Channel1: %s", ast_channel_name(bridge_channel->chan));
        return -1;
@@ -114,7 +114,7 @@ static int bridge_features_connect_callback(struct ast_bridge *bridge, struct as
 {
        struct ast_bridge_features_limits *limits = hook_pvt;
 
-       if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
                return -1;
        }
 
@@ -126,7 +126,7 @@ static int bridge_features_warning_callback(struct ast_bridge *bridge, struct as
 {
        struct ast_bridge_features_limits *limits = hook_pvt;
 
-       if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (bridge_channel->state == 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);
        }
index dcf11ec..503c0b9 100644 (file)
@@ -576,7 +576,7 @@ static void softmix_bridge_write_voice(struct ast_bridge *bridge, struct ast_bri
        ast_mutex_unlock(&sc->lock);
 
        if (update_talking != -1) {
-               ast_bridge_notify_talking(bridge_channel, update_talking);
+               ast_bridge_channel_notify_talking(bridge_channel, update_talking);
        }
 }
 
index 4d098c3..f4aa763 100644 (file)
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stringfields.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/bridging_basic.h"
+#include "asterisk/bridging_after.h"
 
 /*** DOCUMENTATION
        <function name="CHANNELS" language="en_US">
@@ -531,7 +532,7 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
 
                locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len);
        } else if (!strcasecmp(data, "after_bridge_goto")) {
-               ast_after_bridge_goto_read(chan, buf, len);
+               ast_bridge_read_after_goto(chan, buf, len);
        } else if (!strcasecmp(data, "amaflags")) {
                ast_channel_lock(chan);
                snprintf(buf, len, "%d", ast_channel_amaflags(chan));
@@ -575,9 +576,9 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio
                locked_string_field_set(chan, userfield, value);
        else if (!strcasecmp(data, "after_bridge_goto")) {
                if (ast_strlen_zero(value)) {
-                       ast_after_bridge_goto_discard(chan);
+                       ast_bridge_discard_after_goto(chan);
                } else {
-                       ast_after_bridge_set_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
+                       ast_bridge_set_after_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
                }
        } else if (!strcasecmp(data, "amaflags")) {
                ast_channel_lock(chan);
index bc16ae0..7e22dba 100644 (file)
@@ -447,7 +447,7 @@ void ast_bridge_notify_masquerade(struct ast_channel *chan);
  * If channel specific features are enabled a pointer to the features structure
  * can be specified in the features parameter.
  */
-enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+enum bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
        struct ast_channel *chan,
        struct ast_channel *swap,
        struct ast_bridge_features *features,
@@ -884,202 +884,6 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
  */
 enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee,
                struct ast_channel *to_transfer_target);
-/*!
- * \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.
- *
- * \note chan is locked by this function.
- *
- * \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.
- *
- * \note chan is locked by this function.
- *
- * \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.
- *
- * \note chan is locked by this function.
- *
- * \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.
- *
- * \note chan is locked by this function.
- *
- * \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.
- *
- * \note chan is locked by this function.
- *
- * \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.
- *
- * \note chan is locked by this function.
- *
- * \return Nothing
- */
-void ast_after_bridge_goto_discard(struct ast_channel *chan);
-
-/*!
- * \brief Read after bridge goto if it exists
- * \since 12.0.0
- *
- * \param chan Channel to read the after bridge goto parseable goto string from
- * \param buffer Buffer to write the after bridge goto data to
- * \param buf_size size of the buffer being written to
- */
-void ast_after_bridge_goto_read(struct ast_channel *chan, char *buffer, size_t buf_size);
-
-/*! Reason the the after bridge callback will not be called. */
-enum ast_after_bridge_cb_reason {
-       /*! The datastore is being destroyed.  Likely due to hangup. (Enum value must be zero.) */
-       AST_AFTER_BRIDGE_CB_REASON_DESTROY,
-       /*! Something else replaced the callback with another. */
-       AST_AFTER_BRIDGE_CB_REASON_REPLACED,
-       /*! The callback was removed because of a masquerade. (fixup) */
-       AST_AFTER_BRIDGE_CB_REASON_MASQUERADE,
-       /*! The channel was departed from the bridge. */
-       AST_AFTER_BRIDGE_CB_REASON_DEPART,
-       /*! Was explicitly removed by external code. */
-       AST_AFTER_BRIDGE_CB_REASON_REMOVED,
-};
-
-/*!
- * \brief After bridge callback failed.
- * \since 12.0.0
- *
- * \param reason Reason callback is failing.
- * \param data Extra data what setup the callback wanted to pass.
- *
- * \note Called when the channel leaves the bridging system or
- * is destroyed.
- *
- * \return Nothing
- */
-typedef void (*ast_after_bridge_cb_failed)(enum ast_after_bridge_cb_reason reason, void *data);
-
-/*!
- * \brief After bridge callback function.
- * \since 12.0.0
- *
- * \param chan Channel just leaving bridging system.
- * \param data Extra data what setup the callback wanted to pass.
- *
- * \return Nothing
- */
-typedef void (*ast_after_bridge_cb)(struct ast_channel *chan, void *data);
-
-/*!
- * \brief Discard channel after bridge callback.
- * \since 12.0.0
- *
- * \param chan Channel to discard after bridge callback.
- * \param reason Why are we doing this.
- *
- * \note chan is locked by this function.
- *
- * \return Nothing
- */
-void ast_after_bridge_callback_discard(struct ast_channel *chan, enum ast_after_bridge_cb_reason reason);
-
-/*!
- * \brief Setup an after bridge callback for when the channel leaves the bridging system.
- * \since 12.0.0
- *
- * \param chan Channel to setup an after bridge callback on.
- * \param callback Function to call when the channel leaves the bridging system.
- * \param failed Function to call when it will not be calling the callback.
- * \param data Extra data to pass with the callback.
- *
- * \note chan is locked by this function.
- *
- * \note failed is called when the channel leaves the bridging
- * system or is destroyed.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_after_bridge_callback_set(struct ast_channel *chan, ast_after_bridge_cb callback, ast_after_bridge_cb_failed failed, void *data);
-
-/*!
- * \brief Get a string representation of an after bridge callback reason
- * \since 12.0.0
- *
- * \param reason The reason to interpret to a string
- * \retval NULL Unrecognized reason
- * \retval non-NULL String representation of reason
- */
-const char *ast_after_bridge_cb_reason_string(enum ast_after_bridge_cb_reason reason);
 
 /*!
  * \brief Get a container of all channels in the bridge
diff --git a/include/asterisk/bridging_after.h b/include/asterisk/bridging_after.h
new file mode 100644 (file)
index 0000000..53f30b9
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@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 After Bridge Execution API
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_BRIDGING_AFTER_H
+#define _ASTERISK_BRIDGING_AFTER_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*! Reason the the after bridge callback will not be called. */
+enum ast_bridge_after_cb_reason {
+       /*! The datastore is being destroyed.  Likely due to hangup. (Enum value must be zero.) */
+       AST_BRIDGE_AFTER_CB_REASON_DESTROY,
+       /*! Something else replaced the callback with another. */
+       AST_BRIDGE_AFTER_CB_REASON_REPLACED,
+       /*! The callback was removed because of a masquerade. (fixup) */
+       AST_BRIDGE_AFTER_CB_REASON_MASQUERADE,
+       /*! The channel was departed from the bridge. */
+       AST_BRIDGE_AFTER_CB_REASON_DEPART,
+       /*! Was explicitly removed by external code. */
+       AST_BRIDGE_AFTER_CB_REASON_REMOVED,
+};
+
+/*!
+ * \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.
+ *
+ * \note chan is locked by this function.
+ *
+ * \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_bridge_set_after_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.
+ *
+ * \note chan is locked by this function.
+ *
+ * \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_bridge_set_after_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.
+ *
+ * \note chan is locked by this function.
+ *
+ * \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_bridge_set_after_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.
+ *
+ * \note chan is locked by this function.
+ *
+ * \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_bridge_setup_after_goto(struct ast_channel *chan);
+
+/*!
+ * \brief Run any after bridge callback.
+ * \since 12.0.0
+ *
+ * \param chan Channel to run after bridge callback.
+ *
+ * \return Nothing
+ */
+void ast_bridge_run_after_callback(struct ast_channel *chan);
+
+/*!
+ * \brief Run discarding any after bridge callbacks.
+ * \since 12.0.0
+ *
+ * \param chan Channel to run after bridge callback.
+ *
+ * \return Nothing
+ */
+void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason);
+
+/*!
+ * \brief Run a PBX on any after bridge goto location.
+ * \since 12.0.0
+ *
+ * \param chan Channel to execute after bridge goto location.
+ *
+ * \note chan is locked by this function.
+ *
+ * \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_bridge_run_after_goto(struct ast_channel *chan);
+
+/*!
+ * \brief Discard channel after bridge goto location.
+ * \since 12.0.0
+ *
+ * \param chan Channel to discard after bridge goto location.
+ *
+ * \note chan is locked by this function.
+ *
+ * \return Nothing
+ */
+void ast_bridge_discard_after_goto(struct ast_channel *chan);
+
+/*!
+ * \brief Read after bridge goto if it exists
+ * \since 12.0.0
+ *
+ * \param chan Channel to read the after bridge goto parseable goto string from
+ * \param buffer Buffer to write the after bridge goto data to
+ * \param buf_size size of the buffer being written to
+ */
+void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size);
+
+/*!
+ * \brief After bridge callback failed.
+ * \since 12.0.0
+ *
+ * \param reason Reason callback is failing.
+ * \param data Extra data what setup the callback wanted to pass.
+ *
+ * \note Called when the channel leaves the bridging system or
+ * is destroyed.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_after_cb_failed)(enum ast_bridge_after_cb_reason reason, void *data);
+
+/*!
+ * \brief After bridge callback function.
+ * \since 12.0.0
+ *
+ * \param chan Channel just leaving bridging system.
+ * \param data Extra data what setup the callback wanted to pass.
+ *
+ * \return Nothing
+ */
+typedef void (*ast_bridge_after_cb)(struct ast_channel *chan, void *data);
+
+/*!
+ * \brief Setup an after bridge callback for when the channel leaves the bridging system.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup an after bridge callback on.
+ * \param callback Function to call when the channel leaves the bridging system.
+ * \param failed Function to call when it will not be calling the callback.
+ * \param data Extra data to pass with the callback.
+ *
+ * \note chan is locked by this function.
+ *
+ * \note failed is called when the channel leaves the bridging
+ * system or is destroyed.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data);
+
+/*!
+ * \brief Get a string representation of an after bridge callback reason
+ * \since 12.0.0
+ *
+ * \param reason The reason to interpret to a string
+ * \retval NULL Unrecognized reason
+ * \retval non-NULL String representation of reason
+ */
+const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_BRIDGING_H */
index cdbb2ec..f58fba7 100644 (file)
 
 /*!
  * \file
- * \brief Bridging Channel API
+ * \page AstBridgeChannel Bridging Channel API
  *
  * An API that act on a channel in a bridge. Note that while the
  * \ref ast_bridge_channel is owned by a channel, it should only be used
  * by members of the bridging system. The only places where this API should
  * be used is:
- *  - The \ref AstBridging API itself
- *  - Bridge mixing technologies
- *  - Bridge sub-classes
+ *  \arg \ref AstBridging API itself
+ *  \arg Bridge mixing technologies
+ *  \arg Bridge sub-classes
  *
  * In general, anywhere else it is unsafe to use this API. Care should be
  * taken when using this API to ensure that the locking order remains
  * correct. The locking order must be:
- *  - The \ref ast_bridge
- *  - The \ref ast_bridge_channel
- *  - The \ref ast_channel
+ *  \arg The \ref \c ast_bridge
+ *  \arg The \ref \c ast_bridge_channel
+ *  \arg The \ref \c ast_channel
  *
  * \author Joshua Colp <jcolp@digium.com>
  * \author Richard Mudgett <rmudgett@digium.com>
  * \author Matt Jordan <mjordan@digium.com>
  *
  * See Also:
- * \ref bridging.h
+ * \arg \ref AstBridging
  * \arg \ref AstCREDITS
  */
 
@@ -56,22 +56,22 @@ extern "C" {
 #include "asterisk/bridging_technology.h"
 
 /*! \brief State information about a bridged channel */
-enum ast_bridge_channel_state {
+enum bridge_channel_state {
        /*! Waiting for a signal (Channel in the bridge) */
-       AST_BRIDGE_CHANNEL_STATE_WAIT = 0,
+       BRIDGE_CHANNEL_STATE_WAIT = 0,
        /*! Bridged channel was forced out and should be hung up (Bridge may dissolve.) */
-       AST_BRIDGE_CHANNEL_STATE_END,
+       BRIDGE_CHANNEL_STATE_END,
        /*! Bridged channel was forced out. Don't dissolve the bridge regardless */
-       AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
+       BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
 };
 
-enum ast_bridge_channel_thread_state {
+enum bridge_channel_thread_state {
        /*! Bridge channel thread is idle/waiting. */
-       AST_BRIDGE_CHANNEL_THREAD_IDLE,
+       BRIDGE_CHANNEL_THREAD_IDLE,
        /*! Bridge channel thread is writing a normal/simple frame. */
-       AST_BRIDGE_CHANNEL_THREAD_SIMPLE,
+       BRIDGE_CHANNEL_THREAD_SIMPLE,
        /*! Bridge channel thread is processing a frame. */
-       AST_BRIDGE_CHANNEL_THREAD_FRAME,
+       BRIDGE_CHANNEL_THREAD_FRAME,
 };
 
 struct ast_bridge;
@@ -85,7 +85,7 @@ struct ast_bridge_channel {
        /*! Condition, used if we want to wake up a thread waiting on the bridged channel */
        ast_cond_t cond;
        /*! Current bridged channel state */
-       enum ast_bridge_channel_state state;
+       enum bridge_channel_state state;
        /*! Asterisk channel participating in the bridge */
        struct ast_channel *chan;
        /*! Asterisk channel we are swapping with (if swapping) */
@@ -154,7 +154,7 @@ struct ast_bridge_channel {
         *
         * \note Needs to be atomically settable.
         */
-       enum ast_bridge_channel_thread_state activity;
+       enum bridge_channel_thread_state activity;
 };
 
 /*!
@@ -217,6 +217,24 @@ static inline void _ast_bridge_channel_unlock(struct ast_bridge_channel *bridge_
 void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel);
 
 /*!
+ * \brief Lets the bridging indicate when a bridge channel has stopped or started talking.
+ *
+ * \note All DSP functionality on the bridge has been pushed down to the lowest possible
+ * layer, which in this case is the specific bridging technology being used. Since it
+ * is necessary for the knowledge of which channels are talking to make its way up to the
+ * application, this function has been created to allow the bridging technology to communicate
+ * that information with the bridging core.
+ *
+ * \param bridge_channel The bridge channel that has either started or stopped talking.
+ * \param started_talking set to 1 when this indicates the channel has started talking set to 0
+ * when this indicates the channel has stopped talking.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_bridge_channel_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking);
+
+/*!
  * \brief Set bridge channel state to leave bridge (if not leaving already).
  *
  * \param bridge_channel Channel to change the state on
@@ -225,14 +243,14 @@ void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel);
  * Example usage:
  *
  * \code
- * ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+ * ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
  * \endcode
  *
  * This places the channel pointed to by bridge_channel into the
- * state AST_BRIDGE_CHANNEL_STATE_END if it was
- * AST_BRIDGE_CHANNEL_STATE_WAIT before.
+ * state BRIDGE_CHANNEL_STATE_END if it was
+ * BRIDGE_CHANNEL_STATE_WAIT before.
  */
-void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state);
+void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state);
 
 /*!
  * \brief Set bridge channel state to leave bridge (if not leaving already).
@@ -243,14 +261,82 @@ void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel,
  * Example usage:
  *
  * \code
- * ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
+ * ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
  * \endcode
  *
  * This places the channel pointed to by bridge_channel into the
- * state AST_BRIDGE_CHANNEL_STATE_END if it was
- * AST_BRIDGE_CHANNEL_STATE_WAIT before.
+ * state BRIDGE_CHANNEL_STATE_END if it was
+ * BRIDGE_CHANNEL_STATE_WAIT before.
+ */
+void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state);
+
+/*!
+ * \brief Get the peer bridge channel of a two party bridge.
+ * \since 12.0.0
+ *
+ * \param bridge_channel What to get the peer of.
+ *
+ * \note On entry, bridge_channel->bridge is already locked.
+ *
+ * \note This is an internal bridge function.
+ *
+ * \retval peer on success.
+ * \retval NULL no peer channel.
+ */
+struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel);
+
+/*!
+ * \brief Restore the formats of a bridge channel's channel to how they were before bridge_channel_internal_join
+ * \since 12.0.0
+ *
+ * \param bridge_channel Channel to restore
+ */
+void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel);
+
+/*!
+ * \brief Adjust the bridge_channel's bridge merge inhibit request count.
+ * \since 12.0.0
+ *
+ * \param bridge_channel What to operate on.
+ * \param request Inhibit request increment.
+ *     (Positive to add requests.  Negative to remove requests.)
+ *
+ * \note This API call is meant for internal bridging operations.
+ *
+ * \retval bridge adjusted merge inhibit with reference count.
+ */
+struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request);
+
+/*!
+ * \internal
+ * \brief Update the linkedids for all channels in a bridge
+ * \since 12.0.0
+ *
+ * \param bridge_channel The channel joining the bridge
+ * \param swap The channel being swapped out of the bridge. May be NULL.
+ *
+ * \note The bridge must be locked prior to calling this function. This should be called
+ * during a \ref bridge_channel_internal_push operation, typically by a sub-class of a bridge
+ */
+void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
+
+/*!
+ * \internal
+ * \brief Update the accountcodes for a channel entering a bridge
+ * \since 12.0.0
+ *
+ * This function updates the accountcode and peeraccount on channels in two-party
+ * bridges. In multi-party bridges, peeraccount is not set - it doesn't make much sense -
+ * however accountcode propagation will still occur if the channel joining has an
+ * accountcode.
+ *
+ * \param bridge_channel The channel joining the bridge
+ * \param swap The channel being swapped out of the bridge. May be NULL.
+ *
+ * \note The bridge must be locked prior to calling this function. This should be called
+ * during a \ref bridge_channel_internal_push operation, typically by a sub-class of a bridge
  */
-void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state);
+void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
 
 /*!
  * \brief Write a frame to the specified bridge_channel.
@@ -497,79 +583,6 @@ int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel,
 int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid,
        const char *parker_uuid, const char *app_data);
 
-/*!
- * \brief Restore the formats of a bridge channel's channel to how they were before bridge_channel_join
- * \since 12.0.0
- *
- * \param bridge_channel Channel to restore
- */
-void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel);
-
-/*!
- * \brief Get the peer bridge channel of a two party bridge.
- * \since 12.0.0
- *
- * \param bridge_channel What to get the peer of.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \note This is an internal bridge function.
- *
- * \retval peer on success.
- * \retval NULL no peer channel.
- */
-struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel);
-
-struct blind_transfer_data {
-       char exten[AST_MAX_EXTENSION];
-       char context[AST_MAX_CONTEXT];
-};
-
-/*!
- * \brief Adjust the bridge_channel's bridge merge inhibit request count.
- * \since 12.0.0
- *
- * \param bridge_channel What to operate on.
- * \param request Inhibit request increment.
- *     (Positive to add requests.  Negative to remove requests.)
- *
- * \note This API call is meant for internal bridging operations.
- *
- * \retval bridge adjusted merge inhibit with reference count.
- */
-struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request);
-
-/*!
- * \internal
- * \brief Update the linkedids for all channels in a bridge
- * \since 12.0.0
- *
- * \param bridge_channel The channel joining the bridge
- * \param swap The channel being swapped out of the bridge. May be NULL.
- *
- * \note The bridge must be locked prior to calling this function. This should be called
- * during a \ref bridge_channel_push operation, typically by a sub-class of a bridge
- */
-void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
-
-/*!
- * \internal
- * \brief Update the accountcodes for a channel entering a bridge
- * \since 12.0.0
- *
- * This function updates the accountcode and peeraccount on channels in two-party
- * bridges. In multi-party bridges, peeraccount is not set - it doesn't make much sense -
- * however accountcode propagation will still occur if the channel joining has an
- * accountcode.
- *
- * \param bridge_channel The channel joining the bridge
- * \param swap The channel being swapped out of the bridge. May be NULL.
- *
- * \note The bridge must be locked prior to calling this function. This should be called
- * during a \ref bridge_channel_push operation, typically by a sub-class of a bridge
- */
-void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap);
-
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
index cbfa20a..6c3add1 100644 (file)
@@ -16,6 +16,9 @@
  * at the top of the source tree.
  */
 
+#ifndef _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H
+#define _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H
+
 /*!
  * \file
  * \brief Private Bridging Channel API
  * \author Matt Jordan <mjordan@digium.com>
  *
  * A private API to manipulate channels in a bridge. These can be called on a channel in
- * a bridge by the bridging API, but should not be called by external consumers of the
- * Bridging API.
+ * a bridge by \ref bridging.c. These functions should not be called elsewhere, including
+ * by other members of the Bridging API.
  *
  * See Also:
  * \arg \ref AstCREDITS
+ * \arg \ref Ast
  */
 
-#ifndef _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H
-#define _ASTERISK_PRIVATE_BRIDGING_CHANNEL_H
-
 /*!
  * \internal
  * \brief Actions that can be taken on a channel in a bridge
@@ -73,6 +74,18 @@ enum bridge_channel_action_type {
 
 /*!
  * \internal
+ * \brief Allocate a new ao2 ref counted bridge_channel
+ * \since 12.0.0
+ *
+ * \param bridge The bridge to make the bridge_channel for
+ *
+ * \retval NULL on error
+ * \retval ao2 ref counted object on success
+ */
+struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge);
+
+/*!
+ * \internal
  * \brief Push the bridge channel into its specified bridge.
  * \since 12.0.0
  *
@@ -83,7 +96,7 @@ enum bridge_channel_action_type {
  * \retval 0 on success.
  * \retval -1 on failure.  The channel did not get pushed.
  */
-int bridge_channel_push(struct ast_bridge_channel *bridge_channel);
+int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \internal
@@ -96,7 +109,7 @@ int bridge_channel_push(struct ast_bridge_channel *bridge_channel);
  *
  * \return Nothing
  */
-void bridge_channel_pull(struct ast_bridge_channel *bridge_channel);
+void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \internal
@@ -108,7 +121,7 @@ void bridge_channel_pull(struct ast_bridge_channel *bridge_channel);
  * it is in the bridge. It will return when the channel has been instructed to
  * leave the bridge.
  */
-void bridge_channel_join(struct ast_bridge_channel *bridge_channel);
+void bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \internal
@@ -118,7 +131,7 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel);
  * \param bridge_channel The channel in the bridge
  * \note This function assumes that \ref bridge_channel is already locked
  */
-void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel);
+void bridge_channel_internal_suspend_nolock(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \internal
@@ -127,7 +140,7 @@ void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel);
  * \param bridge_channel The channel in the bridge
  * \note This function assumes that \ref bridge_channel is already locked
  */
-void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel);
+void bridge_channel_internal_unsuspend_nolock(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \internal
@@ -146,11 +159,35 @@ void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel);
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int bridge_channel_queue_blind_transfer(struct ast_channel *transferee,
+int bridge_channel_internal_queue_blind_transfer(struct ast_channel *transferee,
                const char *exten, const char *context,
                transfer_channel_cb new_channel_cb, void *user_data);
 
-int bridge_channel_queue_attended_transfer(struct ast_channel *transferee,
+/*!
+ * \internal
+ * \brief Queue an attended transfer action on a transferee bridge channel
+ *
+ * This is only relevant for when an attended transfer is performed on a two-party
+ * bridge. The transferee's bridge channel will have an attended transfer bridge
+ * action queued onto it.
+ *
+ * \param transferee The channel to have the action queued on
+ * \param unbridged_chan The unbridged channel who is the target of the attended
+ * transfer
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int bridge_channel_internal_queue_attended_transfer(struct ast_channel *transferee,
                struct ast_channel *unbridged_chan);
 
+/*!
+ * \internal
+ * \brief Return whether or not the bridge_channel would allow optimization
+ *
+ * \retval 0 if optimization is not allowed
+ * \retval non-zero if optimization is allowed
+ */
+int bridge_channel_internal_allows_optimization(struct ast_bridge_channel *bridge_channel);
+
 #endif /* _ASTERISK_PRIVATE_BRIDGING_H */
index dacb6c6..05fdf25 100644 (file)
@@ -16,7 +16,8 @@
  * at the top of the source tree.
  */
 
-/*! \file
+/*!
+ * \file
  * \brief Channel Bridging API
  * \author Joshua Colp <jcolp@digium.com>
  */
@@ -75,7 +76,7 @@ enum ast_bridge_builtin_feature {
         * how it was imparted.
         *
         * \note Joined channels exit the bridge with
-        * AST_BRIDGE_CHANNEL_STATE_END_WITH_DISSOLVE.
+        * BRIDGE_CHANNEL_STATE_END_WITH_DISSOLVE.
         */
        AST_BRIDGE_BUILTIN_HANGUP,
        /*!
index cafa693..18ef56e 100644 (file)
@@ -180,8 +180,8 @@ void bridge_merge_inhibit_nolock(struct ast_bridge *bridge, int request);
  * \param colp_update Whether to perform COLP updates.
  *
  * \details
- * After a series of bridge_channel_push and
- * bridge_channel_pull calls, you need to call this function
+ * After a series of bridge_channel_internal_push and
+ * bridge_channel_internal_pull calls, you need to call this function
  * to cause the bridge to complete restructuring for the change
  * in the channel makeup of the bridge.
  *
index e037b74..534eb54 100644 (file)
@@ -203,24 +203,6 @@ int __ast_bridge_technology_register(struct ast_bridge_technology *technology, s
 int ast_bridge_technology_unregister(struct ast_bridge_technology *technology);
 
 /*!
- * \brief Lets the bridging indicate when a bridge channel has stopped or started talking.
- *
- * \note All DSP functionality on the bridge has been pushed down to the lowest possible
- * layer, which in this case is the specific bridging technology being used. Since it
- * is necessary for the knowledge of which channels are talking to make its way up to the
- * application, this function has been created to allow the bridging technology to communicate
- * that information with the bridging core.
- *
- * \param bridge_channel The bridge channel that has either started or stopped talking.
- * \param started_talking set to 1 when this indicates the channel has started talking set to 0
- * when this indicates the channel has stopped talking.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking);
-
-/*!
  * \brief Suspend a bridge technology from consideration
  *
  * \param technology The bridge technology to suspend
index dda0732..1e1e6c7 100644 (file)
@@ -38,9 +38,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/lock.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/bridging.h"
+#include "asterisk/bridging_internal.h"
+#include "asterisk/bridging_channel_internal.h"
 #include "asterisk/bridging_basic.h"
 #include "asterisk/bridging_technology.h"
 #include "asterisk/bridging_channel.h"
+#include "asterisk/bridging_after.h"
 #include "asterisk/stasis_bridging.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/app.h"
@@ -61,8 +64,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/parking.h"
 #include "asterisk/core_local.h"
 #include "asterisk/core_unreal.h"
-#include "asterisk/bridging_internal.h"
-#include "asterisk/bridging_channel_internal.h"
 
 /*! All bridges container. */
 static struct ao2_container *bridges;
@@ -268,7 +269,7 @@ void bridge_dissolve(struct ast_bridge *bridge)
 
 /* BUGBUG need a cause code on the bridge for the later ejected channels. */
        AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
        }
 
        /* Must defer dissolving bridge because it is already locked. */
@@ -1343,24 +1344,6 @@ static void set_bridge_peer_vars(struct ast_bridge *bridge)
        }
 }
 
-/*!
- * \internal
- * \brief Notify the bridge that it has been reconfigured.
- * \since 12.0.0
- *
- * \param bridge Reconfigured bridge.
- * \param colp_update Whether to perform COLP updates.
- *
- * \details
- * After a series of bridge_channel_push and
- * bridge_channel_pull calls, you need to call this function
- * to cause the bridge to complete restructuring for the change
- * in the channel makeup of the bridge.
- *
- * \note On entry, the bridge is already locked.
- *
- * \return Nothing
- */
 void bridge_reconfigured(struct ast_bridge *bridge, unsigned int colp_update)
 {
        if (!bridge->reconfigured) {
@@ -1387,726 +1370,17 @@ void bridge_reconfigured(struct ast_bridge *bridge, unsigned int colp_update)
        }
 }
 
-/*!
- * \internal
- * \brief Close a pipe.
- * \since 12.0.0
- *
- * \param my_pipe What to close.
- *
- * \return Nothing
- */
-static void pipe_close(int *my_pipe)
-{
-       if (my_pipe[0] > -1) {
-               close(my_pipe[0]);
-               my_pipe[0] = -1;
-       }
-       if (my_pipe[1] > -1) {
-               close(my_pipe[1]);
-               my_pipe[1] = -1;
-       }
-}
-
-/*!
- * \internal
- * \brief Initialize a pipe as non-blocking.
- * \since 12.0.0
- *
- * \param my_pipe What to initialize.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int pipe_init_nonblock(int *my_pipe)
-{
-       int flags;
-
-       my_pipe[0] = -1;
-       my_pipe[1] = -1;
-       if (pipe(my_pipe)) {
-               ast_log(LOG_WARNING, "Can't create pipe! Try increasing max file descriptors with ulimit -n\n");
-               return -1;
-       }
-       flags = fcntl(my_pipe[0], F_GETFL);
-       if (fcntl(my_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
-               ast_log(LOG_WARNING, "Unable to set read pipe nonblocking! (%d: %s)\n",
-                       errno, strerror(errno));
-               return -1;
-       }
-       flags = fcntl(my_pipe[1], F_GETFL);
-       if (fcntl(my_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
-               ast_log(LOG_WARNING, "Unable to set write pipe nonblocking! (%d: %s)\n",
-                       errno, strerror(errno));
-               return -1;
-       }
-       return 0;
-}
-
-/* Destroy elements of the bridge channel structure and the bridge channel structure itself */
-static void bridge_channel_destroy(void *obj)
-{
-       struct ast_bridge_channel *bridge_channel = obj;
-       struct ast_frame *fr;
-
-       if (bridge_channel->callid) {
-               bridge_channel->callid = ast_callid_unref(bridge_channel->callid);
-       }
-
-       if (bridge_channel->bridge) {
-               ao2_ref(bridge_channel->bridge, -1);
-               bridge_channel->bridge = NULL;
-       }
-
-       /* Flush any unhandled wr_queue frames. */
-       while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) {
-               ast_frfree(fr);
-       }
-       pipe_close(bridge_channel->alert_pipe);
-
-       ast_cond_destroy(&bridge_channel->cond);
-}
-
-static struct ast_bridge_channel *bridge_channel_alloc(struct ast_bridge *bridge)
+struct ast_bridge_channel *bridge_find_channel(struct ast_bridge *bridge, struct ast_channel *chan)
 {
        struct ast_bridge_channel *bridge_channel;
 
-       bridge_channel = ao2_alloc(sizeof(struct ast_bridge_channel), bridge_channel_destroy);
-       if (!bridge_channel) {
-               return NULL;
-       }
-       ast_cond_init(&bridge_channel->cond, NULL);
-       if (pipe_init_nonblock(bridge_channel->alert_pipe)) {
-               ao2_ref(bridge_channel, -1);
-               return NULL;
-       }
-       if (bridge) {
-               bridge_channel->bridge = bridge;
-               ao2_ref(bridge_channel->bridge, +1);
-       }
-
-       return bridge_channel;
-}
-
-struct after_bridge_cb_node {
-       /*! Next list node. */
-       AST_LIST_ENTRY(after_bridge_cb_node) list;
-       /*! Desired callback function. */
-       ast_after_bridge_cb callback;
-       /*! After bridge callback will not be called and destroy any resources data may contain. */
-       ast_after_bridge_cb_failed failed;
-       /*! Extra data to pass to the callback. */
-       void *data;
-       /*! Reason the after bridge callback failed. */
-       enum ast_after_bridge_cb_reason reason;
-};
-
-struct after_bridge_cb_ds {
-       /*! After bridge callbacks container. */
-       AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
-};
-
-/*!
- * \internal
- * \brief Indicate after bridge callback failed.
- * \since 12.0.0
- *
- * \param node After bridge callback node.
- *
- * \return Nothing
- */
-static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
-{
-       if (node->failed) {
-               node->failed(node->reason, node->data);
-               node->failed = NULL;
-       }
-}
-
-/*!
- * \internal
- * \brief Run discarding any after bridge callbacks.
- * \since 12.0.0
- *
- * \param after_bridge After bridge callback container process.
- * \param reason Why are we doing this.
- *
- * \return Nothing
- */
-static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_after_bridge_cb_reason reason)
-{
-       struct after_bridge_cb_node *node;
-
-       for (;;) {
-               AST_LIST_LOCK(&after_bridge->callbacks);
-               node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
-               AST_LIST_UNLOCK(&after_bridge->callbacks);
-               if (!node) {
-                       break;
-               }
-               if (!node->reason) {
-                       node->reason = reason;
-               }
-               after_bridge_cb_failed(node);
-               ast_free(node);
-       }
-}
-
-/*!
- * \internal
- * \brief Destroy the after bridge callback datastore.
- * \since 12.0.0
- *
- * \param data After bridge callback data to destroy.
- *
- * \return Nothing
- */
-static void after_bridge_cb_destroy(void *data)
-{
-       struct after_bridge_cb_ds *after_bridge = data;
-
-       after_bridge_cb_run_discard(after_bridge, AST_AFTER_BRIDGE_CB_REASON_DESTROY);
-
-       AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
-       ast_free(after_bridge);
-}
-
-/*!
- * \internal
- * \brief Fixup the after bridge callback datastore.
- * \since 12.0.0
- *
- * \param data After bridge callback 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_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
-       ast_after_bridge_callback_discard(new_chan, AST_AFTER_BRIDGE_CB_REASON_MASQUERADE);
-}
-
-static const struct ast_datastore_info after_bridge_cb_info = {
-       .type = "after-bridge-cb",
-       .destroy = after_bridge_cb_destroy,
-       .chan_fixup = after_bridge_cb_fixup,
-};
-
-/*!
- * \internal
- * \brief Setup/create an after bridge callback datastore container.
- * \since 12.0.0
- *
- * \param chan Channel to setup/create the after bridge callback container on.
- *
- * \retval after_bridge datastore container on success.
- * \retval NULL on error.
- */
-static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
-{
-       struct ast_datastore *datastore;
-       struct after_bridge_cb_ds *after_bridge;
-       SCOPED_CHANNELLOCK(lock, chan);
-
-       datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
-       if (datastore) {
-               return datastore->data;
-       }
-
-       /* Create a new datastore. */
-       datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
-       if (!datastore) {
-               return NULL;
-       }
-       after_bridge = ast_calloc(1, sizeof(*after_bridge));
-       if (!after_bridge) {
-               ast_datastore_free(datastore);
-               return NULL;
-       }
-       AST_LIST_HEAD_INIT(&after_bridge->callbacks);
-       datastore->data = after_bridge;
-       ast_channel_datastore_add(chan, datastore);
-
-       return datastore->data;
-}
-
-/*!
- * \internal
- * \brief Find an after bridge callback datastore container.
- * \since 12.0.0
- *
- * \param chan Channel to find the after bridge callback container on.
- *
- * \retval after_bridge datastore container on success.
- * \retval NULL on error.
- */
-static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
-{
-       struct ast_datastore *datastore;
-       SCOPED_CHANNELLOCK(lock, chan);
-
-       datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
-       if (!datastore) {
-               return NULL;
-       }
-       return datastore->data;
-}
-
-/*!
- * \internal
- * \brief Run any after bridge callback.
- * \since 12.0.0
- *
- * \param chan Channel to run after bridge callback.
- *
- * \return Nothing
- */
-static void after_bridge_callback_run(struct ast_channel *chan)
-{
-       struct after_bridge_cb_ds *after_bridge;
-       struct after_bridge_cb_node *node;
-
-       after_bridge = after_bridge_cb_find(chan);
-       if (!after_bridge) {
-               return;
-       }
-
-       for (;;) {
-               AST_LIST_LOCK(&after_bridge->callbacks);
-               node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
-               AST_LIST_UNLOCK(&after_bridge->callbacks);
-               if (!node) {
+       AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
+               if (bridge_channel->chan == chan) {
                        break;
                }
-               if (node->reason) {
-                       after_bridge_cb_failed(node);
-               } else {
-                       node->failed = NULL;
-                       node->callback(chan, node->data);
-               }
-               ast_free(node);
        }
-}
 
-/*!
- * \internal
- * \brief Run discarding any after bridge callbacks.
- * \since 12.0.0
- *
- * \param chan Channel to run after bridge callback.
- *
- * \return Nothing
- */
-static void after_bridge_callback_run_discard(struct ast_channel *chan, enum ast_after_bridge_cb_reason reason)
-{
-       struct after_bridge_cb_ds *after_bridge;
-
-       after_bridge = after_bridge_cb_find(chan);
-       if (!after_bridge) {
-               return;
-       }
-
-       after_bridge_cb_run_discard(after_bridge, reason);
-}
-
-void ast_after_bridge_callback_discard(struct ast_channel *chan, enum ast_after_bridge_cb_reason reason)
-{
-       struct after_bridge_cb_ds *after_bridge;
-       struct after_bridge_cb_node *node;
-
-       after_bridge = after_bridge_cb_find(chan);
-       if (!after_bridge) {
-               return;
-       }
-
-       AST_LIST_LOCK(&after_bridge->callbacks);
-       node = AST_LIST_LAST(&after_bridge->callbacks);
-       if (node && !node->reason) {
-               node->reason = reason;
-       }
-       AST_LIST_UNLOCK(&after_bridge->callbacks);
-}
-
-int ast_after_bridge_callback_set(struct ast_channel *chan, ast_after_bridge_cb callback, ast_after_bridge_cb_failed failed, void *data)
-{
-       struct after_bridge_cb_ds *after_bridge;
-       struct after_bridge_cb_node *new_node;
-       struct after_bridge_cb_node *last_node;
-
-       /* Sanity checks. */
-       ast_assert(chan != NULL);
-       if (!chan || !callback) {
-               return -1;
-       }
-
-       after_bridge = after_bridge_cb_setup(chan);
-       if (!after_bridge) {
-               return -1;
-       }
-
-       /* Create a new callback node. */
-       new_node = ast_calloc(1, sizeof(*new_node));
-       if (!new_node) {
-               return -1;
-       }
-       new_node->callback = callback;
-       new_node->failed = failed;
-       new_node->data = data;
-
-       /* Put it in the container disabling any previously active one. */
-       AST_LIST_LOCK(&after_bridge->callbacks);
-       last_node = AST_LIST_LAST(&after_bridge->callbacks);
-       if (last_node && !last_node->reason) {
-               last_node->reason = AST_AFTER_BRIDGE_CB_REASON_REPLACED;
-       }
-       AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
-       AST_LIST_UNLOCK(&after_bridge->callbacks);
-       return 0;
-}
-
-const char *reason_strings[] = {
-       [AST_AFTER_BRIDGE_CB_REASON_DESTROY] = "Channel destroyed (hungup)",
-       [AST_AFTER_BRIDGE_CB_REASON_REPLACED] = "Callback was replaced",
-       [AST_AFTER_BRIDGE_CB_REASON_MASQUERADE] = "Channel masqueraded",
-       [AST_AFTER_BRIDGE_CB_REASON_DEPART] = "Channel was departed from bridge",
-       [AST_AFTER_BRIDGE_CB_REASON_REMOVED] = "Callback was removed",
-};
-
-const char *ast_after_bridge_cb_reason_string(enum ast_after_bridge_cb_reason reason)
-{
-       if (reason < AST_AFTER_BRIDGE_CB_REASON_DESTROY
-               || AST_AFTER_BRIDGE_CB_REASON_REMOVED < reason
-               || !reason_strings[reason]) {
-               return "Unknown";
-       }
-
-       return reason_strings[reason];
-}
-
-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);
-       }
-}
-
-void ast_after_bridge_goto_read(struct ast_channel *chan, char *buffer, size_t buf_size)
-{
-       struct ast_datastore *datastore;
-       struct after_bridge_goto_ds *after_bridge;
-       char *current_pos = buffer;
-       size_t remaining_size = buf_size;
-
-       SCOPED_CHANNELLOCK(lock, chan);
-
-       datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
-       if (!datastore) {
-               buffer[0] = '\0';
-               return;
-       }
-
-       after_bridge = datastore->data;
-
-       if (after_bridge->parseable_goto) {
-               snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
-               return;
-       }
-
-       if (!ast_strlen_zero(after_bridge->context)) {
-               snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
-               remaining_size = remaining_size - strlen(current_pos);
-               current_pos += strlen(current_pos);
-       }
-
-       if (after_bridge->run_h_exten) {
-               snprintf(current_pos, remaining_size, "h,");
-               remaining_size = remaining_size - strlen(current_pos);
-               current_pos += strlen(current_pos);
-       } else if (!ast_strlen_zero(after_bridge->exten)) {
-               snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
-               remaining_size = remaining_size - strlen(current_pos);
-               current_pos += strlen(current_pos);
-       }
-
-       snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
-}
-
-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) {
-                       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
-                               ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
-                       }
-
-                       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);
+       return bridge_channel;
 }
 
 void ast_bridge_notify_masquerade(struct ast_channel *chan)
@@ -2146,7 +1420,7 @@ void ast_bridge_notify_masquerade(struct ast_channel *chan)
  * Need to update the features parameter doxygen when this
  * change is made to be like ast_bridge_impart().
  */
-enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+enum bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
        struct ast_channel *chan,
        struct ast_channel *swap,
        struct ast_bridge_features *features,
@@ -2154,21 +1428,21 @@ enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
        int pass_reference)
 {
        struct ast_bridge_channel *bridge_channel;
-       enum ast_bridge_channel_state state;
+       enum bridge_channel_state state;
 
-       bridge_channel = bridge_channel_alloc(bridge);
+       bridge_channel = bridge_channel_internal_alloc(bridge);
        if (pass_reference) {
                ao2_ref(bridge, -1);
        }
        if (!bridge_channel) {
-               state = AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE;
+               state = BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE;
                goto join_exit;
        }
 /* BUGBUG features cannot be NULL when passed in. When it is changed to allocated we can do like ast_bridge_impart() and allocate one. */
        ast_assert(features != NULL);
        if (!features) {
                ao2_ref(bridge_channel, -1);
-               state = AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE;
+               state = BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE;
                goto join_exit;
        }
        if (tech_args) {
@@ -2184,7 +1458,7 @@ enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
        bridge_channel->swap = swap;
        bridge_channel->features = features;
 
-       bridge_channel_join(bridge_channel);
+       bridge_channel_internal_join(bridge_channel);
        state = bridge_channel->state;
 
        /* Cleanup all the data in the bridge channel after it leaves the bridge. */
@@ -2199,9 +1473,9 @@ enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
 
 join_exit:;
 /* BUGBUG this is going to cause problems for DTMF atxfer attended bridge between B & C.  Maybe an ast_bridge_join_internal() that does not do the after bridge goto for this case. */
-       after_bridge_callback_run(chan);
+       ast_bridge_run_after_callback(chan);
        if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)
-               && !ast_after_bridge_goto_setup(chan)) {
+               && !ast_bridge_setup_after_goto(chan)) {
                /* Claim the after bridge goto is an async goto destination. */
                ast_channel_lock(chan);
                ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
@@ -2219,15 +1493,15 @@ static void *bridge_channel_depart_thread(void *data)
                ast_callid_threadassoc_add(bridge_channel->callid);
        }
 
-       bridge_channel_join(bridge_channel);
+       bridge_channel_internal_join(bridge_channel);
 
        /* cleanup */
        bridge_channel->swap = NULL;
        ast_bridge_features_destroy(bridge_channel->features);
        bridge_channel->features = NULL;
 
-       after_bridge_callback_run_discard(bridge_channel->chan, AST_AFTER_BRIDGE_CB_REASON_DEPART);
-       ast_after_bridge_goto_discard(bridge_channel->chan);
+       ast_bridge_discard_after_callback(bridge_channel->chan, AST_BRIDGE_AFTER_CB_REASON_DEPART);
+       ast_bridge_discard_after_goto(bridge_channel->chan);
 
        return NULL;
 }
@@ -2242,7 +1516,7 @@ static void *bridge_channel_ind_thread(void *data)
                ast_callid_threadassoc_add(bridge_channel->callid);
        }
 
-       bridge_channel_join(bridge_channel);
+       bridge_channel_internal_join(bridge_channel);
        chan = bridge_channel->chan;
 
        /* cleanup */
@@ -2256,8 +1530,8 @@ static void *bridge_channel_ind_thread(void *data)
 
        ao2_ref(bridge_channel, -1);
 
-       after_bridge_callback_run(chan);
-       ast_after_bridge_goto_run(chan);
+       ast_bridge_run_after_callback(chan);
+       ast_bridge_run_after_goto(chan);
        return NULL;
 }
 
@@ -2275,7 +1549,7 @@ int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struc
        }
 
        /* Try to allocate a structure for the bridge channel */
-       bridge_channel = bridge_channel_alloc(bridge);
+       bridge_channel = bridge_channel_internal_alloc(bridge);
        if (!bridge_channel) {
                ast_bridge_features_destroy(features);
                return -1;
@@ -2350,7 +1624,7 @@ int ast_bridge_depart(struct ast_channel *chan)
         * channel thread.
         */
 
-       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
 
        /* Wait for the depart thread to die */
        ast_debug(1, "Waiting for %p(%s) bridge thread to die.\n",
@@ -2378,7 +1652,7 @@ int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
                return -1;
        }
 
-       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
 
        ast_bridge_unlock(bridge);
 
@@ -2425,10 +1699,10 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
         * Move channels from src_bridge over to dst_bridge.
         *
         * We must use AST_LIST_TRAVERSE_SAFE_BEGIN() because
-        * bridge_channel_pull() alters the list we are traversing.
+        * bridge_channel_internal_pull() alters the list we are traversing.
         */
        AST_LIST_TRAVERSE_SAFE_BEGIN(&src_bridge->channels, bridge_channel, entry) {
-               if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+               if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
                        /*
                         * The channel is already leaving let it leave normally because
                         * pulling it may delete hooks that should run for this channel.
@@ -2443,13 +1717,13 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
                if (kick_me) {
                        for (idx = 0; idx < num_kick; ++idx) {
                                if (bridge_channel == kick_me[idx]) {
-                                       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+                                       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                                        break;
                                }
                        }
                }
-               bridge_channel_pull(bridge_channel);
-               if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+               bridge_channel_internal_pull(bridge_channel);
+               if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
                        /*
                         * The channel died as a result of being pulled or it was
                         * kicked.  Leave it pointing to the original bridge.
@@ -2460,8 +1734,8 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
                /* Point to new bridge.*/
                bridge_channel_change_bridge(bridge_channel, dst_bridge);
 
-               if (bridge_channel_push(bridge_channel)) {
-                       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               if (bridge_channel_internal_push(bridge_channel)) {
+                       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                }
        }
        AST_LIST_TRAVERSE_SAFE_END;
@@ -2474,9 +1748,9 @@ void bridge_do_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
                for (idx = 0; idx < num_kick; ++idx) {
                        bridge_channel = kick_me[idx];
                        ast_bridge_channel_lock(bridge_channel);
-                       if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
-                               ast_bridge_channel_leave_bridge_nolock(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
-                               bridge_channel_pull(bridge_channel);
+                       if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
+                               ast_bridge_channel_leave_bridge_nolock(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+                               bridge_channel_internal_pull(bridge_channel);
                        }
                        ast_bridge_channel_unlock(bridge_channel);
                }
@@ -2689,8 +1963,8 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
        orig_bridge = bridge_channel->bridge;
        was_in_bridge = bridge_channel->in_bridge;
 
-       bridge_channel_pull(bridge_channel);
-       if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       bridge_channel_internal_pull(bridge_channel);
+       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
                /*
                 * The channel died as a result of being pulled.  Leave it
                 * pointing to the original bridge.
@@ -2703,17 +1977,17 @@ int bridge_do_move(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bri
        ao2_ref(orig_bridge, +1);/* Keep a ref in case the push fails. */
        bridge_channel_change_bridge(bridge_channel, dst_bridge);
 
-       if (bridge_channel_push(bridge_channel)) {
+       if (bridge_channel_internal_push(bridge_channel)) {
                /* Try to put the channel back into the original bridge. */
                if (attempt_recovery && was_in_bridge) {
                        /* Point back to original bridge. */
                        bridge_channel_change_bridge(bridge_channel, orig_bridge);
 
-                       if (bridge_channel_push(bridge_channel)) {
-                               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+                       if (bridge_channel_internal_push(bridge_channel)) {
+                               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                        }
                } else {
-                       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+                       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                }
                res = -1;
        }
@@ -2767,7 +2041,7 @@ static int bridge_move_locked(struct ast_bridge *dst_bridge, struct ast_bridge *
                        ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
                return -1;
        }
-       if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
                ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, channel leaving bridge.\n",
                        ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid);
                return -1;
@@ -2789,7 +2063,7 @@ static int bridge_move_locked(struct ast_bridge *dst_bridge, struct ast_bridge *
                                ast_channel_name(swap));
                        return -1;
                }
-               if (bridge_channel_swap->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+               if (bridge_channel_swap->state != BRIDGE_CHANNEL_STATE_WAIT) {
                        ast_debug(1, "Can't move channel %s from bridge %s into bridge %s, swap channel %s leaving bridge.\n",
                                ast_channel_name(chan), src_bridge->uniqueid, dst_bridge->uniqueid,
                                ast_channel_name(swap));
@@ -2894,12 +2168,6 @@ static int bridge_allows_optimization(struct ast_bridge *bridge)
                || ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_MASQUERADE_ONLY));
 }
 
-static int bridge_channel_allows_optimization(struct ast_bridge_channel *bridge_channel)
-{
-       return bridge_channel->in_bridge
-               && AST_LIST_EMPTY(&bridge_channel->wr_queue);
-}
-
 /*!
  * \internal
  * \brief Lock the unreal channel stack for chan and prequalify it.
@@ -2929,13 +2197,13 @@ static struct ast_bridge *optimize_lock_chan_stack(struct ast_channel *chan)
                return NULL;
        }
        bridge = bridge_channel->bridge;
-       if (bridge_channel->activity != AST_BRIDGE_CHANNEL_THREAD_SIMPLE
-               || bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT
+       if (bridge_channel->activity != BRIDGE_CHANNEL_THREAD_SIMPLE
+               || bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT
                || ast_bridge_trylock(bridge)) {
                ast_bridge_channel_unlock(bridge_channel);
                return NULL;
        }
-       if (!bridge_channel_allows_optimization(bridge_channel) ||
+       if (!bridge_channel_internal_allows_optimization(bridge_channel) ||
                        !bridge_allows_optimization(bridge)) {
                ast_bridge_unlock(bridge);
                ast_bridge_channel_unlock(bridge_channel);
@@ -2977,15 +2245,15 @@ static struct ast_bridge *optimize_lock_peer_stack(struct ast_channel *peer)
                return NULL;
        }
        bridge = bridge_channel->bridge;
-       if (bridge_channel->activity != AST_BRIDGE_CHANNEL_THREAD_IDLE
-               || bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT
+       if (bridge_channel->activity != BRIDGE_CHANNEL_THREAD_IDLE
+               || bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT
                || ast_bridge_trylock(bridge)) {
                ast_bridge_channel_unlock(bridge_channel);
                ast_channel_unlock(peer);
                return NULL;
        }
        if (!bridge_allows_optimization(bridge) ||
-                       !bridge_channel_allows_optimization(bridge_channel)) {
+                       !bridge_channel_internal_allows_optimization(bridge_channel)) {
                ast_bridge_unlock(bridge);
                ast_bridge_channel_unlock(bridge_channel);
                ast_channel_unlock(peer);
@@ -3099,7 +2367,7 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
        }
 
        other = ast_bridge_channel_peer(src_bridge_channel);
-       if (other && other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (other && other->state == BRIDGE_CHANNEL_STATE_WAIT) {
                ast_verb(3, "Move-swap optimizing %s <-- %s.\n",
                        ast_channel_name(dst_bridge_channel->chan),
                        ast_channel_name(other->chan));
@@ -3111,7 +2379,7 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
                }
                other->swap = dst_bridge_channel->chan;
                if (!bridge_do_move(dst_bridge, other, 1, 1)) {
-                       ast_bridge_channel_leave_bridge(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+                       ast_bridge_channel_leave_bridge(src_bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                        res = -1;
                        if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
                                pvt->callbacks->optimization_finished(pvt);
@@ -3343,7 +2611,7 @@ int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
                return -1;
        }
 
-       bridge_channel_suspend_nolock(bridge_channel);
+       bridge_channel_internal_suspend_nolock(bridge_channel);
 
        ast_bridge_unlock(bridge);
 
@@ -3362,7 +2630,7 @@ int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
                return -1;
        }
 
-       bridge_channel_unsuspend_nolock(bridge_channel);
+       bridge_channel_internal_unsuspend_nolock(bridge_channel);
 
        ast_bridge_unlock(bridge);
 
@@ -4686,7 +3954,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
                goto publish;
        }
 
-       if (bridge_channel_queue_blind_transfer(transferee, exten, context,
+       if (bridge_channel_internal_queue_blind_transfer(transferee, exten, context,
                                new_channel_cb, user_data)) {
                transfer_result = AST_BRIDGE_TRANSFER_FAIL;
                goto publish;
@@ -4722,7 +3990,7 @@ static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge
 
        bridged_to_source = ast_bridge_channel_peer(source_bridge_channel);
        if (bridged_to_source
-               && bridged_to_source->state == AST_BRIDGE_CHANNEL_STATE_WAIT
+               && bridged_to_source->state == BRIDGE_CHANNEL_STATE_WAIT
                && !ast_test_flag(&bridged_to_source->features->feature_flags,
                        AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
                bridged_to_source->swap = swap_channel;
@@ -4730,7 +3998,7 @@ static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge
                        return AST_BRIDGE_TRANSFER_FAIL;
                }
                /* Must kick the source channel out of its bridge. */
-               ast_bridge_channel_leave_bridge(source_bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(source_bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                return AST_BRIDGE_TRANSFER_SUCCESS;
        } else {
                return AST_BRIDGE_TRANSFER_INVALID;
@@ -4953,7 +4221,7 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
        }
 
        app = ast_strdupa(ast_channel_appl(chan_unbridged));
-       if (bridge_channel_queue_attended_transfer(transferee, chan_unbridged)) {
+       if (bridge_channel_internal_queue_attended_transfer(transferee, chan_unbridged)) {
                res = AST_BRIDGE_TRANSFER_FAIL;
                goto end;
        }
diff --git a/main/bridging_after.c b/main/bridging_after.c
new file mode 100644 (file)
index 0000000..8ab4bc8
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2007 - 2009, Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@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 After Bridge Execution API
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/logger.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/bridging_after.h"
+
+struct after_bridge_cb_node {
+       /*! Next list node. */
+       AST_LIST_ENTRY(after_bridge_cb_node) list;
+       /*! Desired callback function. */
+       ast_bridge_after_cb callback;
+       /*! After bridge callback will not be called and destroy any resources data may contain. */
+       ast_bridge_after_cb_failed failed;
+       /*! Extra data to pass to the callback. */
+       void *data;
+       /*! Reason the after bridge callback failed. */
+       enum ast_bridge_after_cb_reason reason;
+};
+
+struct after_bridge_cb_ds {
+       /*! After bridge callbacks container. */
+       AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
+};
+
+/*!
+ * \internal
+ * \brief Indicate after bridge callback failed.
+ * \since 12.0.0
+ *
+ * \param node After bridge callback node.
+ *
+ * \return Nothing
+ */
+static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
+{
+       if (node->failed) {
+               node->failed(node->reason, node->data);
+               node->failed = NULL;
+       }
+}
+
+/*!
+ * \internal
+ * \brief Run discarding any after bridge callbacks.
+ * \since 12.0.0
+ *
+ * \param after_bridge After bridge callback container process.
+ * \param reason Why are we doing this.
+ *
+ * \return Nothing
+ */
+static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
+{
+       struct after_bridge_cb_node *node;
+
+       for (;;) {
+               AST_LIST_LOCK(&after_bridge->callbacks);
+               node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
+               AST_LIST_UNLOCK(&after_bridge->callbacks);
+               if (!node) {
+                       break;
+               }
+               if (!node->reason) {
+                       node->reason = reason;
+               }
+               after_bridge_cb_failed(node);
+               ast_free(node);
+       }
+}
+
+/*!
+ * \internal
+ * \brief Destroy the after bridge callback datastore.
+ * \since 12.0.0
+ *
+ * \param data After bridge callback data to destroy.
+ *
+ * \return Nothing
+ */
+static void after_bridge_cb_destroy(void *data)
+{
+       struct after_bridge_cb_ds *after_bridge = data;
+
+       after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
+
+       AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
+       ast_free(after_bridge);
+}
+
+static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
+
+/*!
+ * \internal
+ * \brief Fixup the after bridge callback datastore.
+ * \since 12.0.0
+ *
+ * \param data After bridge callback 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_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+       struct after_bridge_cb_ds *after_bridge;
+       struct after_bridge_cb_node *node;
+
+       after_bridge = after_bridge_cb_find(new_chan);
+       if (!after_bridge) {
+               return;
+       }
+
+       AST_LIST_LOCK(&after_bridge->callbacks);
+       node = AST_LIST_LAST(&after_bridge->callbacks);
+       if (node && !node->reason) {
+               node->reason = AST_BRIDGE_AFTER_CB_REASON_MASQUERADE;
+       }
+       AST_LIST_UNLOCK(&after_bridge->callbacks);
+}
+
+static const struct ast_datastore_info after_bridge_cb_info = {
+       .type = "after-bridge-cb",
+       .destroy = after_bridge_cb_destroy,
+       .chan_fixup = after_bridge_cb_fixup,
+};
+
+/*!
+ * \internal
+ * \brief Find an after bridge callback datastore container.
+ * \since 12.0.0
+ *
+ * \param chan Channel to find the after bridge callback container on.
+ *
+ * \retval after_bridge datastore container on success.
+ * \retval NULL on error.
+ */
+static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
+{
+       struct ast_datastore *datastore;
+       SCOPED_CHANNELLOCK(lock, chan);
+
+       datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
+       if (!datastore) {
+               return NULL;
+       }
+       return datastore->data;
+}
+
+/*!
+ * \internal
+ * \brief Setup/create an after bridge callback datastore container.
+ * \since 12.0.0
+ *
+ * \param chan Channel to setup/create the after bridge callback container on.
+ *
+ * \retval after_bridge datastore container on success.
+ * \retval NULL on error.
+ */
+static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
+{
+       struct ast_datastore *datastore;
+       struct after_bridge_cb_ds *after_bridge;
+       SCOPED_CHANNELLOCK(lock, chan);
+
+       datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
+       if (datastore) {
+               return datastore->data;
+       }
+
+       /* Create a new datastore. */
+       datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
+       if (!datastore) {
+               return NULL;
+       }
+       after_bridge = ast_calloc(1, sizeof(*after_bridge));
+       if (!after_bridge) {
+               ast_datastore_free(datastore);
+               return NULL;
+       }
+       AST_LIST_HEAD_INIT(&after_bridge->callbacks);
+       datastore->data = after_bridge;
+       ast_channel_datastore_add(chan, datastore);
+
+       return datastore->data;
+}
+
+void ast_bridge_run_after_callback(struct ast_channel *chan)
+{
+       struct after_bridge_cb_ds *after_bridge;
+       struct after_bridge_cb_node *node;
+
+       after_bridge = after_bridge_cb_find(chan);
+       if (!after_bridge) {
+               return;
+       }
+
+       for (;;) {
+               AST_LIST_LOCK(&after_bridge->callbacks);
+               node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
+               AST_LIST_UNLOCK(&after_bridge->callbacks);
+               if (!node) {
+                       break;
+               }
+               if (node->reason) {
+                       after_bridge_cb_failed(node);
+               } else {
+                       node->failed = NULL;
+                       node->callback(chan, node->data);
+               }
+               ast_free(node);
+       }
+}
+
+void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
+{
+       struct after_bridge_cb_ds *after_bridge;
+
+       after_bridge = after_bridge_cb_find(chan);
+       if (!after_bridge) {
+               return;
+       }
+
+       after_bridge_cb_run_discard(after_bridge, reason);
+}
+
+int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
+{
+       struct after_bridge_cb_ds *after_bridge;
+       struct after_bridge_cb_node *new_node;
+       struct after_bridge_cb_node *last_node;
+
+       /* Sanity checks. */
+       ast_assert(chan != NULL);
+       if (!chan || !callback) {
+               return -1;
+       }
+
+       after_bridge = after_bridge_cb_setup(chan);
+       if (!after_bridge) {
+               return -1;
+       }
+
+       /* Create a new callback node. */
+       new_node = ast_calloc(1, sizeof(*new_node));
+       if (!new_node) {
+               return -1;
+       }
+       new_node->callback = callback;
+       new_node->failed = failed;
+       new_node->data = data;
+
+       /* Put it in the container disabling any previously active one. */
+       AST_LIST_LOCK(&after_bridge->callbacks);
+       last_node = AST_LIST_LAST(&after_bridge->callbacks);
+       if (last_node && !last_node->reason) {
+               last_node->reason = AST_BRIDGE_AFTER_CB_REASON_REPLACED;
+       }
+       AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
+       AST_LIST_UNLOCK(&after_bridge->callbacks);
+       return 0;
+}
+
+const char *reason_strings[] = {
+       [AST_BRIDGE_AFTER_CB_REASON_DESTROY] = "Channel destroyed (hungup)",
+       [AST_BRIDGE_AFTER_CB_REASON_REPLACED] = "Callback was replaced",
+       [AST_BRIDGE_AFTER_CB_REASON_MASQUERADE] = "Channel masqueraded",
+       [AST_BRIDGE_AFTER_CB_REASON_DEPART] = "Channel was departed from bridge",
+       [AST_BRIDGE_AFTER_CB_REASON_REMOVED] = "Callback was removed",
+};
+
+const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
+{
+       if (reason < AST_BRIDGE_AFTER_CB_REASON_DESTROY
+               || AST_BRIDGE_AFTER_CB_REASON_REMOVED < reason
+               || !reason_strings[reason]) {
+               return "Unknown";
+       }
+
+       return reason_strings[reason];
+}
+
+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_bridge_discard_after_goto(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_bridge_discard_after_goto(struct ast_channel *chan)
+{
+       struct ast_datastore *datastore;
+
+       datastore = after_bridge_goto_remove(chan);
+       if (datastore) {
+               ast_datastore_free(datastore);
+       }
+}
+
+void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
+{
+       struct ast_datastore *datastore;
+       struct after_bridge_goto_ds *after_bridge;
+       char *current_pos = buffer;
+       size_t remaining_size = buf_size;
+
+       SCOPED_CHANNELLOCK(lock, chan);
+
+       datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
+       if (!datastore) {
+               buffer[0] = '\0';
+               return;
+       }
+
+       after_bridge = datastore->data;
+
+       if (after_bridge->parseable_goto) {
+               snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
+               return;
+       }
+
+       if (!ast_strlen_zero(after_bridge->context)) {
+               snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
+               remaining_size = remaining_size - strlen(current_pos);
+               current_pos += strlen(current_pos);
+       }
+
+       if (after_bridge->run_h_exten) {
+               snprintf(current_pos, remaining_size, "h,");
+               remaining_size = remaining_size - strlen(current_pos);
+               current_pos += strlen(current_pos);
+       } else if (!ast_strlen_zero(after_bridge->exten)) {
+               snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
+               remaining_size = remaining_size - strlen(current_pos);
+               current_pos += strlen(current_pos);
+       }
+
+       snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
+}
+
+int ast_bridge_setup_after_goto(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) {
+                       if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
+                               ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
+                       }
+
+                       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_bridge_run_after_goto(struct ast_channel *chan)
+{
+       int goto_failed;
+
+       goto_failed = ast_bridge_setup_after_goto(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_bridge_discard_after_goto(chan);
+       ast_channel_datastore_add(chan, datastore);
+       ast_channel_unlock(chan);
+}
+
+void ast_bridge_set_after_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_bridge_set_after_h(struct ast_channel *chan, const char *context)
+{
+       __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
+}
+
+void ast_bridge_set_after_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);
+}
index 8fcad75..7f9cb71 100644 (file)
@@ -36,13 +36,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/linkedlists.h"
 #include "asterisk/bridging.h"
 #include "asterisk/bridging_basic.h"
+#include "asterisk/bridging_after.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/features_config.h"
 #include "asterisk/pbx.h"
 #include "asterisk/file.h"
 #include "asterisk/app.h"
 #include "asterisk/bridging_internal.h"
-#include "asterisk/bridging_channel_internal.h"
 #include "asterisk/dial.h"
 #include "asterisk/stasis_bridging.h"
 
@@ -279,13 +279,13 @@ static int basic_hangup_hook(struct ast_bridge *bridge, struct ast_bridge_channe
 
        ast_bridge_channel_lock_bridge(bridge_channel);
        AST_LIST_TRAVERSE(&bridge->channels, iter, entry) {
-               if (iter != bridge_channel && iter->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+               if (iter != bridge_channel && iter->state == BRIDGE_CHANNEL_STATE_WAIT) {
                        ++bridge_count;
                }
        }
        if (2 <= bridge_count) {
                /* Just allow this channel to leave the multi-party bridge. */
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
        }
        ast_bridge_unlock(bridge_channel->bridge);
        return 0;
@@ -2300,7 +2300,7 @@ static int bridge_personality_atxfer_push(struct ast_bridge *self, struct ast_br
 
 static void transfer_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct attended_transfer_properties *props)
 {
-       if (self->num_channels > 1 || bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (self->num_channels > 1 || bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
                return;
        }
 
@@ -2794,13 +2794,13 @@ static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_c
        if (!ast_strlen_zero(goto_on_blindxfr)) {
                ast_debug(1, "After transfer, transferer %s goes to %s\n",
                                ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
-               ast_after_bridge_set_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
+               ast_bridge_set_after_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
        }
 
        if (ast_bridge_transfer_blind(0, bridge_channel->chan, exten, context, blind_transfer_cb,
                        bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS &&
                        !ast_strlen_zero(goto_on_blindxfr)) {
-               ast_after_bridge_goto_discard(bridge_channel->chan);
+               ast_bridge_discard_after_goto(bridge_channel->chan);
        }
 
        return 0;
index 385545c..284f087 100644 (file)
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/timing.h"
 #include "asterisk/bridging.h"
 #include "asterisk/bridging_channel.h"
+#include "asterisk/bridging_after.h"
 #include "asterisk/bridging_channel_internal.h"
 #include "asterisk/bridging_internal.h"
 #include "asterisk/stasis_bridging.h"
@@ -67,18 +68,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  */
 typedef int (*ast_bridge_channel_post_action_data)(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen);
 
-struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request)
-{
-       struct ast_bridge *bridge;
-
-       ast_bridge_channel_lock_bridge(bridge_channel);
-       bridge = bridge_channel->bridge;
-       ao2_ref(bridge, +1);
-       bridge_merge_inhibit_nolock(bridge, request);
-       ast_bridge_unlock(bridge);
-       return bridge;
-}
-
 void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
 {
        struct ast_bridge *bridge;
@@ -101,6 +90,25 @@ void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
        }
 }
 
+int ast_bridge_channel_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
+{
+       struct ast_frame action = {
+               .frametype = AST_FRAME_BRIDGE_ACTION,
+               .subclass.integer = started_talking
+                       ? BRIDGE_CHANNEL_ACTION_TALKING_START : BRIDGE_CHANNEL_ACTION_TALKING_STOP,
+       };
+
+       return ast_bridge_channel_queue_frame(bridge_channel, &action);
+}
+
+void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state)
+{
+       ast_bridge_channel_lock(bridge_channel);
+       ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state);
+       ast_bridge_channel_unlock(bridge_channel);
+}
+
+/*! \internal \brief Poke the bridge_channel thread */
 static void bridge_channel_poke(struct ast_bridge_channel *bridge_channel)
 {
        if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
@@ -111,6 +119,102 @@ static void bridge_channel_poke(struct ast_bridge_channel *bridge_channel)
        }
 }
 
+void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state)
+{
+/* BUGBUG need cause code for the bridge_channel leaving the bridge. */
+       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
+               return;
+       }
+
+       ast_debug(1, "Setting %p(%s) state from:%d to:%d\n",
+               bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->state,
+               new_state);
+
+       /* Change the state on the bridge channel */
+       bridge_channel->state = new_state;
+
+       bridge_channel_poke(bridge_channel);
+}
+
+struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
+{
+       struct ast_bridge *bridge = bridge_channel->bridge;
+       struct ast_bridge_channel *other = NULL;
+
+       if (bridge_channel->in_bridge && bridge->num_channels == 2) {
+               AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
+                       if (other != bridge_channel) {
+                               break;
+                       }
+               }
+       }
+
+       return other;
+}
+
+void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel)
+{
+       /* Restore original formats of the channel as they came in */
+       if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &bridge_channel->read_format) == AST_FORMAT_CMP_NOT_EQUAL) {
+               ast_debug(1, "Bridge is returning %p(%s) to read format %s\n",
+                       bridge_channel, ast_channel_name(bridge_channel->chan),
+                       ast_getformatname(&bridge_channel->read_format));
+               if (ast_set_read_format(bridge_channel->chan, &bridge_channel->read_format)) {
+                       ast_debug(1, "Bridge failed to return %p(%s) to read format %s\n",
+                               bridge_channel, ast_channel_name(bridge_channel->chan),
+                               ast_getformatname(&bridge_channel->read_format));
+               }
+       }
+       if (ast_format_cmp(ast_channel_writeformat(bridge_channel->chan), &bridge_channel->write_format) == AST_FORMAT_CMP_NOT_EQUAL) {
+               ast_debug(1, "Bridge is returning %p(%s) to write format %s\n",
+                       bridge_channel, ast_channel_name(bridge_channel->chan),
+                       ast_getformatname(&bridge_channel->write_format));
+               if (ast_set_write_format(bridge_channel->chan, &bridge_channel->write_format)) {
+                       ast_debug(1, "Bridge failed to return %p(%s) to write format %s\n",
+                               bridge_channel, ast_channel_name(bridge_channel->chan),
+                               ast_getformatname(&bridge_channel->write_format));
+               }
+       }
+}
+
+struct ast_bridge *ast_bridge_channel_merge_inhibit(struct ast_bridge_channel *bridge_channel, int request)
+{
+       struct ast_bridge *bridge;
+
+       ast_bridge_channel_lock_bridge(bridge_channel);
+       bridge = bridge_channel->bridge;
+       ao2_ref(bridge, +1);
+       bridge_merge_inhibit_nolock(bridge, request);
+       ast_bridge_unlock(bridge);
+       return bridge;
+}
+
+void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+{
+       struct ast_bridge_channel *other = NULL;
+       struct ast_bridge *bridge = bridge_channel->bridge;
+       const char *oldest_linkedid = ast_channel_linkedid(bridge_channel->chan);
+
+       AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
+               if (other == swap) {
+                       continue;
+               }
+               oldest_linkedid = ast_channel_oldest_linkedid(oldest_linkedid, ast_channel_linkedid(other->chan));
+       }
+
+       if (ast_strlen_zero(oldest_linkedid)) {
+               return;
+       }
+
+       ast_channel_linkedid_set(bridge_channel->chan, oldest_linkedid);
+       AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
+               if (other == swap) {
+                       continue;
+               }
+               ast_channel_linkedid_set(other->chan, oldest_linkedid);
+       }
+}
+
 void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
 {
        struct ast_bridge *bridge = bridge_channel->bridge;
@@ -156,30 +260,120 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch
        }
 }
 
-void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
+/*!
+* \internal
+* \brief Handle bridge hangup event.
+* \since 12.0.0
+*
+* \param bridge_channel Which channel is hanging up.
+*
+* \return Nothing
+*/
+static void bridge_channel_handle_hangup(struct ast_bridge_channel *bridge_channel)
 {
-       struct ast_bridge_channel *other = NULL;
-       struct ast_bridge *bridge = bridge_channel->bridge;
-       const char *oldest_linkedid = ast_channel_linkedid(bridge_channel->chan);
+       struct ast_bridge_features *features = bridge_channel->features;
+       struct ast_bridge_hook *hook;
+       struct ao2_iterator iter;
 
-       AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-               if (other == swap) {
+       /* Run any hangup hooks. */
+       iter = ao2_iterator_init(features->other_hooks, 0);
+       for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
+               int remove_me;
+
+               if (hook->type != AST_BRIDGE_HOOK_TYPE_HANGUP) {
                        continue;
                }
-               oldest_linkedid = ast_channel_oldest_linkedid(oldest_linkedid, ast_channel_linkedid(other->chan));
+               remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
+               if (remove_me) {
+                       ast_debug(1, "Hangup hook %p is being removed from %p(%s)\n",
+                               hook, bridge_channel, ast_channel_name(bridge_channel->chan));
+                       ao2_unlink(features->other_hooks, hook);
+               }
        }
+       ao2_iterator_destroy(&iter);
 
-       if (ast_strlen_zero(oldest_linkedid)) {
-               return;
-       }
+       /* Default hangup action. */
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END);
+}
 
-       ast_channel_linkedid_set(bridge_channel->chan, oldest_linkedid);
-       AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-               if (other == swap) {
-                       continue;
-               }
-               ast_channel_linkedid_set(other->chan, oldest_linkedid);
-       }
+/*!
+ * \internal
+ * \brief Write an \ref ast_frame onto the bridge channel
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param frame The frame to write onto the bridge_channel
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+{
+       ast_bridge_channel_lock_bridge(bridge_channel);
+/*
+ * BUGBUG need to implement a deferred write queue for when there is no peer channel in the bridge (yet or it was kicked).
+ *
+ * The tech decides if a frame needs to be pushed back for deferral.
+ * simple_bridge/native_bridge are likely the only techs that will do this.
+ */
+       bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
+       ast_bridge_unlock(bridge_channel->bridge);
+
+       /*
+        * Claim successful write to bridge.  If deferred frame
+        * support is added, claim successfully deferred.
+        */
+       return 0;
+}
+
+/*!
+ * \internal
+ * \brief Queue an action frame onto the bridge channel with data.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+{
+       struct ast_frame frame = {
+               .frametype = AST_FRAME_BRIDGE_ACTION,
+               .subclass.integer = action,
+               .datalen = datalen,
+               .data.ptr = (void *) data,
+       };
+
+       return ast_bridge_channel_queue_frame(bridge_channel, &frame);
+}
+
+/*!
+ * \internal
+ * \brief Write an action frame onto the bridge channel with data.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Which channel to queue the frame onto.
+ * \param action Type of bridge action frame.
+ * \param data Frame payload data to pass.
+ * \param datalen Frame payload data length to pass.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+{
+       struct ast_frame frame = {
+               .frametype = AST_FRAME_BRIDGE_ACTION,
+               .subclass.integer = action,
+               .datalen = datalen,
+               .data.ptr = (void *) data,
+       };
+
+       return bridge_channel_write_frame(bridge_channel, &frame);
 }
 
 int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *fr)
@@ -206,7 +400,7 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
        }
 
        ast_bridge_channel_lock(bridge_channel);
-       if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
                /* Drop frames on channels leaving the bridge. */
                ast_bridge_channel_unlock(bridge_channel);
                ast_frfree(dup);
@@ -218,44 +412,8 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
                ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n",
                        bridge_channel, ast_channel_name(bridge_channel->chan));
        }
-       ast_bridge_channel_unlock(bridge_channel);
-       return 0;
-}
-
-/*!
- * \brief Queue an action frame onto the bridge channel with data.
- * \since 12.0.0
- *
- * \param bridge_channel Which channel to queue the frame onto.
- * \param action Type of bridge action frame.
- * \param data Frame payload data to pass.
- * \param datalen Frame payload data length to pass.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-static int ast_bridge_channel_queue_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
-{
-       struct ast_frame frame = {
-               .frametype = AST_FRAME_BRIDGE_ACTION,
-               .subclass.integer = action,
-               .datalen = datalen,
-               .data.ptr = (void *) data,
-       };
-
-       return ast_bridge_channel_queue_frame(bridge_channel, &frame);
-}
-
-int ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
-{
-       struct ast_frame frame = {
-               .frametype = AST_FRAME_CONTROL,
-               .subclass.integer = control,
-               .datalen = datalen,
-               .data.ptr = (void *) data,
-       };
-
-       return ast_bridge_channel_queue_frame(bridge_channel, &frame);
+       ast_bridge_channel_unlock(bridge_channel);
+       return 0;
 }
 
 int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
@@ -279,60 +437,16 @@ int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_
        return not_written;
 }
 
-void ast_bridge_channel_restore_formats(struct ast_bridge_channel *bridge_channel)
-{
-       /* Restore original formats of the channel as they came in */
-       if (ast_format_cmp(ast_channel_readformat(bridge_channel->chan), &bridge_channel->read_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-               ast_debug(1, "Bridge is returning %p(%s) to read format %s\n",
-                       bridge_channel, ast_channel_name(bridge_channel->chan),
-                       ast_getformatname(&bridge_channel->read_format));
-               if (ast_set_read_format(bridge_channel->chan, &bridge_channel->read_format)) {
-                       ast_debug(1, "Bridge failed to return %p(%s) to read format %s\n",
-                               bridge_channel, ast_channel_name(bridge_channel->chan),
-                               ast_getformatname(&bridge_channel->read_format));
-               }
-       }
-       if (ast_format_cmp(ast_channel_writeformat(bridge_channel->chan), &bridge_channel->write_format) == AST_FORMAT_CMP_NOT_EQUAL) {
-               ast_debug(1, "Bridge is returning %p(%s) to write format %s\n",
-                       bridge_channel, ast_channel_name(bridge_channel->chan),
-                       ast_getformatname(&bridge_channel->write_format));
-               if (ast_set_write_format(bridge_channel->chan, &bridge_channel->write_format)) {
-                       ast_debug(1, "Bridge failed to return %p(%s) to write format %s\n",
-                               bridge_channel, ast_channel_name(bridge_channel->chan),
-                               ast_getformatname(&bridge_channel->write_format));
-               }
-       }
-}
-
-static int bridge_channel_write_frame(struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
-{
-       ast_bridge_channel_lock_bridge(bridge_channel);
-/*
- * BUGBUG need to implement a deferred write queue for when there is no peer channel in the bridge (yet or it was kicked).
- *
- * The tech decides if a frame needs to be pushed back for deferral.
- * simple_bridge/native_bridge are likely the only techs that will do this.
- */
-       bridge_channel->bridge->technology->write(bridge_channel->bridge, bridge_channel, frame);
-       ast_bridge_unlock(bridge_channel->bridge);
-
-       /*
-        * Claim successful write to bridge.  If deferred frame
-        * support is added, claim successfully deferred.
-        */
-       return 0;
-}
-
-static int ast_bridge_channel_write_action_data(struct ast_bridge_channel *bridge_channel, enum bridge_channel_action_type action, const void *data, size_t datalen)
+int ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
 {
        struct ast_frame frame = {
-               .frametype = AST_FRAME_BRIDGE_ACTION,
-               .subclass.integer = action,
+               .frametype = AST_FRAME_CONTROL,
+               .subclass.integer = control,
                .datalen = datalen,
                .data.ptr = (void *) data,
        };
 
-       return bridge_channel_write_frame(bridge_channel, &frame);
+       return ast_bridge_channel_queue_frame(bridge_channel, &frame);
 }
 
 int ast_bridge_channel_write_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
@@ -373,6 +487,7 @@ int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)
        return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0);
 }
 
+/*! \internal \brief Helper function to kick off a PBX app on a bridge_channel */
 static int run_app_helper(struct ast_channel *chan, const char *app_name, const char *app_args)
 {
        int res = 0;
@@ -394,42 +509,6 @@ static int run_app_helper(struct ast_channel *chan, const char *app_name, const
        return res;
 }
 
-/*!
-* \internal
-* \brief Handle bridge hangup event.
-* \since 12.0.0
-*
-* \param bridge_channel Which channel is hanging up.
-*
-* \return Nothing
-*/
-static void bridge_channel_handle_hangup(struct ast_bridge_channel *bridge_channel)
-{
-       struct ast_bridge_features *features = bridge_channel->features;
-       struct ast_bridge_hook *hook;
-       struct ao2_iterator iter;
-
-       /* Run any hangup hooks. */
-       iter = ao2_iterator_init(features->other_hooks, 0);
-       for (; (hook = ao2_iterator_next(&iter)); ao2_ref(hook, -1)) {
-               int remove_me;
-
-               if (hook->type != AST_BRIDGE_HOOK_TYPE_HANGUP) {
-                       continue;
-               }
-               remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt);
-               if (remove_me) {
-                       ast_debug(1, "Hangup hook %p is being removed from %p(%s)\n",
-                               hook, bridge_channel, ast_channel_name(bridge_channel->chan));
-                       ao2_unlink(features->other_hooks, hook);
-               }
-       }
-       ao2_iterator_destroy(&iter);
-
-       /* Default hangup action. */
-       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
-}
-
 void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
 {
        if (moh_class) {
@@ -444,7 +523,6 @@ void ast_bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, const
        }
 }
 
-
 struct bridge_run_app {
        /*! Offset into app_name[] where the MOH class name starts.  (zero if no MOH) */
        int moh_offset;
@@ -471,6 +549,10 @@ static void bridge_channel_run_app(struct ast_bridge_channel *bridge_channel, st
                data->moh_offset ? &data->app_name[data->moh_offset] : NULL);
 }
 
+/*!
+ * \internal
+ * \brief Marshal an application to be executed on a bridge_channel
+ */
 static int payload_helper_app(ast_bridge_channel_post_action_data post_it,
        struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
 {
@@ -497,13 +579,13 @@ static int payload_helper_app(ast_bridge_channel_post_action_data post_it,
 
 int ast_bridge_channel_write_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
 {
-       return payload_helper_app(ast_bridge_channel_write_action_data,
+       return payload_helper_app(bridge_channel_write_action_data,
                bridge_channel, app_name, app_args, moh_class);
 }
 
 int ast_bridge_channel_queue_app(struct ast_bridge_channel *bridge_channel, const char *app_name, const char *app_args, const char *moh_class)
 {
-       return payload_helper_app(ast_bridge_channel_queue_action_data,
+       return payload_helper_app(bridge_channel_queue_action_data,
                bridge_channel, app_name, app_args, moh_class);
 }
 
@@ -560,6 +642,10 @@ static void bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, s
                payload->moh_offset ? &payload->playfile[payload->moh_offset] : NULL);
 }
 
+/*!
+ * \internal
+ * \brief Marshal a file to be played on a bridge_channel
+ */
 static int payload_helper_playfile(ast_bridge_channel_post_action_data post_it,
        struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
 {
@@ -582,13 +668,13 @@ static int payload_helper_playfile(ast_bridge_channel_post_action_data post_it,
 
 int ast_bridge_channel_write_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
 {
-       return payload_helper_playfile(ast_bridge_channel_write_action_data,
+       return payload_helper_playfile(bridge_channel_write_action_data,
                bridge_channel, custom_play, playfile, moh_class);
 }
 
 int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
 {
-       return payload_helper_playfile(ast_bridge_channel_queue_action_data,
+       return payload_helper_playfile(bridge_channel_queue_action_data,
                bridge_channel, custom_play, playfile, moh_class);
 }
 
@@ -618,6 +704,10 @@ static void bridge_channel_do_callback(struct ast_bridge_channel *bridge_channel
        data->callback(bridge_channel, data->payload_exists ? data->payload : NULL, data->payload_size);
 }
 
+/*!
+ * \internal
+ * \brief Marshal a custom callback function to be called on a bridge_channel
+ */
 static int payload_helper_cb(ast_bridge_channel_post_action_data post_it,
        struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
 {
@@ -644,13 +734,13 @@ static int payload_helper_cb(ast_bridge_channel_post_action_data post_it,
 
 int ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
 {
-       return payload_helper_cb(ast_bridge_channel_write_action_data,
+       return payload_helper_cb(bridge_channel_write_action_data,
                bridge_channel, callback, payload, payload_size);
 }
 
 int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
 {
-       return payload_helper_cb(ast_bridge_channel_queue_action_data,
+       return payload_helper_cb(bridge_channel_queue_action_data,
                bridge_channel, callback, payload, payload_size);
 }
 
@@ -661,6 +751,10 @@ struct bridge_park {
        char parkee_uuid[0];
 };
 
+/*!
+ * \internal
+ * \brief Park a bridge_cahnnel
+ */
 static void bridge_channel_park(struct ast_bridge_channel *bridge_channel, struct bridge_park *payload)
 {
        ast_bridge_channel_park(bridge_channel, payload->parkee_uuid,
@@ -668,6 +762,10 @@ static void bridge_channel_park(struct ast_bridge_channel *bridge_channel, struc
                payload->app_data_offset ? &payload->parkee_uuid[payload->app_data_offset] : NULL);
 }
 
+/*!
+ * \internal
+ * \brief Marshal a park action onto a bridge_channel
+ */
 static int payload_helper_park(ast_bridge_channel_post_action_data post_it,
        struct ast_bridge_channel *bridge_channel,
        const char *parkee_uuid,
@@ -694,50 +792,10 @@ static int payload_helper_park(ast_bridge_channel_post_action_data post_it,
 
 int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
 {
-       return payload_helper_park(ast_bridge_channel_write_action_data,
+       return payload_helper_park(bridge_channel_write_action_data,
                bridge_channel, parkee_uuid, parker_uuid, app_data);
 }
 
-int ast_bridge_notify_talking(struct ast_bridge_channel *bridge_channel, int started_talking)
-{
-       struct ast_frame action = {
-               .frametype = AST_FRAME_BRIDGE_ACTION,
-               .subclass.integer = started_talking
-                       ? BRIDGE_CHANNEL_ACTION_TALKING_START : BRIDGE_CHANNEL_ACTION_TALKING_STOP,
-       };
-
-       return ast_bridge_channel_queue_frame(bridge_channel, &action);
-}
-
-struct ast_bridge_channel *ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
-{
-       struct ast_bridge *bridge = bridge_channel->bridge;
-       struct ast_bridge_channel *other = NULL;
-
-       if (bridge_channel->in_bridge && bridge->num_channels == 2) {
-               AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
-                       if (other != bridge_channel) {
-                               break;
-                       }
-               }
-       }
-
-       return other;
-}
-
-struct ast_bridge_channel *bridge_find_channel(struct ast_bridge *bridge, struct ast_channel *chan)
-{
-       struct ast_bridge_channel *bridge_channel;
-
-       AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
-               if (bridge_channel->chan == chan) {
-                       break;
-               }
-       }
-
-       return bridge_channel;
-}
-
 /*!
  * \internal
  * \brief Suspend a channel from a bridge.
@@ -748,7 +806,7 @@ struct ast_bridge_channel *bridge_find_channel(struct ast_bridge *bridge, struct
  *
  * \return Nothing
  */
-void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel)
+void bridge_channel_internal_suspend_nolock(struct ast_bridge_channel *bridge_channel)
 {
        bridge_channel->suspended = 1;
        if (bridge_channel->in_bridge) {
@@ -772,7 +830,7 @@ void bridge_channel_suspend_nolock(struct ast_bridge_channel *bridge_channel)
 static void bridge_channel_suspend(struct ast_bridge_channel *bridge_channel)
 {
        ast_bridge_channel_lock_bridge(bridge_channel);
-       bridge_channel_suspend_nolock(bridge_channel);
+       bridge_channel_internal_suspend_nolock(bridge_channel);
        ast_bridge_unlock(bridge_channel->bridge);
 }
 
@@ -786,7 +844,7 @@ static void bridge_channel_suspend(struct ast_bridge_channel *bridge_channel)
  *
  * \return Nothing
  */
-void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel)
+void bridge_channel_internal_unsuspend_nolock(struct ast_bridge_channel *bridge_channel)
 {
        bridge_channel->suspended = 0;
        if (bridge_channel->in_bridge) {
@@ -815,7 +873,7 @@ void bridge_channel_unsuspend_nolock(struct ast_bridge_channel *bridge_channel)
 static void bridge_channel_unsuspend(struct ast_bridge_channel *bridge_channel)
 {
        ast_bridge_channel_lock_bridge(bridge_channel);
-       bridge_channel_unsuspend_nolock(bridge_channel);
+       bridge_channel_internal_unsuspend_nolock(bridge_channel);
        ast_bridge_unlock(bridge_channel->bridge);
 }
 
@@ -913,14 +971,15 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha
        }
 }
 
+/*! \internal \brief Write a DTMF stream out to a channel */
 static int bridge_channel_write_dtmf_stream(struct ast_bridge_channel *bridge_channel, const char *dtmf)
 {
-       return ast_bridge_channel_write_action_data(bridge_channel,
+       return bridge_channel_write_action_data(bridge_channel,
                BRIDGE_CHANNEL_ACTION_DTMF_STREAM, dtmf, strlen(dtmf) + 1);
 }
 
 /*!
- * \brief Internal function that executes a feature on a bridge channel
+ * \internal \brief Internal function that executes a feature on a bridge channel
  * \note Neither the bridge nor the bridge_channel locks should be held when entering
  * this function.
  */
@@ -1017,6 +1076,7 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel)
        }
 }
 
+/*! \internal \brief Indicate that a bridge_channel is talking */
 static void bridge_channel_talking(struct ast_bridge_channel *bridge_channel, int talking)
 {
        struct ast_bridge_features *features = bridge_channel->features;
@@ -1051,13 +1111,13 @@ static void bridge_channel_dtmf_stream(struct ast_bridge_channel *bridge_channel
        ast_dtmf_stream(bridge_channel->chan, NULL, dtmf, 0, 0);
 }
 
-static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_channel,
-               struct blind_transfer_data *blind_data)
-{
-       ast_async_goto(bridge_channel->chan, blind_data->context, blind_data->exten, 1);
-       bridge_channel_handle_hangup(bridge_channel);
-}
+/*! \brief Data specifying where a blind transfer is going to */
+struct blind_transfer_data {
+       char exten[AST_MAX_EXTENSION];
+       char context[AST_MAX_CONTEXT];
+};
 
+/*! \internal \brief Execute after bridge actions on a channel when it leaves a bridge */
 static void after_bridge_move_channel(struct ast_channel *chan_bridged, void *data)
 {
        RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
@@ -1094,15 +1154,25 @@ static void after_bridge_move_channel(struct ast_channel *chan_bridged, void *da
        ast_party_connected_line_free(&connected_target);
 }
 
-static void after_bridge_move_channel_fail(enum ast_after_bridge_cb_reason reason, void *data)
+/*! \internal \brief Execute logic to cleanup when after bridge fails */
+static void after_bridge_move_channel_fail(enum ast_bridge_after_cb_reason reason, void *data)
 {
        RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
 
        ast_log(LOG_WARNING, "Unable to complete transfer: %s\n",
-               ast_after_bridge_cb_reason_string(reason));
+               ast_bridge_after_cb_reason_string(reason));
        ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
 }
 
+/*! \internal \brief Perform a blind transfer on a channel in a bridge */
+static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_channel,
+               struct blind_transfer_data *blind_data)
+{
+       ast_async_goto(bridge_channel->chan, blind_data->context, blind_data->exten, 1);
+       bridge_channel_handle_hangup(bridge_channel);
+}
+
+/*! \internal \brief Perform an attended transfer on a channel in a bridge */
 static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_channel,
                const char *target_chan_name)
 {
@@ -1122,11 +1192,11 @@ static void bridge_channel_attended_transfer(struct ast_bridge_channel *bridge_c
        ao2_ref(chan_bridged, +1);
        ast_bridge_channel_unlock(bridge_channel);
 
-       if (ast_after_bridge_callback_set(chan_bridged, after_bridge_move_channel,
+       if (ast_bridge_set_after_callback(chan_bridged, after_bridge_move_channel,
                after_bridge_move_channel_fail, ast_channel_ref(chan_target))) {
                ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
 
-               /* Release the ref we tried to pass to ast_after_bridge_callback_set(). */
+               /* Release the ref we tried to pass to ast_bridge_set_after_callback(). */
                ast_channel_unref(chan_target);
        }
        bridge_channel_handle_hangup(bridge_channel);
@@ -1214,7 +1284,7 @@ static void bridge_channel_handle_action(struct ast_bridge_channel *bridge_chann
  *
  * \return Nothing
  */
-static void bridge_dissolve_check(struct ast_bridge_channel *bridge_channel)
+static void bridge_channel_dissolve_check(struct ast_bridge_channel *bridge_channel)
 {
        struct ast_bridge *bridge = bridge_channel->bridge;
 
@@ -1230,7 +1300,7 @@ static void bridge_dissolve_check(struct ast_bridge_channel *bridge_channel)
        }
 
        switch (bridge_channel->state) {
-       case AST_BRIDGE_CHANNEL_STATE_END:
+       case BRIDGE_CHANNEL_STATE_END:
                /* Do we need to dissolve the bridge because this channel hung up? */
                if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_DISSOLVE_HANGUP)
                        || (bridge_channel->features->usable
@@ -1246,18 +1316,7 @@ static void bridge_dissolve_check(struct ast_bridge_channel *bridge_channel)
 /* BUGBUG need to implement AST_BRIDGE_CHANNEL_FLAG_LONELY support here */
 }
 
-/*!
- * \internal
- * \brief Pull the bridge channel out of its current bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to pull.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \return Nothing
- */
-void bridge_channel_pull(struct ast_bridge_channel *bridge_channel)
+void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel)
 {
        struct ast_bridge *bridge = bridge_channel->bridge;
 
@@ -1306,25 +1365,13 @@ void bridge_channel_pull(struct ast_bridge_channel *bridge_channel)
                ast_clear_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING);
        }
 
-       bridge_dissolve_check(bridge_channel);
+       bridge_channel_dissolve_check(bridge_channel);
 
        bridge->reconfigured = 1;
        ast_bridge_publish_leave(bridge, bridge_channel->chan);
 }
 
-/*!
- * \internal
- * \brief Push the bridge channel into its specified bridge.
- * \since 12.0.0
- *
- * \param bridge_channel Channel to push.
- *
- * \note On entry, bridge_channel->bridge is already locked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.  The channel did not get pushed.
- */
-int bridge_channel_push(struct ast_bridge_channel *bridge_channel)
+int bridge_channel_internal_push(struct ast_bridge_channel *bridge_channel)
 {
        struct ast_bridge *bridge = bridge_channel->bridge;
        struct ast_bridge_channel *swap;
@@ -1345,8 +1392,8 @@ int bridge_channel_push(struct ast_bridge_channel *bridge_channel)
 
        /* Add channel to the bridge */
        if (bridge->dissolved
-               || bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT
-               || (swap && swap->state != AST_BRIDGE_CHANNEL_STATE_WAIT)
+               || bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT
+               || (swap && swap->state != BRIDGE_CHANNEL_STATE_WAIT)
                || bridge->v_table->push(bridge, bridge_channel, swap)
                || ast_bridge_channel_establish_roles(bridge_channel)) {
                ast_debug(1, "Bridge %s: pushing %p(%s) into bridge failed\n",
@@ -1373,8 +1420,8 @@ int bridge_channel_push(struct ast_bridge_channel *bridge_channel)
 
        ast_bridge_publish_enter(bridge, bridge_channel->chan);
        if (swap) {
-               ast_bridge_channel_leave_bridge(swap, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
-               bridge_channel_pull(swap);
+               ast_bridge_channel_leave_bridge(swap, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               bridge_channel_internal_pull(swap);
        }
 
        /* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */
@@ -1517,7 +1564,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
                break;
        default:
                /* Write the frame to the channel. */
-               bridge_channel->activity = AST_BRIDGE_CHANNEL_THREAD_SIMPLE;
+               bridge_channel->activity = BRIDGE_CHANNEL_THREAD_SIMPLE;
                ast_write(bridge_channel->chan, fr);
                break;
        }
@@ -1661,7 +1708,7 @@ static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel)
 
        /* Wait for data to either come from the channel or us to be signaled */
        ast_bridge_channel_lock(bridge_channel);
-       if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
        } else if (bridge_channel->suspended) {
 /* BUGBUG the external party use of suspended will go away as will these references because this is the bridge channel thread */
                ast_debug(1, "Bridge %s: %p(%s) is going into a signal wait\n",
@@ -1687,10 +1734,10 @@ static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel)
                        ast_bridge_unlock(bridge_channel->bridge);
                }
                ast_bridge_channel_lock(bridge_channel);
-               bridge_channel->activity = AST_BRIDGE_CHANNEL_THREAD_FRAME;
+               bridge_channel->activity = BRIDGE_CHANNEL_THREAD_FRAME;
                ast_bridge_channel_unlock(bridge_channel);
                if (!bridge_channel->suspended
-                       && bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+                       && bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
                        if (chan) {
                                bridge_handle_trip(bridge_channel);
                        } else if (-1 < outfd) {
@@ -1700,7 +1747,7 @@ static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel)
                                bridge_channel_handle_interval(bridge_channel);
                        }
                }
-               bridge_channel->activity = AST_BRIDGE_CHANNEL_THREAD_IDLE;
+               bridge_channel->activity = BRIDGE_CHANNEL_THREAD_IDLE;
                return;
        }
        ast_bridge_channel_unlock(bridge_channel);
@@ -1747,7 +1794,7 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch
 }
 
 /*! \brief Join a channel to a bridge and handle anything the bridge may want us to do */
-void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
+void bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel)
 {
        ast_format_copy(&bridge_channel->read_format, ast_channel_readformat(bridge_channel->chan));
        ast_format_copy(&bridge_channel->write_format, ast_channel_writeformat(bridge_channel->chan));
@@ -1777,12 +1824,12 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
                bridge_channel->bridge->callid = ast_read_threadstorage_callid();
        }
 
-       if (bridge_channel_push(bridge_channel)) {
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+       if (bridge_channel_internal_push(bridge_channel)) {
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
        }
        bridge_reconfigured(bridge_channel->bridge, 1);
 
-       if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+       if (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
                /*
                 * Indicate a source change since this channel is entering the
                 * bridge system only if the bridge technology is not MULTIMIX
@@ -1795,7 +1842,7 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
 
                ast_bridge_unlock(bridge_channel->bridge);
                bridge_channel_event_join_leave(bridge_channel, AST_BRIDGE_HOOK_TYPE_JOIN);
-               while (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
+               while (bridge_channel->state == BRIDGE_CHANNEL_STATE_WAIT) {
                        /* Wait for something to do. */
                        bridge_channel_wait(bridge_channel);
                }
@@ -1803,7 +1850,7 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
                ast_bridge_channel_lock_bridge(bridge_channel);
        }
 
-       bridge_channel_pull(bridge_channel);
+       bridge_channel_internal_pull(bridge_channel);
        bridge_reconfigured(bridge_channel->bridge, 1);
 
        ast_bridge_unlock(bridge_channel->bridge);
@@ -1836,48 +1883,7 @@ void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
        ast_bridge_channel_restore_formats(bridge_channel);
 }
 
-void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
-{
-       ast_bridge_channel_lock(bridge_channel);
-       ast_bridge_channel_leave_bridge_nolock(bridge_channel, new_state);
-       ast_bridge_channel_unlock(bridge_channel);
-}
-
-void ast_bridge_channel_leave_bridge_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. */
-       if (bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT) {
-               return;
-       }
-
-       ast_debug(1, "Setting %p(%s) state from:%d to:%d\n",
-               bridge_channel, ast_channel_name(bridge_channel->chan), bridge_channel->state,
-               new_state);
-
-       /* Change the state on the bridge channel */
-       bridge_channel->state = new_state;
-
-       bridge_channel_poke(bridge_channel);
-}
-
-/*!
- * \internal
- * \brief Queue a blind transfer action on a transferee bridge channel
- *
- * This is only relevant for when a blind transfer is performed on a two-party
- * bridge. The transferee's bridge channel will have a blind transfer bridge
- * action queued onto it, resulting in the party being redirected to a new
- * destination
- *
- * \param transferee The channel to have the action queued on
- * \param exten The destination extension for the transferee
- * \param context The destination context for the transferee
- * \param hook Frame hook to attach to transferee
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int bridge_channel_queue_blind_transfer(struct ast_channel *transferee,
+int bridge_channel_internal_queue_blind_transfer(struct ast_channel *transferee,
                const char *exten, const char *context,
                transfer_channel_cb new_channel_cb, void *user_data)
 {
@@ -1899,11 +1905,11 @@ int bridge_channel_queue_blind_transfer(struct ast_channel *transferee,
        ast_copy_string(blind_data.exten, exten, sizeof(blind_data.exten));
        ast_copy_string(blind_data.context, context, sizeof(blind_data.context));
 
-       return ast_bridge_channel_queue_action_data(transferee_bridge_channel,
+       return bridge_channel_queue_action_data(transferee_bridge_channel,
                BRIDGE_CHANNEL_ACTION_BLIND_TRANSFER, &blind_data, sizeof(blind_data));
 }
 
-int bridge_channel_queue_attended_transfer(struct ast_channel *transferee,
+int bridge_channel_internal_queue_attended_transfer(struct ast_channel *transferee,
                struct ast_channel *unbridged_chan)
 {
        RAII_VAR(struct ast_bridge_channel *, transferee_bridge_channel, NULL, ao2_cleanup);
@@ -1920,7 +1926,114 @@ int bridge_channel_queue_attended_transfer(struct ast_channel *transferee,
        ast_copy_string(unbridged_chan_name, ast_channel_name(unbridged_chan),
                sizeof(unbridged_chan_name));
 
-       return ast_bridge_channel_queue_action_data(transferee_bridge_channel,
+       return bridge_channel_queue_action_data(transferee_bridge_channel,
                BRIDGE_CHANNEL_ACTION_ATTENDED_TRANSFER, unbridged_chan_name,
                sizeof(unbridged_chan_name));
 }
+
+int bridge_channel_internal_allows_optimization(struct ast_bridge_channel *bridge_channel)
+{
+       return bridge_channel->in_bridge
+               && AST_LIST_EMPTY(&bridge_channel->wr_queue);
+}
+
+/*!
+ * \internal
+ * \brief Close a pipe.
+ * \since 12.0.0
+ *
+ * \param my_pipe What to close.
+ *
+ * \return Nothing
+ */
+static void pipe_close(int *my_pipe)
+{
+       if (my_pipe[0] > -1) {
+               close(my_pipe[0]);
+               my_pipe[0] = -1;
+       }
+       if (my_pipe[1] > -1) {
+               close(my_pipe[1]);
+               my_pipe[1] = -1;
+       }
+}
+
+/*!
+ * \internal
+ * \brief Initialize a pipe as non-blocking.
+ * \since 12.0.0
+ *
+ * \param my_pipe What to initialize.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int pipe_init_nonblock(int *my_pipe)
+{
+       int flags;
+
+       my_pipe[0] = -1;
+       my_pipe[1] = -1;
+       if (pipe(my_pipe)) {
+               ast_log(LOG_WARNING, "Can't create pipe! Try increasing max file descriptors with ulimit -n\n");
+               return -1;
+       }
+       flags = fcntl(my_pipe[0], F_GETFL);
+       if (fcntl(my_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
+               ast_log(LOG_WARNING, "Unable to set read pipe nonblocking! (%d: %s)\n",
+                       errno, strerror(errno));
+               return -1;
+       }
+       flags = fcntl(my_pipe[1], F_GETFL);
+       if (fcntl(my_pipe[1], F_SETFL, flags | O_NONBLOCK) < 0) {
+               ast_log(LOG_WARNING, "Unable to set write pipe nonblocking! (%d: %s)\n",
+                       errno, strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+/* Destroy elements of the bridge channel structure and the bridge channel structure itself */
+static void bridge_channel_destroy(void *obj)
+{
+       struct ast_bridge_channel *bridge_channel = obj;
+       struct ast_frame *fr;
+
+       if (bridge_channel->callid) {
+               bridge_channel->callid = ast_callid_unref(bridge_channel->callid);
+       }
+
+       if (bridge_channel->bridge) {
+               ao2_ref(bridge_channel->bridge, -1);
+               bridge_channel->bridge = NULL;
+       }
+
+       /* Flush any unhandled wr_queue frames. */
+       while ((fr = AST_LIST_REMOVE_HEAD(&bridge_channel->wr_queue, frame_list))) {
+               ast_frfree(fr);
+       }
+       pipe_close(bridge_channel->alert_pipe);
+
+       ast_cond_destroy(&bridge_channel->cond);
+}
+
+struct ast_bridge_channel *bridge_channel_internal_alloc(struct ast_bridge *bridge)
+{
+       struct ast_bridge_channel *bridge_channel;
+
+       bridge_channel = ao2_alloc(sizeof(struct ast_bridge_channel), bridge_channel_destroy);
+       if (!bridge_channel) {
+               return NULL;
+       }
+       ast_cond_init(&bridge_channel->cond, NULL);
+       if (pipe_init_nonblock(bridge_channel->alert_pipe)) {
+               ao2_ref(bridge_channel, -1);
+               return NULL;
+       }
+       if (bridge) {
+               bridge_channel->bridge = bridge;
+               ao2_ref(bridge_channel->bridge, +1);
+       }
+
+       return bridge_channel;
+}
index ddbd04b..d1b33d5 100644 (file)
@@ -73,6 +73,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/test.h"
 #include "asterisk/bridging.h"
 #include "asterisk/bridging_basic.h"
+#include "asterisk/bridging_after.h"
 #include "asterisk/stasis.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/features_config.h"
@@ -839,15 +840,15 @@ static void *bridge_call_thread(void *data)
        }
 
        if (tobj->return_to_pbx) {
-               ast_after_bridge_set_goto(tobj->chan, ast_channel_context(tobj->chan),
+               ast_bridge_set_after_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_bridge_set_after_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);
 
-       ast_after_bridge_goto_run(tobj->chan);
+       ast_bridge_run_after_goto(tobj->chan);
 
        ast_free(tobj);
 
@@ -3544,7 +3545,7 @@ static void bridge_check_monitor(struct ast_channel *chan, struct ast_channel *p
  */
 static void bridge_failed_peer_goto(struct ast_channel *chan, struct ast_channel *peer)
 {
-       if (ast_after_bridge_goto_setup(peer)
+       if (ast_bridge_setup_after_goto(peer)
                || ast_pbx_start(peer)) {
                ast_autoservice_chan_hangup_peer(chan, peer);
        }
@@ -4399,7 +4400,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
                return 0;
        }
 
-       ast_after_bridge_set_go_on(chana, chana_context, chana_exten, chana_priority, NULL);
+       ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL);
        if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) {
                snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana));
                astman_send_error(s, m, buf);
@@ -4407,7 +4408,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
                return 0;
        }
 
-       ast_after_bridge_set_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL);
+       ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL);
        if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) {
                snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb));
                astman_send_error(s, m, buf);
@@ -5046,7 +5047,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
                extension = ast_strdupa(ast_channel_exten(chan));
                priority = ast_channel_priority(chan);
                ast_channel_unlock(chan);
-               ast_after_bridge_set_go_on(current_dest_chan, context, extension, priority,
+               ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority,
                        opt_args[OPT_ARG_CALLEE_GO_ON]);
        } else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
                ast_channel_lock(current_dest_chan);
@@ -5054,7 +5055,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
                extension = ast_strdupa(ast_channel_exten(current_dest_chan));
                priority = ast_channel_priority(current_dest_chan);
                ast_channel_unlock(current_dest_chan);
-               ast_after_bridge_set_goto(current_dest_chan, context, extension, priority);
+               ast_bridge_set_after_goto(current_dest_chan, context, extension, priority);
        }
 
        if (ast_bridge_features_init(&chan_features)) {
index ced288c..15d4980 100644 (file)
@@ -34,7 +34,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/pbx.h"
 #include "asterisk/bridging.h"
 #include "asterisk/bridging_internal.h"
-#include "asterisk/bridging_channel_internal.h"
 #include "asterisk/bridging_channel.h"
 #include "asterisk/bridging_features.h"
 #include "asterisk/features.h"
@@ -404,7 +403,7 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg
        user->resolution = PARK_TIMEOUT;
        ao2_unlock(user);
 
-       ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
 
        /* Set parking timeout channel variables */
        snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
@@ -492,14 +491,14 @@ void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *pa
        if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
                /* If say_parking_space is called with a non-numeric string, we have a problem. */
                ast_assert(0);
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
                return;
        }
 
        ast_say_digits(bridge_channel->chan, numeric_value, "", ast_channel_language(bridge_channel->chan));
 
        if (hangup_after) {
-               ast_bridge_channel_leave_bridge(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
        }
 }