Author: dlee
Date: Mon Jul 29 13:37:06 2013
New Revision: 395701

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395701
Log:
Merged revisions 395439-395588 from http://svn.asterisk.org/svn/asterisk/trunk

Modified:
    team/dlee/stasis-cache-split/   (props changed)
    team/dlee/stasis-cache-split/apps/app_agent_pool.c
    team/dlee/stasis-cache-split/apps/app_bridgewait.c
    team/dlee/stasis-cache-split/apps/app_confbridge.c
    team/dlee/stasis-cache-split/apps/confbridge/conf_config_parser.c
    team/dlee/stasis-cache-split/bridges/bridge_builtin_features.c
    team/dlee/stasis-cache-split/bridges/bridge_builtin_interval_features.c
    team/dlee/stasis-cache-split/include/asterisk/bridge.h
    team/dlee/stasis-cache-split/include/asterisk/bridge_channel_internal.h
    team/dlee/stasis-cache-split/include/asterisk/bridge_features.h
    team/dlee/stasis-cache-split/include/asterisk/parking.h
    team/dlee/stasis-cache-split/main/bridge.c
    team/dlee/stasis-cache-split/main/bridge_basic.c
    team/dlee/stasis-cache-split/main/bridge_channel.c
    team/dlee/stasis-cache-split/main/features.c
    team/dlee/stasis-cache-split/main/parking.c
    team/dlee/stasis-cache-split/res/parking/parking_bridge_features.c
    team/dlee/stasis-cache-split/res/res_sip.c
    team/dlee/stasis-cache-split/res/res_sip/sip_configuration.c
    team/dlee/stasis-cache-split/res/res_sip_session.c
    team/dlee/stasis-cache-split/res/stasis/app.c
    team/dlee/stasis-cache-split/res/stasis_http/resource_events.c
    team/dlee/stasis-cache-split/tests/test_cel.c

Propchange: team/dlee/stasis-cache-split/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Jul 29 13:37:06 2013
@@ -1,1 +1,1 @@
-/trunk:1-395430
+/trunk:1-395588

Modified: team/dlee/stasis-cache-split/apps/app_agent_pool.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/apps/app_agent_pool.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/apps/app_agent_pool.c (original)
+++ team/dlee/stasis-cache-split/apps/app_agent_pool.c Mon Jul 29 13:37:06 2013
@@ -1078,12 +1078,11 @@
                 * The agent is in the new bridge so we can invoke the
                 * mixmonitor hook to only start recording.
                 */
-               ast_bridge_features_do(AST_BRIDGE_BUILTIN_AUTOMIXMON, 
caller_bridge,
-                       bridge_channel, &options);
-       }
-}
-
-static int bridge_agent_hold_ack(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+               ast_bridge_features_do(AST_BRIDGE_BUILTIN_AUTOMIXMON, 
bridge_channel, &options);
+       }
+}
+
+static int bridge_agent_hold_ack(struct ast_bridge_channel *bridge_channel, 
void *hook_pvt)
 {
        struct agent_pvt *agent = hook_pvt;
 
@@ -1101,7 +1100,7 @@
        return 0;
 }
 
-static int bridge_agent_hold_heartbeat(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int bridge_agent_hold_heartbeat(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt)
 {
        struct agent_pvt *agent = hook_pvt;
        int probation_timedout = 0;
@@ -1709,7 +1708,7 @@
        ast_bridge_channel_unlock(logged);
 }
 
-static int caller_safety_timeout(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int caller_safety_timeout(struct ast_bridge_channel *bridge_channel, 
void *hook_pvt)
 {
        struct agent_pvt *agent = hook_pvt;
 

Modified: team/dlee/stasis-cache-split/apps/app_bridgewait.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/apps/app_bridgewait.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/apps/app_bridgewait.c (original)
+++ team/dlee/stasis-cache-split/apps/app_bridgewait.c Mon Jul 29 13:37:06 2013
@@ -47,6 +47,7 @@
 #include "asterisk/app.h"
 #include "asterisk/bridge.h"
 #include "asterisk/musiconhold.h"
+#include "asterisk/astobj2.h"
 
 /*** DOCUMENTATION
        <application name="BridgeWait" language="en_US">
@@ -54,6 +55,12 @@
                        Put a call into the holding bridge.
                </synopsis>
                <syntax>
+                       <parameter name="name">
+                               <para>Name of the holding bridge to join. This 
is a handle for <literal>BridgeWait</literal>
+                               only and does not affect the actual bridges 
that are created. If not provided,
+                               the reserved name <literal>default</literal> 
will be used.
+                               </para>
+                       </parameter>
                        <parameter name="role" required="false">
                                <para>Defines the channel's purpose for 
entering the holding bridge. Values are case sensitive.
                                </para>
@@ -99,19 +106,81 @@
                </syntax>
                <description>
                        <para>This application places the incoming channel into 
a holding bridge.
-                       The channel will then wait in the holding bridge until 
some
-                       event occurs which removes it from the holding 
bridge.</para>
+                       The channel will then wait in the holding bridge until 
some event occurs
+                       which removes it from the holding bridge.</para>
+                       <note><para>This application will answer calls which 
haven't already
+                       been answered.</para></note>
                </description>
        </application>
  ***/
-/* BUGBUG Add bridge name/id parameter to specify which holding bridge to join 
(required) */
-/* BUGBUG The channel may or may not be answered with the r option. */
-/* BUGBUG You should not place an announcer into a holding bridge with 
unanswered channels. */
-
-static char *app = "BridgeWait";
-static struct ast_bridge *holding_bridge;
-
-AST_MUTEX_DEFINE_STATIC(bridgewait_lock);
+
+#define APP_NAME "BridgeWait"
+#define DEFAULT_BRIDGE_NAME "default"
+
+static struct ao2_container *wait_bridge_wrappers;
+
+struct wait_bridge_wrapper {
+       struct ast_bridge *bridge;     /*!< Bridge being wrapped by this 
wrapper */
+       char name[0];                  /*!< Name of the holding bridge wrapper 
*/
+};
+
+static void wait_bridge_wrapper_destructor(void *obj)
+{
+       struct wait_bridge_wrapper *wrapper = obj;
+       if (wrapper->bridge) {
+               ast_bridge_destroy(wrapper->bridge);
+       }
+}
+
+static struct wait_bridge_wrapper *wait_bridge_wrapper_find_by_name(const char 
*bridge_name)
+{
+       return ao2_find(wait_bridge_wrappers, bridge_name, OBJ_KEY);
+}
+
+static int wait_bridge_hash_fn(const void *obj, const int flags)
+{
+       const struct wait_bridge_wrapper *entry;
+       const char *key;
+
+       switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+       case OBJ_KEY:
+               key = obj;
+               return ast_str_hash(key);
+       case OBJ_POINTER:
+               entry = obj;
+               return ast_str_hash(entry->name);
+       default:
+               /* Hash can only work on something with a full key. */
+               ast_assert(0);
+               return 0;
+       }
+}
+
+static int wait_bridge_sort_fn(const void *obj_left, const void *obj_right, 
const int flags)
+{
+       const struct wait_bridge_wrapper *left = obj_left;
+       const struct wait_bridge_wrapper *right = obj_right;
+       const char *right_key = obj_right;
+       int cmp;
+
+       switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+       case OBJ_POINTER:
+               right_key = right->name;
+               /* Fall through */
+       case OBJ_KEY:
+               cmp = strcmp(left->name, right_key);
+               break;
+       case OBJ_PARTIAL_KEY:
+               cmp = strncmp(left->name, right_key, strlen(right_key));
+               break;
+       default:
+               /* Sort can only work on something with a full or partial key. 
*/
+               ast_assert(0);
+               cmp = 0;
+               break;
+       }
+       return cmp;
+}
 
 enum bridgewait_flags {
        MUXFLAG_MOHCLASS = (1 << 0),
@@ -132,30 +201,33 @@
        AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT),
 });
 
+static int bridgewait_timeout_callback(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt)
+{
+       ast_verb(3, "Channel %s timed out.\n", 
ast_channel_name(bridge_channel->chan));
+       ast_bridge_channel_leave_bridge(bridge_channel, 
BRIDGE_CHANNEL_STATE_END);
+       return -1;
+}
+
 static int apply_option_timeout(struct ast_bridge_features *features, char 
*duration_arg)
 {
-       struct ast_bridge_features_limits hold_limits;
+       unsigned int duration;
 
        if (ast_strlen_zero(duration_arg)) {
-               ast_log(LOG_ERROR, "No duration value provided for the timeout 
('S') option.\n");
-               return -1;
-       }
-
-       if (ast_bridge_features_limits_construct(&hold_limits)) {
-               ast_log(LOG_ERROR, "Could not construct duration limits. Bridge 
canceled.\n");
-               return -1;
-       }
-
-       if (sscanf(duration_arg, "%u", &(hold_limits.duration)) != 1 || 
hold_limits.duration == 0) {
-               ast_log(LOG_ERROR, "Duration value provided for the timeout 
('S') option must be greater than 0\n");
-               ast_bridge_features_limits_destroy(&hold_limits);
-               return -1;
-       }
-
-       /* Limits struct holds time as milliseconds, so muliply 1000x */
-       hold_limits.duration *= 1000;
-       ast_bridge_features_set_limits(features, &hold_limits, 
AST_BRIDGE_HOOK_REMOVE_ON_PULL);
-       ast_bridge_features_limits_destroy(&hold_limits);
+               ast_log(LOG_ERROR, "Timeout option 'S': No value provided.\n");
+               return -1;
+       }
+       if (sscanf(duration_arg, "%u", &duration) != 1 || duration == 0) {
+               ast_log(LOG_ERROR, "Timeout option 'S': Invalid value provided 
'%s'.\n",
+                       duration_arg);
+               return -1;
+       }
+
+       duration *= 1000;
+       if (ast_bridge_interval_hook(features, duration, 
bridgewait_timeout_callback,
+               NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
+               ast_log(LOG_ERROR, "Timeout option 'S': Could not create 
timer.\n");
+               return -1;
+       }
 
        return 0;
 }
@@ -168,6 +240,7 @@
 static int apply_option_entertainment(struct ast_channel *chan, const char 
*entertainment_arg)
 {
        char entertainment = entertainment_arg[0];
+
        switch (entertainment) {
        case 'm':
                return ast_channel_set_bridge_role_option(chan, 
"holding_participant", "idle_mode", "musiconhold");
@@ -231,6 +304,98 @@
        return 0;
 }
 
+/*!
+ * \internal
+ * \since 12.0.0
+ * \brief Allocate a new holding bridge wrapper with the given bridge name and 
bridge ID.
+ *
+ * \param bridge_name name of the bridge wrapper
+ * \param bridge the bridge being wrapped
+ *
+ * \retval Pointer to the newly allocated holding bridge wrapper
+ * \retval NULL if allocation failed. The bridge will be destroyed if this 
function fails.
+ */
+static struct wait_bridge_wrapper *wait_bridge_wrapper_alloc(const char 
*bridge_name, struct ast_bridge *bridge)
+{
+       struct wait_bridge_wrapper *bridge_wrapper;
+
+       bridge_wrapper = ao2_alloc_options(sizeof(*bridge_wrapper) + 
strlen(bridge_name) + 1,
+               wait_bridge_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+
+       if (!bridge_wrapper) {
+               ast_bridge_destroy(bridge);
+               return NULL;
+       }
+
+       strcpy(bridge_wrapper->name, bridge_name);
+       bridge_wrapper->bridge = bridge;
+
+       if (!ao2_link(wait_bridge_wrappers, bridge_wrapper)) {
+               ao2_cleanup(bridge_wrapper);
+               return NULL;
+       }
+
+       return bridge_wrapper;
+}
+
+static struct wait_bridge_wrapper *get_wait_bridge_wrapper(const char 
*bridge_name)
+{
+       struct wait_bridge_wrapper * wrapper;
+       struct ast_bridge *bridge = NULL;
+
+       SCOPED_AO2LOCK(lock, wait_bridge_wrappers);
+
+       if ((wrapper = wait_bridge_wrapper_find_by_name(bridge_name))) {
+               return wrapper;
+       }
+
+       bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
+               AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | 
AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
+               | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | 
AST_BRIDGE_FLAG_TRANSFER_PROHIBITED
+               | AST_BRIDGE_FLAG_DISSOLVE_EMPTY);
+
+       if (!bridge) {
+               return NULL;
+       }
+
+       /* The bridge reference is unconditionally passed. */
+       return wait_bridge_wrapper_alloc(bridge_name, bridge);
+}
+
+/*!
+ * \internal
+ * \since 12.0.0
+ * \brief If we are down to the last reference of a wrapper and it's still 
contained within the list, remove it from the list.
+ *
+ * \param wrapper reference to wait bridge wrapper being checked for list 
culling - will be cleared on exit
+ */
+static void wait_wrapper_removal(struct wait_bridge_wrapper *wrapper)
+{
+       if (!wrapper) {
+               return;
+       }
+
+       ao2_lock(wait_bridge_wrappers);
+       if (ao2_ref(wrapper, 0) == 2) {
+               /* Either we have the only real reference or else wrapper isn't 
in the container anyway. */
+               ao2_unlink(wait_bridge_wrappers, wrapper);
+       }
+       ao2_unlock(wait_bridge_wrappers);
+
+       ao2_cleanup(wrapper);
+}
+
+/*!
+ * \internal
+ * \since 12.0.0
+ * \brief Application callback for the bridgewait application
+ *
+ * \param chan channel running the application
+ * \param data Arguments to the application
+ *
+ * \retval 0 Ran successfully and the call didn't hang up
+ * \retval -1 Failed or the call was hung up by the time the channel exited 
the holding bridge
+ */
 static enum wait_bridge_roles validate_role(const char *role)
 {
        if (!strcmp(role, "participant")) {
@@ -244,32 +409,27 @@
 
 static int bridgewait_exec(struct ast_channel *chan, const char *data)
 {
+       char *bridge_name = DEFAULT_BRIDGE_NAME;
        struct ast_bridge_features chan_features;
        struct ast_flags flags = { 0 };
        char *parse;
+       int bridge_join_failed = 0;
        enum wait_bridge_roles role = ROLE_PARTICIPANT;
        char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
 
        AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(name);
                AST_APP_ARG(role);
                AST_APP_ARG(options);
                AST_APP_ARG(other);             /* Any remaining unused 
arguments */
        );
 
-       ast_mutex_lock(&bridgewait_lock);
-       if (!holding_bridge) {
-               holding_bridge = 
ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
-                       AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | 
AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
-                               | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | 
AST_BRIDGE_FLAG_TRANSFER_PROHIBITED);
-       }
-       ast_mutex_unlock(&bridgewait_lock);
-       if (!holding_bridge) {
-               ast_log(LOG_ERROR, "Could not create holding bridge for 
'%s'.\n", ast_channel_name(chan));
-               return -1;
-       }
-
        parse = ast_strdupa(data);
        AST_STANDARD_APP_ARGS(args, parse);
+
+       if (!ast_strlen_zero(args.name)) {
+               bridge_name = args.name;
+       }
 
        if (!ast_strlen_zero(args.role)) {
                role = validate_role(args.role);
@@ -281,6 +441,8 @@
 
        if (ast_bridge_features_init(&chan_features)) {
                ast_bridge_features_cleanup(&chan_features);
+               ast_log(LOG_ERROR, "'%s' failed to enter the waiting bridge - 
could not set up channel features\n",
+                       ast_channel_name(chan));
                return -1;
        }
 
@@ -288,28 +450,66 @@
                ast_app_parse_options(bridgewait_opts, &flags, opts, 
args.options);
        }
 
+       /* Answer the channel if needed */
+       if (ast_channel_state(chan) != AST_STATE_UP) {
+               ast_answer(chan);
+       }
+
        if (process_options(chan, &flags, opts, &chan_features, role)) {
                ast_bridge_features_cleanup(&chan_features);
                return -1;
        }
 
-       ast_bridge_join(holding_bridge, chan, NULL, &chan_features, NULL, 0);
+       for (;;) {
+               RAII_VAR(struct wait_bridge_wrapper *, bridge_wrapper, 
get_wait_bridge_wrapper(bridge_name), wait_wrapper_removal);
+
+               if (!bridge_wrapper) {
+                       ast_log(LOG_WARNING, "Failed to find or create waiting 
bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
+                       bridge_join_failed = 1;
+                       break;
+               }
+
+               ast_verb(3, "%s is entering waiting bridge %s:%s\n", 
ast_channel_name(chan), bridge_name, bridge_wrapper->bridge->uniqueid);
+
+               if (ast_bridge_join(bridge_wrapper->bridge, chan, NULL, 
&chan_features, NULL, 0)) {
+                       /* It's possible for a holding bridge to vanish out 
from under us since we can't lock it.
+                        * Unlink the wrapper and then loop if the bridge we 
try to enter is dissolved. */
+                       ast_verb(3, "Waiting bridge '%s:%s' is no longer 
joinable. Creating new bridge and trying again.\n",
+                               bridge_name, bridge_wrapper->bridge->uniqueid);
+                       ao2_unlink(wait_bridge_wrappers, bridge_wrapper);
+                       continue;
+               }
+
+               break;
+       }
 
        ast_bridge_features_cleanup(&chan_features);
+
+       if (bridge_join_failed) {
+               return -1;
+       }
+
        return ast_check_hangup_locked(chan) ? -1 : 0;
 }
 
 static int unload_module(void)
 {
-       ao2_cleanup(holding_bridge);
-       holding_bridge = NULL;
-
-       return ast_unregister_application(app);
+       ao2_cleanup(wait_bridge_wrappers);
+
+       return ast_unregister_application(APP_NAME);
 }
 
 static int load_module(void)
 {
-       return ast_register_application_xml(app, bridgewait_exec);
+       wait_bridge_wrappers = ao2_container_alloc_hash(
+               AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
+               37, wait_bridge_hash_fn, wait_bridge_sort_fn, NULL);
+
+       if (!wait_bridge_wrappers) {
+               return -1;
+       }
+
+       return ast_register_application_xml(APP_NAME, bridgewait_exec);
 }
 
 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Place the channel into a holding 
bridge application");

Modified: team/dlee/stasis-cache-split/apps/app_confbridge.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/apps/app_confbridge.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/apps/app_confbridge.c (original)
+++ team/dlee/stasis-cache-split/apps/app_confbridge.c Mon Jul 29 13:37:06 2013
@@ -1402,9 +1402,9 @@
        ast_free(pvt_data);
 }
 
-static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, 
void *pvt_data, int talking)
-{
-       const char *conf_name = pvt_data;
+static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, 
void *hook_pvt, int talking)
+{
+       const char *conf_name = hook_pvt;
        struct confbridge_conference *conference = ao2_find(conference_bridges, 
conf_name, OBJ_KEY);
        struct ast_json *talking_extras;
 

Modified: team/dlee/stasis-cache-split/apps/confbridge/conf_config_parser.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/apps/confbridge/conf_config_parser.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/apps/confbridge/conf_config_parser.c (original)
+++ team/dlee/stasis-cache-split/apps/confbridge/conf_config_parser.c Mon Jul 
29 13:37:06 2013
@@ -2080,9 +2080,10 @@
        ast_free(pvt);
 }
 
-static int menu_hook_callback(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void 
*hook_pvt)
 {
        struct dtmf_menu_hook_pvt *pvt = hook_pvt;
+
        return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, 
pvt->menu);
 }
 

Modified: team/dlee/stasis-cache-split/bridges/bridge_builtin_features.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/bridges/bridge_builtin_features.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/bridges/bridge_builtin_features.c (original)
+++ team/dlee/stasis-cache-split/bridges/bridge_builtin_features.c Mon Jul 29 
13:37:06 2013
@@ -214,7 +214,7 @@
        pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", 
touch_filename);
 }
 
-static int feature_automonitor(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void 
*hook_pvt)
 {
        const char *start_message;
        const char *stop_message;
@@ -226,7 +226,9 @@
        RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, 
ao2_cleanup);
 
        features_cfg = 
ast_get_chan_features_general_config(bridge_channel->chan);
-       peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
+       ast_bridge_channel_lock_bridge(bridge_channel);
+       peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, 
bridge_channel->chan);
+       ast_bridge_unlock(bridge_channel->bridge);
 
        if (!peer_chan) {
                ast_verb(3, "Cannot start AutoMonitor for %s - can not 
determine peer in bridge.\n",
@@ -397,7 +399,7 @@
        pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", 
touch_filename);
 }
 
-static int feature_automixmonitor(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, 
void *hook_pvt)
 {
        static const char *mixmonitor_spy_type = "MixMonitor";
        const char *stop_message;
@@ -410,7 +412,9 @@
        RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, 
ao2_cleanup);
 
        features_cfg = 
ast_get_chan_features_general_config(bridge_channel->chan);
-       peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
+       ast_bridge_channel_lock_bridge(bridge_channel);
+       peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, 
bridge_channel->chan);
+       ast_bridge_unlock(bridge_channel->bridge);
 
        if (!peer_chan) {
                ast_verb(3, "Cannot do AutoMixMonitor for %s - cannot determine 
peer in bridge.\n",
@@ -476,7 +480,7 @@
 }
 
 /*! \brief Internal built in feature for hangup */
-static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel 
*bridge_channel, void *hook_pvt)
+static int feature_hangup(struct ast_bridge_channel *bridge_channel, void 
*hook_pvt)
 {
        /*
         * This is very simple, we simply change the state on the

Modified: 
team/dlee/stasis-cache-split/bridges/bridge_builtin_interval_features.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/bridges/bridge_builtin_interval_features.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/bridges/bridge_builtin_interval_features.c 
(original)
+++ team/dlee/stasis-cache-split/bridges/bridge_builtin_interval_features.c Mon 
Jul 29 13:37:06 2013
@@ -31,7 +31,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$REVISION: 381278 $")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -50,7 +50,7 @@
 #include "asterisk/stringfields.h"
 #include "asterisk/musiconhold.h"
 
-static int bridge_features_duration_callback(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int bridge_features_duration_callback(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt)
 {
        struct ast_bridge_features_limits *limits = hook_pvt;
 
@@ -64,7 +64,7 @@
        return -1;
 }
 
-static void limits_interval_playback(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, struct ast_bridge_features_limits *limits, 
const char *file)
+static void limits_interval_playback(struct ast_bridge_channel 
*bridge_channel, struct ast_bridge_features_limits *limits, const char *file)
 {
        if (!strcasecmp(file, "timeleft")) {
                unsigned int remaining = ast_tvdiff_ms(limits->quitting_time, 
ast_tvnow()) / 1000;
@@ -110,88 +110,87 @@
        }
 }
 
-static int bridge_features_connect_callback(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int bridge_features_connect_callback(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt)
 {
        struct ast_bridge_features_limits *limits = hook_pvt;
 
-       if (bridge_channel->state != BRIDGE_CHANNEL_STATE_WAIT) {
-               return -1;
-       }
-
-       limits_interval_playback(bridge, bridge_channel, limits, 
limits->connect_sound);
+       limits_interval_playback(bridge_channel, limits, limits->connect_sound);
        return -1;
 }
 
-static int bridge_features_warning_callback(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
+static int bridge_features_warning_callback(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt)
 {
        struct ast_bridge_features_limits *limits = hook_pvt;
 
-       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);
-       }
-
-       return !limits->frequency ? -1 : limits->frequency;
-}
-
-static void copy_bridge_features_limits(struct ast_bridge_features_limits 
*dst, struct ast_bridge_features_limits *src)
-{
+       limits_interval_playback(bridge_channel, limits, limits->warning_sound);
+       return limits->frequency ?: -1;
+}
+
+static void bridge_features_limits_copy(struct ast_bridge_features_limits 
*dst, struct ast_bridge_features_limits *src)
+{
+       ast_string_fields_copy(dst, src);
+       dst->quitting_time = src->quitting_time;
        dst->duration = src->duration;
        dst->warning = src->warning;
        dst->frequency = src->frequency;
-       dst->quitting_time = src->quitting_time;
-
-       ast_string_field_set(dst, duration_sound, src->duration_sound);
-       ast_string_field_set(dst, warning_sound, src->warning_sound);
-       ast_string_field_set(dst, connect_sound, src->connect_sound);
+}
+
+static void bridge_features_limits_dtor(void *vdoomed)
+{
+       struct ast_bridge_features_limits *doomed = vdoomed;
+
+       ast_bridge_features_limits_destroy(doomed);
+       ast_module_unref(ast_module_info->self);
 }
 
 static int bridge_builtin_set_limits(struct ast_bridge_features *features,
-               struct ast_bridge_features_limits *limits, enum 
ast_bridge_hook_remove_flags remove_flags)
-{
-       struct ast_bridge_features_limits *feature_limits;
+       struct ast_bridge_features_limits *limits,
+       enum ast_bridge_hook_remove_flags remove_flags)
+{
+       RAII_VAR(struct ast_bridge_features_limits *, feature_limits, NULL, 
ao2_cleanup);
 
        if (!limits->duration) {
                return -1;
        }
 
-       if (features->limits) {
-               ast_log(LOG_ERROR, "Tried to apply limits to a feature set that 
already has limits.\n");
-               return -1;
-       }
-
-       feature_limits = ast_malloc(sizeof(*feature_limits));
+       /* Create limits hook_pvt data. */
+       ast_module_ref(ast_module_info->self);
+       feature_limits = ao2_alloc_options(sizeof(*feature_limits),
+               bridge_features_limits_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
        if (!feature_limits) {
-               return -1;
-       }
-
+               ast_module_unref(ast_module_info->self);
+               return -1;
+       }
        if (ast_bridge_features_limits_construct(feature_limits)) {
                return -1;
        }
-
-       copy_bridge_features_limits(feature_limits, limits);
-       features->limits = feature_limits;
-
-/* BUGBUG feature interval hooks need to be reimplemented to be more stand 
alone. */
+       bridge_features_limits_copy(feature_limits, limits);
+       feature_limits->quitting_time = ast_tvadd(ast_tvnow(),
+               ast_samp2tv(feature_limits->duration, 1000));
+
+       /* Install limit hooks. */
+       ao2_ref(feature_limits, +1);
        if (ast_bridge_interval_hook(features, feature_limits->duration,
-               bridge_features_duration_callback, feature_limits, NULL, 
remove_flags)) {
+               bridge_features_duration_callback, feature_limits, 
__ao2_cleanup, remove_flags)) {
                ast_log(LOG_ERROR, "Failed to schedule the duration limiter to 
the bridge channel.\n");
-               return -1;
-       }
-
-       feature_limits->quitting_time = ast_tvadd(ast_tvnow(), 
ast_samp2tv(feature_limits->duration, 1000));
-
+               ao2_ref(feature_limits, -1);
+               return -1;
+       }
        if (!ast_strlen_zero(feature_limits->connect_sound)) {
+               ao2_ref(feature_limits, +1);
                if (ast_bridge_interval_hook(features, 1,
-                       bridge_features_connect_callback, feature_limits, NULL, 
remove_flags)) {
+                       bridge_features_connect_callback, feature_limits, 
__ao2_cleanup, remove_flags)) {
                        ast_log(LOG_WARNING, "Failed to schedule connect sound 
to the bridge channel.\n");
-               }
-       }
-
+                       ao2_ref(feature_limits, -1);
+               }
+       }
        if (feature_limits->warning && feature_limits->warning < 
feature_limits->duration) {
-               if (ast_bridge_interval_hook(features, feature_limits->duration 
- feature_limits->warning,
-                       bridge_features_warning_callback, feature_limits, NULL, 
remove_flags)) {
+               ao2_ref(feature_limits, +1);
+               if (ast_bridge_interval_hook(features,
+                       feature_limits->duration - feature_limits->warning,
+                       bridge_features_warning_callback, feature_limits, 
__ao2_cleanup, remove_flags)) {
                        ast_log(LOG_WARNING, "Failed to schedule warning sound 
playback to the bridge channel.\n");
+                       ao2_ref(feature_limits, -1);
                }
        }
 
@@ -200,17 +199,14 @@
 
 static int unload_module(void)
 {
+       ast_bridge_interval_unregister(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS);
        return 0;
 }
 
 static int load_module(void)
 {
-       ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS, 
bridge_builtin_set_limits);
-
-       /* Bump up our reference count so we can't be unloaded. */
-       ast_module_ref(ast_module_info->self);
-
-       return AST_MODULE_LOAD_SUCCESS;
+       return ast_bridge_interval_register(AST_BRIDGE_BUILTIN_INTERVAL_LIMITS,
+               bridge_builtin_set_limits);
 }
 
 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging interval 
features");

Modified: team/dlee/stasis-cache-split/include/asterisk/bridge.h
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/include/asterisk/bridge.h?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/include/asterisk/bridge.h (original)
+++ team/dlee/stasis-cache-split/include/asterisk/bridge.h Mon Jul 29 13:37:06 
2013
@@ -430,7 +430,8 @@
  * \note Absolutely _NO_ locks should be held before calling
  * this function since it blocks.
  *
- * \retval state that channel exited the bridge with
+ * \retval 0 if the channel successfully joined the bridge before it exited.
+ * \retval -1 if the channel failed to join the bridge
  *
  * Example usage:
  *
@@ -449,7 +450,7 @@
  * If channel specific features are enabled a pointer to the features structure
  * can be specified in the features parameter.
  */
-enum bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+int ast_bridge_join(struct ast_bridge *bridge,
        struct ast_channel *chan,
        struct ast_channel *swap,
        struct ast_bridge_features *features,

Modified: 
team/dlee/stasis-cache-split/include/asterisk/bridge_channel_internal.h
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/include/asterisk/bridge_channel_internal.h?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/include/asterisk/bridge_channel_internal.h 
(original)
+++ team/dlee/stasis-cache-split/include/asterisk/bridge_channel_internal.h Mon 
Jul 29 13:37:06 2013
@@ -117,11 +117,14 @@
  *
  * \param bridge_channel The Channel in the bridge
  *
+ * \retval 0 bridge channel successfully joined the bridge
+ * \retval -1 bridge channel failed to join the bridge
+ *
  * \note This API call starts the bridge_channel's processing of events while
  * it is in the bridge. It will return when the channel has been instructed to
  * leave the bridge.
  */
-void bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel);
+int bridge_channel_internal_join(struct ast_bridge_channel *bridge_channel);
 
 /*!
  * \internal

Modified: team/dlee/stasis-cache-split/include/asterisk/bridge_features.h
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/include/asterisk/bridge_features.h?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/include/asterisk/bridge_features.h (original)
+++ team/dlee/stasis-cache-split/include/asterisk/bridge_features.h Mon Jul 29 
13:37:06 2013
@@ -118,7 +118,6 @@
 /*!
  * \brief Hook callback type
  *
- * \param bridge The bridge that the channel is part of
  * \param bridge_channel Channel executing the feature
  * \param hook_pvt Private data passed in when the hook was created
  *
@@ -131,7 +130,7 @@
  * \retval 0 Keep the callback hook.
  * \retval -1 Remove the callback hook.
  */
-typedef int (*ast_bridge_hook_callback)(struct ast_bridge *bridge, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt);
+typedef int (*ast_bridge_hook_callback)(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt);
 
 /*!
  * \brief Hook pvt destructor callback
@@ -143,17 +142,19 @@
 /*!
  * \brief Talking indicator callback
  *
- * \details This callback can be registered with the bridge in order
- * to receive updates on when a bridge_channel has started and stopped
- * talking
+ * \details
+ * This callback can be registered with the bridge channel in
+ * order to receive updates when the bridge_channel has started
+ * and stopped talking.
  *
  * \param bridge_channel Channel executing the feature
+ * \param hook_pvt Private data passed in when the hook was created
  * \param talking TRUE if the channel is now talking
  *
  * \retval 0 Keep the callback hook.
  * \retval -1 Remove the callback hook.
  */
-typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel 
*bridge_channel, void *pvt_data, int talking);
+typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel 
*bridge_channel, void *hook_pvt, int talking);
 
 enum ast_bridge_hook_remove_flags {
        /*! The hook is removed when the channel is pulled from the bridge. */
@@ -237,8 +238,6 @@
        struct ao2_container *other_hooks;
        /*! Attached interval hooks */
        struct ast_heap *interval_hooks;
-       /*! Limits feature data */
-       struct ast_bridge_features_limits *limits;
        /*! Feature flags that are enabled */
        struct ast_flags feature_flags;
        /*! Used to assign the sequence number to the next interval hook added. 
*/
@@ -298,13 +297,6 @@
  * \brief Structure that contains configuration information for the limits 
feature
  */
 struct ast_bridge_features_limits {
-       /*! Maximum duration that the channel is allowed to be in the bridge 
(specified in milliseconds) */
-       unsigned int duration;
-       /*! Duration into the call when warnings should begin (specified in 
milliseconds or 0 to disable) */
-       unsigned int warning;
-       /*! Interval between the warnings (specified in milliseconds or 0 to 
disable) */
-       unsigned int frequency;
-
        AST_DECLARE_STRING_FIELDS(
                /*! Sound file to play when the maximum duration is reached (if 
empty, then nothing will be played) */
                AST_STRING_FIELD(duration_sound);
@@ -315,6 +307,12 @@
        );
        /*! Time when the bridge will be terminated by the limits feature */
        struct timeval quitting_time;
+       /*! Maximum duration that the channel is allowed to be in the bridge 
(specified in milliseconds) */
+       unsigned int duration;
+       /*! Duration into the call when warnings should begin (specified in 
milliseconds or 0 to disable) */
+       unsigned int warning;
+       /*! Interval between the warnings (specified in milliseconds or 0 to 
disable) */
+       unsigned int frequency;
 };
 
 /*!
@@ -360,6 +358,8 @@
  * \brief Invoke a built in feature hook now.
  *
  * \param feature The feature to invoke
+ * \param bridge_channel Channel executing the feature
+ * \param hook_pvt Private data passed in when the hook was created
  *
  * \note This API call is only meant to be used by bridge
  * subclasses and hook callbacks to request a builtin feature
@@ -371,10 +371,10 @@
  * Example usage:
  *
  * \code
- * ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge, 
bridge_channel, hook_pvt);
- * \endcode
- */
-int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct 
ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
+ * ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, 
bridge_channel, hook_pvt);
+ * \endcode
+ */
+int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt);
 
 /*!
  * \brief Attach interval hooks to a bridge features structure

Modified: team/dlee/stasis-cache-split/include/asterisk/parking.h
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/include/asterisk/parking.h?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/include/asterisk/parking.h (original)
+++ team/dlee/stasis-cache-split/include/asterisk/parking.h Mon Jul 29 13:37:06 
2013
@@ -111,8 +111,7 @@
        const char *parker_uuid,
        const char *app_data);
 
-typedef int (*ast_park_blind_xfer_fn)(struct ast_bridge *bridge, struct 
ast_bridge_channel *parker,
-       struct ast_exten *park_exten);
+typedef int (*ast_park_blind_xfer_fn)(struct ast_bridge_channel *parker, 
struct ast_exten *park_exten);
 
 /*!
  * \brief install a callback for handling blind transfers to a parking 
extension
@@ -132,15 +131,13 @@
  * \brief use the installed park blind xfer func
  * \since 12
  *
- * \param bridge Bridge being transferred from
- * \param bridge_channel Bridge channel initiating the transfer
- * \param app_data arguments to the park application
+ * \param parker Bridge channel initiating the park
+ * \param park_exten Exten to blind transfer part to.
  *
  * \retval 0 on success
  * \retval -1 on failure
  */
-int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel 
*parker,
-               struct ast_exten *park_exten);
+int ast_park_blind_xfer(struct ast_bridge_channel *parker, struct ast_exten 
*park_exten);
 
 typedef void (*ast_bridge_channel_park_fn)(struct ast_bridge_channel *parkee, 
const char *parkee_uuid,
        const char *parker_uuid, const char *app_data);

Modified: team/dlee/stasis-cache-split/main/bridge.c
URL: 
http://svnview.digium.com/svn/asterisk/team/dlee/stasis-cache-split/main/bridge.c?view=diff&rev=395701&r1=395700&r2=395701
==============================================================================
--- team/dlee/stasis-cache-split/main/bridge.c (original)
+++ team/dlee/stasis-cache-split/main/bridge.c Mon Jul 29 13:37:06 2013
@@ -1430,7 +1430,7 @@
  * Need to update the features parameter doxygen when this
  * change is made to be like ast_bridge_impart().
  */
-enum bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+int ast_bridge_join(struct ast_bridge *bridge,
        struct ast_channel *chan,
        struct ast_channel *swap,
        struct ast_bridge_features *features,
@@ -1438,21 +1438,21 @@
        int pass_reference)
 {
        struct ast_bridge_channel *bridge_channel;
-       enum bridge_channel_state state;
+       int res;
 
        bridge_channel = bridge_channel_internal_alloc(bridge);
        if (pass_reference) {
                ao2_ref(bridge, -1);
        }
        if (!bridge_channel) {
-               state = BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE;
+               res = -1;
                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 = BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE;
+               res = -1;
                goto join_exit;
        }
        if (tech_args) {
@@ -1468,8 +1468,7 @@
        bridge_channel->swap = swap;
        bridge_channel->features = features;
 
-       bridge_channel_internal_join(bridge_channel);
-       state = bridge_channel->state;
+       res = bridge_channel_internal_join(bridge_channel);
 
        /* Cleanup all the data in the bridge channel after it leaves the 
bridge. */
        ast_channel_lock(chan);
@@ -1491,7 +1490,7 @@
                ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
                ast_channel_unlock(chan);
        }
-       return state;
+       return res;
 }
 
 /*! \brief Thread responsible for imparted bridged channels to be departed */
@@ -2686,7 +2685,7 @@
        return 0;
 }
 
-int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct 
ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct 
ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
        ast_bridge_hook_callback callback;
 
@@ -2698,7 +2697,7 @@
        if (!callback) {
                return -1;
        }
-       callback(bridge, bridge_channel, hook_pvt);
+       callback(bridge_channel, hook_pvt);
 
        return 0;
 }
@@ -2985,7 +2984,6 @@
        memset(limits, 0, sizeof(*limits));
 
        if (ast_string_field_init(limits, 256)) {
-               ast_free(limits);
                return -1;
        }
 
@@ -2998,13 +2996,14 @@
 }
 
 int ast_bridge_features_set_limits(struct ast_bridge_features *features,
-               struct ast_bridge_features_limits *limits, enum 
ast_bridge_hook_remove_flags remove_flags)
+       struct ast_bridge_features_limits *limits,
+       enum ast_bridge_hook_remove_flags remove_flags)
 {
        if (builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS]) {
-               ast_bridge_builtin_set_limits_fn 
bridge_features_set_limits_callback;
-
-               bridge_features_set_limits_callback = 
builtin_interval_handlers[AST_BRIDGE_BUILTIN_INTERVAL_LIMITS];
-               return bridge_features_set_limits_callback(features, limits, 
remove_flags);
+               ast_bridge_builtin_set_limits_fn callback;
+

[... 744 lines stripped ...]

--
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to