app_bridgewait.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2013, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Author: Jonathan Rose <jrose@digium.com>
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief Application to place the channel into a holding Bridge
00024  *
00025  * \author Jonathan Rose <jrose@digium.com>
00026  *
00027  * \ingroup applications
00028  */
00029 
00030 /*** MODULEINFO
00031    <depend>bridge_holding</depend>
00032    <support_level>core</support_level>
00033  ***/
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 419539 $")
00038 
00039 #include "asterisk/file.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/features.h"
00044 #include "asterisk/say.h"
00045 #include "asterisk/lock.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/bridge.h"
00049 #include "asterisk/musiconhold.h"
00050 #include "asterisk/astobj2.h"
00051 #include "asterisk/causes.h"
00052 
00053 /*** DOCUMENTATION
00054    <application name="BridgeWait" language="en_US">
00055       <synopsis>
00056          Put a call into the holding bridge.
00057       </synopsis>
00058       <syntax>
00059          <parameter name="name">
00060             <para>Name of the holding bridge to join. This is a handle for <literal>BridgeWait</literal>
00061             only and does not affect the actual bridges that are created. If not provided,
00062             the reserved name <literal>default</literal> will be used.
00063             </para>
00064          </parameter>
00065          <parameter name="role" required="false">
00066             <para>Defines the channel's purpose for entering the holding bridge. Values are case sensitive.
00067             </para>
00068             <enumlist>
00069                <enum name="participant">
00070                   <para>The channel will enter the holding bridge to be placed on hold
00071                   until it is removed from the bridge for some reason. (default)</para>
00072                </enum>
00073                <enum name="announcer">
00074                   <para>The channel will enter the holding bridge to make announcements
00075                   to channels that are currently in the holding bridge. While an
00076                   announcer is present, holding for the participants will be
00077                   suspended.</para>
00078                </enum>
00079             </enumlist>
00080          </parameter>
00081          <parameter name="options">
00082             <optionlist>
00083                <option name="m">
00084                   <argument name="class" required="true" />
00085                   <para>The specified MOH class will be used/suggested for
00086                   music on hold operations. This option will only be useful for
00087                   entertainment modes that use it (m and h).</para>
00088                </option>
00089                <option name="e">
00090                   <para>Which entertainment mechanism should be used while on hold
00091                   in the holding bridge. Only the first letter is read.</para>
00092                   <enumlist>
00093                      <enum name="m"><para>Play music on hold (default)</para></enum>
00094                      <enum name="r"><para>Ring without pause</para></enum>
00095                      <enum name="s"><para>Generate silent audio</para></enum>
00096                      <enum name="h"><para>Put the channel on hold</para></enum>
00097                      <enum name="n"><para>No entertainment</para></enum>
00098                   </enumlist>
00099                </option>
00100                <option name="S">
00101                   <argument name="duration" required="true" />
00102                   <para>Automatically exit the bridge and return to the PBX after
00103                   <emphasis>duration</emphasis> seconds.</para>
00104                </option>
00105             </optionlist>
00106          </parameter>
00107       </syntax>
00108       <description>
00109          <para>This application places the incoming channel into a holding bridge.
00110          The channel will then wait in the holding bridge until some event occurs
00111          which removes it from the holding bridge.</para>
00112          <note><para>This application will answer calls which haven't already
00113          been answered.</para></note>
00114       </description>
00115    </application>
00116  ***/
00117 
00118 #define APP_NAME "BridgeWait"
00119 #define DEFAULT_BRIDGE_NAME "default"
00120 
00121 static struct ao2_container *wait_bridge_wrappers;
00122 
00123 struct wait_bridge_wrapper {
00124    struct ast_bridge *bridge;     /*!< Bridge being wrapped by this wrapper */
00125    char name[0];                  /*!< Name of the holding bridge wrapper */
00126 };
00127 
00128 static void wait_bridge_wrapper_destructor(void *obj)
00129 {
00130    struct wait_bridge_wrapper *wrapper = obj;
00131 
00132    if (wrapper->bridge) {
00133       ast_bridge_destroy(wrapper->bridge, 0);
00134    }
00135 }
00136 
00137 static struct wait_bridge_wrapper *wait_bridge_wrapper_find_by_name(const char *bridge_name)
00138 {
00139    return ao2_find(wait_bridge_wrappers, bridge_name, OBJ_KEY);
00140 }
00141 
00142 static int wait_bridge_hash_fn(const void *obj, const int flags)
00143 {
00144    const struct wait_bridge_wrapper *entry;
00145    const char *key;
00146 
00147    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
00148    case OBJ_KEY:
00149       key = obj;
00150       return ast_str_hash(key);
00151    case OBJ_POINTER:
00152       entry = obj;
00153       return ast_str_hash(entry->name);
00154    default:
00155       /* Hash can only work on something with a full key. */
00156       ast_assert(0);
00157       return 0;
00158    }
00159 }
00160 
00161 static int wait_bridge_sort_fn(const void *obj_left, const void *obj_right, const int flags)
00162 {
00163    const struct wait_bridge_wrapper *left = obj_left;
00164    const struct wait_bridge_wrapper *right = obj_right;
00165    const char *right_key = obj_right;
00166    int cmp;
00167 
00168    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
00169    case OBJ_POINTER:
00170       right_key = right->name;
00171       /* Fall through */
00172    case OBJ_KEY:
00173       cmp = strcmp(left->name, right_key);
00174       break;
00175    case OBJ_PARTIAL_KEY:
00176       cmp = strncmp(left->name, right_key, strlen(right_key));
00177       break;
00178    default:
00179       /* Sort can only work on something with a full or partial key. */
00180       ast_assert(0);
00181       cmp = 0;
00182       break;
00183    }
00184    return cmp;
00185 }
00186 
00187 enum bridgewait_flags {
00188    MUXFLAG_MOHCLASS = (1 << 0),
00189    MUXFLAG_ENTERTAINMENT = (1 << 1),
00190    MUXFLAG_TIMEOUT = (1 << 2),
00191 };
00192 
00193 enum bridgewait_args {
00194    OPT_ARG_ENTERTAINMENT,
00195    OPT_ARG_MOHCLASS,
00196    OPT_ARG_TIMEOUT,
00197    OPT_ARG_ARRAY_SIZE, /* Always the last element of the enum */
00198 };
00199 
00200 AST_APP_OPTIONS(bridgewait_opts, {
00201    AST_APP_OPTION_ARG('e', MUXFLAG_ENTERTAINMENT, OPT_ARG_ENTERTAINMENT),
00202    AST_APP_OPTION_ARG('m', MUXFLAG_MOHCLASS, OPT_ARG_MOHCLASS),
00203    AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT),
00204 });
00205 
00206 static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
00207 {
00208    ast_verb(3, "Channel %s timed out.\n", ast_channel_name(bridge_channel->chan));
00209    ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END,
00210       AST_CAUSE_NORMAL_CLEARING);
00211    return -1;
00212 }
00213 
00214 static int apply_option_timeout(struct ast_bridge_features *features, char *duration_arg)
00215 {
00216    unsigned int duration;
00217 
00218    if (ast_strlen_zero(duration_arg)) {
00219       ast_log(LOG_ERROR, "Timeout option 'S': No value provided.\n");
00220       return -1;
00221    }
00222    if (sscanf(duration_arg, "%u", &duration) != 1 || duration == 0) {
00223       ast_log(LOG_ERROR, "Timeout option 'S': Invalid value provided '%s'.\n",
00224          duration_arg);
00225       return -1;
00226    }
00227 
00228    duration *= 1000;
00229    if (ast_bridge_interval_hook(features, 0, duration, bridgewait_timeout_callback,
00230       NULL, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
00231       ast_log(LOG_ERROR, "Timeout option 'S': Could not create timer.\n");
00232       return -1;
00233    }
00234 
00235    return 0;
00236 }
00237 
00238 static int apply_option_moh(struct ast_channel *chan, const char *class_arg)
00239 {
00240    return ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", class_arg);
00241 }
00242 
00243 static int apply_option_entertainment(struct ast_channel *chan, const char *entertainment_arg)
00244 {
00245    char entertainment = entertainment_arg[0];
00246 
00247    switch (entertainment) {
00248    case 'm':
00249       return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
00250    case 'r':
00251       return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing");
00252    case 's':
00253       return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "silence");
00254    case 'h':
00255       return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "hold");
00256    case 'n':
00257       return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "none");
00258    default:
00259       ast_log(LOG_ERROR, "Invalid argument for BridgeWait entertainment '%s'\n", entertainment_arg);
00260       return -1;
00261    }
00262 }
00263 
00264 enum wait_bridge_roles {
00265    ROLE_PARTICIPANT = 0,
00266    ROLE_ANNOUNCER,
00267    ROLE_INVALID,
00268 };
00269 
00270 static int process_options(struct ast_channel *chan, struct ast_flags *flags, char **opts, struct ast_bridge_features *features, enum wait_bridge_roles role)
00271 {
00272    if (ast_test_flag(flags, MUXFLAG_TIMEOUT)) {
00273       if (apply_option_timeout(features, opts[OPT_ARG_TIMEOUT])) {
00274          return -1;
00275       }
00276    }
00277 
00278    switch (role) {
00279    case ROLE_PARTICIPANT:
00280       if (ast_channel_add_bridge_role(chan, "holding_participant")) {
00281          return -1;
00282       }
00283 
00284       if (ast_test_flag(flags, MUXFLAG_MOHCLASS)) {
00285          if (apply_option_moh(chan, opts[OPT_ARG_MOHCLASS])) {
00286             return -1;
00287          }
00288       }
00289 
00290       if (ast_test_flag(flags, MUXFLAG_ENTERTAINMENT)) {
00291          if (apply_option_entertainment(chan, opts[OPT_ARG_ENTERTAINMENT])) {
00292             return -1;
00293          }
00294       }
00295 
00296       break;
00297    case ROLE_ANNOUNCER:
00298       if (ast_channel_add_bridge_role(chan, "announcer")) {
00299          return -1;
00300       }
00301       break;
00302    case ROLE_INVALID:
00303       ast_assert(0);
00304       return -1;
00305    }
00306 
00307    return 0;
00308 }
00309 
00310 /*!
00311  * \internal
00312  * \since 12.0.0
00313  * \brief Allocate a new holding bridge wrapper with the given bridge name and bridge ID.
00314  *
00315  * \param bridge_name name of the bridge wrapper
00316  * \param bridge the bridge being wrapped
00317  *
00318  * \retval Pointer to the newly allocated holding bridge wrapper
00319  * \retval NULL if allocation failed. The bridge will be destroyed if this function fails.
00320  */
00321 static struct wait_bridge_wrapper *wait_bridge_wrapper_alloc(const char *bridge_name, struct ast_bridge *bridge)
00322 {
00323    struct wait_bridge_wrapper *bridge_wrapper;
00324 
00325    bridge_wrapper = ao2_alloc_options(sizeof(*bridge_wrapper) + strlen(bridge_name) + 1,
00326       wait_bridge_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
00327    if (!bridge_wrapper) {
00328       ast_bridge_destroy(bridge, 0);
00329       return NULL;
00330    }
00331 
00332    strcpy(bridge_wrapper->name, bridge_name);
00333    bridge_wrapper->bridge = bridge;
00334 
00335    if (!ao2_link(wait_bridge_wrappers, bridge_wrapper)) {
00336       ao2_cleanup(bridge_wrapper);
00337       return NULL;
00338    }
00339 
00340    return bridge_wrapper;
00341 }
00342 
00343 static struct wait_bridge_wrapper *get_wait_bridge_wrapper(const char *bridge_name)
00344 {
00345    struct wait_bridge_wrapper * wrapper;
00346    struct ast_bridge *bridge = NULL;
00347 
00348    SCOPED_AO2LOCK(lock, wait_bridge_wrappers);
00349 
00350    if ((wrapper = wait_bridge_wrapper_find_by_name(bridge_name))) {
00351       return wrapper;
00352    }
00353 
00354    /*
00355     * Holding bridges can allow local channel move/swap
00356     * optimization to the bridge.  However, we cannot allow it for
00357     * this holding bridge because the call will lose the channel
00358     * roles and dialplan location as a result.
00359     */
00360    bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING,
00361       AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
00362       | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
00363       | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED, APP_NAME, bridge_name, NULL);
00364 
00365    if (!bridge) {
00366       return NULL;
00367    }
00368 
00369    /* The bridge reference is unconditionally passed. */
00370    return wait_bridge_wrapper_alloc(bridge_name, bridge);
00371 }
00372 
00373 /*!
00374  * \internal
00375  * \since 12.0.0
00376  * \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.
00377  *
00378  * \param wrapper reference to wait bridge wrapper being checked for list culling - will be cleared on exit
00379  */
00380 static void wait_wrapper_removal(struct wait_bridge_wrapper *wrapper)
00381 {
00382    if (!wrapper) {
00383       return;
00384    }
00385 
00386    ao2_lock(wait_bridge_wrappers);
00387    if (ao2_ref(wrapper, 0) == 2) {
00388       /* Either we have the only real reference or else wrapper isn't in the container anyway. */
00389       ao2_unlink(wait_bridge_wrappers, wrapper);
00390    }
00391    ao2_unlock(wait_bridge_wrappers);
00392 
00393    ao2_cleanup(wrapper);
00394 }
00395 
00396 /*!
00397  * \internal
00398  * \since 12.0.0
00399  * \brief Application callback for the bridgewait application
00400  *
00401  * \param chan channel running the application
00402  * \param data Arguments to the application
00403  *
00404  * \retval 0 Ran successfully and the call didn't hang up
00405  * \retval -1 Failed or the call was hung up by the time the channel exited the holding bridge
00406  */
00407 static enum wait_bridge_roles validate_role(const char *role)
00408 {
00409    if (!strcmp(role, "participant")) {
00410       return ROLE_PARTICIPANT;
00411    } else if (!strcmp(role, "announcer")) {
00412       return ROLE_ANNOUNCER;
00413    } else {
00414       return ROLE_INVALID;
00415    }
00416 }
00417 
00418 static int bridgewait_exec(struct ast_channel *chan, const char *data)
00419 {
00420    char *bridge_name = DEFAULT_BRIDGE_NAME;
00421    struct ast_bridge_features chan_features;
00422    struct ast_flags flags = { 0 };
00423    char *parse;
00424    enum wait_bridge_roles role = ROLE_PARTICIPANT;
00425    char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00426    struct wait_bridge_wrapper *bridge_wrapper;
00427    int res;
00428 
00429    AST_DECLARE_APP_ARGS(args,
00430       AST_APP_ARG(name);
00431       AST_APP_ARG(role);
00432       AST_APP_ARG(options);
00433       AST_APP_ARG(other);     /* Any remaining unused arguments */
00434    );
00435 
00436    parse = ast_strdupa(data);
00437    AST_STANDARD_APP_ARGS(args, parse);
00438 
00439    if (!ast_strlen_zero(args.name)) {
00440       bridge_name = args.name;
00441    }
00442 
00443    if (!ast_strlen_zero(args.role)) {
00444       role = validate_role(args.role);
00445       if (role == ROLE_INVALID) {
00446          ast_log(LOG_ERROR, "Requested waiting bridge role '%s' is invalid.\n", args.role);
00447          return -1;
00448       }
00449    }
00450 
00451    if (ast_bridge_features_init(&chan_features)) {
00452       ast_bridge_features_cleanup(&chan_features);
00453       ast_log(LOG_ERROR, "'%s' failed to enter the waiting bridge - could not set up channel features\n",
00454          ast_channel_name(chan));
00455       return -1;
00456    }
00457 
00458    if (args.options) {
00459       ast_app_parse_options(bridgewait_opts, &flags, opts, args.options);
00460    }
00461 
00462    /* Answer the channel if needed */
00463    if (ast_channel_state(chan) != AST_STATE_UP) {
00464       ast_answer(chan);
00465    }
00466 
00467    if (process_options(chan, &flags, opts, &chan_features, role)) {
00468       ast_bridge_features_cleanup(&chan_features);
00469       return -1;
00470    }
00471 
00472    bridge_wrapper = get_wait_bridge_wrapper(bridge_name);
00473    if (!bridge_wrapper) {
00474       ast_log(LOG_WARNING, "Failed to find or create waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
00475       ast_bridge_features_cleanup(&chan_features);
00476       return -1;
00477    }
00478 
00479    ast_verb(3, "%s is entering waiting bridge %s:%s\n", ast_channel_name(chan), bridge_name, bridge_wrapper->bridge->uniqueid);
00480    res = ast_bridge_join(bridge_wrapper->bridge, chan, NULL, &chan_features, NULL, 0);
00481    wait_wrapper_removal(bridge_wrapper);
00482    ast_bridge_features_cleanup(&chan_features);
00483 
00484    if (res) {
00485       /* For the lifetime of the bridge wrapper the bridge itself will be valid, if an error occurs it is because
00486        * of extreme situations.
00487        */
00488       ast_log(LOG_WARNING, "Failed to join waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
00489    }
00490 
00491    return (res || ast_check_hangup_locked(chan)) ? -1 : 0;
00492 }
00493 
00494 static int unload_module(void)
00495 {
00496    ao2_cleanup(wait_bridge_wrappers);
00497 
00498    return ast_unregister_application(APP_NAME);
00499 }
00500 
00501 static int load_module(void)
00502 {
00503    wait_bridge_wrappers = ao2_container_alloc_hash(
00504       AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
00505       37, wait_bridge_hash_fn, wait_bridge_sort_fn, NULL);
00506 
00507    if (!wait_bridge_wrappers) {
00508       return -1;
00509    }
00510 
00511    return ast_register_application_xml(APP_NAME, bridgewait_exec);
00512 }
00513 
00514 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Place the channel into a holding bridge application");

Generated on Thu Apr 16 06:27:08 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6