@ -54,26 +54,44 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
Put a call into the holding bridge .
< / synopsis >
< syntax >
< parameter name = " role " required = " false " >
< para > Defines the channel ' s purpose for entering the holding bridge . Values are case sensitive .
< / para >
< enumlist >
< enum name = " participant " >
< para > The channel will enter the holding bridge to be placed on hold
until it is removed from the bridge for some reason . ( default ) < / para >
< / enum >
< enum name = " announcer " >
< para > The channel will enter the holding bridge to make announcements
to channels that are currently in the holding bridge . While an
announcer is present , holding for the participants will be
suspended . < / para >
< / enum >
< / enumlist >
< / parameter >
< parameter name = " options " >
< optionlist >
< option name = " A " >
< para > The channel will join the holding bridge as an
announcer < / para >
< / option >
< option name = " m " >
< argument name = " class " required = " false " / >
< para > Play music on hold to the entering channel while it is
on hold . If the < emphasis > class < / emphasis > is included , then
that class of music on hold will take priority over the
channel default . < / para >
< argument name = " class " required = " true " / >
< para > The specified MOH class will be used / suggested for
music on hold operations . This option will only be useful for
entertainment modes that use it ( m and h ) . < / para >
< / option >
< option name = " r " >
< para > Play a ringing tone to the entering channel while it is
on hold . < / para >
< option name = " e " >
< para > Which entertainment mechanism should be used while on hold
in the holding bridge . Only the first letter is read . < / para >
< enumlist >
< enum name = " m " > < para > Play music on hold ( default ) < / para > < / enum >
< enum name = " r " > < para > Ring without pause < / para > < / enum >
< enum name = " s " > < para > Generate silent audio < / para > < / enum >
< enum name = " h " > < para > Put the channel on hold < / para > < / enum >
< enum name = " n " > < para > No entertainment < / para > < / enum >
< / enumlist >
< / option >
< option name = " S " >
< argument name = " duration " required = " true " / >
< para > Automatically end the hold and return to the PBX after
< para > Automatically e xit the bridge and return to the PBX after
< emphasis > duration < / emphasis > seconds . < / para >
< / option >
< / optionlist >
@ -87,12 +105,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
< / application >
* * */
/* BUGBUG Add bridge name/id parameter to specify which holding bridge to join (required) */
/* BUGBUG Add h(moh-class) option to put channel on hold using AST_CONTROL_HOLD/AST_CONTROL_UNHOLD while in bridge */
/* BUGBUG Add s option to send silence media frames to channel while in bridge (uses a silence generator) */
/* BUGBUG Add n option to send no media to channel while in bridge (Channel should not be answered yet) */
/* BUGBUG The channel may or may not be answered with the r option. */
/* BUGBUG You should not place an announcer into a holding bridge with unanswered channels. */
/* BUGBUG Not supplying any option flags will assume the m option with the default music class. */
static char * app = " BridgeWait " ;
static struct ast_bridge * holding_bridge ;
@ -100,22 +114,21 @@ static struct ast_bridge *holding_bridge;
AST_MUTEX_DEFINE_STATIC ( bridgewait_lock ) ;
enum bridgewait_flags {
MUXFLAG_ PLAY MOH = ( 1 < < 0 ) ,
MUXFLAG_ RINGING = ( 1 < < 1 ) ,
MUXFLAG_ MOHCLASS = ( 1 < < 0 ) ,
MUXFLAG_ ENTERTAINMENT = ( 1 < < 1 ) ,
MUXFLAG_TIMEOUT = ( 1 < < 2 ) ,
MUXFLAG_ANNOUNCER = ( 1 < < 3 ) ,
} ;
enum bridgewait_args {
OPT_ARG_ENTERTAINMENT ,
OPT_ARG_MOHCLASS ,
OPT_ARG_TIMEOUT ,
OPT_ARG_ARRAY_SIZE , /* Always the last element of the enum */
} ;
AST_APP_OPTIONS ( bridgewait_opts , {
AST_APP_OPTION ( ' A ' , MUXFLAG_ANNOUNCER ) ,
AST_APP_OPTION ( ' r ' , MUXFLAG_RINGING ) ,
AST_APP_OPTION_ARG ( ' m ' , MUXFLAG_PLAYMOH , OPT_ARG_MOHCLASS ) ,
AST_APP_OPTION_ARG ( ' e ' , MUXFLAG_ENTERTAINMENT , OPT_ARG_ENTERTAINMENT ) ,
AST_APP_OPTION_ARG ( ' m ' , MUXFLAG_MOHCLASS , OPT_ARG_MOHCLASS ) ,
AST_APP_OPTION_ARG ( ' S ' , MUXFLAG_TIMEOUT , OPT_ARG_TIMEOUT ) ,
} ) ;
@ -147,18 +160,38 @@ static int apply_option_timeout(struct ast_bridge_features *features, char *dura
return 0 ;
}
static void apply_option_moh ( struct ast_channel * chan , char * class_arg )
static int apply_option_moh ( struct ast_channel * chan , const char * class_arg )
{
ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " musiconhold " ) ;
ast_channel_set_bridge_role_option ( chan , " holding_participant " , " moh_class " , class_arg ) ;
return ast_channel_set_bridge_role_option ( chan , " holding_participant " , " moh_class " , class_arg ) ;
}
static void apply_option_ringing ( struct ast_channel * chan )
static int apply_option_entertainment ( struct ast_channel * chan , const char * entertainment_arg )
{
ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " ringing " ) ;
char entertainment = entertainment_arg [ 0 ] ;
switch ( entertainment ) {
case ' m ' :
return ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " musiconhold " ) ;
case ' r ' :
return ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " ringing " ) ;
case ' s ' :
return ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " silence " ) ;
case ' h ' :
return ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " hold " ) ;
case ' n ' :
return ast_channel_set_bridge_role_option ( chan , " holding_participant " , " idle_mode " , " none " ) ;
default :
ast_log ( LOG_ERROR , " Invalid argument for BridgeWait entertainment '%s' \n " , entertainment_arg ) ;
return - 1 ;
}
}
static int process_options ( struct ast_channel * chan , struct ast_flags * flags , char * * opts , struct ast_bridge_features * features )
enum wait_bridge_roles {
ROLE_PARTICIPANT = 0 ,
ROLE_ANNOUNCER ,
ROLE_INVALID ,
} ;
static int process_options ( struct ast_channel * chan , struct ast_flags * flags , char * * opts , struct ast_bridge_features * features , enum wait_bridge_roles role )
{
if ( ast_test_flag ( flags , MUXFLAG_TIMEOUT ) ) {
if ( apply_option_timeout ( features , opts [ OPT_ARG_TIMEOUT ] ) ) {
@ -166,30 +199,59 @@ static int process_options(struct ast_channel *chan, struct ast_flags *flags, ch
}
}
if ( ast_test_flag ( flags , MUXFLAG_ANNOUNCER ) ) {
/* Announcer specific stuff */
ast_channel_add_bridge_role ( chan , " announcer " ) ;
} else {
/* Non Announcer specific stuff */
ast_channel_add_bridge_role ( chan , " holding_participant " ) ;
switch ( role ) {
case ROLE_PARTICIPANT :
if ( ast_channel_add_bridge_role ( chan , " holding_participant " ) ) {
return - 1 ;
}
if ( ast_test_flag ( flags , MUXFLAG_MOHCLASS ) ) {
if ( apply_option_moh ( chan , opts [ OPT_ARG_MOHCLASS ] ) ) {
return - 1 ;
}
}
if ( ast_test_flag ( flags , MUXFLAG_PLAYMOH ) ) {
apply_option_moh ( chan , opts [ OPT_ARG_MOHCLASS ] ) ;
} else if ( ast_test_flag ( flags , MUXFLAG_RINGING ) ) {
apply_option_ringing ( chan ) ;
if ( ast_test_flag ( flags , MUXFLAG_ ENTERTAINMENT ) ) {
if ( apply_option_entertainment ( chan , opts [ OPT_ARG_ENTERTAINMENT ] ) ) {
return - 1 ;
}
}
break ;
case ROLE_ANNOUNCER :
if ( ast_channel_add_bridge_role ( chan , " announcer " ) ) {
return - 1 ;
}
break ;
case ROLE_INVALID :
ast_assert ( 0 ) ;
return - 1 ;
}
return 0 ;
}
static enum wait_bridge_roles validate_role ( const char * role )
{
if ( ! strcmp ( role , " participant " ) ) {
return ROLE_PARTICIPANT ;
} else if ( ! strcmp ( role , " announcer " ) ) {
return ROLE_ANNOUNCER ;
} else {
return ROLE_INVALID ;
}
}
static int bridgewait_exec ( struct ast_channel * chan , const char * data )
{
struct ast_bridge_features chan_features ;
struct ast_flags flags = { 0 } ;
char * parse ;
enum wait_bridge_roles role = ROLE_PARTICIPANT ;
char * opts [ OPT_ARG_ARRAY_SIZE ] = { NULL , } ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( role ) ;
AST_APP_ARG ( options ) ;
AST_APP_ARG ( other ) ; /* Any remaining unused arguments */
) ;
@ -209,18 +271,26 @@ static int bridgewait_exec(struct ast_channel *chan, const char *data)
parse = ast_strdupa ( data ) ;
AST_STANDARD_APP_ARGS ( args , parse ) ;
if ( ! ast_strlen_zero ( args . role ) ) {
role = validate_role ( args . role ) ;
if ( role = = ROLE_INVALID ) {
ast_log ( LOG_ERROR , " Requested waiting bridge role '%s' is invalid. \n " , args . role ) ;
return - 1 ;
}
}
if ( ast_bridge_features_init ( & chan_features ) ) {
ast_bridge_features_cleanup ( & chan_features ) ;
return - 1 ;
}
if ( args . options ) {
char * opts [ OPT_ARG_ARRAY_SIZE ] = { NULL , } ;
ast_app_parse_options ( bridgewait_opts , & flags , opts , args . options ) ;
if ( process_options ( chan , & flags , opts , & chan_features ) ) {
ast_bridge_features_cleanup ( & chan_features ) ;
return - 1 ;
}
}
if ( process_options ( chan , & flags , opts , & chan_features , role ) ) {
ast_bridge_features_cleanup ( & chan_features ) ;
return - 1 ;
}
ast_bridge_join ( holding_bridge , chan , NULL , & chan_features , NULL , 0 ) ;