bridge_holding.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  * Jonathan Rose <jrose@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Bridging technology for storing channels in a bridge for
00022  *        the purpose of holding, parking, queues, and other such
00023  *        states where a channel may need to be in a bridge but not
00024  *        actually communicating with anything.
00025  *
00026  * \author Jonathan Rose <jrose@digium.com>
00027  *
00028  * \ingroup bridges
00029  */
00030 
00031 /*** MODULEINFO
00032    <support_level>core</support_level>
00033  ***/
00034 
00035 #include "asterisk.h"
00036 
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 434430 $")
00038 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044 
00045 #include "asterisk/module.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/bridge.h"
00048 #include "asterisk/bridge_technology.h"
00049 #include "asterisk/frame.h"
00050 #include "asterisk/musiconhold.h"
00051 #include "asterisk/format_cache.h"
00052 
00053 enum holding_roles {
00054    HOLDING_ROLE_PARTICIPANT,
00055    HOLDING_ROLE_ANNOUNCER,
00056 };
00057 
00058 enum idle_modes {
00059    IDLE_MODE_NONE,
00060    IDLE_MODE_MOH,
00061    IDLE_MODE_RINGING,
00062    IDLE_MODE_SILENCE,
00063    IDLE_MODE_HOLD,
00064 };
00065 
00066 /*! \brief Structure which contains per-channel role information */
00067 struct holding_channel {
00068    struct ast_silence_generator *silence_generator;
00069    enum holding_roles role;
00070    enum idle_modes idle_mode;
00071    /*! TRUE if the entertainment is started. */
00072    unsigned int entertainment_active:1;
00073 };
00074 
00075 typedef void (*deferred_cb)(struct ast_bridge_channel *bridge_channel);
00076 
00077 struct deferred_data {
00078    /*! Deferred holding technology callback */
00079    deferred_cb callback;
00080 };
00081 
00082 static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size);
00083 
00084 /*!
00085  * \internal
00086  * \brief Defer an action to a bridge_channel.
00087  * \since 12.0.0
00088  *
00089  * \param bridge_channel Which channel to operate on.
00090  * \param callback action to defer.
00091  *
00092  * \retval 0 on success.
00093  * \retval -1 on error.
00094  */
00095 static int defer_action(struct ast_bridge_channel *bridge_channel, deferred_cb callback)
00096 {
00097    struct deferred_data data = { .callback = callback };
00098    int res;
00099 
00100    res = ast_bridge_channel_queue_callback(bridge_channel, 0, deferred_action,
00101       &data, sizeof(data));
00102    if (res) {
00103       ast_log(LOG_WARNING, "Bridge %s: Could not defer action on %s.\n",
00104          bridge_channel->bridge->uniqueid, ast_channel_name(bridge_channel->chan));
00105    }
00106    return res;
00107 }
00108 
00109 /*!
00110  * \internal
00111  * \brief Setup participant idle mode from channel.
00112  * \since 12.0.0
00113  *
00114  * \param bridge_channel Channel to setup idle mode.
00115  *
00116  * \return Nothing
00117  */
00118 static void participant_idle_mode_setup(struct ast_bridge_channel *bridge_channel)
00119 {
00120    const char *idle_mode = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "idle_mode");
00121    struct holding_channel *hc = bridge_channel->tech_pvt;
00122 
00123    ast_assert(hc != NULL);
00124 
00125    if (ast_strlen_zero(idle_mode)) {
00126       hc->idle_mode = IDLE_MODE_MOH;
00127    } else if (!strcmp(idle_mode, "musiconhold")) {
00128       hc->idle_mode = IDLE_MODE_MOH;
00129    } else if (!strcmp(idle_mode, "ringing")) {
00130       hc->idle_mode = IDLE_MODE_RINGING;
00131    } else if (!strcmp(idle_mode, "none")) {
00132       hc->idle_mode = IDLE_MODE_NONE;
00133    } else if (!strcmp(idle_mode, "silence")) {
00134       hc->idle_mode = IDLE_MODE_SILENCE;
00135    } else if (!strcmp(idle_mode, "hold")) {
00136       hc->idle_mode = IDLE_MODE_HOLD;
00137    } else {
00138       /* Invalid idle mode requested. */
00139       ast_debug(1, "channel %s idle mode '%s' doesn't match any defined idle mode\n",
00140          ast_channel_name(bridge_channel->chan), idle_mode);
00141       ast_assert(0);
00142    }
00143 }
00144 
00145 static void participant_entertainment_stop(struct ast_bridge_channel *bridge_channel)
00146 {
00147    struct holding_channel *hc = bridge_channel->tech_pvt;
00148 
00149    ast_assert(hc != NULL);
00150 
00151    if (!hc->entertainment_active) {
00152       /* Already stopped */
00153       return;
00154    }
00155    hc->entertainment_active = 0;
00156 
00157    switch (hc->idle_mode) {
00158    case IDLE_MODE_MOH:
00159       ast_moh_stop(bridge_channel->chan);
00160       break;
00161    case IDLE_MODE_RINGING:
00162       ast_indicate(bridge_channel->chan, -1);
00163       break;
00164    case IDLE_MODE_NONE:
00165       break;
00166    case IDLE_MODE_SILENCE:
00167       if (hc->silence_generator) {
00168          ast_channel_stop_silence_generator(bridge_channel->chan, hc->silence_generator);
00169          hc->silence_generator = NULL;
00170       }
00171       break;
00172    case IDLE_MODE_HOLD:
00173       ast_indicate(bridge_channel->chan, AST_CONTROL_UNHOLD);
00174       break;
00175    }
00176 }
00177 
00178 static void participant_reaction_announcer_join(struct ast_bridge_channel *bridge_channel)
00179 {
00180    struct ast_channel *chan;
00181 
00182    chan = bridge_channel->chan;
00183    participant_entertainment_stop(bridge_channel);
00184    if (ast_set_write_format(chan, ast_format_slin)) {
00185       ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(chan));
00186    }
00187 }
00188 
00189 /* This should only be called on verified holding_participants. */
00190 static void participant_entertainment_start(struct ast_bridge_channel *bridge_channel)
00191 {
00192    struct holding_channel *hc = bridge_channel->tech_pvt;
00193    const char *moh_class;
00194    size_t moh_length;
00195 
00196    ast_assert(hc != NULL);
00197 
00198    if (hc->entertainment_active) {
00199       /* Already started */
00200       return;
00201    }
00202    hc->entertainment_active = 1;
00203 
00204    participant_idle_mode_setup(bridge_channel);
00205    switch(hc->idle_mode) {
00206    case IDLE_MODE_MOH:
00207       moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
00208       ast_moh_start(bridge_channel->chan, moh_class, NULL);
00209       break;
00210    case IDLE_MODE_RINGING:
00211       ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
00212       break;
00213    case IDLE_MODE_NONE:
00214       break;
00215    case IDLE_MODE_SILENCE:
00216       hc->silence_generator = ast_channel_start_silence_generator(bridge_channel->chan);
00217       break;
00218    case IDLE_MODE_HOLD:
00219       moh_class = ast_bridge_channel_get_role_option(bridge_channel, "holding_participant", "moh_class");
00220       moh_length = moh_class ? strlen(moh_class + 1) : 0;
00221       ast_indicate_data(bridge_channel->chan, AST_CONTROL_HOLD, moh_class, moh_length);
00222       break;
00223    }
00224 }
00225 
00226 static void handle_participant_join(struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
00227 {
00228    struct ast_channel *us = bridge_channel->chan;
00229 
00230    /* If the announcer channel isn't present, we need to set up ringing, music on hold, or whatever. */
00231    if (!announcer_channel) {
00232       defer_action(bridge_channel, participant_entertainment_start);
00233       return;
00234    }
00235 
00236    /* We need to get compatible with the announcer. */
00237    if (ast_set_write_format(us, ast_format_slin)) {
00238       ast_log(LOG_WARNING, "Could not make participant %s compatible.\n", ast_channel_name(us));
00239    }
00240 }
00241 
00242 static int holding_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
00243 {
00244    struct ast_bridge_channel *other_channel;
00245    struct ast_bridge_channel *announcer_channel;
00246    struct holding_channel *hc;
00247    struct ast_channel *us = bridge_channel->chan; /* The joining channel */
00248 
00249    ast_assert(bridge_channel->tech_pvt == NULL);
00250 
00251    if (!(hc = ast_calloc(1, sizeof(*hc)))) {
00252       return -1;
00253    }
00254 
00255    bridge_channel->tech_pvt = hc;
00256 
00257    /* The bridge pvt holds the announcer channel if we have one. */
00258    announcer_channel = bridge->tech_pvt;
00259 
00260    if (ast_bridge_channel_has_role(bridge_channel, "announcer")) {
00261       if (announcer_channel) {
00262          /* Another announcer already exists. */
00263          bridge_channel->tech_pvt = NULL;
00264          ast_free(hc);
00265          ast_log(LOG_WARNING, "Bridge %s: Channel %s tried to be an announcer.  Bridge already has one.\n",
00266             bridge->uniqueid, ast_channel_name(bridge_channel->chan));
00267          return -1;
00268       }
00269 
00270       bridge->tech_pvt = bridge_channel;
00271       hc->role = HOLDING_ROLE_ANNOUNCER;
00272 
00273       /* The announcer should always be made compatible with signed linear */
00274       if (ast_set_read_format(us, ast_format_slin)) {
00275          ast_log(LOG_ERROR, "Could not make announcer %s compatible.\n", ast_channel_name(us));
00276       }
00277 
00278       /* Make everyone listen to the announcer. */
00279       AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
00280          /* Skip the reaction if we are the channel in question */
00281          if (bridge_channel == other_channel) {
00282             continue;
00283          }
00284          defer_action(other_channel, participant_reaction_announcer_join);
00285       }
00286 
00287       return 0;
00288    }
00289 
00290    hc->role = HOLDING_ROLE_PARTICIPANT;
00291    handle_participant_join(bridge_channel, announcer_channel);
00292    return 0;
00293 }
00294 
00295 static void participant_reaction_announcer_leave(struct ast_bridge_channel *bridge_channel)
00296 {
00297    ast_bridge_channel_restore_formats(bridge_channel);
00298    participant_entertainment_start(bridge_channel);
00299 }
00300 
00301 static void holding_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
00302 {
00303    struct ast_bridge_channel *other_channel;
00304    struct holding_channel *hc = bridge_channel->tech_pvt;
00305 
00306    if (!hc) {
00307       return;
00308    }
00309 
00310    switch (hc->role) {
00311    case HOLDING_ROLE_ANNOUNCER:
00312       /* The announcer is leaving */
00313       bridge->tech_pvt = NULL;
00314 
00315       /* Reset the other channels back to moh/ringing. */
00316       AST_LIST_TRAVERSE(&bridge->channels, other_channel, entry) {
00317          defer_action(other_channel, participant_reaction_announcer_leave);
00318       }
00319       break;
00320    default:
00321       /* Nothing needs to react to its departure. */
00322       participant_entertainment_stop(bridge_channel);
00323       break;
00324    }
00325    bridge_channel->tech_pvt = NULL;
00326    ast_free(hc);
00327 }
00328 
00329 static int holding_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
00330 {
00331    struct holding_channel *hc = bridge_channel ? bridge_channel->tech_pvt : NULL;
00332 
00333    /* If there is no tech_pvt, then the channel failed to allocate one when it joined and is borked. Don't listen to him. */
00334    if (!hc) {
00335       /* "Accept" the frame and discard it. */
00336       return 0;
00337    }
00338 
00339    switch (hc->role) {
00340    case HOLDING_ROLE_ANNOUNCER:
00341       /* Write the frame to all other channels if any. */
00342       ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
00343       break;
00344    default:
00345       /* "Accept" the frame and discard it. */
00346       break;
00347    }
00348 
00349    return 0;
00350 }
00351 
00352 static void holding_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
00353 {
00354    struct holding_channel *hc = bridge_channel->tech_pvt;
00355 
00356    if (!hc) {
00357       return;
00358    }
00359 
00360    switch (hc->role) {
00361    case HOLDING_ROLE_PARTICIPANT:
00362       participant_entertainment_stop(bridge_channel);
00363       break;
00364    default:
00365       break;
00366    }
00367 }
00368 
00369 static void holding_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
00370 {
00371    struct holding_channel *hc = bridge_channel->tech_pvt;
00372    struct ast_bridge_channel *announcer_channel = bridge->tech_pvt;
00373 
00374    if (!hc) {
00375       return;
00376    }
00377 
00378    switch (hc->role) {
00379    case HOLDING_ROLE_PARTICIPANT:
00380       if (announcer_channel) {
00381          /* There is an announcer channel in the bridge. */
00382          break;
00383       }
00384       /* We need to restart the entertainment. */
00385       participant_entertainment_start(bridge_channel);
00386       break;
00387    default:
00388       break;
00389    }
00390 }
00391 
00392 static struct ast_bridge_technology holding_bridge = {
00393    .name = "holding_bridge",
00394    .capabilities = AST_BRIDGE_CAPABILITY_HOLDING,
00395    .preference = AST_BRIDGE_PREFERENCE_BASE_HOLDING,
00396    .write = holding_bridge_write,
00397    .join = holding_bridge_join,
00398    .leave = holding_bridge_leave,
00399    .suspend = holding_bridge_suspend,
00400    .unsuspend = holding_bridge_unsuspend,
00401 };
00402 
00403 /*!
00404  * \internal
00405  * \brief Deferred action to start/stop participant entertainment.
00406  * \since 12.0.0
00407  *
00408  * \param bridge_channel Which channel to operate on.
00409  * \param payload Data to pass to the callback. (NULL if none).
00410  * \param payload_size Size of the payload if payload is non-NULL.  A number otherwise.
00411  *
00412  * \return Nothing
00413  */
00414 static void deferred_action(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
00415 {
00416    const struct deferred_data *data = payload;
00417 
00418    ast_bridge_channel_lock_bridge(bridge_channel);
00419    if (bridge_channel->bridge->technology != &holding_bridge
00420       || !bridge_channel->tech_pvt) {
00421       /* Not valid anymore. */
00422       ast_bridge_unlock(bridge_channel->bridge);
00423       return;
00424    }
00425    data->callback(bridge_channel);
00426    ast_bridge_unlock(bridge_channel->bridge);
00427 }
00428 
00429 static int unload_module(void)
00430 {
00431    ast_bridge_technology_unregister(&holding_bridge);
00432    return 0;
00433 }
00434 
00435 static int load_module(void)
00436 {
00437    if (ast_bridge_technology_register(&holding_bridge)) {
00438       unload_module();
00439       return AST_MODULE_LOAD_DECLINE;
00440    }
00441    return AST_MODULE_LOAD_SUCCESS;
00442 }
00443 
00444 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Holding bridge module");
00445 

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