Author: dlee Date: Mon Jul 29 09:50:04 2013 New Revision: 395652 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395652 Log: Multiple revisions 395635,395650
........ r395635 | dlee | 2013-07-29 08:36:27 -0500 (Mon, 29 Jul 2013) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-395390" from http://svn.asterisk.org/svn/asterisk/trunk ........ r395650 | dlee | 2013-07-29 09:31:44 -0500 (Mon, 29 Jul 2013) | 2 lines Merged revisions 395400-395588 from http://svn.asterisk.org/svn/asterisk/trunk ........ Merged revisions 395635,395650 from http://svn.asterisk.org/svn/asterisk/team/dlee/allow-multiple Modified: team/dlee/asterisk-info/ (props changed) team/dlee/asterisk-info/apps/app_agent_pool.c team/dlee/asterisk-info/apps/app_bridgewait.c team/dlee/asterisk-info/apps/app_confbridge.c team/dlee/asterisk-info/apps/confbridge/conf_config_parser.c team/dlee/asterisk-info/bridges/bridge_builtin_features.c team/dlee/asterisk-info/bridges/bridge_builtin_interval_features.c team/dlee/asterisk-info/include/asterisk/bridge.h team/dlee/asterisk-info/include/asterisk/bridge_channel_internal.h team/dlee/asterisk-info/include/asterisk/bridge_features.h team/dlee/asterisk-info/include/asterisk/features.h team/dlee/asterisk-info/include/asterisk/parking.h team/dlee/asterisk-info/main/bridge.c team/dlee/asterisk-info/main/bridge_basic.c team/dlee/asterisk-info/main/bridge_channel.c team/dlee/asterisk-info/main/features.c team/dlee/asterisk-info/main/parking.c team/dlee/asterisk-info/res/parking/parking_bridge_features.c team/dlee/asterisk-info/res/res_sip.c team/dlee/asterisk-info/res/res_sip/sip_configuration.c team/dlee/asterisk-info/res/res_sip_session.c team/dlee/asterisk-info/res/stasis/app.c team/dlee/asterisk-info/res/stasis_http/resource_events.c team/dlee/asterisk-info/tests/test_cel.c Propchange: team/dlee/asterisk-info/ ------------------------------------------------------------------------------ --- svnmerge-integrated (original) +++ svnmerge-integrated Mon Jul 29 09:50:04 2013 @@ -1,1 +1,1 @@ -/team/dlee/allow-multiple:1-395492 +/team/dlee/allow-multiple:1-395651 Modified: team/dlee/asterisk-info/apps/app_agent_pool.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/apps/app_agent_pool.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/apps/app_agent_pool.c (original) +++ team/dlee/asterisk-info/apps/app_agent_pool.c Mon Jul 29 09:50:04 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/asterisk-info/apps/app_bridgewait.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/apps/app_bridgewait.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/apps/app_bridgewait.c (original) +++ team/dlee/asterisk-info/apps/app_bridgewait.c Mon Jul 29 09:50:04 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/asterisk-info/apps/app_confbridge.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/apps/app_confbridge.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/apps/app_confbridge.c (original) +++ team/dlee/asterisk-info/apps/app_confbridge.c Mon Jul 29 09:50:04 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/asterisk-info/apps/confbridge/conf_config_parser.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/apps/confbridge/conf_config_parser.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/apps/confbridge/conf_config_parser.c (original) +++ team/dlee/asterisk-info/apps/confbridge/conf_config_parser.c Mon Jul 29 09:50:04 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/asterisk-info/bridges/bridge_builtin_features.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/bridges/bridge_builtin_features.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/bridges/bridge_builtin_features.c (original) +++ team/dlee/asterisk-info/bridges/bridge_builtin_features.c Mon Jul 29 09:50:04 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/asterisk-info/bridges/bridge_builtin_interval_features.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/bridges/bridge_builtin_interval_features.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/bridges/bridge_builtin_interval_features.c (original) +++ team/dlee/asterisk-info/bridges/bridge_builtin_interval_features.c Mon Jul 29 09:50:04 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/asterisk-info/include/asterisk/bridge.h URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/include/asterisk/bridge.h?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/include/asterisk/bridge.h (original) +++ team/dlee/asterisk-info/include/asterisk/bridge.h Mon Jul 29 09:50:04 2013 @@ -428,7 +428,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: * @@ -447,7 +448,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/asterisk-info/include/asterisk/bridge_channel_internal.h URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/include/asterisk/bridge_channel_internal.h?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/include/asterisk/bridge_channel_internal.h (original) +++ team/dlee/asterisk-info/include/asterisk/bridge_channel_internal.h Mon Jul 29 09:50:04 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/asterisk-info/include/asterisk/bridge_features.h URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/include/asterisk/bridge_features.h?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/include/asterisk/bridge_features.h (original) +++ team/dlee/asterisk-info/include/asterisk/bridge_features.h Mon Jul 29 09:50:04 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/asterisk-info/include/asterisk/features.h URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/include/asterisk/features.h?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/include/asterisk/features.h (original) +++ team/dlee/asterisk-info/include/asterisk/features.h Mon Jul 29 09:50:04 2013 @@ -62,52 +62,6 @@ AST_FEATURE_FLAG_BYCALLER = (1 << 4), AST_FEATURE_FLAG_BYBOTH = (3 << 3), }; - -/*! - * \brief Park a call and read back parked location - * - * \param park_me Channel to be parked. - * \param parker Channel parking the call. - * \param timeout is a timeout in milliseconds - * \param park_exten Parking lot access extension (Not used) - * \param extout is a parameter to an int that will hold the parked location, or NULL if you want. - * - * \details - * Park the park_me channel, and read back the parked location - * to the parker channel. If the call is not picked up within a - * specified period of time, then the call will return to the - * last step that it was in (in terms of exten, priority and - * context). - * - * \note Use ast_park_call_exten() instead. - * - * \retval 0 on success. - * \retval -1 on failure. - */ -int ast_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout); - -/*! - * \brief Park a call and read back parked location - * \since 1.8.9 - * - * \param park_me Channel to be parked. - * \param parker Channel parking the call. - * \param park_exten Parking lot access extension - * \param park_context Parking lot context - * \param timeout is a timeout in milliseconds - * \param extout is a parameter to an int that will hold the parked location, or NULL if you want. - * - * \details - * Park the park_me channel, and read back the parked location - * to the parker channel. If the call is not picked up within a - * specified period of time, then the call will return to the - * last step that it was in (in terms of exten, priority and - * context). - * - * \retval 0 on success. - * \retval -1 on failure. - */ -int ast_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout); /*! * \brief Park a call via a masqueraded channel Modified: team/dlee/asterisk-info/include/asterisk/parking.h URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/include/asterisk/parking.h?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/include/asterisk/parking.h (original) +++ team/dlee/asterisk-info/include/asterisk/parking.h Mon Jul 29 09:50:04 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/asterisk-info/main/bridge.c URL: http://svnview.digium.com/svn/asterisk/team/dlee/asterisk-info/main/bridge.c?view=diff&rev=395652&r1=395651&r2=395652 ============================================================================== --- team/dlee/asterisk-info/main/bridge.c (original) +++ team/dlee/asterisk-info/main/bridge.c Mon Jul 29 09:50:04 2013 @@ -1420,7 +1420,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, @@ -1428,21 +1428,21 @@ int pass_reference) { [... 2309 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
