2013-05-14 21:45:08 +00:00
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2013, Digium, Inc.
*
* David M. Lee, II <dlee@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Stasis application control support.
*
* \author David M. Lee, II <dlee@digium.com>
*/
# include "asterisk.h"
# include "asterisk/stasis_channels.h"
2016-05-09 14:48:51 -05:00
# include "asterisk/stasis_app.h"
2013-05-14 21:45:08 +00:00
# include "command.h"
# include "control.h"
2014-03-13 19:33:22 +00:00
# include "app.h"
2013-07-01 18:19:15 +00:00
# include "asterisk/dial.h"
2013-07-25 04:06:32 +00:00
# include "asterisk/bridge.h"
2013-08-13 15:27:32 +00:00
# include "asterisk/bridge_after.h"
2013-07-25 04:06:32 +00:00
# include "asterisk/bridge_basic.h"
2017-10-06 21:48:48 -04:00
# include "asterisk/bridge_features.h"
2013-07-18 16:03:12 +00:00
# include "asterisk/frame.h"
2013-06-26 19:29:57 +00:00
# include "asterisk/pbx.h"
2013-07-19 19:40:27 +00:00
# include "asterisk/musiconhold.h"
2013-11-01 14:38:21 +00:00
# include "asterisk/app.h"
2013-05-14 21:45:08 +00:00
2013-12-13 16:38:57 +00:00
AST_LIST_HEAD ( app_control_rules , stasis_app_control_rule ) ;
2016-05-09 14:48:51 -05:00
/*!
* \brief Indicates if the Stasis app internals are being shut down
*/
static int shutting_down ;
2013-05-14 21:45:08 +00:00
struct stasis_app_control {
2013-08-13 15:27:32 +00:00
ast_cond_t wait_cond ;
2013-05-14 21:45:08 +00:00
/*! Queue of commands to dispatch on the channel */
struct ao2_container * command_queue ;
/*!
* The associated channel.
* Be very careful with the threading associated w/ manipulating
* the channel.
*/
struct ast_channel * channel ;
2013-08-13 15:27:32 +00:00
/*!
* When a channel is in a bridge, the bridge that it is in.
*/
struct ast_bridge * bridge ;
2017-10-06 21:48:48 -04:00
/*!
* Bridge features which should be applied to the channel when it enters the next bridge. These only apply to the next bridge and will be emptied thereafter.
*/
struct ast_bridge_features * bridge_features ;
2013-08-13 15:27:32 +00:00
/*!
* Holding place for channel's PBX while imparted to a bridge.
*/
struct ast_pbx * pbx ;
2013-12-13 16:38:57 +00:00
/*!
* A list of rules to check before adding a channel to a bridge.
*/
struct app_control_rules add_rules ;
/*!
* A list of rules to check before removing a channel from a bridge.
*/
struct app_control_rules remove_rules ;
2013-11-21 15:56:34 +00:00
/*!
* Silence generator, when silence is being generated.
*/
struct ast_silence_generator * silgen ;
2014-03-13 19:33:22 +00:00
/*!
2019-03-07 07:41:14 -06:00
* The app for which this control is currently controlling.
* This can change through the use of the /channels/{channelId}/move
* command.
2014-03-13 19:33:22 +00:00
*/
struct stasis_app * app ;
2019-03-07 07:41:14 -06:00
/*!
* The name of the next Stasis application to move to.
*/
char * next_app ;
/*!
* The list of arguments to pass to StasisStart when moving to another app.
*/
AST_VECTOR ( , char * ) next_app_args ;
2013-08-13 15:27:32 +00:00
/*!
* When set, /c app_stasis should exit and continue in the dialplan.
*/
int is_done : 1 ;
2013-05-14 21:45:08 +00:00
} ;
2013-08-13 15:27:32 +00:00
static void control_dtor ( void * obj )
{
struct stasis_app_control * control = obj ;
2016-03-28 18:10:40 -05:00
ao2_cleanup ( control - > command_queue ) ;
2013-12-13 16:38:57 +00:00
2016-03-28 18:10:40 -05:00
ast_channel_cleanup ( control - > channel ) ;
ao2_cleanup ( control - > app ) ;
2013-11-21 15:56:34 +00:00
2019-03-07 07:41:14 -06:00
control_move_cleanup ( control ) ;
2013-08-13 15:27:32 +00:00
ast_cond_destroy ( & control - > wait_cond ) ;
2016-03-28 18:10:40 -05:00
AST_LIST_HEAD_DESTROY ( & control - > add_rules ) ;
AST_LIST_HEAD_DESTROY ( & control - > remove_rules ) ;
2017-10-06 21:48:48 -04:00
ast_bridge_features_destroy ( control - > bridge_features ) ;
2013-08-13 15:27:32 +00:00
}
2014-03-13 19:33:22 +00:00
struct stasis_app_control * control_create ( struct ast_channel * channel , struct stasis_app * app )
2013-05-14 21:45:08 +00:00
{
2016-03-28 18:10:40 -05:00
struct stasis_app_control * control ;
2013-08-13 15:27:32 +00:00
int res ;
2013-05-14 21:45:08 +00:00
2013-08-13 15:27:32 +00:00
control = ao2_alloc ( sizeof ( * control ) , control_dtor ) ;
2013-05-14 21:45:08 +00:00
if ( ! control ) {
return NULL ;
}
2016-03-28 18:10:40 -05:00
AST_LIST_HEAD_INIT ( & control - > add_rules ) ;
AST_LIST_HEAD_INIT ( & control - > remove_rules ) ;
2014-03-13 19:33:22 +00:00
2013-08-13 15:27:32 +00:00
res = ast_cond_init ( & control - > wait_cond , NULL ) ;
if ( res ! = 0 ) {
ast_log ( LOG_ERROR , " Error initializing ast_cond_t: %s \n " ,
strerror ( errno ) ) ;
2016-03-28 18:10:40 -05:00
ao2_ref ( control , - 1 ) ;
2013-08-13 15:27:32 +00:00
return NULL ;
}
2016-03-28 18:10:40 -05:00
control - > app = ao2_bump ( app ) ;
ast_channel_ref ( channel ) ;
control - > channel = channel ;
2013-05-23 20:11:35 +00:00
control - > command_queue = ao2_container_alloc_list (
AO2_ALLOC_OPT_LOCK_MUTEX , 0 , NULL , NULL ) ;
2013-07-19 19:35:21 +00:00
if ( ! control - > command_queue ) {
2016-03-28 18:10:40 -05:00
ao2_ref ( control , - 1 ) ;
2013-07-19 19:35:21 +00:00
return NULL ;
}
2019-03-07 07:41:14 -06:00
control - > next_app = NULL ;
AST_VECTOR_INIT ( & control - > next_app_args , 0 ) ;
2013-05-14 21:45:08 +00:00
return control ;
}
2013-12-13 16:38:57 +00:00
static void app_control_register_rule (
2015-06-02 19:27:28 +02:00
struct stasis_app_control * control ,
2013-12-13 16:38:57 +00:00
struct app_control_rules * list , struct stasis_app_control_rule * obj )
{
2018-01-06 03:17:15 -05:00
ao2_lock ( control - > command_queue ) ;
2013-12-13 16:38:57 +00:00
AST_LIST_INSERT_TAIL ( list , obj , next ) ;
2018-01-06 03:17:15 -05:00
ao2_unlock ( control - > command_queue ) ;
2013-12-13 16:38:57 +00:00
}
static void app_control_unregister_rule (
2015-06-02 19:27:28 +02:00
struct stasis_app_control * control ,
2013-12-13 16:38:57 +00:00
struct app_control_rules * list , struct stasis_app_control_rule * obj )
{
struct stasis_app_control_rule * rule ;
2018-01-06 03:17:15 -05:00
ao2_lock ( control - > command_queue ) ;
2013-12-13 16:38:57 +00:00
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( list , rule , next ) {
if ( rule = = obj ) {
AST_RWLIST_REMOVE_CURRENT ( next ) ;
break ;
}
}
AST_RWLIST_TRAVERSE_SAFE_END ;
2018-01-06 03:17:15 -05:00
ao2_unlock ( control - > command_queue ) ;
2013-12-13 16:38:57 +00:00
}
/*!
* \internal
* \brief Checks to make sure each rule in the given list passes.
*
* \details Loops over a list of rules checking for rejections or failures.
* If one rule fails its resulting error code is returned.
*
* \note Command queue should be locked before calling this function.
*
* \param control The stasis application control
* \param list The list of rules to check
*
* \retval 0 if all rules pass
* \retval non-zero error code if a rule fails
*/
static enum stasis_app_control_channel_result app_control_check_rules (
const struct stasis_app_control * control ,
struct app_control_rules * list )
{
int res = 0 ;
struct stasis_app_control_rule * rule ;
AST_LIST_TRAVERSE ( list , rule , next ) {
if ( ( res = rule - > check_rule ( control ) ) ) {
return res ;
}
}
return res ;
}
void stasis_app_control_register_add_rule (
struct stasis_app_control * control ,
struct stasis_app_control_rule * rule )
{
return app_control_register_rule ( control , & control - > add_rules , rule ) ;
}
void stasis_app_control_unregister_add_rule (
struct stasis_app_control * control ,
struct stasis_app_control_rule * rule )
{
app_control_unregister_rule ( control , & control - > add_rules , rule ) ;
}
void stasis_app_control_register_remove_rule (
struct stasis_app_control * control ,
struct stasis_app_control_rule * rule )
{
return app_control_register_rule ( control , & control - > remove_rules , rule ) ;
}
void stasis_app_control_unregister_remove_rule (
struct stasis_app_control * control ,
struct stasis_app_control_rule * rule )
{
app_control_unregister_rule ( control , & control - > remove_rules , rule ) ;
}
static int app_control_can_add_channel_to_bridge (
struct stasis_app_control * control )
{
return app_control_check_rules ( control , & control - > add_rules ) ;
}
static int app_control_can_remove_channel_from_bridge (
struct stasis_app_control * control )
{
return app_control_check_rules ( control , & control - > remove_rules ) ;
}
static int noop_cb ( struct stasis_app_control * control ,
2013-08-13 15:27:32 +00:00
struct ast_channel * chan , void * data )
{
2013-12-13 16:38:57 +00:00
return 0 ;
2013-08-13 15:27:32 +00:00
}
2013-12-13 16:38:57 +00:00
/*! Callback type to see if the command can execute
note: command_queue is locked during callback */
typedef int ( * app_command_can_exec_cb ) ( struct stasis_app_control * control ) ;
2013-08-13 15:27:32 +00:00
2013-12-13 16:38:57 +00:00
static struct stasis_app_command * exec_command_on_condition (
2013-05-14 21:45:08 +00:00
struct stasis_app_control * control , stasis_app_command_cb command_fn ,
2014-08-22 16:52:51 +00:00
void * data , command_data_destructor_fn data_destructor ,
app_command_can_exec_cb can_exec_fn )
2013-05-14 21:45:08 +00:00
{
2013-12-13 16:38:57 +00:00
int retval ;
struct stasis_app_command * command ;
2013-05-14 21:45:08 +00:00
2013-08-13 15:27:32 +00:00
command_fn = command_fn ? : noop_cb ;
2014-08-22 16:52:51 +00:00
command = command_create ( command_fn , data , data_destructor ) ;
2013-05-14 21:45:08 +00:00
if ( ! command ) {
return NULL ;
}
2013-08-13 15:27:32 +00:00
ao2_lock ( control - > command_queue ) ;
2016-03-29 13:47:08 -05:00
if ( control - > is_done ) {
ao2_unlock ( control - > command_queue ) ;
ao2_ref ( command , - 1 ) ;
return NULL ;
}
2013-12-13 16:38:57 +00:00
if ( can_exec_fn & & ( retval = can_exec_fn ( control ) ) ) {
ao2_unlock ( control - > command_queue ) ;
command_complete ( command , retval ) ;
return command ;
}
2013-08-13 15:27:32 +00:00
ao2_link_flags ( control - > command_queue , command , OBJ_NOLOCK ) ;
ast_cond_signal ( & control - > wait_cond ) ;
ao2_unlock ( control - > command_queue ) ;
2013-05-14 21:45:08 +00:00
return command ;
}
2013-12-13 16:38:57 +00:00
static struct stasis_app_command * exec_command (
struct stasis_app_control * control , stasis_app_command_cb command_fn ,
2014-08-22 16:52:51 +00:00
void * data , command_data_destructor_fn data_destructor )
2013-12-13 16:38:57 +00:00
{
2014-08-22 16:52:51 +00:00
return exec_command_on_condition ( control , command_fn , data , data_destructor , NULL ) ;
2013-12-13 16:38:57 +00:00
}
2016-01-21 10:58:02 -06:00
static int app_control_add_role ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
char * role = data ;
return ast_channel_add_bridge_role ( chan , role ) ;
}
2013-08-05 16:59:13 +00:00
int stasis_app_control_add_role ( struct stasis_app_control * control , const char * role )
{
2016-01-21 10:58:02 -06:00
char * role_dup ;
role_dup = ast_strdup ( role ) ;
if ( ! role_dup ) {
return - 1 ;
}
stasis_app_send_command_async ( control , app_control_add_role , role_dup , ast_free_ptr ) ;
return 0 ;
}
static int app_control_clear_roles ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
ast_channel_clear_bridge_roles ( chan ) ;
return 0 ;
2013-08-05 16:59:13 +00:00
}
void stasis_app_control_clear_roles ( struct stasis_app_control * control )
{
2016-01-21 10:58:02 -06:00
stasis_app_send_command_async ( control , app_control_clear_roles , NULL , NULL ) ;
2013-08-05 16:59:13 +00:00
}
2014-04-18 20:09:24 +00:00
int control_command_count ( struct stasis_app_control * control )
{
return ao2_container_count ( control - > command_queue ) ;
}
2013-05-14 21:45:08 +00:00
int control_is_done ( struct stasis_app_control * control )
{
/* Called from stasis_app_exec thread; no lock needed */
return control - > is_done ;
}
2014-04-18 20:09:24 +00:00
void control_mark_done ( struct stasis_app_control * control )
{
2016-03-29 13:47:08 -05:00
/* Locking necessary to sync with other threads adding commands to the queue. */
ao2_lock ( control - > command_queue ) ;
2014-04-18 20:09:24 +00:00
control - > is_done = 1 ;
2016-03-29 13:47:08 -05:00
ao2_unlock ( control - > command_queue ) ;
2014-04-18 20:09:24 +00:00
}
2013-06-26 19:29:57 +00:00
struct stasis_app_control_continue_data {
char context [ AST_MAX_CONTEXT ] ;
char extension [ AST_MAX_EXTENSION ] ;
int priority ;
} ;
2013-12-13 16:38:57 +00:00
static int app_control_continue ( struct stasis_app_control * control ,
2013-05-14 21:45:08 +00:00
struct ast_channel * chan , void * data )
{
2014-08-22 16:52:51 +00:00
struct stasis_app_control_continue_data * continue_data = data ;
2013-06-26 19:29:57 +00:00
2013-08-13 15:27:32 +00:00
ast_assert ( control - > channel ! = NULL ) ;
/* If we're in a Stasis bridge, depart it before going back to the
* dialplan */
if ( stasis_app_get_bridge ( control ) ) {
ast_bridge_depart ( control - > channel ) ;
}
2013-05-14 21:45:08 +00:00
/* Called from stasis_app_exec thread; no lock needed */
2013-06-26 19:29:57 +00:00
ast_explicit_goto ( control - > channel , continue_data - > context , continue_data - > extension , continue_data - > priority ) ;
2016-03-29 13:47:08 -05:00
control_mark_done ( control ) ;
2013-06-26 19:29:57 +00:00
2013-12-13 16:38:57 +00:00
return 0 ;
2013-05-14 21:45:08 +00:00
}
2013-06-26 19:29:57 +00:00
int stasis_app_control_continue ( struct stasis_app_control * control , const char * context , const char * extension , int priority )
2013-05-14 21:45:08 +00:00
{
2013-06-26 19:29:57 +00:00
struct stasis_app_control_continue_data * continue_data ;
if ( ! ( continue_data = ast_calloc ( 1 , sizeof ( * continue_data ) ) ) ) {
return - 1 ;
}
ast_copy_string ( continue_data - > context , S_OR ( context , " " ) , sizeof ( continue_data - > context ) ) ;
ast_copy_string ( continue_data - > extension , S_OR ( extension , " " ) , sizeof ( continue_data - > extension ) ) ;
if ( priority > 0 ) {
continue_data - > priority = priority ;
} else {
continue_data - > priority = - 1 ;
}
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_continue , continue_data , ast_free_ptr ) ;
2013-06-26 19:29:57 +00:00
return 0 ;
2013-05-14 21:45:08 +00:00
}
2019-03-07 07:41:14 -06:00
struct stasis_app_control_move_data {
char * app_name ;
char * app_args ;
} ;
static int app_control_move ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
struct stasis_app_control_move_data * move_data = data ;
control - > next_app = ast_strdup ( move_data - > app_name ) ;
if ( ! control - > next_app ) {
ast_log ( LOG_ERROR , " Allocation failed for next app \n " ) ;
return - 1 ;
}
if ( move_data - > app_args ) {
char * token ;
while ( ( token = strtok_r ( move_data - > app_args , " , " , & move_data - > app_args ) ) ) {
int res ;
char * arg ;
if ( ! ( arg = ast_strdup ( token ) ) ) {
ast_log ( LOG_ERROR , " Allocation failed for next app arg \n " ) ;
control_move_cleanup ( control ) ;
return - 1 ;
}
res = AST_VECTOR_APPEND ( & control - > next_app_args , arg ) ;
if ( res ) {
ast_log ( LOG_ERROR , " Failed to append arg to next app args \n " ) ;
ast_free ( arg ) ;
control_move_cleanup ( control ) ;
return - 1 ;
}
}
}
return 0 ;
}
int stasis_app_control_move ( struct stasis_app_control * control , const char * app_name , const char * app_args )
{
struct stasis_app_control_move_data * move_data ;
size_t size ;
size = sizeof ( * move_data ) + strlen ( app_name ) + strlen ( app_args ) + 2 ;
if ( ! ( move_data = ast_calloc ( 1 , size ) ) ) {
return - 1 ;
}
move_data - > app_name = ( char * ) move_data + sizeof ( * move_data ) ;
move_data - > app_args = move_data - > app_name + strlen ( app_name ) + 1 ;
strcpy ( move_data - > app_name , app_name ) ; /* Safe */
if ( app_args ) {
strcpy ( move_data - > app_args , app_args ) ; /* Safe */
} else {
move_data - > app_args = NULL ;
}
stasis_app_send_command_async ( control , app_control_move , move_data , ast_free_ptr ) ;
return 0 ;
}
2015-02-12 20:34:37 +00:00
static int app_control_redirect ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
char * endpoint = data ;
int res ;
ast_assert ( control - > channel ! = NULL ) ;
ast_assert ( endpoint ! = NULL ) ;
res = ast_transfer ( control - > channel , endpoint ) ;
if ( ! res ) {
ast_log ( LOG_NOTICE , " Unsupported transfer requested on channel '%s' \n " ,
ast_channel_name ( control - > channel ) ) ;
return 0 ;
}
return 0 ;
}
int stasis_app_control_redirect ( struct stasis_app_control * control , const char * endpoint )
{
char * endpoint_data = ast_strdup ( endpoint ) ;
if ( ! endpoint_data ) {
return - 1 ;
}
stasis_app_send_command_async ( control , app_control_redirect , endpoint_data , ast_free_ptr ) ;
return 0 ;
}
2013-11-01 14:38:21 +00:00
struct stasis_app_control_dtmf_data {
int before ;
int between ;
unsigned int duration ;
int after ;
char dtmf [ ] ;
} ;
2018-06-13 16:41:43 -05:00
static void dtmf_in_bridge ( struct ast_channel * chan , struct stasis_app_control_dtmf_data * dtmf_data )
2013-11-01 14:38:21 +00:00
{
2018-06-13 16:41:43 -05:00
if ( dtmf_data - > before ) {
usleep ( dtmf_data - > before * 1000 ) ;
}
2013-11-01 14:38:21 +00:00
2018-06-13 16:41:43 -05:00
ast_dtmf_stream_external ( chan , dtmf_data - > dtmf , dtmf_data - > between , dtmf_data - > duration ) ;
if ( dtmf_data - > after ) {
usleep ( dtmf_data - > after * 1000 ) ;
2014-04-30 12:42:42 +00:00
}
2018-06-13 16:41:43 -05:00
}
2014-04-30 12:42:42 +00:00
2018-06-13 16:41:43 -05:00
static void dtmf_no_bridge ( struct ast_channel * chan , struct stasis_app_control_dtmf_data * dtmf_data )
{
2013-11-01 14:38:21 +00:00
if ( dtmf_data - > before ) {
ast_safe_sleep ( chan , dtmf_data - > before ) ;
}
ast_dtmf_stream ( chan , NULL , dtmf_data - > dtmf , dtmf_data - > between , dtmf_data - > duration ) ;
if ( dtmf_data - > after ) {
ast_safe_sleep ( chan , dtmf_data - > after ) ;
}
2018-06-13 16:41:43 -05:00
}
static int app_control_dtmf ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
struct stasis_app_control_dtmf_data * dtmf_data = data ;
if ( ast_channel_state ( chan ) ! = AST_STATE_UP ) {
ast_indicate ( chan , AST_CONTROL_PROGRESS ) ;
}
if ( stasis_app_get_bridge ( control ) ) {
dtmf_in_bridge ( chan , dtmf_data ) ;
} else {
dtmf_no_bridge ( chan , dtmf_data ) ;
}
2013-11-01 14:38:21 +00:00
2013-12-13 16:38:57 +00:00
return 0 ;
2013-11-01 14:38:21 +00:00
}
int stasis_app_control_dtmf ( struct stasis_app_control * control , const char * dtmf , int before , int between , unsigned int duration , int after )
{
struct stasis_app_control_dtmf_data * dtmf_data ;
if ( ! ( dtmf_data = ast_calloc ( 1 , sizeof ( * dtmf_data ) + strlen ( dtmf ) + 1 ) ) ) {
return - 1 ;
}
dtmf_data - > before = before ;
dtmf_data - > between = between ;
dtmf_data - > duration = duration ;
dtmf_data - > after = after ;
strcpy ( dtmf_data - > dtmf , dtmf ) ;
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_dtmf , dtmf_data , ast_free_ptr ) ;
2013-11-01 14:38:21 +00:00
return 0 ;
}
2013-12-13 16:38:57 +00:00
static int app_control_ring ( struct stasis_app_control * control ,
2013-11-01 14:38:21 +00:00
struct ast_channel * chan , void * data )
{
ast_indicate ( control - > channel , AST_CONTROL_RINGING ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-11-01 14:38:21 +00:00
}
int stasis_app_control_ring ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_ring , NULL , NULL ) ;
2013-11-01 14:38:21 +00:00
return 0 ;
}
2013-12-13 16:38:57 +00:00
static int app_control_ring_stop ( struct stasis_app_control * control ,
2013-11-13 23:11:32 +00:00
struct ast_channel * chan , void * data )
{
ast_indicate ( control - > channel , - 1 ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-11-13 23:11:32 +00:00
}
int stasis_app_control_ring_stop ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_ring_stop , NULL , NULL ) ;
2013-11-13 23:11:32 +00:00
return 0 ;
}
2013-07-18 16:03:12 +00:00
struct stasis_app_control_mute_data {
enum ast_frame_type frametype ;
unsigned int direction ;
} ;
2013-12-13 16:38:57 +00:00
static int app_control_mute ( struct stasis_app_control * control ,
2013-07-18 16:03:12 +00:00
struct ast_channel * chan , void * data )
{
2014-08-22 16:52:51 +00:00
struct stasis_app_control_mute_data * mute_data = data ;
2013-07-18 16:03:12 +00:00
2018-01-06 03:17:15 -05:00
ast_channel_lock ( chan ) ;
2013-07-18 16:03:12 +00:00
ast_channel_suppress ( control - > channel , mute_data - > direction , mute_data - > frametype ) ;
2018-01-06 03:17:15 -05:00
ast_channel_unlock ( chan ) ;
2013-07-18 16:03:12 +00:00
2013-12-13 16:38:57 +00:00
return 0 ;
2013-07-18 16:03:12 +00:00
}
int stasis_app_control_mute ( struct stasis_app_control * control , unsigned int direction , enum ast_frame_type frametype )
{
struct stasis_app_control_mute_data * mute_data ;
if ( ! ( mute_data = ast_calloc ( 1 , sizeof ( * mute_data ) ) ) ) {
return - 1 ;
}
mute_data - > direction = direction ;
mute_data - > frametype = frametype ;
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_mute , mute_data , ast_free_ptr ) ;
2013-07-18 16:03:12 +00:00
return 0 ;
}
2013-12-13 16:38:57 +00:00
static int app_control_unmute ( struct stasis_app_control * control ,
2013-07-18 16:03:12 +00:00
struct ast_channel * chan , void * data )
{
2014-08-22 16:52:51 +00:00
struct stasis_app_control_mute_data * mute_data = data ;
2013-07-18 16:03:12 +00:00
2018-01-06 03:17:15 -05:00
ast_channel_lock ( chan ) ;
2013-07-18 16:03:12 +00:00
ast_channel_unsuppress ( control - > channel , mute_data - > direction , mute_data - > frametype ) ;
2018-01-06 03:17:15 -05:00
ast_channel_unlock ( chan ) ;
2013-07-18 16:03:12 +00:00
2013-12-13 16:38:57 +00:00
return 0 ;
2013-07-18 16:03:12 +00:00
}
int stasis_app_control_unmute ( struct stasis_app_control * control , unsigned int direction , enum ast_frame_type frametype )
{
struct stasis_app_control_mute_data * mute_data ;
if ( ! ( mute_data = ast_calloc ( 1 , sizeof ( * mute_data ) ) ) ) {
return - 1 ;
}
mute_data - > direction = direction ;
mute_data - > frametype = frametype ;
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_unmute , mute_data , ast_free_ptr ) ;
2013-07-18 16:03:12 +00:00
return 0 ;
}
2016-01-25 10:23:18 -06:00
/*!
* \brief structure for queuing ARI channel variable setting
*
* It may seem weird to define this custom structure given that we already have
* ast_var_t and ast_variable defined elsewhere. The problem with those is that
* they are not tolerant of NULL channel variable value pointers. In fact, in both
* cases, the best they could do is to have a zero-length variable value. However,
* when un-setting a channel variable, it is important to pass a NULL value, not
* a zero-length string.
*/
struct chanvar {
/*! Name of variable to set/unset */
char * name ;
/*! Value of variable to set. If unsetting, this will be NULL */
char * value ;
} ;
static void free_chanvar ( void * data )
{
struct chanvar * var = data ;
ast_free ( var - > name ) ;
ast_free ( var - > value ) ;
ast_free ( var ) ;
}
2016-01-21 10:58:02 -06:00
static int app_control_set_channel_var ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
2016-01-25 10:23:18 -06:00
struct chanvar * var = data ;
2016-01-21 10:58:02 -06:00
pbx_builtin_setvar_helper ( control - > channel , var - > name , var - > value ) ;
return 0 ;
}
2013-07-08 14:46:20 +00:00
int stasis_app_control_set_channel_var ( struct stasis_app_control * control , const char * variable , const char * value )
{
2016-01-25 10:23:18 -06:00
struct chanvar * var ;
2016-01-21 10:58:02 -06:00
2016-01-25 10:23:18 -06:00
var = ast_calloc ( 1 , sizeof ( * var ) ) ;
2016-01-21 10:58:02 -06:00
if ( ! var ) {
return - 1 ;
}
2016-01-25 10:23:18 -06:00
var - > name = ast_strdup ( variable ) ;
if ( ! var - > name ) {
free_chanvar ( var ) ;
return - 1 ;
}
/* It's kosher for value to be NULL. It means the variable is being unset */
if ( value ) {
var - > value = ast_strdup ( value ) ;
if ( ! var - > value ) {
free_chanvar ( var ) ;
return - 1 ;
}
}
stasis_app_send_command_async ( control , app_control_set_channel_var , var , free_chanvar ) ;
2016-01-21 10:58:02 -06:00
return 0 ;
2013-07-08 14:46:20 +00:00
}
2013-12-13 16:38:57 +00:00
static int app_control_hold ( struct stasis_app_control * control ,
2013-07-01 18:56:21 +00:00
struct ast_channel * chan , void * data )
{
ast_indicate ( control - > channel , AST_CONTROL_HOLD ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-07-01 18:56:21 +00:00
}
void stasis_app_control_hold ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_hold , NULL , NULL ) ;
2013-07-01 18:56:21 +00:00
}
2013-12-13 16:38:57 +00:00
static int app_control_unhold ( struct stasis_app_control * control ,
2013-07-01 18:56:21 +00:00
struct ast_channel * chan , void * data )
{
ast_indicate ( control - > channel , AST_CONTROL_UNHOLD ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-07-01 18:56:21 +00:00
}
void stasis_app_control_unhold ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_unhold , NULL , NULL ) ;
2013-07-01 18:56:21 +00:00
}
2013-12-13 16:38:57 +00:00
static int app_control_moh_start ( struct stasis_app_control * control ,
2013-07-19 19:40:27 +00:00
struct ast_channel * chan , void * data )
{
char * moh_class = data ;
2014-04-30 12:42:42 +00:00
if ( ast_channel_state ( chan ) ! = AST_STATE_UP ) {
ast_indicate ( chan , AST_CONTROL_PROGRESS ) ;
}
2013-07-19 19:40:27 +00:00
ast_moh_start ( chan , moh_class , NULL ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-07-19 19:40:27 +00:00
}
void stasis_app_control_moh_start ( struct stasis_app_control * control , const char * moh_class )
{
char * data = NULL ;
if ( ! ast_strlen_zero ( moh_class ) ) {
data = ast_strdup ( moh_class ) ;
}
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_moh_start , data , ast_free_ptr ) ;
2013-07-19 19:40:27 +00:00
}
2013-12-13 16:38:57 +00:00
static int app_control_moh_stop ( struct stasis_app_control * control ,
2013-07-19 19:40:27 +00:00
struct ast_channel * chan , void * data )
{
ast_moh_stop ( chan ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-07-19 19:40:27 +00:00
}
void stasis_app_control_moh_stop ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_moh_stop , NULL , NULL ) ;
2013-07-19 19:40:27 +00:00
}
2013-12-13 16:38:57 +00:00
static int app_control_silence_start ( struct stasis_app_control * control ,
2013-11-21 15:56:34 +00:00
struct ast_channel * chan , void * data )
{
2014-04-30 12:42:42 +00:00
if ( ast_channel_state ( chan ) ! = AST_STATE_UP ) {
ast_indicate ( chan , AST_CONTROL_PROGRESS ) ;
}
2013-11-21 15:56:34 +00:00
if ( control - > silgen ) {
/* We have a silence generator, but it may have been implicitly
* disabled by media actions (music on hold, playing media,
* etc.) Just stop it and restart a new one.
*/
ast_channel_stop_silence_generator (
control - > channel , control - > silgen ) ;
}
ast_debug ( 3 , " %s: Starting silence generator \n " ,
stasis_app_control_get_channel_id ( control ) ) ;
control - > silgen = ast_channel_start_silence_generator ( control - > channel ) ;
if ( ! control - > silgen ) {
ast_log ( LOG_WARNING ,
" %s: Failed to start silence generator. \n " ,
stasis_app_control_get_channel_id ( control ) ) ;
}
2013-12-13 16:38:57 +00:00
return 0 ;
2013-11-21 15:56:34 +00:00
}
void stasis_app_control_silence_start ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_silence_start , NULL , NULL ) ;
2013-11-21 15:56:34 +00:00
}
2016-03-28 18:10:40 -05:00
void control_silence_stop_now ( struct stasis_app_control * control )
2013-11-21 15:56:34 +00:00
{
if ( control - > silgen ) {
ast_debug ( 3 , " %s: Stopping silence generator \n " ,
stasis_app_control_get_channel_id ( control ) ) ;
ast_channel_stop_silence_generator (
control - > channel , control - > silgen ) ;
control - > silgen = NULL ;
}
2016-03-28 18:10:40 -05:00
}
2013-11-21 15:56:34 +00:00
2016-03-28 18:10:40 -05:00
static int app_control_silence_stop ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
control_silence_stop_now ( control ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-11-21 15:56:34 +00:00
}
void stasis_app_control_silence_stop ( struct stasis_app_control * control )
{
2014-08-22 16:52:51 +00:00
stasis_app_send_command_async ( control , app_control_silence_stop , NULL , NULL ) ;
2013-11-21 15:56:34 +00:00
}
2013-05-14 21:45:08 +00:00
struct ast_channel_snapshot * stasis_app_control_get_snapshot (
const struct stasis_app_control * control )
{
2018-01-06 03:17:15 -05:00
struct stasis_message * msg ;
2013-05-14 21:45:08 +00:00
struct ast_channel_snapshot * snapshot ;
2013-08-01 13:49:34 +00:00
msg = stasis_cache_get ( ast_channel_cache ( ) , ast_channel_snapshot_type ( ) ,
2013-05-14 21:45:08 +00:00
stasis_app_control_get_channel_id ( control ) ) ;
if ( ! msg ) {
return NULL ;
}
snapshot = stasis_message_data ( msg ) ;
ast_assert ( snapshot ! = NULL ) ;
ao2_ref ( snapshot , + 1 ) ;
2018-01-06 03:17:15 -05:00
ao2_ref ( msg , - 1 ) ;
2013-05-14 21:45:08 +00:00
return snapshot ;
}
2013-12-13 16:38:57 +00:00
static int app_send_command_on_condition ( struct stasis_app_control * control ,
stasis_app_command_cb command_fn , void * data ,
2014-08-22 16:52:51 +00:00
command_data_destructor_fn data_destructor ,
2013-12-13 16:38:57 +00:00
app_command_can_exec_cb can_exec_fn )
2013-05-14 21:45:08 +00:00
{
2018-01-06 03:17:15 -05:00
int ret ;
struct stasis_app_command * command ;
2013-05-14 21:45:08 +00:00
2015-06-18 13:16:29 -05:00
if ( control = = NULL | | control - > is_done ) {
2016-01-22 15:08:58 -06:00
/* If exec_command_on_condition fails, it calls the data_destructor.
* In order to provide consistent behavior, we'll also call the data_destructor
* on this error path. This way, callers never have to call the
* data_destructor themselves.
*/
if ( data_destructor ) {
data_destructor ( data ) ;
}
2013-12-13 16:38:57 +00:00
return - 1 ;
2013-05-14 21:45:08 +00:00
}
2013-12-13 16:38:57 +00:00
command = exec_command_on_condition (
2014-08-22 16:52:51 +00:00
control , command_fn , data , data_destructor , can_exec_fn ) ;
2013-05-14 21:45:08 +00:00
if ( ! command ) {
2013-12-13 16:38:57 +00:00
return - 1 ;
2013-05-14 21:45:08 +00:00
}
2018-01-06 03:17:15 -05:00
ret = command_join ( command ) ;
ao2_ref ( command , - 1 ) ;
return ret ;
2013-05-14 21:45:08 +00:00
}
2013-12-13 16:38:57 +00:00
int stasis_app_send_command ( struct stasis_app_control * control ,
2014-08-22 16:52:51 +00:00
stasis_app_command_cb command_fn , void * data , command_data_destructor_fn data_destructor )
2013-12-13 16:38:57 +00:00
{
2014-08-22 16:52:51 +00:00
return app_send_command_on_condition ( control , command_fn , data , data_destructor , NULL ) ;
2013-12-13 16:38:57 +00:00
}
2013-05-14 21:45:08 +00:00
int stasis_app_send_command_async ( struct stasis_app_control * control ,
2014-08-22 16:52:51 +00:00
stasis_app_command_cb command_fn , void * data ,
command_data_destructor_fn data_destructor )
2013-05-14 21:45:08 +00:00
{
2018-01-06 03:17:15 -05:00
struct stasis_app_command * command ;
2013-05-14 21:45:08 +00:00
2015-06-18 13:16:29 -05:00
if ( control = = NULL | | control - > is_done ) {
2016-01-22 15:08:58 -06:00
/* If exec_command fails, it calls the data_destructor. In order to
* provide consistent behavior, we'll also call the data_destructor
* on this error path. This way, callers never have to call the
* data_destructor themselves.
*/
if ( data_destructor ) {
data_destructor ( data ) ;
}
2013-05-14 21:45:08 +00:00
return - 1 ;
}
2014-08-22 16:52:51 +00:00
command = exec_command ( control , command_fn , data , data_destructor ) ;
2013-05-14 21:45:08 +00:00
if ( ! command ) {
return - 1 ;
}
2018-01-06 03:17:15 -05:00
ao2_ref ( command , - 1 ) ;
2013-05-14 21:45:08 +00:00
return 0 ;
}
2013-08-13 15:27:32 +00:00
struct ast_bridge * stasis_app_get_bridge ( struct stasis_app_control * control )
{
2018-01-06 03:17:15 -05:00
struct ast_bridge * ret ;
2013-08-13 15:27:32 +00:00
if ( ! control ) {
return NULL ;
}
2018-01-06 03:17:15 -05:00
ao2_lock ( control ) ;
ret = control - > bridge ;
ao2_unlock ( control ) ;
return ret ;
2013-08-13 15:27:32 +00:00
}
2016-05-09 14:48:51 -05:00
/*!
* \brief Singleton dial bridge
*
* The dial bridge is a holding bridge used to hold all
* outbound dialed channels that are not in any "real" ARI-created
* bridge. The dial bridge is invisible, meaning that it does not
* show up in channel snapshots, AMI or ARI output, and no events
* get raised for it.
*
* This is used to keep dialed channels confined to the bridging system
* and unify the threading model used for dialing outbound channels.
*/
static struct ast_bridge * dial_bridge ;
AST_MUTEX_DEFINE_STATIC ( dial_bridge_lock ) ;
/*!
* \brief Retrieve a reference to the dial bridge.
*
* If the dial bridge has not been created yet, it will
* be created, otherwise, a reference to the existing bridge
* will be returned.
*
* The caller will need to unreference the dial bridge once
* they are finished with it.
*
* \retval NULL Unable to find/create the dial bridge
2017-12-20 12:14:54 -05:00
* \retval non-NULL A reference to the dial bridge
2016-05-09 14:48:51 -05:00
*/
static struct ast_bridge * get_dial_bridge ( void )
{
struct ast_bridge * ret_bridge = NULL ;
ast_mutex_lock ( & dial_bridge_lock ) ;
if ( shutting_down ) {
goto end ;
}
if ( dial_bridge ) {
ret_bridge = ao2_bump ( dial_bridge ) ;
goto end ;
}
dial_bridge = stasis_app_bridge_create_invisible ( " holding " , " dial_bridge " , NULL ) ;
if ( ! dial_bridge ) {
goto end ;
}
ret_bridge = ao2_bump ( dial_bridge ) ;
end :
ast_mutex_unlock ( & dial_bridge_lock ) ;
return ret_bridge ;
}
2016-07-11 19:07:20 -06:00
static int bridge_channel_depart ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data ) ;
2016-05-09 14:48:51 -05:00
/*!
* \brief after bridge callback for the dial bridge
*
* The only purpose of this callback is to ensure that the control structure's
* bridge pointer is NULLed
*/
static void dial_bridge_after_cb ( struct ast_channel * chan , void * data )
{
struct stasis_app_control * control = data ;
2016-07-11 19:07:20 -06:00
struct ast_bridge_channel * bridge_channel ;
ast_channel_lock ( chan ) ;
bridge_channel = ast_channel_get_bridge_channel ( chan ) ;
ast_channel_unlock ( chan ) ;
ast_debug ( 3 , " Channel: <%s> Reason: %d \n " , ast_channel_name ( control - > channel ) , ast_channel_hangupcause ( chan ) ) ;
stasis_app_send_command_async ( control , bridge_channel_depart , bridge_channel , __ao2_cleanup ) ;
2016-05-09 14:48:51 -05:00
control - > bridge = NULL ;
}
static void dial_bridge_after_cb_failed ( enum ast_bridge_after_cb_reason reason , void * data )
{
struct stasis_app_control * control = data ;
2016-07-11 19:07:20 -06:00
ast_debug ( 3 , " Channel: <%s> Reason: %d \n " , ast_channel_name ( control - > channel ) , reason ) ;
2016-05-09 14:48:51 -05:00
dial_bridge_after_cb ( control - > channel , data ) ;
}
/*!
* \brief Add a channel to the singleton dial bridge.
*
* \param control The Stasis control structure
* \param chan The channel to add to the bridge
* \retval -1 Failed
* \retval 0 Success
*/
static int add_to_dial_bridge ( struct stasis_app_control * control , struct ast_channel * chan )
{
struct ast_bridge * bridge ;
bridge = get_dial_bridge ( ) ;
if ( ! bridge ) {
return - 1 ;
}
control - > bridge = bridge ;
ast_bridge_set_after_callback ( chan , dial_bridge_after_cb , dial_bridge_after_cb_failed , control ) ;
if ( ast_bridge_impart ( bridge , chan , NULL , NULL , AST_BRIDGE_IMPART_CHAN_DEPARTABLE ) ) {
control - > bridge = NULL ;
ao2_ref ( bridge , - 1 ) ;
return - 1 ;
}
ao2_ref ( bridge , - 1 ) ;
return 0 ;
}
/*!
* \brief Depart a channel from a bridge, and potentially add it back to the dial bridge
*
* \param control Take a guess
* \param chan Take another guess
*/
static int depart_channel ( struct stasis_app_control * control , struct ast_channel * chan )
{
ast_bridge_depart ( chan ) ;
if ( ! ast_check_hangup ( chan ) & & ast_channel_state ( chan ) ! = AST_STATE_UP ) {
/* Channel is still being dialed, so put it back in the dialing bridge */
add_to_dial_bridge ( control , chan ) ;
}
return 0 ;
}
2013-12-13 16:38:57 +00:00
static int bridge_channel_depart ( struct stasis_app_control * control ,
2013-11-01 12:13:09 +00:00
struct ast_channel * chan , void * data )
{
2018-01-06 03:17:15 -05:00
struct ast_bridge_channel * bridge_channel ;
2013-11-01 12:13:09 +00:00
2018-01-06 03:17:15 -05:00
ast_channel_lock ( chan ) ;
bridge_channel = ast_channel_internal_bridge_channel ( chan ) ;
ast_channel_unlock ( chan ) ;
2013-11-01 12:13:09 +00:00
2018-01-06 03:17:15 -05:00
if ( bridge_channel ! = data ) {
ast_debug ( 3 , " %s: Channel is no longer in departable state \n " ,
ast_channel_uniqueid ( chan ) ) ;
return - 1 ;
2013-11-01 12:13:09 +00:00
}
ast_debug ( 3 , " %s: Channel departing bridge \n " ,
ast_channel_uniqueid ( chan ) ) ;
2016-05-09 14:48:51 -05:00
depart_channel ( control , chan ) ;
2013-11-01 12:13:09 +00:00
2013-12-13 16:38:57 +00:00
return 0 ;
2013-11-01 12:13:09 +00:00
}
2013-08-13 15:27:32 +00:00
2017-09-01 04:17:02 -06:00
static void internal_bridge_after_cb ( struct ast_channel * chan , void * data ,
enum ast_bridge_after_cb_reason reason )
2013-08-13 15:27:32 +00:00
{
struct stasis_app_control * control = data ;
2013-11-01 12:13:09 +00:00
struct ast_bridge_channel * bridge_channel ;
2013-08-13 15:27:32 +00:00
2018-01-06 03:17:15 -05:00
ao2_lock ( control ) ;
2017-09-01 04:17:02 -06:00
ast_debug ( 3 , " %s, %s: %s \n " ,
ast_channel_uniqueid ( chan ) , control - > bridge ? control - > bridge - > uniqueid : " unknown " ,
ast_bridge_after_cb_reason_string ( reason ) ) ;
if ( reason = = AST_BRIDGE_AFTER_CB_REASON_IMPART_FAILED ) {
/* The impart actually failed so control->bridge isn't valid. */
control - > bridge = NULL ;
}
2013-08-13 15:27:32 +00:00
ast_assert ( chan = = control - > channel ) ;
/* Restore the channel's PBX */
ast_channel_pbx_set ( control - > channel , control - > pbx ) ;
control - > pbx = NULL ;
2017-09-01 04:17:02 -06:00
if ( control - > bridge ) {
app_unsubscribe_bridge ( control - > app , control - > bridge ) ;
2014-03-13 19:33:22 +00:00
2017-09-01 04:17:02 -06:00
/* No longer in the bridge */
control - > bridge = NULL ;
2013-08-13 15:27:32 +00:00
2017-09-01 04:17:02 -06:00
/* Get the bridge channel so we don't depart from the wrong bridge */
ast_channel_lock ( chan ) ;
bridge_channel = ast_channel_get_bridge_channel ( chan ) ;
ast_channel_unlock ( chan ) ;
/* Depart this channel from the bridge using the command queue if possible */
stasis_app_send_command_async ( control , bridge_channel_depart , bridge_channel , __ao2_cleanup ) ;
}
2013-11-01 12:13:09 +00:00
2014-08-21 21:37:03 +00:00
if ( stasis_app_channel_is_stasis_end_published ( chan ) ) {
/* The channel has had a StasisEnd published on it, but until now had remained in
* the bridging system. This means that the channel moved from a Stasis bridge to a
* non-Stasis bridge and is now exiting the bridging system. Because of this, the
* channel needs to exit the Stasis application and go to wherever the non-Stasis
* bridge has directed it to go. If the non-Stasis bridge has not set up an after
* bridge destination, then the channel should be hung up.
*/
int hangup_flag ;
hangup_flag = ast_bridge_setup_after_goto ( chan ) ? AST_SOFTHANGUP_DEV : AST_SOFTHANGUP_ASYNCGOTO ;
ast_channel_lock ( chan ) ;
ast_softhangup_nolock ( chan , hangup_flag ) ;
ast_channel_unlock ( chan ) ;
}
2018-01-06 03:17:15 -05:00
ao2_unlock ( control ) ;
2013-08-13 15:27:32 +00:00
}
2017-09-01 04:17:02 -06:00
static void bridge_after_cb ( struct ast_channel * chan , void * data )
{
struct stasis_app_control * control = data ;
internal_bridge_after_cb ( control - > channel , data , AST_BRIDGE_AFTER_CB_REASON_DEPART ) ;
}
2013-08-13 15:27:32 +00:00
static void bridge_after_cb_failed ( enum ast_bridge_after_cb_reason reason ,
void * data )
{
struct stasis_app_control * control = data ;
2017-09-01 04:17:02 -06:00
internal_bridge_after_cb ( control - > channel , data , reason ) ;
2013-08-13 15:27:32 +00:00
ast_debug ( 3 , " reason: %s \n " ,
ast_bridge_after_cb_reason_string ( reason ) ) ;
}
2016-05-09 14:48:51 -05:00
/*!
* \brief Dial timeout datastore
*
* A datastore is used because a channel may change
* bridges during the course of a dial attempt. This
* may be because the channel changes from the dial bridge
* to a standard bridge, or it may move between standard
* bridges. In order to keep the dial timeout, we need
* to keep the timeout information local to the channel.
* That is what this datastore is for
*/
struct ast_datastore_info timeout_datastore = {
. type = " ARI dial timeout " ,
} ;
static int hangup_channel ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
ast_softhangup ( chan , AST_SOFTHANGUP_EXPLICIT ) ;
return 0 ;
}
/*!
* \brief Dial timeout
*
* This is a bridge interval hook callback. The interval hook triggering
* means that the dial timeout has been reached. If the channel has not
* been answered by the time this callback is called, then the channel
* is hung up
*
* \param bridge_channel Bridge channel on which interval hook has been called
* \param ignore Ignored
* \return -1 (i.e. remove the interval hook)
*/
static int bridge_timeout ( struct ast_bridge_channel * bridge_channel , void * ignore )
{
struct ast_datastore * datastore ;
RAII_VAR ( struct stasis_app_control * , control , NULL , ao2_cleanup ) ;
control = stasis_app_control_find_by_channel ( bridge_channel - > chan ) ;
ast_channel_lock ( bridge_channel - > chan ) ;
if ( ast_channel_state ( bridge_channel - > chan ) ! = AST_STATE_UP ) {
/* Don't bother removing the datastore because it will happen when the channel is hung up */
ast_channel_unlock ( bridge_channel - > chan ) ;
stasis_app_send_command_async ( control , hangup_channel , NULL , NULL ) ;
return - 1 ;
}
datastore = ast_channel_datastore_find ( bridge_channel - > chan , & timeout_datastore , NULL ) ;
if ( ! datastore ) {
ast_channel_unlock ( bridge_channel - > chan ) ;
return - 1 ;
}
ast_channel_datastore_remove ( bridge_channel - > chan , datastore ) ;
ast_channel_unlock ( bridge_channel - > chan ) ;
ast_datastore_free ( datastore ) ;
return - 1 ;
}
/*!
* \brief Set a dial timeout interval hook on the channel.
*
* The absolute time that the timeout should occur is stored on
* a datastore on the channel. This time is converted into a relative
* number of milliseconds in the future. Then an interval hook is set
* to trigger in that number of milliseconds.
*
* \pre chan is locked
*
* \param chan The channel on which to set the interval hook
*/
static void set_interval_hook ( struct ast_channel * chan )
{
struct ast_datastore * datastore ;
struct timeval * hangup_time ;
int64_t ms ;
struct ast_bridge_channel * bridge_channel ;
datastore = ast_channel_datastore_find ( chan , & timeout_datastore , NULL ) ;
if ( ! datastore ) {
return ;
}
hangup_time = datastore - > data ;
ms = ast_tvdiff_ms ( * hangup_time , ast_tvnow ( ) ) ;
bridge_channel = ast_channel_get_bridge_channel ( chan ) ;
if ( ! bridge_channel ) {
return ;
}
if ( ast_bridge_interval_hook ( bridge_channel - > features , 0 , ms > 0 ? ms : 1 ,
bridge_timeout , NULL , NULL , 0 ) ) {
2017-09-06 13:38:17 -05:00
ao2_ref ( bridge_channel , - 1 ) ;
2016-05-09 14:48:51 -05:00
return ;
}
ast_queue_frame ( bridge_channel - > chan , & ast_null_frame ) ;
2017-09-06 13:38:17 -05:00
ao2_ref ( bridge_channel , - 1 ) ;
2016-05-09 14:48:51 -05:00
}
2016-04-15 14:36:59 -05:00
int control_swap_channel_in_bridge ( struct stasis_app_control * control , struct ast_bridge * bridge , struct ast_channel * chan , struct ast_channel * swap )
2013-08-13 15:27:32 +00:00
{
int res ;
2017-10-06 21:48:48 -04:00
struct ast_bridge_features * features ;
2013-08-13 15:27:32 +00:00
if ( ! control | | ! bridge ) {
2013-12-13 16:38:57 +00:00
return - 1 ;
2013-08-13 15:27:32 +00:00
}
ast_debug ( 3 , " %s: Adding to bridge %s \n " ,
stasis_app_control_get_channel_id ( control ) ,
bridge - > uniqueid ) ;
ast_assert ( chan ! = NULL ) ;
/* Depart whatever Stasis bridge we're currently in. */
if ( stasis_app_get_bridge ( control ) ) {
/* Note that it looks like there's a race condition here, since
* we don't have control locked. But this happens from the
* control callback thread, so there won't be any other
* concurrent attempts to bridge.
*/
ast_bridge_depart ( chan ) ;
}
res = ast_bridge_set_after_callback ( chan , bridge_after_cb ,
bridge_after_cb_failed , control ) ;
if ( res ! = 0 ) {
ast_log ( LOG_ERROR , " Error setting after-bridge callback \n " ) ;
2013-12-13 16:38:57 +00:00
return - 1 ;
2013-08-13 15:27:32 +00:00
}
2017-09-01 04:17:02 -06:00
ao2_lock ( control ) ;
2013-08-13 15:27:32 +00:00
2017-09-01 04:17:02 -06:00
/* Ensure the controlling application is subscribed early enough
* to receive the ChannelEnteredBridge message. This works in concert
* with the subscription handled in the Stasis application execution
* loop */
app_subscribe_bridge ( control - > app , bridge ) ;
2013-08-13 15:27:32 +00:00
2017-09-01 04:17:02 -06:00
/* Save off the channel's PBX */
ast_assert ( control - > pbx = = NULL ) ;
if ( ! control - > pbx ) {
control - > pbx = ast_channel_pbx ( chan ) ;
ast_channel_pbx_set ( chan , NULL ) ;
}
2013-08-13 15:27:32 +00:00
2017-10-06 21:48:48 -04:00
/* Pull bridge features from the control */
features = control - > bridge_features ;
control - > bridge_features = NULL ;
2017-09-01 04:17:02 -06:00
ast_assert ( stasis_app_get_bridge ( control ) = = NULL ) ;
/* We need to set control->bridge here since bridge_after_cb may be run
* before ast_bridge_impart returns. bridge_after_cb gets a reason
* code so it can tell if the bridge is actually valid or not.
*/
control - > bridge = bridge ;
2016-05-09 14:48:51 -05:00
2017-09-01 04:17:02 -06:00
/* We can't be holding the control lock while impart is running
* or we could create a deadlock with bridge_after_cb which also
* tries to lock control.
*/
ao2_unlock ( control ) ;
res = ast_bridge_impart ( bridge ,
chan ,
swap ,
2017-10-06 21:48:48 -04:00
features , /* features */
2017-09-01 04:17:02 -06:00
AST_BRIDGE_IMPART_CHAN_DEPARTABLE ) ;
if ( res ! = 0 ) {
/* ast_bridge_impart failed before it could spawn the depart
* thread. The callbacks aren't called in this case.
* The impart could still fail even if ast_bridge_impart returned
* ok but that's handled by bridge_after_cb.
*/
ast_log ( LOG_ERROR , " Error adding channel to bridge \n " ) ;
ao2_lock ( control ) ;
ast_channel_pbx_set ( chan , control - > pbx ) ;
control - > pbx = NULL ;
control - > bridge = NULL ;
ao2_unlock ( control ) ;
} else {
2016-05-09 14:48:51 -05:00
ast_channel_lock ( chan ) ;
set_interval_hook ( chan ) ;
ast_channel_unlock ( chan ) ;
2013-08-13 15:27:32 +00:00
}
2017-09-01 04:17:02 -06:00
return res ;
2013-08-13 15:27:32 +00:00
}
2016-04-15 14:36:59 -05:00
int control_add_channel_to_bridge ( struct stasis_app_control * control , struct ast_channel * chan , void * data )
{
return control_swap_channel_in_bridge ( control , data , chan , NULL ) ;
}
2013-08-23 17:19:02 +00:00
int stasis_app_control_add_channel_to_bridge (
2013-08-13 15:27:32 +00:00
struct stasis_app_control * control , struct ast_bridge * bridge )
{
ast_debug ( 3 , " %s: Sending channel add_to_bridge command \n " ,
stasis_app_control_get_channel_id ( control ) ) ;
2013-12-13 16:38:57 +00:00
return app_send_command_on_condition (
2014-08-22 16:52:51 +00:00
control , control_add_channel_to_bridge , bridge , NULL ,
2013-12-13 16:38:57 +00:00
app_control_can_add_channel_to_bridge ) ;
2013-08-13 15:27:32 +00:00
}
2013-12-13 16:38:57 +00:00
static int app_control_remove_channel_from_bridge (
2013-08-13 15:27:32 +00:00
struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
struct ast_bridge * bridge = data ;
if ( ! control ) {
2013-12-13 16:38:57 +00:00
return - 1 ;
2013-08-13 15:27:32 +00:00
}
/* We should only depart from our own bridge */
ast_debug ( 3 , " %s: Departing bridge %s \n " ,
stasis_app_control_get_channel_id ( control ) ,
bridge - > uniqueid ) ;
if ( bridge ! = stasis_app_get_bridge ( control ) ) {
ast_log ( LOG_WARNING , " %s: Not in bridge %s; not removing \n " ,
stasis_app_control_get_channel_id ( control ) ,
bridge - > uniqueid ) ;
2013-12-13 16:38:57 +00:00
return - 1 ;
2013-08-13 15:27:32 +00:00
}
2016-05-09 14:48:51 -05:00
depart_channel ( control , chan ) ;
2013-12-13 16:38:57 +00:00
return 0 ;
2013-08-13 15:27:32 +00:00
}
2013-08-23 17:19:02 +00:00
int stasis_app_control_remove_channel_from_bridge (
2013-08-13 15:27:32 +00:00
struct stasis_app_control * control , struct ast_bridge * bridge )
{
ast_debug ( 3 , " %s: Sending channel remove_from_bridge command \n " ,
stasis_app_control_get_channel_id ( control ) ) ;
2013-12-13 16:38:57 +00:00
return app_send_command_on_condition (
2014-08-22 16:52:51 +00:00
control , app_control_remove_channel_from_bridge , bridge , NULL ,
2013-12-13 16:38:57 +00:00
app_control_can_remove_channel_from_bridge ) ;
2013-08-13 15:27:32 +00:00
}
2013-05-14 21:45:08 +00:00
const char * stasis_app_control_get_channel_id (
const struct stasis_app_control * control )
{
return ast_channel_uniqueid ( control - > channel ) ;
}
void stasis_app_control_publish (
struct stasis_app_control * control , struct stasis_message * message )
{
if ( ! control | | ! control - > channel | | ! message ) {
return ;
}
stasis_publish ( ast_channel_topic ( control - > channel ) , message ) ;
}
2013-05-23 20:21:16 +00:00
int stasis_app_control_queue_control ( struct stasis_app_control * control ,
enum ast_control_frame_type frame_type )
{
return ast_queue_control ( control - > channel , frame_type ) ;
}
2017-10-06 21:48:48 -04:00
int stasis_app_control_bridge_features_init (
struct stasis_app_control * control )
{
struct ast_bridge_features * features ;
features = ast_bridge_features_new ( ) ;
if ( ! features ) {
return 1 ;
}
control - > bridge_features = features ;
return 0 ;
}
void stasis_app_control_absorb_dtmf_in_bridge (
struct stasis_app_control * control , int absorb )
{
control - > bridge_features - > dtmf_passthrough = ! absorb ;
}
void stasis_app_control_mute_in_bridge (
struct stasis_app_control * control , int mute )
{
control - > bridge_features - > mute = mute ;
}
2016-03-29 13:47:08 -05:00
void control_flush_queue ( struct stasis_app_control * control )
{
struct ao2_iterator iter ;
struct stasis_app_command * command ;
iter = ao2_iterator_init ( control - > command_queue , AO2_ITERATOR_UNLINK ) ;
while ( ( command = ao2_iterator_next ( & iter ) ) ) {
command_complete ( command , - 1 ) ;
ao2_ref ( command , - 1 ) ;
}
ao2_iterator_destroy ( & iter ) ;
}
2013-05-14 21:45:08 +00:00
int control_dispatch_all ( struct stasis_app_control * control ,
struct ast_channel * chan )
{
int count = 0 ;
2016-03-29 13:47:08 -05:00
struct ao2_iterator iter ;
struct stasis_app_command * command ;
2013-05-14 21:45:08 +00:00
ast_assert ( control - > channel = = chan ) ;
2016-03-29 13:47:08 -05:00
iter = ao2_iterator_init ( control - > command_queue , AO2_ITERATOR_UNLINK ) ;
while ( ( command = ao2_iterator_next ( & iter ) ) ) {
2013-05-14 21:45:08 +00:00
command_invoke ( command , control , chan ) ;
2016-03-29 13:47:08 -05:00
ao2_ref ( command , - 1 ) ;
2013-05-14 21:45:08 +00:00
+ + count ;
}
2016-03-29 13:47:08 -05:00
ao2_iterator_destroy ( & iter ) ;
2013-05-14 21:45:08 +00:00
return count ;
}
2013-06-10 13:07:11 +00:00
2013-08-13 15:27:32 +00:00
void control_wait ( struct stasis_app_control * control )
2013-06-10 13:07:11 +00:00
{
2013-08-13 15:27:32 +00:00
if ( ! control ) {
return ;
}
ast_assert ( control - > command_queue ! = NULL ) ;
ao2_lock ( control - > command_queue ) ;
while ( ao2_container_count ( control - > command_queue ) = = 0 ) {
int res = ast_cond_wait ( & control - > wait_cond ,
ao2_object_get_lockaddr ( control - > command_queue ) ) ;
if ( res < 0 ) {
ast_log ( LOG_ERROR , " Error waiting on command queue \n " ) ;
break ;
}
}
ao2_unlock ( control - > command_queue ) ;
2013-06-10 13:07:11 +00:00
}
2014-08-07 15:30:19 +00:00
int control_prestart_dispatch_all ( struct stasis_app_control * control ,
struct ast_channel * chan )
{
struct ao2_container * command_queue ;
int count = 0 ;
struct ao2_iterator iter ;
struct stasis_app_command * command ;
ast_channel_lock ( chan ) ;
command_queue = command_prestart_get_container ( chan ) ;
ast_channel_unlock ( chan ) ;
if ( ! command_queue ) {
return 0 ;
}
iter = ao2_iterator_init ( command_queue , AO2_ITERATOR_UNLINK ) ;
while ( ( command = ao2_iterator_next ( & iter ) ) ) {
command_invoke ( command , control , chan ) ;
ao2_cleanup ( command ) ;
+ + count ;
}
ao2_iterator_destroy ( & iter ) ;
ao2_cleanup ( command_queue ) ;
return count ;
}
struct stasis_app * control_app ( struct stasis_app_control * control )
{
return control - > app ;
}
2016-03-30 17:18:39 -05:00
2016-05-09 14:48:51 -05:00
struct control_dial_args {
unsigned int timeout ;
char dialstring [ 0 ] ;
} ;
static struct control_dial_args * control_dial_args_alloc ( const char * dialstring ,
unsigned int timeout )
2016-03-30 17:18:39 -05:00
{
2016-05-09 14:48:51 -05:00
struct control_dial_args * args ;
args = ast_malloc ( sizeof ( * args ) + strlen ( dialstring ) + 1 ) ;
if ( ! args ) {
return NULL ;
}
args - > timeout = timeout ;
/* Safe */
strcpy ( args - > dialstring , dialstring ) ;
2016-03-30 17:18:39 -05:00
2016-05-09 14:48:51 -05:00
return args ;
2016-03-30 17:18:39 -05:00
}
2016-05-09 14:48:51 -05:00
static void control_dial_args_destroy ( void * data )
2016-03-30 17:18:39 -05:00
{
2016-05-09 14:48:51 -05:00
struct control_dial_args * args = data ;
ast_free ( args ) ;
2016-03-30 17:18:39 -05:00
}
2016-05-09 14:48:51 -05:00
/*!
* \brief Set dial timeout on a channel to be dialed.
*
* \param chan The channel on which to set the dial timeout
* \param timeout The timeout in seconds
*/
static int set_timeout ( struct ast_channel * chan , unsigned int timeout )
2016-03-30 17:18:39 -05:00
{
2016-05-09 14:48:51 -05:00
struct ast_datastore * datastore ;
struct timeval * hangup_time ;
2016-03-30 17:18:39 -05:00
2016-05-09 14:48:51 -05:00
hangup_time = ast_malloc ( sizeof ( struct timeval ) ) ;
2016-03-30 17:18:39 -05:00
2016-05-09 14:48:51 -05:00
datastore = ast_datastore_alloc ( & timeout_datastore , NULL ) ;
if ( ! datastore ) {
return - 1 ;
}
* hangup_time = ast_tvadd ( ast_tvnow ( ) , ast_samp2tv ( timeout , 1 ) ) ;
datastore - > data = hangup_time ;
ast_channel_lock ( chan ) ;
ast_channel_datastore_add ( chan , datastore ) ;
if ( ast_channel_is_bridged ( chan ) ) {
set_interval_hook ( chan ) ;
2016-03-30 17:18:39 -05:00
}
2016-05-09 14:48:51 -05:00
ast_channel_unlock ( chan ) ;
return 0 ;
2016-03-30 17:18:39 -05:00
}
static int app_control_dial ( struct stasis_app_control * control ,
struct ast_channel * chan , void * data )
{
2016-05-09 14:48:51 -05:00
struct control_dial_args * args = data ;
int bridged ;
2016-03-30 17:18:39 -05:00
2016-05-09 14:48:51 -05:00
ast_channel_lock ( chan ) ;
bridged = ast_channel_is_bridged ( chan ) ;
ast_channel_unlock ( chan ) ;
if ( ! bridged & & add_to_dial_bridge ( control , chan ) ) {
return - 1 ;
}
if ( args - > timeout & & set_timeout ( chan , args - > timeout ) ) {
return - 1 ;
}
if ( ast_call ( chan , args - > dialstring , 0 ) ) {
return - 1 ;
}
2016-03-30 17:18:39 -05:00
2016-07-11 19:07:20 -06:00
ast_channel_publish_dial ( NULL , chan , args - > dialstring , NULL ) ;
2016-03-30 17:18:39 -05:00
return 0 ;
}
2016-05-09 14:48:51 -05:00
int stasis_app_control_dial ( struct stasis_app_control * control ,
const char * dialstring , unsigned int timeout )
2016-03-30 17:18:39 -05:00
{
2016-05-09 14:48:51 -05:00
struct control_dial_args * args ;
args = control_dial_args_alloc ( dialstring , timeout ) ;
if ( ! args ) {
return - 1 ;
}
return stasis_app_send_command_async ( control , app_control_dial ,
args , control_dial_args_destroy ) ;
2016-03-30 17:18:39 -05:00
}
2016-05-09 14:48:51 -05:00
void stasis_app_control_shutdown ( void )
2016-03-30 17:18:39 -05:00
{
2016-05-09 14:48:51 -05:00
ast_mutex_lock ( & dial_bridge_lock ) ;
shutting_down = 1 ;
2018-01-07 22:38:49 -05:00
if ( dial_bridge ) {
ast_bridge_destroy ( dial_bridge , 0 ) ;
dial_bridge = NULL ;
}
2016-05-09 14:48:51 -05:00
ast_mutex_unlock ( & dial_bridge_lock ) ;
2016-03-30 17:18:39 -05:00
}
2019-03-07 07:41:14 -06:00
void control_set_app ( struct stasis_app_control * control , struct stasis_app * app )
{
ao2_cleanup ( control - > app ) ;
control - > app = ao2_bump ( app ) ;
}
char * control_next_app ( struct stasis_app_control * control )
{
return control - > next_app ;
}
void control_move_cleanup ( struct stasis_app_control * control )
{
ast_free ( control - > next_app ) ;
control - > next_app = NULL ;
AST_VECTOR_RESET ( & control - > next_app_args , ast_free_ptr ) ;
}
char * * control_next_app_args ( struct stasis_app_control * control )
{
return AST_VECTOR_STEAL_ELEMENTS ( & control - > next_app_args ) ;
}
int control_next_app_args_size ( struct stasis_app_control * control )
{
return AST_VECTOR_SIZE ( & control - > next_app_args ) ;
}