bridge_holding.c File Reference

Bridging technology for storing channels in a bridge for the purpose of holding, parking, queues, and other such states where a channel may need to be in a bridge but not actually communicating with anything. More...

#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_technology.h"
#include "asterisk/frame.h"
#include "asterisk/musiconhold.h"
#include "asterisk/format_cache.h"

Include dependency graph for bridge_holding.c:

Go to the source code of this file.

Data Structures

struct  deferred_data
struct  holding_channel
 Structure which contains per-channel role information. More...

Typedefs

typedef void(* deferred_cb )(struct ast_bridge_channel *bridge_channel)

Enumerations

enum  holding_roles { HOLDING_ROLE_PARTICIPANT, HOLDING_ROLE_ANNOUNCER }
enum  idle_modes {
  IDLE_MODE_NONE, IDLE_MODE_MOH, IDLE_MODE_RINGING, IDLE_MODE_SILENCE,
  IDLE_MODE_HOLD
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int defer_action (struct ast_bridge_channel *bridge_channel, deferred_cb callback)
static void deferred_action (struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
static void handle_participant_join (struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *announcer_channel)
static int holding_bridge_join (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static void holding_bridge_leave (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static void holding_bridge_suspend (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static void holding_bridge_unsuspend (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
static int holding_bridge_write (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
static int load_module (void)
static void participant_entertainment_start (struct ast_bridge_channel *bridge_channel)
static void participant_entertainment_stop (struct ast_bridge_channel *bridge_channel)
static void participant_idle_mode_setup (struct ast_bridge_channel *bridge_channel)
static void participant_reaction_announcer_join (struct ast_bridge_channel *bridge_channel)
static void participant_reaction_announcer_leave (struct ast_bridge_channel *bridge_channel)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Holding bridge module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_bridge_technology holding_bridge


Detailed Description

Bridging technology for storing channels in a bridge for the purpose of holding, parking, queues, and other such states where a channel may need to be in a bridge but not actually communicating with anything.

Author:
Jonathan Rose <jrose@digium.com>

Definition in file bridge_holding.c.


Typedef Documentation

typedef void(* deferred_cb)(struct ast_bridge_channel *bridge_channel)

Definition at line 75 of file bridge_holding.c.


Enumeration Type Documentation

Enumerator:
HOLDING_ROLE_PARTICIPANT 
HOLDING_ROLE_ANNOUNCER 

Definition at line 53 of file bridge_holding.c.

00053                    {
00054    HOLDING_ROLE_PARTICIPANT,
00055    HOLDING_ROLE_ANNOUNCER,
00056 };

enum idle_modes

Enumerator:
IDLE_MODE_NONE 
IDLE_MODE_MOH 
IDLE_MODE_RINGING 
IDLE_MODE_SILENCE 
IDLE_MODE_HOLD 

Definition at line 58 of file bridge_holding.c.

00058                 {
00059    IDLE_MODE_NONE,
00060    IDLE_MODE_MOH,
00061    IDLE_MODE_RINGING,
00062    IDLE_MODE_SILENCE,
00063    IDLE_MODE_HOLD,
00064 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 444 of file bridge_holding.c.

static void __unreg_module ( void   )  [static]

Definition at line 444 of file bridge_holding.c.

static int defer_action ( struct ast_bridge_channel bridge_channel,
deferred_cb  callback 
) [static]

Definition at line 95 of file bridge_holding.c.

References ast_bridge_channel_queue_callback(), ast_channel_name(), ast_log, ast_bridge_channel::bridge, deferred_data::callback, ast_bridge_channel::chan, deferred_action(), LOG_WARNING, and ast_bridge::uniqueid.

Referenced by handle_participant_join(), holding_bridge_join(), and holding_bridge_leave().

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 }

static void deferred_action ( struct ast_bridge_channel bridge_channel,
const void *  payload,
size_t  payload_size 
) [static]

Definition at line 414 of file bridge_holding.c.

References ast_bridge_channel_lock_bridge(), ast_bridge_unlock, ast_bridge_channel::bridge, deferred_data::callback, ast_bridge_channel::tech_pvt, and ast_bridge::technology.

Referenced by defer_action(), and smart_bridge_operation().

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 }

static void handle_participant_join ( struct ast_bridge_channel bridge_channel,
struct ast_bridge_channel announcer_channel 
) [static]

Definition at line 226 of file bridge_holding.c.

References ast_channel_name(), ast_format_slin, ast_log, ast_set_write_format(), ast_bridge_channel::chan, defer_action(), LOG_WARNING, and participant_entertainment_start().

Referenced by holding_bridge_join().

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 }

static int holding_bridge_join ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
) [static]

Definition at line 242 of file bridge_holding.c.

References ast_assert, ast_bridge_channel_has_role(), ast_calloc, ast_channel_name(), ast_format_slin, ast_free, AST_LIST_TRAVERSE, ast_log, ast_set_read_format(), ast_bridge_channel::chan, ast_bridge::channels, defer_action(), handle_participant_join(), HOLDING_ROLE_ANNOUNCER, HOLDING_ROLE_PARTICIPANT, LOG_ERROR, LOG_WARNING, NULL, participant_reaction_announcer_join(), holding_channel::role, ast_bridge::tech_pvt, ast_bridge_channel::tech_pvt, and ast_bridge::uniqueid.

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 }

static void holding_bridge_leave ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
) [static]

Definition at line 301 of file bridge_holding.c.

References ast_free, AST_LIST_TRAVERSE, ast_bridge::channels, defer_action(), HOLDING_ROLE_ANNOUNCER, NULL, participant_entertainment_stop(), participant_reaction_announcer_leave(), holding_channel::role, ast_bridge::tech_pvt, and ast_bridge_channel::tech_pvt.

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 }

static void holding_bridge_suspend ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
) [static]

Definition at line 352 of file bridge_holding.c.

References HOLDING_ROLE_PARTICIPANT, participant_entertainment_stop(), holding_channel::role, and ast_bridge_channel::tech_pvt.

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 }

static void holding_bridge_unsuspend ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel 
) [static]

Definition at line 369 of file bridge_holding.c.

References HOLDING_ROLE_PARTICIPANT, participant_entertainment_start(), holding_channel::role, ast_bridge::tech_pvt, and ast_bridge_channel::tech_pvt.

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 }

static int holding_bridge_write ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
struct ast_frame frame 
) [static]

Definition at line 329 of file bridge_holding.c.

References ast_bridge_queue_everyone_else(), HOLDING_ROLE_ANNOUNCER, NULL, holding_channel::role, and ast_bridge_channel::tech_pvt.

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 }

static int load_module ( void   )  [static]

static void participant_entertainment_start ( struct ast_bridge_channel bridge_channel  )  [static]

Definition at line 190 of file bridge_holding.c.

References ast_assert, ast_bridge_channel_get_role_option(), ast_channel_start_silence_generator(), AST_CONTROL_HOLD, AST_CONTROL_RINGING, ast_indicate(), ast_indicate_data(), ast_moh_start(), ast_bridge_channel::chan, holding_channel::entertainment_active, holding_channel::idle_mode, IDLE_MODE_HOLD, IDLE_MODE_MOH, IDLE_MODE_NONE, IDLE_MODE_RINGING, IDLE_MODE_SILENCE, NULL, participant_idle_mode_setup(), holding_channel::silence_generator, and ast_bridge_channel::tech_pvt.

Referenced by handle_participant_join(), holding_bridge_unsuspend(), and participant_reaction_announcer_leave().

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 }

static void participant_entertainment_stop ( struct ast_bridge_channel bridge_channel  )  [static]

Definition at line 145 of file bridge_holding.c.

References ast_assert, ast_channel_stop_silence_generator(), AST_CONTROL_UNHOLD, ast_indicate(), ast_moh_stop(), ast_bridge_channel::chan, holding_channel::entertainment_active, holding_channel::idle_mode, IDLE_MODE_HOLD, IDLE_MODE_MOH, IDLE_MODE_NONE, IDLE_MODE_RINGING, IDLE_MODE_SILENCE, NULL, holding_channel::silence_generator, and ast_bridge_channel::tech_pvt.

Referenced by holding_bridge_leave(), holding_bridge_suspend(), and participant_reaction_announcer_join().

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 }

static void participant_idle_mode_setup ( struct ast_bridge_channel bridge_channel  )  [static]

Definition at line 118 of file bridge_holding.c.

References ast_assert, ast_bridge_channel_get_role_option(), ast_channel_name(), ast_debug, ast_strlen_zero, ast_bridge_channel::chan, holding_channel::idle_mode, IDLE_MODE_HOLD, IDLE_MODE_MOH, IDLE_MODE_NONE, IDLE_MODE_RINGING, IDLE_MODE_SILENCE, NULL, and ast_bridge_channel::tech_pvt.

Referenced by participant_entertainment_start().

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 }

static void participant_reaction_announcer_join ( struct ast_bridge_channel bridge_channel  )  [static]

Definition at line 178 of file bridge_holding.c.

References ast_channel_name(), ast_format_slin, ast_log, ast_set_write_format(), ast_bridge_channel::chan, LOG_WARNING, and participant_entertainment_stop().

Referenced by holding_bridge_join().

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 }

static void participant_reaction_announcer_leave ( struct ast_bridge_channel bridge_channel  )  [static]

Definition at line 295 of file bridge_holding.c.

References ast_bridge_channel_restore_formats(), and participant_entertainment_start().

Referenced by holding_bridge_leave().

00296 {
00297    ast_bridge_channel_restore_formats(bridge_channel);
00298    participant_entertainment_start(bridge_channel);
00299 }

static int unload_module ( void   )  [static]

Definition at line 429 of file bridge_holding.c.

References ast_bridge_technology_unregister().

00430 {
00431    ast_bridge_technology_unregister(&holding_bridge);
00432    return 0;
00433 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Holding bridge module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, } [static]

Definition at line 444 of file bridge_holding.c.

Definition at line 444 of file bridge_holding.c.

Definition at line 392 of file bridge_holding.c.


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