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:52:20 -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:52:20 -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.
*/
2019-10-23 12:36:17 -05:00
unsigned 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:52:20 -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:52:20 -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:52:20 -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 ;
2019-03-13 08:05:57 -03:00
size = sizeof ( * move_data ) + strlen ( app_name ) + 1 ;
if ( app_args ) {
/* Application arguments are optional */
size += strlen ( app_args ) + 1 ;
}
2019-03-07 07:52:20 -06:00
if ( ! ( move_data = ast_calloc ( 1 , size ))) {
return - 1 ;
}
move_data -> app_name = ( char * ) move_data + sizeof ( * move_data );
strcpy ( move_data -> app_name , app_name ); /* Safe */
2019-03-13 08:05:57 -03:00
2019-03-07 07:52:20 -06:00
if ( app_args ) {
2019-03-13 08:05:57 -03:00
move_data -> app_args = move_data -> app_name + strlen ( app_name ) + 1 ;
2019-03-07 07:52:20 -06:00
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-10-10 11:28:18 -03:00
return ast_channel_snapshot_get_latest ( stasis_app_control_get_channel_id ( control ));
2013-05-14 21:45:08 +00:00
}
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 );
2019-04-30 19:51:46 +05:30
/* Channels which have a PBX are not ones that have been created and dialed from ARI. They
* have externally come in from the dialplan, and thus should not be placed into the dial
* bridge. Only channels which are created and dialed in ARI should go into the dial bridge.
*/
if ( ! ast_check_hangup ( chan ) && ast_channel_state ( chan ) != AST_STATE_UP && ! ast_channel_pbx ( chan )) {
2016-05-09 14:48:51 -05:00
/* 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 ;
2019-11-22 15:32:42 +01:00
int flags = AST_BRIDGE_IMPART_CHAN_DEPARTABLE ;
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 ;
2019-11-22 15:32:42 +01:00
if ( features && features -> inhibit_colp ) {
flags |= AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP ;
}
2017-10-06 21:48:48 -04:00
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 */
2019-11-22 15:32:42 +01:00
flags );
2017-09-01 04:17:02 -06:00
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 ;
}
2019-11-22 15:32:42 +01:00
void stasis_app_control_inhibit_colp_in_bridge (
struct stasis_app_control * control , int inhibit_colp )
{
control -> bridge_features -> inhibit_colp = inhibit_colp ;
}
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 )) {
2019-05-03 21:19:31 +05:30
/* If call fails normally this channel would then just be normally hung up and destroyed.
* In this case though the channel is being handled by the ARI control thread and dial
* bridge which needs to be notified that the channel should be hung up. To do this we
* queue a soft hangup which will cause each to wake up, see that the channel has been
* hung up, and then destroy it.
*/
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 );
2016-05-09 14:48:51 -05:00
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:52:20 -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 );
}