Wed Jan 8 2020 09:49:53

Asterisk developer's documentation


app_confbridge.c File Reference

Conference Bridge application. More...

#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/bridging.h"
#include "asterisk/musiconhold.h"
#include "asterisk/say.h"
#include "asterisk/audiohook.h"
#include "asterisk/astobj2.h"

Go to the source code of this file.

Data Structures

struct  conference_bridge
 The structure that represents a conference bridge. More...
 
struct  conference_bridge_user
 The structure that represents a conference bridge user. More...
 

Macros

#define CONFERENCE_BRIDGE_BUCKETS   53
 
#define MAX_CONF_NAME   AST_MAX_EXTENSION
 

Enumerations

enum  {
  OPTION_ADMIN = (1 << 0), OPTION_MENU = (1 << 1), OPTION_MUSICONHOLD = (1 << 2), OPTION_NOONLYPERSON = (1 << 3),
  OPTION_STARTMUTED = (1 << 4), OPTION_ANNOUNCEUSERCOUNT = (1 << 5), OPTION_MARKEDUSER = (1 << 6), OPTION_WAITMARKED = (1 << 7),
  OPTION_QUIET = (1 << 8)
}
 
enum  { OPTION_MUSICONHOLD_CLASS, OPTION_ARRAY_SIZE }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int announce_user_count (struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 Announce number of users in the conference bridge to the caller. More...
 
static int confbridge_exec (struct ast_channel *chan, const char *data)
 The ConfBridge application. More...
 
static int conference_bridge_cmp_cb (void *obj, void *arg, int flags)
 Comparison function used for conference bridges container. More...
 
static int conference_bridge_hash_cb (const void *obj, const int flags)
 Hashing function used for conference bridges container. More...
 
static void destroy_conference_bridge (void *obj)
 Destroy a conference bridge. More...
 
static struct conference_bridgejoin_conference_bridge (const char *name, struct conference_bridge_user *conference_bridge_user)
 Join a conference bridge. More...
 
static void leave_conference_bridge (struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 Leave a conference bridge. More...
 
static int load_module (void)
 Called when module is being loaded. More...
 
static int menu_callback (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 DTMF Menu Callback. More...
 
static int play_prompt_to_channel (struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
 Play back an audio file to a channel. More...
 
static int play_sound_file (struct conference_bridge *conference_bridge, const char *filename)
 Play sound file into conference bridge. More...
 
static int post_join_marked (struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 Perform post-joining marked specific actions. More...
 
static int post_join_unmarked (struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 Perform post-joining non-marked specific actions. More...
 
static int unload_module (void)
 Called when module is being unloaded. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Conference Bridge Application" , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
 
static const char app [] = "ConfBridge"
 
static struct ast_app_option app_opts [128] = { [ 'A' ] = { .flag = OPTION_MARKEDUSER }, [ 'a' ] = { .flag = OPTION_ADMIN }, [ 'c' ] = { .flag = OPTION_ANNOUNCEUSERCOUNT }, [ 'm' ] = { .flag = OPTION_STARTMUTED }, [ 'M' ] = { .flag = OPTION_MUSICONHOLD , .arg_index = OPTION_MUSICONHOLD_CLASS + 1 }, [ '1' ] = { .flag = OPTION_NOONLYPERSON }, [ 's' ] = { .flag = OPTION_MENU }, [ 'w' ] = { .flag = OPTION_WAITMARKED }, [ 'q' ] = { .flag = OPTION_QUIET }, }
 
static struct ast_module_infoast_module_info = &__mod_info
 
static struct ao2_containerconference_bridges
 Container to hold all conference bridges in progress. More...
 

Detailed Description

Conference Bridge application.

Author
Joshua Colp <jcolp@digium.com> 

This is a conference bridge application utilizing the bridging core.

Definition in file app_confbridge.c.

Macro Definition Documentation

#define CONFERENCE_BRIDGE_BUCKETS   53

Definition at line 155 of file app_confbridge.c.

Referenced by load_module().

#define MAX_CONF_NAME   AST_MAX_EXTENSION

Definition at line 152 of file app_confbridge.c.

Referenced by confbridge_exec().

Enumeration Type Documentation

anonymous enum
Enumerator
OPTION_ADMIN 

Set if the caller is an administrator

OPTION_MENU 

Set if the caller should have access to the conference bridge IVR menu

OPTION_MUSICONHOLD 

Set if music on hold should be played if nobody else is in the conference bridge

OPTION_NOONLYPERSON 

Set if the "you are currently the only person in this conference" sound file should not be played

OPTION_STARTMUTED 

Set if the caller should be initially set muted

OPTION_ANNOUNCEUSERCOUNT 

Set if the number of users should be announced to the caller

OPTION_MARKEDUSER 

Set if the caller is a marked user

OPTION_WAITMARKED 

Set if the conference must wait for a marked user before starting

OPTION_QUIET 

Set if no audio prompts should be played

Definition at line 121 of file app_confbridge.c.

121  {
122  OPTION_ADMIN = (1 << 0), /*!< Set if the caller is an administrator */
123  OPTION_MENU = (1 << 1), /*!< Set if the caller should have access to the conference bridge IVR menu */
124  OPTION_MUSICONHOLD = (1 << 2), /*!< Set if music on hold should be played if nobody else is in the conference bridge */
125  OPTION_NOONLYPERSON = (1 << 3), /*!< Set if the "you are currently the only person in this conference" sound file should not be played */
126  OPTION_STARTMUTED = (1 << 4), /*!< Set if the caller should be initially set muted */
127  OPTION_ANNOUNCEUSERCOUNT = (1 << 5), /*!< Set if the number of users should be announced to the caller */
128  OPTION_MARKEDUSER = (1 << 6), /*!< Set if the caller is a marked user */
129  OPTION_WAITMARKED = (1 << 7), /*!< Set if the conference must wait for a marked user before starting */
130  OPTION_QUIET = (1 << 8), /*!< Set if no audio prompts should be played */
131 };
anonymous enum
Enumerator
OPTION_MUSICONHOLD_CLASS 

If the 'M' option is set, the music on hold class to play

OPTION_ARRAY_SIZE 

Definition at line 133 of file app_confbridge.c.

133  {
134  OPTION_MUSICONHOLD_CLASS, /*!< If the 'M' option is set, the music on hold class to play */
135  /*This must be the last element */
137 };

Function Documentation

static void __reg_module ( void  )
static

Definition at line 860 of file app_confbridge.c.

static void __unreg_module ( void  )
static

Definition at line 860 of file app_confbridge.c.

static int announce_user_count ( struct conference_bridge conference_bridge,
struct conference_bridge_user conference_bridge_user 
)
static

Announce number of users in the conference bridge to the caller.

Parameters
conference_bridgeConference bridge to peek at
conference_bridge_userCaller
Returns
Returns 0 on success, -1 if the user hung up

Definition at line 207 of file app_confbridge.c.

References ast_say_number(), ast_stream_and_wait(), conference_bridge_user::chan, ast_channel::language, and conference_bridge::users.

Referenced by post_join_unmarked().

208 {
209  if (conference_bridge->users == 1) {
210  /* Awww we are the only person in the conference bridge */
211  return 0;
212  } else if (conference_bridge->users == 2) {
213  /* Eep, there is one other person */
214  if (ast_stream_and_wait(conference_bridge_user->chan, "conf-onlyone", "")) {
215  return -1;
216  }
217  } else {
218  /* Alas multiple others in here */
219  if (ast_stream_and_wait(conference_bridge_user->chan, "conf-thereare", "")) {
220  return -1;
221  }
222  if (ast_say_number(conference_bridge_user->chan, conference_bridge->users - 1, "", conference_bridge_user->chan->language, NULL)) {
223  return -1;
224  }
225  if (ast_stream_and_wait(conference_bridge_user->chan, "conf-otherinparty", "")) {
226  return -1;
227  }
228  }
229  return 0;
230 }
unsigned int users
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8397
struct ast_channel * chan
const ast_string_field language
Definition: channel.h:787
static int confbridge_exec ( struct ast_channel chan,
const char *  data 
)
static

The ConfBridge application.

Definition at line 724 of file app_confbridge.c.

References app_opts, args, AST_APP_ARG, ast_app_parse_options(), AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, ast_audiohook_volume_get(), ast_audiohook_volume_set(), ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_features_cleanup(), ast_bridge_features_hook(), ast_bridge_features_init(), ast_bridge_join(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, conference_bridge::bridge, conference_bridge_user::chan, conference_bridge_user::features, conference_bridge_user::flags, join_conference_bridge(), conference_bridge_user::kicked, leave_conference_bridge(), LOG_WARNING, MAX_CONF_NAME, menu_callback(), ast_bridge_features::mute, conference_bridge_user::opt_args, OPTION_MENU, OPTION_QUIET, OPTION_STARTMUTED, parse(), pbx_builtin_getvar_helper(), play_sound_file(), and conference_bridge::users.

Referenced by load_module().

725 {
726  int res = 0, volume_adjustments[2];
727  char *parse;
728  struct conference_bridge *conference_bridge = NULL;
730  .chan = chan,
731  };
732  const char *tmp, *join_sound = NULL, *leave_sound = NULL;
734  AST_APP_ARG(conf_name);
735  AST_APP_ARG(options);
736  );
737 
738  /* We need to make a copy of the input string if we are going to modify it! */
739  parse = ast_strdupa(data);
740 
741  AST_STANDARD_APP_ARGS(args, parse);
742 
743  if (ast_strlen_zero(args.conf_name)) {
744  ast_log(LOG_WARNING, "%s requires an argument (conference name[,options])\n", app);
745  return -1;
746  }
747 
748  if (strlen(args.conf_name) >= MAX_CONF_NAME) {
749  ast_log(LOG_WARNING, "%s does not accept conference names longer than %d\n", app, MAX_CONF_NAME - 1);
750  return -1;
751  }
752 
753  if (args.argc == 2) {
754  ast_app_parse_options(app_opts, &conference_bridge_user.flags, conference_bridge_user.opt_args, args.options);
755  }
756 
757  /* Look for a conference bridge matching the provided name */
758  if (!(conference_bridge = join_conference_bridge(args.conf_name, &conference_bridge_user))) {
759  return -1;
760  }
761 
762  /* Keep a copy of volume adjustments so we can restore them later if need be */
763  volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
764  volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
765 
766  /* Always initialize the features structure, we are in most cases always going to need it. */
767  ast_bridge_features_init(&conference_bridge_user.features);
768 
769  /* If the menu option is enabled provide a user or admin menu as a custom feature hook */
770  if (ast_test_flag(&conference_bridge_user.flags, OPTION_MENU)) {
771  ast_bridge_features_hook(&conference_bridge_user.features, "#", menu_callback, &conference_bridge_user);
772  }
773 
774  /* If the caller should be joined already muted, make it so */
775  if (ast_test_flag(&conference_bridge_user.flags, OPTION_STARTMUTED)) {
776  conference_bridge_user.features.mute = 1;
777  }
778 
779  /* Grab join/leave sounds from the channel */
780  ast_channel_lock(chan);
781  if ((tmp = pbx_builtin_getvar_helper(chan, "CONFBRIDGE_JOIN_SOUND"))) {
782  join_sound = ast_strdupa(tmp);
783  }
784  if ((tmp = pbx_builtin_getvar_helper(chan, "CONFBRIDGE_LEAVE_SOUND"))) {
785  leave_sound = ast_strdupa(tmp);
786  }
787  ast_channel_unlock(chan);
788 
789  /* If there is 1 or more people already in the conference then play our join sound unless overridden */
790  if (!ast_test_flag(&conference_bridge_user.flags, OPTION_QUIET) && !ast_strlen_zero(join_sound) && conference_bridge->users >= 2) {
791  ast_autoservice_start(chan);
792  play_sound_file(conference_bridge, join_sound);
793  ast_autoservice_stop(chan);
794  }
795 
796  /* Join our conference bridge for real */
797  ast_bridge_join(conference_bridge->bridge, chan, NULL, &conference_bridge_user.features);
798 
799  /* If there is 1 or more people (not including us) already in the conference then play our leave sound unless overridden */
800  if (!ast_test_flag(&conference_bridge_user.flags, OPTION_QUIET) && !ast_strlen_zero(leave_sound) && conference_bridge->users >= 2) {
801  ast_autoservice_start(chan);
802  play_sound_file(conference_bridge, leave_sound);
803  ast_autoservice_stop(chan);
804  }
805 
806  /* Easy as pie, depart this channel from the conference bridge */
807  leave_conference_bridge(conference_bridge, &conference_bridge_user);
808  conference_bridge = NULL;
809 
810  /* Can't forget to clean up the features structure, or else we risk a memory leak */
811  ast_bridge_features_cleanup(&conference_bridge_user.features);
812 
813  /* If the user was kicked from the conference play back the audio prompt for it */
814  if (!ast_test_flag(&conference_bridge_user.flags, OPTION_QUIET) && conference_bridge_user.kicked) {
815  res = ast_stream_and_wait(chan, "conf-kicked", "");
816  }
817 
818  /* Restore volume adjustments to previous values in case they were changed */
819  if (volume_adjustments[0]) {
820  ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_READ, volume_adjustments[0]);
821  }
822  if (volume_adjustments[1]) {
823  ast_audiohook_volume_set(chan, AST_AUDIOHOOK_DIRECTION_WRITE, volume_adjustments[1]);
824  }
825 
826  return res;
827 }
int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
Adjust the volume on frames read from or written to a channel.
Definition: audiohook.c:979
#define ast_channel_lock(chan)
Definition: channel.h:2466
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
The structure that represents a conference bridge.
int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
Retrieve the volume adjustment value on frames read from or written to a channel. ...
Definition: audiohook.c:1004
enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features)
Join (blocking) a channel to a bridge.
Definition: bridging.c:993
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: app.c:2101
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
Definition: bridging.c:1322
static const char app[]
struct ast_bridge * bridge
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
int ast_bridge_features_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_features_hook_callback callback, void *hook_pvt)
Attach a custom hook to a bridge features structure.
Definition: bridging.c:1274
static int menu_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
DTMF Menu Callback.
struct ast_flags flags
unsigned int users
static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
Leave a conference bridge.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
struct ast_bridge_features features
The structure that represents a conference bridge user.
static struct @350 args
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
Play sound file into conference bridge.
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
static struct conference_bridge * join_conference_bridge(const char *name, struct conference_bridge_user *conference_bridge_user)
Join a conference bridge.
#define MAX_CONF_NAME
char * opt_args[OPTION_ARRAY_SIZE]
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
struct ast_channel * chan
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
int ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
Definition: bridging.c:1333
static struct ast_app_option app_opts[128]
static int conference_bridge_cmp_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Comparison function used for conference bridges container.

Definition at line 193 of file app_confbridge.c.

References CMP_MATCH, CMP_STOP, and conference_bridge::name.

Referenced by load_module().

194 {
195  const struct conference_bridge *conference_bridge0 = obj, *conference_bridge1 = arg;
196  return (!strcasecmp(conference_bridge0->name, conference_bridge1->name) ? CMP_MATCH | CMP_STOP : 0);
197 }
The structure that represents a conference bridge.
char name[MAX_CONF_NAME]
static int conference_bridge_hash_cb ( const void *  obj,
const int  flags 
)
static

Hashing function used for conference bridges container.

Definition at line 186 of file app_confbridge.c.

References ast_str_case_hash(), and conference_bridge::name.

Referenced by load_module().

187 {
188  const struct conference_bridge *conference_bridge = obj;
189  return ast_str_case_hash(conference_bridge->name);
190 }
The structure that represents a conference bridge.
char name[MAX_CONF_NAME]
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:989
static void destroy_conference_bridge ( void *  obj)
static

Destroy a conference bridge.

Parameters
objThe conference bridge object
Returns
Returns nothing

Definition at line 383 of file app_confbridge.c.

References ast_bridge_destroy(), ast_debug, ast_hangup(), ast_mutex_destroy, conference_bridge::bridge, ast_channel_tech::bridged_channel, conference_bridge::name, conference_bridge::playback_chan, conference_bridge::playback_lock, and ast_channel::tech.

Referenced by join_conference_bridge().

384 {
385  struct conference_bridge *conference_bridge = obj;
386 
387  ast_debug(1, "Destroying conference bridge '%s'\n", conference_bridge->name);
388 
389  ast_mutex_destroy(&conference_bridge->playback_lock);
390 
391  if (conference_bridge->playback_chan) {
392  struct ast_channel *underlying_channel = conference_bridge->playback_chan->tech->bridged_channel(conference_bridge->playback_chan, NULL);
393  ast_hangup(underlying_channel);
394  ast_hangup(conference_bridge->playback_chan);
395  conference_bridge->playback_chan = NULL;
396  }
397 
398  /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */
399  if (conference_bridge->bridge) {
400  ast_bridge_destroy(conference_bridge->bridge);
401  conference_bridge->bridge = NULL;
402  }
403 }
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
Main Channel structure associated with a channel.
Definition: channel.h:742
The structure that represents a conference bridge.
ast_mutex_t playback_lock
struct ast_channel * playback_chan
char name[MAX_CONF_NAME]
int ast_bridge_destroy(struct ast_bridge *bridge)
Destroy a bridge.
Definition: bridging.c:515
struct ast_bridge * bridge
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_channel *(*const bridged_channel)(struct ast_channel *chan, struct ast_channel *bridge)
Find bridged channel.
Definition: channel.h:597
#define ast_mutex_destroy(a)
Definition: lock.h:154
struct ast_channel_tech * tech
Definition: channel.h:743
static struct conference_bridge* join_conference_bridge ( const char *  name,
struct conference_bridge_user conference_bridge_user 
)
static

Join a conference bridge.

Parameters
nameThe conference name
conference_bridge_userConference bridge user structure
Returns
A pointer to the conference bridge struct, or NULL if the conference room wasn't found.

Definition at line 415 of file app_confbridge.c.

References ao2_alloc, ao2_find, ao2_link, ao2_lock, ao2_ref, ao2_unlock, AST_BRIDGE_CAPABILITY_1TO1MIX, AST_BRIDGE_FLAG_SMART, ast_bridge_new(), ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_LIST_INSERT_TAIL, ast_log(), ast_mutex_init, ast_stream_and_wait(), ast_test_flag, conference_bridge::bridge, conference_bridge_user::chan, conference_bridge_user::conference_bridge, conference_bridges, destroy_conference_bridge(), conference_bridge_user::flags, leave_conference_bridge(), conference_bridge::locked, LOG_ERROR, conference_bridge::markedusers, conference_bridge::name, OBJ_POINTER, OPTION_ADMIN, OPTION_MARKEDUSER, OPTION_WAITMARKED, conference_bridge::playback_lock, post_join_marked(), post_join_unmarked(), conference_bridge::users, and conference_bridge::users_list.

Referenced by confbridge_exec().

416 {
417  struct conference_bridge *conference_bridge = NULL;
418  struct conference_bridge tmp;
419 
420  ast_copy_string(tmp.name, name, sizeof(tmp.name));
421 
422  /* We explictly lock the conference bridges container ourselves so that other callers can not create duplicate conferences at the same */
424 
425  ast_debug(1, "Trying to find conference bridge '%s'\n", name);
426 
427  /* Attempt to find an existing conference bridge */
428  conference_bridge = ao2_find(conference_bridges, &tmp, OBJ_POINTER);
429 
430  /* When finding a conference bridge that already exists make sure that it is not locked, and if so that we are not an admin */
431  if (conference_bridge && conference_bridge->locked && !ast_test_flag(&conference_bridge_user->flags, OPTION_ADMIN)) {
433  ao2_ref(conference_bridge, -1);
434  ast_debug(1, "Conference bridge '%s' is locked and caller is not an admin\n", name);
435  ast_stream_and_wait(conference_bridge_user->chan, "conf-locked", "");
436  return NULL;
437  }
438 
439  /* If no conference bridge was found see if we can create one */
440  if (!conference_bridge) {
441  /* Try to allocate memory for a new conference bridge, if we fail... this won't end well. */
442  if (!(conference_bridge = ao2_alloc(sizeof(*conference_bridge), destroy_conference_bridge))) {
444  ast_log(LOG_ERROR, "Conference bridge '%s' does not exist.\n", name);
445  return NULL;
446  }
447 
448  /* Setup conference bridge parameters */
449  ast_copy_string(conference_bridge->name, name, sizeof(conference_bridge->name));
450 
451  /* Create an actual bridge that will do the audio mixing */
453  ao2_ref(conference_bridge, -1);
454  conference_bridge = NULL;
456  ast_log(LOG_ERROR, "Conference bridge '%s' could not be created.\n", name);
457  return NULL;
458  }
459 
460  /* Setup lock for playback channel */
461  ast_mutex_init(&conference_bridge->playback_lock);
462 
463  /* Link it into the conference bridges container */
464  ao2_link(conference_bridges, conference_bridge);
465 
466  ast_debug(1, "Created conference bridge '%s' and linked to container '%p'\n", name, conference_bridges);
467  }
468 
470 
471  /* Setup conference bridge user parameters */
472  conference_bridge_user->conference_bridge = conference_bridge;
473 
474  ao2_lock(conference_bridge);
475 
476  /* All good to go, add them in */
477  AST_LIST_INSERT_TAIL(&conference_bridge->users_list, conference_bridge_user, list);
478 
479  /* Increment the users count on the bridge, but record it as it is going to need to be known right after this */
480  conference_bridge->users++;
481 
482  /* If the caller is a marked user bump up the count */
483  if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
484  conference_bridge->markedusers++;
485  }
486 
487  /* Set the device state for this conference */
488  if (conference_bridge->users == 1) {
489  ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
490  }
491 
492  /* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */
493  if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER | OPTION_WAITMARKED)) {
494  if (post_join_marked(conference_bridge, conference_bridge_user)) {
495  ao2_unlock(conference_bridge);
496  leave_conference_bridge(conference_bridge, conference_bridge_user);
497  return NULL;
498  }
499  } else {
500  if (post_join_unmarked(conference_bridge, conference_bridge_user)) {
501  ao2_unlock(conference_bridge);
502  leave_conference_bridge(conference_bridge, conference_bridge_user);
503  return NULL;
504  }
505  }
506 
507  ao2_unlock(conference_bridge);
508 
509  return conference_bridge;
510 }
unsigned int locked
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
The structure that represents a conference bridge.
ast_mutex_t playback_lock
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct conference_bridge * conference_bridge
struct ast_bridge * ast_bridge_new(enum ast_bridge_capability capabilities, int flags)
Create a new bridge.
Definition: bridging.c:449
char name[MAX_CONF_NAME]
#define ao2_unlock(a)
Definition: astobj2.h:497
static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
Perform post-joining non-marked specific actions.
struct ast_bridge * bridge
static void destroy_conference_bridge(void *obj)
Destroy a conference bridge.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_flags flags
unsigned int users
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:516
static void leave_conference_bridge(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
Leave a conference bridge.
struct conference_bridge::@5 users_list
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
static struct ao2_container * conference_bridges
Container to hold all conference bridges in progress.
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
unsigned int markedusers
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
static const char name[]
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
static int post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
Perform post-joining marked specific actions.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define ast_mutex_init(pmutex)
Definition: lock.h:152
struct ast_channel * chan
static void leave_conference_bridge ( struct conference_bridge conference_bridge,
struct conference_bridge_user conference_bridge_user 
)
static

Leave a conference bridge.

Parameters
conference_bridgeThe conference bridge to leave
conference_bridge_userThe conference bridge user structure

Definition at line 519 of file app_confbridge.c.

References ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_autoservice_start(), ast_autoservice_stop(), ast_bridge_suspend(), ast_bridge_unsuspend(), AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_LIST_FIRST, AST_LIST_REMOVE, AST_LIST_TRAVERSE, ast_moh_start(), ast_test_flag, conference_bridge::bridge, conference_bridge_user::chan, conference_bridges, conference_bridge_user::features, conference_bridge_user::flags, conference_bridge_user::list, conference_bridge::markedusers, ast_bridge_features::mute, conference_bridge::name, conference_bridge_user::opt_args, OPTION_MARKEDUSER, OPTION_MUSICONHOLD, OPTION_MUSICONHOLD_CLASS, OPTION_QUIET, play_sound_file(), conference_bridge::users, and conference_bridge::users_list.

Referenced by confbridge_exec(), and join_conference_bridge().

520 {
521  ao2_lock(conference_bridge);
522 
523  /* If this caller is a marked user bump down the count */
524  if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
525  conference_bridge->markedusers--;
526  }
527 
528  /* Decrement the users count while keeping the previous participant count */
529  conference_bridge->users--;
530 
531  /* Drop conference bridge user from the list, they be going bye bye */
532  AST_LIST_REMOVE(&conference_bridge->users_list, conference_bridge_user, list);
533 
534  /* If there are still users in the conference bridge we may need to do things (such as start MOH on them) */
535  if (conference_bridge->users) {
536  if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER) && !conference_bridge->markedusers) {
537  struct conference_bridge_user *other_participant = NULL;
538 
539  /* Start out with muting everyone */
540  AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
541  other_participant->features.mute = 1;
542  }
543 
544  /* Play back the audio prompt saying the leader has left the conference */
545  if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
546  ao2_unlock(conference_bridge);
547  ast_autoservice_start(conference_bridge_user->chan);
548  play_sound_file(conference_bridge, "conf-leaderhasleft");
549  ast_autoservice_stop(conference_bridge_user->chan);
550  ao2_lock(conference_bridge);
551  }
552 
553  /* Now on to starting MOH if needed */
554  AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
555  if (ast_test_flag(&other_participant->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_participant->chan)) {
556  ast_moh_start(other_participant->chan, other_participant->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
557  ast_bridge_unsuspend(conference_bridge->bridge, other_participant->chan);
558  }
559  }
560  } else if (conference_bridge->users == 1) {
561  /* Of course if there is one other person in here we may need to start up MOH on them */
562  struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
563 
564  if (ast_test_flag(&first_participant->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
565  ast_moh_start(first_participant->chan, first_participant->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
566  ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
567  }
568  }
569  } else {
570  /* Set device state to "not in use" */
571  ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name);
572 
573  ao2_unlink(conference_bridges, conference_bridge);
574  }
575 
576  /* Done mucking with the conference bridge, huzzah */
577  ao2_unlock(conference_bridge);
578 
579  ao2_ref(conference_bridge, -1);
580 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
#define ast_test_flag(p, flag)
Definition: utils.h:63
char name[MAX_CONF_NAME]
#define ao2_unlock(a)
Definition: astobj2.h:497
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
struct ast_bridge * bridge
struct ast_flags flags
unsigned int users
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:516
struct conference_bridge::@5 users_list
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_lock(a)
Definition: astobj2.h:488
static struct ao2_container * conference_bridges
Container to hold all conference bridges in progress.
int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
Suspend a channel temporarily from a bridge.
Definition: bridging.c:1200
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
struct ast_bridge_features features
unsigned int markedusers
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
static int play_sound_file(struct conference_bridge *conference_bridge, const char *filename)
Play sound file into conference bridge.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct conference_bridge_user::@6 list
char * opt_args[OPTION_ARRAY_SIZE]
struct ast_channel * chan
#define ao2_unlink(arg1, arg2)
Definition: astobj2.h:817
int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
Unsuspend a channel from a bridge.
Definition: bridging.c:1218
static int load_module ( void  )
static

Called when module is being loaded.

Definition at line 841 of file app_confbridge.c.

References ao2_container_alloc, ao2_ref, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, confbridge_exec(), CONFERENCE_BRIDGE_BUCKETS, conference_bridge_cmp_cb(), conference_bridge_hash_cb(), and conference_bridges.

842 {
843  /* Create a container to hold the conference bridges */
846  }
847 
851  }
852 
854 }
static const char app[]
#define CONFERENCE_BRIDGE_BUCKETS
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static struct ao2_container * conference_bridges
Container to hold all conference bridges in progress.
static int conference_bridge_hash_cb(const void *obj, const int flags)
Hashing function used for conference bridges container.
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
Comparison function used for conference bridges container.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static int confbridge_exec(struct ast_channel *chan, const char *data)
The ConfBridge application.
static int menu_callback ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
)
static

DTMF Menu Callback.

Parameters
bridgeBridge this is involving
bridge_channelBridged channel this is involving
hook_pvtUser's conference bridge structure
Return values
0success
-1failure

Definition at line 644 of file app_confbridge.c.

References ao2_lock, ao2_unlock, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, ast_audiohook_volume_adjust(), AST_BRIDGE_CHANNEL_STATE_WAIT, ast_bridge_remove(), AST_DIGIT_ANY, AST_LIST_LAST, ast_moh_start(), ast_moh_stop(), ast_stopstream(), ast_stream_and_wait(), ast_streamfile(), ast_test_flag, ast_waitstream(), conference_bridge::bridge, ast_bridge_channel::chan, conference_bridge_user::chan, conference_bridge_user::conference_bridge, conference_bridge_user::features, conference_bridge_user::flags, conference_bridge_user::kicked, ast_channel::language, conference_bridge::locked, conference_bridge::markedusers, ast_bridge_features::mute, conference_bridge_user::opt_args, OPTION_ADMIN, OPTION_MUSICONHOLD, OPTION_MUSICONHOLD_CLASS, OPTION_WAITMARKED, ast_bridge_channel::state, conference_bridge::users, and conference_bridge::users_list.

Referenced by confbridge_exec().

645 {
647  struct conference_bridge *conference_bridge = conference_bridge_user->conference_bridge;
648  int digit, res = 0, isadmin = ast_test_flag(&conference_bridge_user->flags, OPTION_ADMIN);
649 
650  /* See if music on hold is playing */
651  ao2_lock(conference_bridge);
652  if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
653  /* Just us so MOH is probably indeed going, let's stop it */
654  ast_moh_stop(bridge_channel->chan);
655  }
656  ao2_unlock(conference_bridge);
657 
658  /* Try to play back the user menu, if it fails pass this back up so the bridging core will act on it */
659  if (ast_streamfile(bridge_channel->chan, (isadmin ? "conf-adminmenu" : "conf-usermenu"), bridge_channel->chan->language)) {
660  res = -1;
661  goto finished;
662  }
663 
664  /* Wait for them to enter a digit from the user menu options */
665  digit = ast_waitstream(bridge_channel->chan, AST_DIGIT_ANY);
666  ast_stopstream(bridge_channel->chan);
667 
668  if (digit == '1') {
669  /* 1 - Mute or unmute yourself, note we only allow manipulation if they aren't waiting for a marked user or if marked users exist */
670  if (!ast_test_flag(&conference_bridge_user->flags, OPTION_WAITMARKED) || conference_bridge->markedusers) {
671  conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0);
672  }
673  res = ast_stream_and_wait(bridge_channel->chan, (conference_bridge_user->features.mute ? "conf-muted" : "conf-unmuted"), "");
674  } else if (isadmin && digit == '2') {
675  /* 2 - Unlock or lock conference */
676  conference_bridge->locked = (!conference_bridge->locked ? 1 : 0);
677  res = ast_stream_and_wait(bridge_channel->chan, (conference_bridge->locked ? "conf-lockednow" : "conf-unlockednow"), "");
678  } else if (isadmin && digit == '3') {
679  /* 3 - Eject last user */
680  struct conference_bridge_user *last_participant = NULL;
681 
682  ao2_lock(conference_bridge);
683  if (((last_participant = AST_LIST_LAST(&conference_bridge->users_list)) == conference_bridge_user) || (ast_test_flag(&last_participant->flags, OPTION_ADMIN))) {
684  ao2_unlock(conference_bridge);
685  res = ast_stream_and_wait(bridge_channel->chan, "conf-errormenu", "");
686  } else {
687  last_participant->kicked = 1;
688  ast_bridge_remove(conference_bridge->bridge, last_participant->chan);
689  ao2_unlock(conference_bridge);
690  }
691  } else if (digit == '4') {
692  /* 4 - Decrease listening volume */
693  ast_audiohook_volume_adjust(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_WRITE, -1);
694  } else if (digit == '6') {
695  /* 6 - Increase listening volume */
697  } else if (digit == '7') {
698  /* 7 - Decrease talking volume */
699  ast_audiohook_volume_adjust(conference_bridge_user->chan, AST_AUDIOHOOK_DIRECTION_READ, -1);
700  } else if (digit == '8') {
701  /* 8 - Exit the IVR */
702  } else if (digit == '9') {
703  /* 9 - Increase talking volume */
705  } else {
706  /* No valid option was selected */
707  res = ast_stream_and_wait(bridge_channel->chan, "conf-errormenu", "");
708  }
709 
710  finished:
711  /* See if music on hold needs to be started back up again */
712  ao2_lock(conference_bridge);
713  if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
714  ast_moh_start(bridge_channel->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
715  }
716  ao2_unlock(conference_bridge);
717 
718  bridge_channel->state = AST_BRIDGE_CHANNEL_STATE_WAIT;
719 
720  return res;
721 }
unsigned int locked
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
The structure that represents a conference bridge.
#define AST_DIGIT_ANY
Definition: file.h:47
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct conference_bridge * conference_bridge
#define ao2_unlock(a)
Definition: astobj2.h:497
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
struct ast_bridge * bridge
struct ast_flags flags
unsigned int users
struct conference_bridge::@5 users_list
#define ao2_lock(a)
Definition: astobj2.h:488
struct ast_bridge_features features
The structure that represents a conference bridge user.
unsigned int markedusers
int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
Remove a channel from a bridge.
Definition: bridging.c:1100
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:428
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
Adjust the volume on frames read from or written to a channel.
Definition: audiohook.c:1030
struct ast_channel * chan
Definition: bridging.h:125
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
char * opt_args[OPTION_ARRAY_SIZE]
struct ast_channel * chan
enum ast_bridge_channel_state state
Definition: bridging.h:123
const ast_string_field language
Definition: channel.h:787
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
static int play_prompt_to_channel ( struct conference_bridge conference_bridge,
struct ast_channel chan,
const char *  file 
)
static

Play back an audio file to a channel.

Parameters
conference_bridgeConference bridge they are in
chanChannel to play audio prompt to
filePrompt to play
Returns
Returns 0 on success, -1 if the user hung up
Note
This function assumes that conference_bridge is locked

Definition at line 243 of file app_confbridge.c.

References ao2_lock, ao2_unlock, and ast_stream_and_wait().

Referenced by post_join_marked(), and post_join_unmarked().

244 {
245  int res;
246  ao2_unlock(conference_bridge);
247  res = ast_stream_and_wait(chan, file, "");
248  ao2_lock(conference_bridge);
249  return res;
250 }
#define ao2_unlock(a)
Definition: astobj2.h:497
#define ao2_lock(a)
Definition: astobj2.h:488
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
static int play_sound_file ( struct conference_bridge conference_bridge,
const char *  filename 
)
static

Play sound file into conference bridge.

Parameters
conference_bridgeThe conference bridge to play sound file into
filenameSound file to play
Return values
0success
-1failure

Definition at line 591 of file app_confbridge.c.

References ast_bridge_depart(), ast_bridge_impart(), ast_call(), ast_debug, AST_FORMAT_SLINEAR, ast_hangup(), ast_mutex_lock, ast_mutex_unlock, ast_request(), ast_stream_and_wait(), conference_bridge::bridge, ast_channel::bridge, ast_channel_tech::bridged_channel, conference_bridge::name, ast_channel::name, conference_bridge::playback_chan, conference_bridge::playback_lock, and ast_channel::tech.

Referenced by confbridge_exec(), and leave_conference_bridge().

592 {
593  struct ast_channel *underlying_channel;
594 
595  ast_mutex_lock(&conference_bridge->playback_lock);
596 
597  if (!(conference_bridge->playback_chan)) {
598  int cause;
599 
600  if (!(conference_bridge->playback_chan = ast_request("Bridge", AST_FORMAT_SLINEAR, NULL, "", &cause))) {
601  ast_mutex_unlock(&conference_bridge->playback_lock);
602  return -1;
603  }
604 
605  conference_bridge->playback_chan->bridge = conference_bridge->bridge;
606 
607  if (ast_call(conference_bridge->playback_chan, "", 0)) {
608  ast_hangup(conference_bridge->playback_chan);
609  conference_bridge->playback_chan = NULL;
610  ast_mutex_unlock(&conference_bridge->playback_lock);
611  return -1;
612  }
613 
614  ast_debug(1, "Created a playback channel to conference bridge '%s'\n", conference_bridge->name);
615 
616  underlying_channel = conference_bridge->playback_chan->tech->bridged_channel(conference_bridge->playback_chan, NULL);
617  } else {
618  /* Channel was already available so we just need to add it back into the bridge */
619  underlying_channel = conference_bridge->playback_chan->tech->bridged_channel(conference_bridge->playback_chan, NULL);
620  ast_bridge_impart(conference_bridge->bridge, underlying_channel, NULL, NULL);
621  }
622 
623  /* The channel is all under our control, in goes the prompt */
624  ast_stream_and_wait(conference_bridge->playback_chan, filename, "");
625 
626  ast_debug(1, "Departing underlying channel '%s' from bridge '%p'\n", underlying_channel->name, conference_bridge->bridge);
627  ast_bridge_depart(conference_bridge->bridge, underlying_channel);
628 
629  ast_mutex_unlock(&conference_bridge->playback_lock);
630 
631  return 0;
632 }
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
Main Channel structure associated with a channel.
Definition: channel.h:742
ast_mutex_t playback_lock
struct ast_channel * playback_chan
int ast_bridge_depart(struct ast_bridge *bridge, struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridging.c:1077
char name[MAX_CONF_NAME]
#define ast_mutex_lock(a)
Definition: lock.h:155
struct ast_bridge * bridge
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features)
Impart (non-blocking) a channel on a bridge.
Definition: bridging.c:1043
const ast_string_field name
Definition: channel.h:787
struct ast_bridge * bridge
Definition: channel.h:865
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
struct ast_channel *(*const bridged_channel)(struct ast_channel *chan, struct ast_channel *bridge)
Find bridged channel.
Definition: channel.h:597
int ast_call(struct ast_channel *chan, char *addr, int timeout)
Make a call.
Definition: channel.c:5761
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
struct ast_channel * ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *status)
Requests a channel.
Definition: channel.c:5695
struct ast_channel_tech * tech
Definition: channel.h:743
#define ast_mutex_unlock(a)
Definition: lock.h:156
static int post_join_marked ( struct conference_bridge conference_bridge,
struct conference_bridge_user conference_bridge_user 
)
static

Perform post-joining marked specific actions.

Parameters
conference_bridgeConference bridge being joined
conference_bridge_userConference bridge user joining
Returns
Returns 0 on success, -1 if the user hung up

Definition at line 260 of file app_confbridge.c.

References ast_bridge_suspend(), ast_bridge_unsuspend(), AST_LIST_TRAVERSE, ast_moh_start(), ast_moh_stop(), ast_test_flag, conference_bridge::bridge, conference_bridge_user::chan, conference_bridge_user::features, conference_bridge_user::flags, conference_bridge_user::list, conference_bridge::markedusers, ast_bridge_features::mute, conference_bridge_user::opt_args, OPTION_MARKEDUSER, OPTION_MUSICONHOLD, OPTION_MUSICONHOLD_CLASS, OPTION_QUIET, play_prompt_to_channel(), and conference_bridge::users_list.

Referenced by join_conference_bridge().

261 {
262  if (ast_test_flag(&conference_bridge_user->flags, OPTION_MARKEDUSER)) {
263  struct conference_bridge_user *other_conference_bridge_user = NULL;
264 
265  /* If we are not the first marked user to join just bail out now */
266  if (conference_bridge->markedusers >= 2) {
267  return 0;
268  }
269 
270  /* Iterate through every participant stopping MOH on them if need be */
271  AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
272  if (other_conference_bridge_user == conference_bridge_user) {
273  continue;
274  }
275  if (ast_test_flag(&other_conference_bridge_user->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_conference_bridge_user->chan)) {
276  ast_moh_stop(other_conference_bridge_user->chan);
277  ast_bridge_unsuspend(conference_bridge->bridge, other_conference_bridge_user->chan);
278  }
279  }
280 
281  /* Next play the audio file stating they are going to be placed into the conference */
282  if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
283  if (play_prompt_to_channel(conference_bridge,
284  conference_bridge_user->chan,
285  "conf-placeintoconf")) {
286  /* user hungup while the sound was playing */
287  return -1;
288  }
289  }
290 
291  /* Finally iterate through and unmute them all */
292  AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
293  if (other_conference_bridge_user == conference_bridge_user) {
294  continue;
295  }
296  other_conference_bridge_user->features.mute = 0;
297  }
298 
299  } else {
300  /* If a marked user already exists in the conference bridge we can just bail out now */
301  if (conference_bridge->markedusers) {
302  return 0;
303  }
304  /* Be sure we are muted so we can't talk to anybody else waiting */
305  conference_bridge_user->features.mute = 1;
306  /* If we have not been quieted play back that they are waiting for the leader */
307  if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET)) {
308  if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-waitforleader")) {
309  /* user hung up while the sound was playing */
310  return -1;
311  }
312  }
313  /* Start music on hold if needed */
314  /* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially
315  * allowing a marked user to enter while the prompt was playing
316  */
317  if (!conference_bridge->markedusers && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
318  ast_moh_start(conference_bridge_user->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
319  }
320  }
321  return 0;
322 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
struct ast_bridge * bridge
struct ast_flags flags
struct conference_bridge::@5 users_list
static int play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
Play back an audio file to a channel.
int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
Suspend a channel temporarily from a bridge.
Definition: bridging.c:1200
struct ast_bridge_features features
unsigned int markedusers
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
struct conference_bridge_user::@6 list
char * opt_args[OPTION_ARRAY_SIZE]
struct ast_channel * chan
int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
Unsuspend a channel from a bridge.
Definition: bridging.c:1218
static int post_join_unmarked ( struct conference_bridge conference_bridge,
struct conference_bridge_user conference_bridge_user 
)
static

Perform post-joining non-marked specific actions.

Parameters
conference_bridgeConference bridge being joined
conference_bridge_userConference bridge user joining
Returns
Returns 0 on success, -1 if the user hung up

Definition at line 332 of file app_confbridge.c.

References announce_user_count(), ao2_lock, ao2_unlock, ast_bridge_suspend(), ast_bridge_unsuspend(), AST_LIST_FIRST, ast_moh_start(), ast_moh_stop(), ast_test_flag, conference_bridge::bridge, conference_bridge_user::chan, conference_bridge_user::flags, conference_bridge_user::opt_args, OPTION_ANNOUNCEUSERCOUNT, OPTION_MUSICONHOLD, OPTION_MUSICONHOLD_CLASS, OPTION_NOONLYPERSON, OPTION_QUIET, play_prompt_to_channel(), conference_bridge::users, and conference_bridge::users_list.

Referenced by join_conference_bridge().

333 {
334  /* Play back audio prompt and start MOH if need be if we are the first participant */
335  if (conference_bridge->users == 1) {
336  /* If audio prompts have not been quieted or this prompt quieted play it on out */
337  if (!ast_test_flag(&conference_bridge_user->flags, OPTION_QUIET | OPTION_NOONLYPERSON)) {
338  if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, "conf-onlyperson")) {
339  /* user hung up while the sound was playing */
340  return -1;
341  }
342  }
343  /* If we need to start music on hold on the channel do so now */
344  /* We need to re-check the number of users in the conference bridge here because another conference bridge
345  * participant could have joined while the above prompt was playing for the first user.
346  */
347  if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->flags, OPTION_MUSICONHOLD)) {
348  ast_moh_start(conference_bridge_user->chan, conference_bridge_user->opt_args[OPTION_MUSICONHOLD_CLASS], NULL);
349  }
350  return 0;
351  }
352 
353  /* Announce number of users if need be */
354  if (ast_test_flag(&conference_bridge_user->flags, OPTION_ANNOUNCEUSERCOUNT)) {
355  ao2_unlock(conference_bridge);
356  if (announce_user_count(conference_bridge, conference_bridge_user)) {
357  ao2_lock(conference_bridge);
358  return -1;
359  }
360  ao2_lock(conference_bridge);
361  }
362 
363  /* If we are the second participant we may need to stop music on hold on the first */
364  if (conference_bridge->users == 2) {
365  struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
366 
367  /* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */
368  if (ast_test_flag(&first_participant->flags, OPTION_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
369  ast_moh_stop(first_participant->chan);
370  ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
371  }
372  }
373  return 0;
374 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int announce_user_count(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
Announce number of users in the conference bridge to the caller.
#define ao2_unlock(a)
Definition: astobj2.h:497
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
struct ast_bridge * bridge
struct ast_flags flags
unsigned int users
struct conference_bridge::@5 users_list
static int play_prompt_to_channel(struct conference_bridge *conference_bridge, struct ast_channel *chan, const char *file)
Play back an audio file to a channel.
#define ao2_lock(a)
Definition: astobj2.h:488
int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
Suspend a channel temporarily from a bridge.
Definition: bridging.c:1200
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
char * opt_args[OPTION_ARRAY_SIZE]
struct ast_channel * chan
int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
Unsuspend a channel from a bridge.
Definition: bridging.c:1218
static int unload_module ( void  )
static

Called when module is being unloaded.

Definition at line 830 of file app_confbridge.c.

References ao2_ref, ast_unregister_application(), and conference_bridges.

831 {
832  int res = ast_unregister_application(app);
833 
834  /* Get rid of the conference bridges container. Since we only allow dynamic ones none will be active. */
836 
837  return res;
838 }
static const char app[]
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static struct ao2_container * conference_bridges
Container to hold all conference bridges in progress.

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Conference Bridge Application" , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
static

Definition at line 860 of file app_confbridge.c.

const char app[] = "ConfBridge"
static
Playing back a file to a channel in a conference
You might notice in this application that while playing a sound file to a channel the actual conference bridge lock is not held. This is done so that other channels are not blocked from interacting with the conference bridge. Unfortunately because of this it is possible for things to change after the sound file is done being played. Data must therefore be checked after reacquiring the conference bridge lock if it is important.

Definition at line 119 of file app_confbridge.c.

struct ast_app_option app_opts[128] = { [ 'A' ] = { .flag = OPTION_MARKEDUSER }, [ 'a' ] = { .flag = OPTION_ADMIN }, [ 'c' ] = { .flag = OPTION_ANNOUNCEUSERCOUNT }, [ 'm' ] = { .flag = OPTION_STARTMUTED }, [ 'M' ] = { .flag = OPTION_MUSICONHOLD , .arg_index = OPTION_MUSICONHOLD_CLASS + 1 }, [ '1' ] = { .flag = OPTION_NOONLYPERSON }, [ 's' ] = { .flag = OPTION_MENU }, [ 'w' ] = { .flag = OPTION_WAITMARKED }, [ 'q' ] = { .flag = OPTION_QUIET }, }
static

Definition at line 149 of file app_confbridge.c.

Referenced by confbridge_exec().

Definition at line 860 of file app_confbridge.c.

struct ao2_container* conference_bridges
static

Container to hold all conference bridges in progress.

Definition at line 181 of file app_confbridge.c.

Referenced by join_conference_bridge(), leave_conference_bridge(), load_module(), and unload_module().