2017-01-06 02:10:15 -05:00
/*
2008-09-23 21:44:18 +00:00
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2018-09-10 14:32:10 -04:00
* Copyright ( C ) 2005 - 2018 , Anthony Minessale II < anthm @ freeswitch . org >
2008-09-23 21:44:18 +00:00
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2008-09-23 21:44:18 +00:00
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
2017-01-06 02:10:15 -05:00
*
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2013-06-26 10:51:44 -05:00
* Emmanuel Schmidbauer < e . schmidbauer @ gmail . com >
2008-09-23 21:44:18 +00:00
*
*
* mod_loopback . c - - Loopback Endpoint Module
*
*/
# include <switch.h>
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <string.h>
2009-04-27 02:04:48 +00:00
# define FRAME_QUEUE_LEN 3
2008-09-23 21:44:18 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_loopback_load ) ;
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_loopback_shutdown ) ;
SWITCH_MODULE_DEFINITION ( mod_loopback , mod_loopback_load , mod_loopback_shutdown , NULL ) ;
2012-10-31 12:56:09 -05:00
static switch_status_t find_non_loopback_bridge ( switch_core_session_t * session , switch_core_session_t * * br_session , const char * * br_uuid ) ;
2008-09-23 21:44:18 +00:00
static switch_endpoint_interface_t * loopback_endpoint_interface = NULL ;
typedef enum {
TFLAG_LINKED = ( 1 < < 0 ) ,
TFLAG_OUTBOUND = ( 1 < < 1 ) ,
2008-09-24 16:32:58 +00:00
TFLAG_WRITE = ( 1 < < 2 ) ,
2011-05-02 17:21:39 -05:00
TFLAG_USEME = ( 1 < < 3 ) ,
2008-09-25 14:26:42 +00:00
TFLAG_BRIDGE = ( 1 < < 4 ) ,
2009-01-19 19:32:44 +00:00
TFLAG_BOWOUT = ( 1 < < 5 ) ,
2010-06-02 15:14:49 -05:00
TFLAG_BLEG = ( 1 < < 6 ) ,
2010-09-29 10:21:14 -05:00
TFLAG_APP = ( 1 < < 7 ) ,
2010-10-21 12:09:52 -05:00
TFLAG_RUNNING_APP = ( 1 < < 8 ) ,
2011-06-01 17:40:56 -05:00
TFLAG_BOWOUT_USED = ( 1 < < 9 ) ,
TFLAG_CLEAR = ( 1 < < 10 )
2008-09-23 21:44:18 +00:00
} TFLAGS ;
2013-05-03 12:30:35 -05:00
struct loopback_private_object {
2008-09-23 21:44:18 +00:00
unsigned int flags ;
switch_mutex_t * flag_mutex ;
2009-04-07 23:44:08 +00:00
switch_mutex_t * mutex ;
2008-09-23 21:44:18 +00:00
switch_core_session_t * session ;
2008-09-25 14:26:42 +00:00
switch_channel_t * channel ;
2008-09-23 21:44:18 +00:00
switch_core_session_t * other_session ;
2013-05-03 12:30:35 -05:00
struct loopback_private_object * other_tech_pvt ;
2008-09-23 21:44:18 +00:00
switch_channel_t * other_channel ;
switch_codec_t read_codec ;
switch_codec_t write_codec ;
switch_frame_t read_frame ;
unsigned char databuf [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
switch_frame_t * x_write_frame ;
2009-04-13 18:35:26 +00:00
switch_frame_t * write_frame ;
2008-09-23 21:44:18 +00:00
unsigned char write_databuf [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
switch_frame_t cng_frame ;
2009-04-25 17:03:04 +00:00
unsigned char cng_databuf [ SWITCH_RECOMMENDED_BUFFER_SIZE ] ;
2011-02-01 11:43:02 -06:00
switch_timer_t timer ;
2008-09-23 21:44:18 +00:00
switch_caller_profile_t * caller_profile ;
2008-10-11 16:28:05 +00:00
int32_t bowout_frame_count ;
2009-04-07 23:44:08 +00:00
char * other_uuid ;
2009-04-13 18:35:26 +00:00
switch_queue_t * frame_queue ;
2011-02-01 16:22:36 -06:00
int64_t packet_count ;
2011-10-31 12:05:15 -05:00
int first_cng ;
2008-09-23 21:44:18 +00:00
} ;
2008-10-11 20:50:48 +00:00
2013-05-03 12:30:35 -05:00
typedef struct loopback_private_object loopback_private_t ;
2008-09-23 21:44:18 +00:00
static struct {
int debug ;
2018-04-24 04:36:01 +01:00
int early_set_loopback_id ;
int fire_bowout_event_bridge ;
int ignore_channel_ready ;
switch_call_cause_t bowout_hangup_cause ;
int bowout_controlled_hangup ;
int bowout_transfer_recordings ;
2019-04-02 17:01:36 +01:00
int bowout_disable_on_inner_bridge ;
2018-04-24 04:36:01 +01:00
} loopback_globals ;
2008-09-23 21:44:18 +00:00
static switch_status_t channel_on_init ( switch_core_session_t * session ) ;
static switch_status_t channel_on_hangup ( switch_core_session_t * session ) ;
2009-04-10 17:43:18 +00:00
static switch_status_t channel_on_destroy ( switch_core_session_t * session ) ;
2008-09-23 21:44:18 +00:00
static switch_status_t channel_on_routing ( switch_core_session_t * session ) ;
static switch_status_t channel_on_exchange_media ( switch_core_session_t * session ) ;
static switch_status_t channel_on_soft_execute ( switch_core_session_t * session ) ;
static switch_call_cause_t channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
2010-02-06 03:38:24 +00:00
switch_core_session_t * * new_session , switch_memory_pool_t * * pool , switch_originate_flag_t flags ,
switch_call_cause_t * cancel_cause ) ;
2008-09-23 21:44:18 +00:00
static switch_status_t channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id ) ;
static switch_status_t channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id ) ;
static switch_status_t channel_kill_channel ( switch_core_session_t * session , int sig ) ;
2011-06-01 17:40:56 -05:00
2013-05-03 12:30:35 -05:00
static void clear_queue ( loopback_private_t * tech_pvt )
2011-06-01 17:40:56 -05:00
{
void * pop ;
while ( switch_queue_trypop ( tech_pvt - > frame_queue , & pop ) = = SWITCH_STATUS_SUCCESS & & pop ) {
switch_frame_t * frame = ( switch_frame_t * ) pop ;
switch_frame_free ( & frame ) ;
}
2011-10-31 12:05:15 -05:00
2011-06-01 17:40:56 -05:00
}
2013-05-03 12:30:35 -05:00
static switch_status_t tech_init ( loopback_private_t * tech_pvt , switch_core_session_t * session , switch_codec_t * codec )
2008-09-23 21:44:18 +00:00
{
const char * iananame = " L16 " ;
2012-04-23 12:16:53 -05:00
uint32_t rate = 8000 ;
uint32_t interval = 20 ;
2008-09-23 21:44:18 +00:00
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2008-09-24 19:36:24 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2011-02-01 11:43:02 -06:00
const switch_codec_implementation_t * read_impl ;
2008-09-23 21:44:18 +00:00
if ( codec ) {
iananame = codec - > implementation - > iananame ;
2008-09-28 00:15:29 +00:00
rate = codec - > implementation - > samples_per_second ;
2008-10-20 17:48:42 +00:00
interval = codec - > implementation - > microseconds_per_packet / 1000 ;
2012-04-23 12:16:53 -05:00
} else {
const char * var ;
2015-08-31 17:08:52 -04:00
char * codec_modname = NULL ;
2012-04-23 12:16:53 -05:00
if ( ( var = switch_channel_get_variable ( channel , " loopback_initial_codec " ) ) ) {
char * dup = switch_core_session_strdup ( session , var ) ;
2014-06-13 01:49:10 -04:00
uint32_t bit , channels ;
2016-05-19 16:32:47 -05:00
iananame = switch_parse_codec_buf ( dup , & interval , & rate , & bit , & channels , & codec_modname , NULL ) ;
2012-04-23 12:16:53 -05:00
}
2017-01-06 02:10:15 -05:00
2008-09-23 21:44:18 +00:00
}
2010-02-06 03:38:24 +00:00
2009-04-09 17:17:12 +00:00
if ( switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
2008-09-24 19:36:24 +00:00
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
}
2009-04-09 17:17:12 +00:00
if ( switch_core_codec_ready ( & tech_pvt - > write_codec ) ) {
2008-09-24 19:36:24 +00:00
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
}
2010-02-06 03:38:24 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s setup codec %s/%d/%d \n " , switch_channel_get_name ( channel ) , iananame , rate ,
interval ) ;
2008-09-23 21:44:18 +00:00
status = switch_core_codec_init ( & tech_pvt - > read_codec ,
iananame ,
NULL ,
2015-03-19 14:26:47 -05:00
NULL ,
2010-02-06 03:38:24 +00:00
rate , interval , 1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , NULL , switch_core_session_get_pool ( session ) ) ;
2008-09-23 21:44:18 +00:00
2009-04-09 17:17:12 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS | | ! tech_pvt - > read_codec . implementation | | ! switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
2008-09-23 21:44:18 +00:00
goto end ;
}
status = switch_core_codec_init ( & tech_pvt - > write_codec ,
iananame ,
NULL ,
2015-03-19 14:26:47 -05:00
NULL ,
2010-02-06 03:38:24 +00:00
rate , interval , 1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , NULL , switch_core_session_get_pool ( session ) ) ;
2008-09-23 21:44:18 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
goto end ;
}
tech_pvt - > read_frame . data = tech_pvt - > databuf ;
tech_pvt - > read_frame . buflen = sizeof ( tech_pvt - > databuf ) ;
tech_pvt - > read_frame . codec = & tech_pvt - > read_codec ;
2010-02-06 03:38:24 +00:00
2009-04-08 18:43:10 +00:00
2008-09-23 21:44:18 +00:00
tech_pvt - > cng_frame . data = tech_pvt - > cng_databuf ;
tech_pvt - > cng_frame . buflen = sizeof ( tech_pvt - > cng_databuf ) ;
2011-05-02 17:21:39 -05:00
2008-09-23 21:44:18 +00:00
tech_pvt - > cng_frame . datalen = 2 ;
2010-02-06 03:38:24 +00:00
tech_pvt - > bowout_frame_count = ( tech_pvt - > read_codec . implementation - > actual_samples_per_second /
2011-10-31 12:05:15 -05:00
tech_pvt - > read_codec . implementation - > samples_per_packet ) * 2 ;
2008-09-23 21:44:18 +00:00
switch_core_session_set_read_codec ( session , & tech_pvt - > read_codec ) ;
switch_core_session_set_write_codec ( session , & tech_pvt - > write_codec ) ;
2010-02-06 03:38:24 +00:00
2011-02-01 11:43:02 -06:00
if ( tech_pvt - > flag_mutex ) {
switch_core_timer_destroy ( & tech_pvt - > timer ) ;
}
read_impl = tech_pvt - > read_codec . implementation ;
switch_core_timer_init ( & tech_pvt - > timer , " soft " ,
read_impl - > microseconds_per_packet / 1000 , read_impl - > samples_per_packet * 4 , switch_core_session_get_pool ( session ) ) ;
2008-09-23 21:44:18 +00:00
2008-09-24 19:36:24 +00:00
if ( ! tech_pvt - > flag_mutex ) {
switch_mutex_init ( & tech_pvt - > flag_mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
2009-04-07 23:44:08 +00:00
switch_mutex_init ( & tech_pvt - > mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
2008-09-24 19:36:24 +00:00
switch_core_session_set_private ( session , tech_pvt ) ;
2009-04-27 02:04:48 +00:00
switch_queue_create ( & tech_pvt - > frame_queue , FRAME_QUEUE_LEN , switch_core_session_get_pool ( session ) ) ;
2008-09-24 19:36:24 +00:00
tech_pvt - > session = session ;
2008-09-25 14:26:42 +00:00
tech_pvt - > channel = switch_core_session_get_channel ( session ) ;
2008-09-24 19:36:24 +00:00
}
2008-09-23 21:44:18 +00:00
2010-02-06 03:38:24 +00:00
end :
2008-09-23 21:44:18 +00:00
return status ;
}
2017-01-06 02:10:15 -05:00
/*
State methods they get called when the state changes to the specific state
2008-09-23 21:44:18 +00:00
returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it .
*/
static switch_status_t channel_on_init ( switch_core_session_t * session )
{
switch_channel_t * channel , * b_channel ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL , * b_tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
switch_core_session_t * b_session ;
char name [ 128 ] ;
switch_caller_profile_t * caller_profile ;
2012-04-17 16:13:41 -05:00
switch_event_t * vars = NULL ;
2012-10-19 13:16:44 -04:00
const char * var ;
2013-10-16 02:24:32 +05:00
switch_status_t status = SWITCH_STATUS_FALSE ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( channel ! = NULL ) ;
2010-02-06 03:38:24 +00:00
2009-04-07 23:44:08 +00:00
2009-01-19 19:32:44 +00:00
if ( switch_test_flag ( tech_pvt , TFLAG_OUTBOUND ) & & ! switch_test_flag ( tech_pvt , TFLAG_BLEG ) ) {
2010-02-06 03:38:24 +00:00
2010-08-26 12:19:49 -05:00
if ( ! ( b_session = switch_core_session_request ( loopback_endpoint_interface , SWITCH_CALL_DIRECTION_INBOUND , SOF_NONE , NULL ) ) ) {
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Failure. \n " ) ;
2008-09-23 21:44:18 +00:00
goto end ;
}
2010-02-06 03:38:24 +00:00
2009-04-07 23:44:08 +00:00
if ( switch_core_session_read_lock ( b_session ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Failure. \n " ) ;
2009-04-07 23:44:08 +00:00
switch_core_session_destroy ( & b_session ) ;
goto end ;
}
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
switch_core_session_add_stream ( b_session , NULL ) ;
b_channel = switch_core_session_get_channel ( b_session ) ;
2013-05-03 12:30:35 -05:00
b_tech_pvt = ( loopback_private_t * ) switch_core_session_alloc ( b_session , sizeof ( * b_tech_pvt ) ) ;
2008-09-24 19:36:24 +00:00
2008-09-29 19:20:06 +00:00
switch_snprintf ( name , sizeof ( name ) , " loopback/%s-b " , tech_pvt - > caller_profile - > destination_number ) ;
2008-09-24 19:36:24 +00:00
switch_channel_set_name ( b_channel , name ) ;
2018-04-24 04:36:01 +01:00
if ( loopback_globals . early_set_loopback_id ) {
switch_channel_set_variable ( channel , " loopback_leg " , " B " ) ;
switch_channel_set_variable ( channel , " is_loopback " , " 1 " ) ;
}
2008-09-23 21:44:18 +00:00
if ( tech_init ( b_tech_pvt , b_session , switch_core_session_get_read_codec ( session ) ) ! = SWITCH_STATUS_SUCCESS ) {
switch_channel_hangup ( channel , SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ) ;
switch_core_session_destroy ( & b_session ) ;
goto end ;
}
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
caller_profile = switch_caller_profile_clone ( b_session , tech_pvt - > caller_profile ) ;
2008-09-24 20:20:33 +00:00
caller_profile - > source = switch_core_strdup ( caller_profile - > pool , modname ) ;
2008-09-23 21:44:18 +00:00
switch_channel_set_caller_profile ( b_channel , caller_profile ) ;
b_tech_pvt - > caller_profile = caller_profile ;
switch_channel_set_state ( b_channel , CS_INIT ) ;
2016-12-22 14:55:51 +01:00
switch_channel_set_flag ( b_channel , CF_AUDIO ) ;
2008-09-23 21:44:18 +00:00
2013-05-03 12:30:35 -05:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
2008-09-23 21:44:18 +00:00
tech_pvt - > other_session = b_session ;
tech_pvt - > other_tech_pvt = b_tech_pvt ;
tech_pvt - > other_channel = b_channel ;
2013-05-03 12:30:35 -05:00
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2008-09-23 21:44:18 +00:00
2009-04-07 23:44:08 +00:00
//b_tech_pvt->other_session = session;
//b_tech_pvt->other_tech_pvt = tech_pvt;
//b_tech_pvt->other_channel = channel;
b_tech_pvt - > other_uuid = switch_core_session_strdup ( b_session , switch_core_session_get_uuid ( session ) ) ;
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
switch_set_flag_locked ( tech_pvt , TFLAG_LINKED ) ;
switch_set_flag_locked ( b_tech_pvt , TFLAG_LINKED ) ;
2009-01-19 19:32:44 +00:00
switch_set_flag_locked ( b_tech_pvt , TFLAG_BLEG ) ;
2010-02-06 03:38:24 +00:00
switch_channel_set_flag ( channel , CF_ACCEPT_CNG ) ;
2016-12-20 11:08:17 -06:00
switch_channel_set_flag ( channel , CF_AUDIO ) ;
2012-04-17 16:13:41 -05:00
if ( ( vars = ( switch_event_t * ) switch_channel_get_private ( channel , " __loopback_vars__ " ) ) ) {
switch_event_header_t * h ;
2017-01-06 02:10:15 -05:00
2012-04-17 16:13:41 -05:00
switch_channel_set_private ( channel , " __loopback_vars__ " , NULL ) ;
for ( h = vars - > headers ; h ; h = h - > next ) {
switch_channel_set_variable ( tech_pvt - > other_channel , h - > name , h - > value ) ;
}
switch_event_destroy ( & vars ) ;
}
2010-02-06 03:38:24 +00:00
2012-10-19 13:16:44 -04:00
if ( ( var = switch_channel_get_variable ( channel , " loopback_export " ) ) ) {
int argc = 0 ;
char * argv [ 128 ] = { 0 } ;
char * dup = switch_core_session_strdup ( session , var ) ;
if ( ( argc = switch_split ( dup , ' , ' , argv ) ) ) {
int i ;
for ( i = 0 ; i < argc ; i + + ) {
2017-01-06 02:10:15 -05:00
2012-10-19 13:16:44 -04:00
if ( ! zstr ( argv [ i ] ) ) {
const char * val = switch_channel_get_variable ( channel , argv [ i ] ) ;
2018-04-24 04:36:01 +01:00
if ( ! zstr ( val ) ) {
2012-10-19 13:16:44 -04:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Transfer variable [%s]=[%s] %s -> %s \n " ,
argv [ i ] , val , switch_channel_get_name ( channel ) , switch_channel_get_name ( tech_pvt - > other_channel ) ) ;
2017-01-06 02:10:15 -05:00
2012-10-19 13:16:44 -04:00
switch_channel_set_variable ( tech_pvt - > other_channel , argv [ i ] , val ) ;
}
}
}
}
}
2010-06-02 15:14:49 -05:00
if ( switch_test_flag ( tech_pvt , TFLAG_APP ) ) {
switch_set_flag ( b_tech_pvt , TFLAG_APP ) ;
switch_clear_flag ( tech_pvt , TFLAG_APP ) ;
}
2009-04-03 16:43:46 +00:00
switch_channel_set_variable ( channel , " other_loopback_leg_uuid " , switch_channel_get_uuid ( b_channel ) ) ;
switch_channel_set_variable ( b_channel , " other_loopback_leg_uuid " , switch_channel_get_uuid ( channel ) ) ;
2018-04-24 04:36:01 +01:00
switch_channel_set_variable ( b_channel , " other_loopback_from_uuid " , switch_channel_get_variable ( channel , " loopback_from_uuid " ) ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( b_session ) , SWITCH_LOG_DEBUG , " setting other_loopback_from_uuid on b leg to %s \n " , switch_channel_get_variable ( channel , " loopback_from_uuid " ) ) ;
2009-04-03 16:43:46 +00:00
2008-09-23 21:44:18 +00:00
if ( switch_core_session_thread_launch ( b_session ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error spawning thread \n " ) ;
2008-09-23 21:44:18 +00:00
switch_channel_hangup ( channel , SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ) ;
goto end ;
}
2017-01-06 02:10:15 -05:00
} else {
2013-05-03 12:30:35 -05:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
if ( ( tech_pvt - > other_session = switch_core_session_locate ( tech_pvt - > other_uuid ) ) ) {
tech_pvt - > other_tech_pvt = switch_core_session_get_private ( tech_pvt - > other_session ) ;
tech_pvt - > other_channel = switch_core_session_get_channel ( tech_pvt - > other_session ) ;
}
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2008-09-23 21:44:18 +00:00
}
2010-02-06 03:38:24 +00:00
2009-04-07 23:44:08 +00:00
if ( ! tech_pvt - > other_session ) {
switch_clear_flag_locked ( tech_pvt , TFLAG_LINKED ) ;
2008-09-23 21:44:18 +00:00
switch_channel_hangup ( channel , SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ) ;
goto end ;
}
2009-01-28 13:43:32 +00:00
switch_channel_set_variable ( channel , " loopback_leg " , switch_test_flag ( tech_pvt , TFLAG_BLEG ) ? " B " : " A " ) ;
2013-10-16 02:24:32 +05:00
status = SWITCH_STATUS_SUCCESS ;
2008-09-23 21:44:18 +00:00
switch_channel_set_state ( channel , CS_ROUTING ) ;
2010-02-06 03:38:24 +00:00
end :
2008-09-23 21:44:18 +00:00
2013-10-16 02:24:32 +05:00
return status ;
2008-09-23 21:44:18 +00:00
}
2013-05-03 12:30:35 -05:00
static void do_reset ( loopback_private_t * tech_pvt )
2008-09-24 19:36:24 +00:00
{
switch_clear_flag_locked ( tech_pvt , TFLAG_WRITE ) ;
2010-02-06 03:38:24 +00:00
2009-04-07 23:44:08 +00:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
2008-09-24 19:36:24 +00:00
if ( tech_pvt - > other_tech_pvt ) {
switch_clear_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_WRITE ) ;
}
2009-04-07 23:44:08 +00:00
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2008-09-24 19:36:24 +00:00
}
2008-09-23 21:44:18 +00:00
static switch_status_t channel_on_routing ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2009-10-09 00:52:25 +00:00
const char * app , * arg ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
2008-09-24 19:36:24 +00:00
do_reset ( tech_pvt ) ;
2008-09-23 21:44:18 +00:00
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL ROUTING \n " , switch_channel_get_name ( channel ) ) ;
2017-01-06 02:10:15 -05:00
2010-10-21 12:09:52 -05:00
if ( switch_test_flag ( tech_pvt , TFLAG_RUNNING_APP ) ) {
switch_clear_flag ( tech_pvt , TFLAG_RUNNING_APP ) ;
}
2017-01-06 02:10:15 -05:00
if ( switch_test_flag ( tech_pvt , TFLAG_APP ) & & ! switch_test_flag ( tech_pvt , TFLAG_OUTBOUND ) & &
2010-06-02 15:14:49 -05:00
( app = switch_channel_get_variable ( channel , " loopback_app " ) ) ) {
switch_caller_extension_t * extension = NULL ;
2009-10-09 00:52:25 +00:00
2010-06-02 15:14:49 -05:00
switch_clear_flag ( tech_pvt , TFLAG_APP ) ;
2010-10-21 12:09:52 -05:00
switch_set_flag ( tech_pvt , TFLAG_RUNNING_APP ) ;
2009-10-09 00:52:25 +00:00
arg = switch_channel_get_variable ( channel , " loopback_app_arg " ) ;
extension = switch_caller_extension_new ( session , app , app ) ;
switch_caller_extension_add_application ( session , extension , " pre_answer " , NULL ) ;
switch_caller_extension_add_application ( session , extension , app , arg ) ;
2010-02-06 03:38:24 +00:00
2009-10-09 00:52:25 +00:00
switch_channel_set_caller_extension ( channel , extension ) ;
switch_channel_set_state ( channel , CS_EXECUTE ) ;
return SWITCH_STATUS_FALSE ;
}
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_on_execute ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2013-05-24 08:13:41 -05:00
switch_caller_extension_t * exten = NULL ;
const char * bowout = NULL ;
2012-10-31 12:56:09 -05:00
int bow = 0 ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL EXECUTE \n " , switch_channel_get_name ( channel ) ) ;
2010-02-06 03:38:24 +00:00
2013-06-17 10:44:43 -05:00
if ( ( bowout = switch_channel_get_variable ( tech_pvt - > channel , " loopback_bowout_on_execute " ) ) & & switch_true ( bowout ) ) {
2013-05-24 08:13:41 -05:00
/* loopback_bowout_on_execute variable is set */
bow = 1 ;
} else if ( ( exten = switch_channel_get_caller_extension ( channel ) ) ) {
/* check for bowout flag */
2012-10-31 12:56:09 -05:00
switch_caller_application_t * app_p ;
for ( app_p = exten - > applications ; app_p ; app_p = app_p - > next ) {
int32_t flags ;
switch_core_session_get_app_flags ( app_p - > application_name , & flags ) ;
if ( ( flags & SAF_NO_LOOPBACK ) ) {
bow = 1 ;
break ;
}
}
}
if ( bow ) {
2013-05-10 10:45:07 -05:00
switch_core_session_t * other_session = NULL ;
2013-05-24 08:13:41 -05:00
switch_caller_profile_t * cp , * clone ;
2013-05-10 10:45:07 -05:00
const char * other_uuid = NULL ;
2015-04-02 19:05:13 -04:00
switch_event_t * event = NULL ;
2013-05-23 08:00:03 -05:00
switch_set_flag ( tech_pvt , TFLAG_BOWOUT ) ;
2012-10-31 12:56:09 -05:00
if ( ( find_non_loopback_bridge ( tech_pvt - > other_session , & other_session , & other_uuid ) = = SWITCH_STATUS_SUCCESS ) ) {
switch_channel_t * other_channel = switch_core_session_get_channel ( other_session ) ;
2013-05-24 08:13:41 -05:00
2013-08-14 02:13:49 +05:00
switch_channel_wait_for_state_timeout ( other_channel , CS_EXCHANGE_MEDIA , 5000 ) ;
2013-05-24 08:13:41 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_INFO , " BOWOUT Replacing loopback channel with real channel: %s \n " ,
switch_channel_get_name ( other_channel ) ) ;
2015-04-02 19:05:13 -04:00
if ( switch_event_create_subclass ( & event , SWITCH_EVENT_CUSTOM , " loopback::bowout " ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Resigning-UUID " , switch_channel_get_uuid ( channel ) ) ;
2018-04-24 04:36:01 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Resigning-Peer-UUID " , switch_channel_get_uuid ( tech_pvt - > other_channel ) ) ;
2015-04-02 19:05:13 -04:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Acquired-UUID " , switch_channel_get_uuid ( other_channel ) ) ;
switch_event_fire ( & event ) ;
}
2013-05-24 08:13:41 -05:00
if ( ( cp = switch_channel_get_caller_profile ( channel ) ) ) {
clone = switch_caller_profile_clone ( other_session , cp ) ;
clone - > originator_caller_profile = NULL ;
clone - > originatee_caller_profile = NULL ;
switch_channel_set_caller_profile ( other_channel , clone ) ;
}
2018-04-24 04:36:01 +01:00
switch_channel_set_variable ( channel , " loopback_hangup_cause " , " bowout " ) ;
switch_channel_set_variable ( tech_pvt - > channel , " loopback_bowout_other_uuid " , switch_channel_get_uuid ( other_channel ) ) ;
2013-05-24 08:13:41 -05:00
switch_channel_caller_extension_masquerade ( channel , other_channel , 0 ) ;
switch_channel_set_state ( other_channel , CS_RESET ) ;
switch_channel_wait_for_state ( other_channel , NULL , CS_RESET ) ;
switch_channel_set_state ( other_channel , CS_EXECUTE ) ;
2012-10-31 12:56:09 -05:00
switch_core_session_rwunlock ( other_session ) ;
2018-04-24 04:36:01 +01:00
switch_channel_hangup ( channel , loopback_globals . bowout_hangup_cause ) ;
2012-10-31 12:56:09 -05:00
}
}
2009-04-10 17:43:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_on_destroy ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2012-04-17 16:13:41 -05:00
switch_event_t * vars ;
2009-04-10 17:43:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
2012-04-17 16:13:41 -05:00
if ( ( vars = ( switch_event_t * ) switch_channel_get_private ( channel , " __loopback_vars__ " ) ) ) {
switch_channel_set_private ( channel , " __loopback_vars__ " , NULL ) ;
switch_event_destroy ( & vars ) ;
}
2017-01-06 02:10:15 -05:00
2009-04-10 20:14:02 +00:00
if ( tech_pvt ) {
2011-02-01 11:43:02 -06:00
switch_core_timer_destroy ( & tech_pvt - > timer ) ;
2010-02-06 03:38:24 +00:00
2009-04-10 20:14:02 +00:00
if ( switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
}
2010-02-06 03:38:24 +00:00
2009-04-10 20:14:02 +00:00
if ( switch_core_codec_ready ( & tech_pvt - > write_codec ) ) {
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
}
2009-04-13 18:35:26 +00:00
if ( tech_pvt - > write_frame ) {
switch_frame_free ( & tech_pvt - > write_frame ) ;
}
2013-10-22 15:44:50 -05:00
clear_queue ( tech_pvt ) ;
2009-04-10 17:43:18 +00:00
}
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2009-04-10 17:43:18 +00:00
2008-09-23 21:44:18 +00:00
static switch_status_t channel_on_hangup ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( channel ! = NULL ) ;
2013-06-26 10:51:44 -05:00
switch_channel_set_variable ( channel , " is_loopback " , " 1 " ) ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL HANGUP \n " , switch_channel_get_name ( channel ) ) ;
2008-09-23 21:44:18 +00:00
switch_clear_flag_locked ( tech_pvt , TFLAG_LINKED ) ;
2008-10-08 18:15:00 +00:00
2009-04-07 23:44:08 +00:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
2013-05-03 12:30:35 -05:00
2008-09-24 16:32:58 +00:00
if ( tech_pvt - > other_tech_pvt ) {
switch_clear_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_LINKED ) ;
2013-05-03 12:30:35 -05:00
if ( tech_pvt - > other_tech_pvt - > session & & tech_pvt - > other_tech_pvt - > session ! = tech_pvt - > other_session ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " OTHER SESSION MISMATCH???? \n " ) ;
tech_pvt - > other_session = tech_pvt - > other_tech_pvt - > session ;
}
2008-10-08 18:15:00 +00:00
tech_pvt - > other_tech_pvt = NULL ;
2008-09-24 16:32:58 +00:00
}
2010-02-06 03:38:24 +00:00
2008-10-08 16:04:39 +00:00
if ( tech_pvt - > other_session ) {
switch_channel_hangup ( tech_pvt - > other_channel , switch_channel_get_cause ( channel ) ) ;
switch_core_session_rwunlock ( tech_pvt - > other_session ) ;
2008-10-08 18:15:00 +00:00
tech_pvt - > other_channel = NULL ;
tech_pvt - > other_session = NULL ;
2008-10-08 16:04:39 +00:00
}
2009-04-08 18:43:10 +00:00
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_kill_channel ( switch_core_session_t * session , int sig )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( channel ! = NULL ) ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2008-09-23 21:44:18 +00:00
switch ( sig ) {
2008-09-24 16:32:58 +00:00
case SWITCH_SIG_BREAK :
break ;
2008-09-23 21:44:18 +00:00
case SWITCH_SIG_KILL :
2018-04-24 04:36:01 +01:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL KILL \n " , switch_channel_get_name ( channel ) ) ;
2008-09-23 21:44:18 +00:00
switch_channel_hangup ( channel , SWITCH_CAUSE_NORMAL_CLEARING ) ;
2008-09-24 16:32:58 +00:00
switch_clear_flag_locked ( tech_pvt , TFLAG_LINKED ) ;
2009-04-07 23:44:08 +00:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
2008-09-24 16:32:58 +00:00
if ( tech_pvt - > other_tech_pvt ) {
switch_clear_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_LINKED ) ;
}
2009-04-07 23:44:08 +00:00
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2008-09-23 21:44:18 +00:00
break ;
default :
break ;
}
2008-10-09 23:12:37 +00:00
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_on_soft_execute ( switch_core_session_t * session )
{
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL TRANSMIT \n " ) ;
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_on_exchange_media ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL LOOPBACK \n " ) ;
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-09-24 19:36:24 +00:00
static switch_status_t channel_on_reset ( switch_core_session_t * session )
{
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = ( loopback_private_t * ) switch_core_session_get_private ( session ) ;
2008-09-24 19:36:24 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
do_reset ( tech_pvt ) ;
2010-02-06 03:38:24 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s RESET \n " ,
switch_channel_get_name ( switch_core_session_get_channel ( session ) ) ) ;
2008-09-24 19:36:24 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_on_hibernate ( switch_core_session_t * session )
{
2008-10-24 16:52:53 +00:00
switch_assert ( switch_core_session_get_private ( session ) ) ;
2008-09-24 19:36:24 +00:00
2010-02-06 03:38:24 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s HIBERNATE \n " ,
switch_channel_get_name ( switch_core_session_get_channel ( session ) ) ) ;
2008-09-24 19:36:24 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-09-23 21:44:18 +00:00
static switch_status_t channel_on_consume_media ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL CONSUME_MEDIA \n " ) ;
2008-09-23 21:44:18 +00:00
2009-04-26 22:10:05 +00:00
return SWITCH_STATUS_SUCCESS ;
2008-09-23 21:44:18 +00:00
}
static switch_status_t channel_send_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf )
{
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2008-09-23 21:44:18 +00:00
2008-09-25 00:01:59 +00:00
if ( tech_pvt - > other_channel ) {
switch_channel_queue_dtmf ( tech_pvt - > other_channel , dtmf ) ;
}
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
switch_status_t status = SWITCH_STATUS_FALSE ;
2009-04-07 23:44:08 +00:00
switch_mutex_t * mutex = NULL ;
2009-04-13 18:35:26 +00:00
void * pop = NULL ;
2008-10-09 23:12:37 +00:00
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( channel ! = NULL ) ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2008-09-23 21:44:18 +00:00
if ( ! switch_test_flag ( tech_pvt , TFLAG_LINKED ) ) {
goto end ;
}
2010-02-06 03:38:24 +00:00
2008-10-08 16:39:43 +00:00
* frame = NULL ;
2010-02-06 03:38:24 +00:00
2009-04-08 18:43:10 +00:00
if ( ! switch_channel_ready ( channel ) ) {
2018-04-24 04:36:01 +01:00
if ( loopback_globals . ignore_channel_ready ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL NOT READY - IGNORED \n " ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL NOT READY \n " ) ;
goto end ;
}
2009-04-08 18:43:10 +00:00
}
2008-10-09 23:12:37 +00:00
2011-02-01 11:43:02 -06:00
switch_core_timer_next ( & tech_pvt - > timer ) ;
2009-05-05 19:35:31 +00:00
2011-02-01 11:43:02 -06:00
mutex = tech_pvt - > mutex ;
switch_mutex_lock ( mutex ) ;
2011-01-25 11:26:32 -06:00
2011-06-01 17:40:56 -05:00
if ( switch_test_flag ( tech_pvt , TFLAG_CLEAR ) ) {
clear_queue ( tech_pvt ) ;
switch_clear_flag ( tech_pvt , TFLAG_CLEAR ) ;
}
2011-02-01 11:43:02 -06:00
if ( switch_queue_trypop ( tech_pvt - > frame_queue , & pop ) = = SWITCH_STATUS_SUCCESS & & pop ) {
2009-04-13 18:35:26 +00:00
if ( tech_pvt - > write_frame ) {
switch_frame_free ( & tech_pvt - > write_frame ) ;
}
2017-01-06 02:10:15 -05:00
2009-04-13 18:35:26 +00:00
tech_pvt - > write_frame = ( switch_frame_t * ) pop ;
2013-10-14 13:06:41 -05:00
switch_clear_flag ( tech_pvt - > write_frame , SFF_RAW_RTP ) ;
2017-01-06 02:10:15 -05:00
tech_pvt - > write_frame - > timestamp = 0 ;
2013-10-14 13:06:41 -05:00
2009-04-13 18:35:26 +00:00
tech_pvt - > write_frame - > codec = & tech_pvt - > read_codec ;
* frame = tech_pvt - > write_frame ;
2011-02-01 16:22:36 -06:00
tech_pvt - > packet_count + + ;
switch_clear_flag ( tech_pvt - > write_frame , SFF_CNG ) ;
2011-10-31 12:05:15 -05:00
tech_pvt - > first_cng = 0 ;
2009-04-08 18:43:10 +00:00
} else {
2008-10-09 23:12:37 +00:00
* frame = & tech_pvt - > cng_frame ;
tech_pvt - > cng_frame . codec = & tech_pvt - > read_codec ;
2009-04-25 17:03:04 +00:00
tech_pvt - > cng_frame . datalen = tech_pvt - > read_codec . implementation - > decoded_bytes_per_packet ;
2011-02-01 16:22:36 -06:00
switch_set_flag ( ( & tech_pvt - > cng_frame ) , SFF_CNG ) ;
2011-10-31 12:05:15 -05:00
if ( ! tech_pvt - > first_cng ) {
switch_yield ( tech_pvt - > read_codec . implementation - > samples_per_packet ) ;
tech_pvt - > first_cng = 1 ;
}
2008-10-09 23:12:37 +00:00
}
2010-02-06 03:38:24 +00:00
2008-10-09 23:12:37 +00:00
2009-04-08 18:43:10 +00:00
if ( * frame ) {
2008-10-08 16:39:43 +00:00
status = SWITCH_STATUS_SUCCESS ;
} else {
status = SWITCH_STATUS_FALSE ;
2010-02-06 03:38:24 +00:00
}
2008-09-23 21:44:18 +00:00
2010-02-06 03:38:24 +00:00
end :
2008-09-23 21:44:18 +00:00
2009-04-07 23:44:08 +00:00
if ( mutex ) {
switch_mutex_unlock ( mutex ) ;
}
2008-09-23 21:44:18 +00:00
return status ;
}
2012-11-13 11:36:50 -06:00
static void switch_channel_wait_for_state_or_greater ( switch_channel_t * channel , switch_channel_t * other_channel , switch_channel_state_t want_state )
{
switch_assert ( channel ) ;
2017-01-06 02:10:15 -05:00
2012-11-13 11:36:50 -06:00
for ( ; ; ) {
2017-01-06 02:10:15 -05:00
if ( ( switch_channel_get_state ( channel ) < CS_HANGUP & &
2012-11-14 19:19:03 -06:00
switch_channel_get_state ( channel ) = = switch_channel_get_running_state ( channel ) & & switch_channel_get_running_state ( channel ) > = want_state ) | |
2012-11-13 11:36:50 -06:00
( other_channel & & switch_channel_down_nosig ( other_channel ) ) | | switch_channel_down ( channel ) ) {
break ;
}
switch_cond_next ( ) ;
}
}
2012-05-17 18:57:22 -05:00
static switch_status_t find_non_loopback_bridge ( switch_core_session_t * session , switch_core_session_t * * br_session , const char * * br_uuid )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2012-11-13 11:36:50 -06:00
const char * a_uuid = NULL ;
2013-05-10 10:45:07 -05:00
switch_core_session_t * sp = NULL ;
2012-05-17 18:57:22 -05:00
2016-08-18 10:11:58 -05:00
2012-05-17 18:57:22 -05:00
* br_session = NULL ;
* br_uuid = NULL ;
2012-05-29 13:10:15 -05:00
a_uuid = switch_channel_get_partner_uuid ( channel ) ;
2012-05-17 18:57:22 -05:00
while ( a_uuid & & ( sp = switch_core_session_locate ( a_uuid ) ) ) {
if ( switch_core_session_check_interface ( sp , loopback_endpoint_interface ) ) {
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt ;
2012-11-13 11:36:50 -06:00
switch_channel_t * spchan = switch_core_session_get_channel ( sp ) ;
switch_channel_wait_for_state_or_greater ( spchan , channel , CS_ROUTING ) ;
2016-08-18 10:11:58 -05:00
if ( switch_false ( switch_channel_get_variable ( spchan , " loopback_bowout " ) ) ) break ;
2012-11-13 11:36:50 -06:00
tech_pvt = switch_core_session_get_private ( sp ) ;
if ( tech_pvt - > other_channel ) {
a_uuid = switch_channel_get_partner_uuid ( tech_pvt - > other_channel ) ;
}
2012-05-17 18:57:22 -05:00
switch_core_session_rwunlock ( sp ) ;
sp = NULL ;
} else {
break ;
}
}
if ( sp ) {
* br_session = sp ;
* br_uuid = a_uuid ;
return SWITCH_STATUS_SUCCESS ;
}
return SWITCH_STATUS_FALSE ;
}
2008-09-23 21:44:18 +00:00
static switch_status_t channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id )
{
switch_channel_t * channel = NULL ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt = NULL ;
2008-09-23 21:44:18 +00:00
switch_status_t status = SWITCH_STATUS_FALSE ;
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( channel ! = NULL ) ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2008-09-23 21:44:18 +00:00
2017-01-06 02:10:15 -05:00
if ( switch_test_flag ( frame , SFF_CNG ) | |
2011-05-02 17:21:39 -05:00
( switch_test_flag ( tech_pvt , TFLAG_BOWOUT ) & & switch_test_flag ( tech_pvt , TFLAG_BOWOUT_USED ) ) ) {
2011-02-01 11:46:15 -06:00
switch_core_timer_sync ( & tech_pvt - > timer ) ;
2018-11-08 23:59:59 +02:00
if ( tech_pvt - > other_tech_pvt ) switch_core_timer_sync ( & tech_pvt - > other_tech_pvt - > timer ) ;
2008-09-24 19:36:24 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-09-25 14:26:42 +00:00
2009-04-07 23:44:08 +00:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
2010-02-06 03:38:24 +00:00
if ( ! switch_test_flag ( tech_pvt , TFLAG_BOWOUT ) & &
tech_pvt - > other_tech_pvt & &
switch_test_flag ( tech_pvt , TFLAG_BRIDGE ) & &
2013-05-08 13:17:07 -05:00
! switch_test_flag ( tech_pvt , TFLAG_BLEG ) & &
2019-04-02 17:01:36 +01:00
( ! loopback_globals . bowout_disable_on_inner_bridge | | ! switch_channel_test_flag ( tech_pvt - > channel , CF_INNER_BRIDGE ) ) & &
2010-02-06 03:38:24 +00:00
switch_test_flag ( tech_pvt - > other_tech_pvt , TFLAG_BRIDGE ) & &
2008-09-25 14:26:42 +00:00
switch_channel_test_flag ( tech_pvt - > channel , CF_BRIDGED ) & &
2008-10-02 16:25:13 +00:00
switch_channel_test_flag ( tech_pvt - > other_channel , CF_BRIDGED ) & &
switch_channel_test_flag ( tech_pvt - > channel , CF_ANSWERED ) & &
2011-10-31 12:05:15 -05:00
switch_channel_test_flag ( tech_pvt - > other_channel , CF_ANSWERED ) & & - - tech_pvt - > bowout_frame_count < = 0 ) {
2012-05-17 18:57:22 -05:00
const char * a_uuid = NULL ;
const char * b_uuid = NULL ;
2009-04-27 14:15:55 +00:00
const char * vetoa , * vetob ;
vetoa = switch_channel_get_variable ( tech_pvt - > channel , " loopback_bowout " ) ;
vetob = switch_channel_get_variable ( tech_pvt - > other_tech_pvt - > channel , " loopback_bowout " ) ;
2010-02-06 03:38:24 +00:00
2009-04-27 14:15:55 +00:00
if ( ( ! vetoa | | switch_true ( vetoa ) ) & & ( ! vetob | | switch_true ( vetob ) ) ) {
2011-10-31 12:05:15 -05:00
switch_core_session_t * br_a , * br_b ;
switch_channel_t * ch_a = NULL , * ch_b = NULL ;
int good_to_go = 0 ;
2012-05-17 18:57:22 -05:00
2012-11-14 19:19:03 -06:00
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2012-05-17 18:57:22 -05:00
find_non_loopback_bridge ( session , & br_a , & a_uuid ) ;
find_non_loopback_bridge ( tech_pvt - > other_session , & br_b , & b_uuid ) ;
2012-11-14 19:19:03 -06:00
switch_mutex_lock ( tech_pvt - > mutex ) ;
2012-10-17 12:49:58 -04:00
2017-01-06 02:10:15 -05:00
2012-05-17 18:57:22 -05:00
if ( br_a ) {
2011-10-31 12:05:15 -05:00
ch_a = switch_core_session_get_channel ( br_a ) ;
2018-03-20 09:20:37 +01:00
switch_ivr_transfer_recordings ( session , br_a ) ;
2011-10-31 12:05:15 -05:00
}
2010-09-29 10:21:14 -05:00
2012-05-17 18:57:22 -05:00
if ( br_b ) {
2011-10-31 12:05:15 -05:00
ch_b = switch_core_session_get_channel ( br_b ) ;
2018-03-20 09:20:37 +01:00
switch_ivr_transfer_recordings ( tech_pvt - > other_session , br_b ) ;
2011-10-31 12:05:15 -05:00
}
2017-01-06 02:10:15 -05:00
2011-10-31 12:05:15 -05:00
if ( ch_a & & ch_b & & switch_channel_test_flag ( ch_a , CF_BRIDGED ) & & switch_channel_test_flag ( ch_b , CF_BRIDGED ) ) {
2012-05-17 18:57:22 -05:00
2011-10-31 12:05:15 -05:00
switch_set_flag_locked ( tech_pvt , TFLAG_BOWOUT ) ;
switch_set_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_BOWOUT ) ;
switch_clear_flag_locked ( tech_pvt , TFLAG_WRITE ) ;
switch_clear_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_WRITE ) ;
switch_set_flag_locked ( tech_pvt , TFLAG_BOWOUT_USED ) ;
switch_set_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_BOWOUT_USED ) ;
if ( a_uuid & & b_uuid ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG ,
" %s detected bridge on both ends, attempting direct connection. \n " , switch_channel_get_name ( channel ) ) ;
2017-01-06 02:10:15 -05:00
2018-04-24 04:36:01 +01:00
if ( loopback_globals . bowout_transfer_recordings ) {
switch_ivr_transfer_recordings ( session , br_a ) ;
switch_ivr_transfer_recordings ( tech_pvt - > other_session , br_b ) ;
}
if ( loopback_globals . fire_bowout_event_bridge ) {
switch_event_t * event = NULL ;
if ( switch_event_create_subclass ( & event , SWITCH_EVENT_CUSTOM , " loopback::direct " ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( tech_pvt - > channel , event ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Resigning-UUID " , switch_channel_get_uuid ( tech_pvt - > channel ) ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Resigning-Peer-UUID " , switch_channel_get_uuid ( tech_pvt - > other_channel ) ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Connecting-Leg-A-UUID " , switch_channel_get_uuid ( ch_a ) ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Connecting-Leg-B-UUID " , switch_channel_get_uuid ( ch_b ) ) ;
switch_event_fire ( & event ) ;
}
if ( switch_event_create_subclass ( & event , SWITCH_EVENT_CUSTOM , " loopback::direct " ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_event_set_data ( tech_pvt - > other_channel , event ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Resigning-UUID " , switch_channel_get_uuid ( tech_pvt - > other_channel ) ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Resigning-Peer-UUID " , switch_channel_get_uuid ( tech_pvt - > channel ) ) ;
2019-04-18 03:39:06 +01:00
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Connecting-Leg-A-UUID " , switch_channel_get_uuid ( ch_b ) ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " Connecting-Leg-B-UUID " , switch_channel_get_uuid ( ch_a ) ) ;
2018-04-24 04:36:01 +01:00
switch_event_fire ( & event ) ;
}
}
2011-10-31 12:05:15 -05:00
/* channel_masquerade eat your heart out....... */
2013-05-08 14:40:10 -05:00
switch_ivr_uuid_bridge ( a_uuid , b_uuid ) ;
2018-04-24 04:36:01 +01:00
switch_channel_set_variable ( tech_pvt - > channel , " loopback_hangup_cause " , " bridge " ) ;
switch_channel_set_variable ( tech_pvt - > channel , " loopback_bowout_other_uuid " , switch_channel_get_uuid ( ch_a ) ) ;
switch_channel_set_variable ( tech_pvt - > other_channel , " loopback_hangup_cause " , " bridge " ) ;
switch_channel_set_variable ( tech_pvt - > other_channel , " loopback_bowout_other_uuid " , switch_channel_get_uuid ( ch_b ) ) ;
if ( loopback_globals . bowout_controlled_hangup ) {
switch_channel_set_flag ( tech_pvt - > channel , CF_INTERCEPTED ) ;
switch_channel_set_flag ( tech_pvt - > other_channel , CF_INTERCEPTED ) ;
switch_channel_hangup ( tech_pvt - > channel , loopback_globals . bowout_hangup_cause ) ;
switch_channel_hangup ( tech_pvt - > other_channel , loopback_globals . bowout_hangup_cause ) ;
}
2011-10-31 12:05:15 -05:00
good_to_go = 1 ;
switch_mutex_unlock ( tech_pvt - > mutex ) ;
}
}
2010-02-06 03:38:24 +00:00
2011-10-31 12:05:15 -05:00
if ( br_a ) switch_core_session_rwunlock ( br_a ) ;
if ( br_b ) switch_core_session_rwunlock ( br_b ) ;
2017-01-06 02:10:15 -05:00
2011-10-31 12:05:15 -05:00
if ( good_to_go ) {
2009-04-27 14:15:55 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2011-10-31 12:05:15 -05:00
2008-09-25 14:26:42 +00:00
}
}
2010-02-06 03:38:24 +00:00
if ( switch_test_flag ( tech_pvt , TFLAG_LINKED ) & & tech_pvt - > other_tech_pvt ) {
2009-04-13 18:35:26 +00:00
switch_frame_t * clone ;
2017-01-06 02:10:15 -05:00
2008-09-24 19:36:24 +00:00
if ( frame - > codec - > implementation ! = tech_pvt - > write_codec . implementation ) {
/* change codecs to match */
tech_init ( tech_pvt , session , frame - > codec ) ;
tech_init ( tech_pvt - > other_tech_pvt , tech_pvt - > other_session , frame - > codec ) ;
}
2009-04-13 18:35:26 +00:00
2009-04-26 22:10:05 +00:00
2011-05-02 17:21:39 -05:00
if ( switch_frame_dup ( frame , & clone ) ! = SWITCH_STATUS_SUCCESS ) {
abort ( ) ;
}
2017-01-06 02:10:15 -05:00
if ( ( status = switch_queue_trypush ( tech_pvt - > other_tech_pvt - > frame_queue , clone ) ) ! = SWITCH_STATUS_SUCCESS ) {
2011-05-02 17:21:39 -05:00
clear_queue ( tech_pvt - > other_tech_pvt ) ;
status = switch_queue_trypush ( tech_pvt - > other_tech_pvt - > frame_queue , clone ) ;
}
2009-04-27 14:15:55 +00:00
2011-05-02 17:21:39 -05:00
if ( status = = SWITCH_STATUS_SUCCESS ) {
2009-04-27 14:15:55 +00:00
switch_set_flag_locked ( tech_pvt - > other_tech_pvt , TFLAG_WRITE ) ;
2011-05-02 17:21:39 -05:00
} else {
switch_frame_free ( & clone ) ;
2009-04-26 22:10:05 +00:00
}
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
status = SWITCH_STATUS_SUCCESS ;
}
2009-04-07 23:44:08 +00:00
switch_mutex_unlock ( tech_pvt - > mutex ) ;
2008-09-23 21:44:18 +00:00
return status ;
}
static switch_status_t channel_receive_message ( switch_core_session_t * session , switch_core_session_message_t * msg )
{
switch_channel_t * channel ;
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt ;
2012-04-17 16:13:41 -05:00
int done = 1 , pass = 0 ;
2013-06-17 10:44:43 -05:00
switch_core_session_t * other_session ;
2017-01-06 02:10:15 -05:00
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( channel ! = NULL ) ;
2008-09-23 21:44:18 +00:00
tech_pvt = switch_core_session_get_private ( session ) ;
2008-10-24 16:52:53 +00:00
switch_assert ( tech_pvt ! = NULL ) ;
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
switch ( msg - > message_id ) {
case SWITCH_MESSAGE_INDICATE_ANSWER :
2009-01-19 19:32:44 +00:00
if ( tech_pvt - > other_channel & & ! switch_test_flag ( tech_pvt , TFLAG_OUTBOUND ) ) {
switch_channel_mark_answered ( tech_pvt - > other_channel ) ;
2008-09-23 21:44:18 +00:00
}
break ;
case SWITCH_MESSAGE_INDICATE_PROGRESS :
2009-01-19 19:32:44 +00:00
if ( tech_pvt - > other_channel & & ! switch_test_flag ( tech_pvt , TFLAG_OUTBOUND ) ) {
switch_channel_mark_pre_answered ( tech_pvt - > other_channel ) ;
2008-09-23 21:44:18 +00:00
}
break ;
2010-10-26 11:52:28 -05:00
case SWITCH_MESSAGE_INDICATE_RINGING :
if ( tech_pvt - > other_channel & & ! switch_test_flag ( tech_pvt , TFLAG_OUTBOUND ) ) {
switch_channel_mark_ring_ready ( tech_pvt - > other_channel ) ;
}
break ;
2008-09-25 14:26:42 +00:00
case SWITCH_MESSAGE_INDICATE_BRIDGE :
{
2010-02-06 03:38:24 +00:00
switch_set_flag_locked ( tech_pvt , TFLAG_BRIDGE ) ;
2018-04-24 04:36:01 +01:00
if ( switch_test_flag ( tech_pvt , TFLAG_BLEG ) ) {
if ( msg - > string_arg ) {
switch_core_session_t * bridged_session ;
switch_channel_t * bridged_channel ;
if ( ( bridged_session = switch_core_session_force_locate ( msg - > string_arg ) ) ! = NULL ) {
bridged_channel = switch_core_session_get_channel ( bridged_session ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( bridged_session ) , SWITCH_LOG_DEBUG , " setting other_leg_true_id to %s \n " , switch_channel_get_variable ( channel , " other_loopback_from_uuid " ) ) ;
switch_channel_set_variable ( bridged_channel , " other_leg_true_id " , switch_channel_get_variable ( channel , " other_loopback_from_uuid " ) ) ;
switch_core_session_rwunlock ( bridged_session ) ;
}
}
}
2008-09-25 14:26:42 +00:00
}
break ;
case SWITCH_MESSAGE_INDICATE_UNBRIDGE :
{
switch_clear_flag_locked ( tech_pvt , TFLAG_BRIDGE ) ;
}
break ;
2008-09-23 21:44:18 +00:00
default :
2010-10-25 11:28:02 -05:00
done = 0 ;
2008-09-23 21:44:18 +00:00
break ;
}
2009-04-14 17:29:38 +00:00
switch ( msg - > message_id ) {
case SWITCH_MESSAGE_INDICATE_BRIDGE :
case SWITCH_MESSAGE_INDICATE_UNBRIDGE :
case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC :
{
2010-10-25 11:28:02 -05:00
done = 1 ;
2011-06-01 17:40:56 -05:00
switch_set_flag ( tech_pvt , TFLAG_CLEAR ) ;
2018-11-08 23:59:59 +02:00
if ( tech_pvt - > other_tech_pvt ) switch_set_flag ( tech_pvt - > other_tech_pvt , TFLAG_CLEAR ) ;
2010-10-25 11:28:02 -05:00
2011-02-01 11:43:02 -06:00
switch_core_timer_sync ( & tech_pvt - > timer ) ;
2018-11-08 23:59:59 +02:00
if ( tech_pvt - > other_tech_pvt ) switch_core_timer_sync ( & tech_pvt - > other_tech_pvt - > timer ) ;
2009-04-14 17:29:38 +00:00
}
break ;
2010-02-06 03:38:24 +00:00
default :
break ;
}
2009-04-14 17:29:38 +00:00
2012-04-17 16:13:41 -05:00
switch ( msg - > message_id ) {
case SWITCH_MESSAGE_INDICATE_DISPLAY :
2013-05-07 08:31:23 -05:00
if ( tech_pvt - > other_channel ) {
2012-04-17 16:13:41 -05:00
2013-04-01 23:02:29 -05:00
if ( switch_test_flag ( tech_pvt , TFLAG_BLEG ) ) {
if ( ! zstr ( msg - > string_array_arg [ 0 ] ) ) {
switch_channel_set_profile_var ( tech_pvt - > other_channel , " caller_id_name " , msg - > string_array_arg [ 0 ] ) ;
}
2017-01-06 02:10:15 -05:00
2013-04-01 23:02:29 -05:00
if ( ! zstr ( msg - > string_array_arg [ 1 ] ) ) {
switch_channel_set_profile_var ( tech_pvt - > other_channel , " caller_id_number " , msg - > string_array_arg [ 1 ] ) ;
}
} else {
if ( ! zstr ( msg - > string_array_arg [ 0 ] ) ) {
switch_channel_set_profile_var ( tech_pvt - > other_channel , " callee_id_name " , msg - > string_array_arg [ 0 ] ) ;
}
2017-01-06 02:10:15 -05:00
2013-04-01 23:02:29 -05:00
if ( ! zstr ( msg - > string_array_arg [ 1 ] ) ) {
switch_channel_set_profile_var ( tech_pvt - > other_channel , " callee_id_number " , msg - > string_array_arg [ 1 ] ) ;
}
2012-04-17 16:13:41 -05:00
}
2017-01-06 02:10:15 -05:00
2012-04-17 16:13:41 -05:00
pass = 1 ;
}
break ;
2013-06-17 10:44:43 -05:00
case SWITCH_MESSAGE_INDICATE_DEFLECT :
{
pass = 0 ;
if ( ! zstr ( msg - > string_arg ) & & switch_core_session_get_partner ( tech_pvt - > other_session , & other_session ) = = SWITCH_STATUS_SUCCESS ) {
char * ext = switch_core_session_strdup ( other_session , msg - > string_arg ) ;
char * context = NULL , * dp = NULL ;
2017-01-06 02:10:15 -05:00
2013-06-17 10:44:43 -05:00
if ( ( context = strchr ( ext , ' ' ) ) ) {
* context + + = ' \0 ' ;
2017-01-06 02:10:15 -05:00
2013-06-17 10:44:43 -05:00
if ( ( dp = strchr ( context , ' ' ) ) ) {
* dp + + = ' \0 ' ;
}
}
switch_ivr_session_transfer ( other_session , ext , context , dp ) ;
switch_core_session_rwunlock ( other_session ) ;
}
}
break ;
2012-04-17 16:13:41 -05:00
default :
break ;
}
if ( ! done & & tech_pvt - > other_session & & ( pass | | switch_test_flag ( tech_pvt , TFLAG_RUNNING_APP ) ) ) {
2010-10-25 11:28:02 -05:00
switch_status_t r = SWITCH_STATUS_FALSE ;
2017-01-06 02:10:15 -05:00
2010-10-30 22:29:26 -05:00
if ( switch_core_session_get_partner ( tech_pvt - > other_session , & other_session ) = = SWITCH_STATUS_SUCCESS ) {
2010-10-25 11:28:02 -05:00
r = switch_core_session_receive_message ( other_session , msg ) ;
switch_core_session_rwunlock ( other_session ) ;
}
2017-01-06 02:10:15 -05:00
2010-10-25 11:28:02 -05:00
return r ;
}
2017-01-06 02:10:15 -05:00
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_call_cause_t channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
2010-02-06 03:38:24 +00:00
switch_core_session_t * * new_session , switch_memory_pool_t * * pool , switch_originate_flag_t flags ,
switch_call_cause_t * cancel_cause )
2008-09-23 21:44:18 +00:00
{
2008-09-24 19:36:24 +00:00
char name [ 128 ] ;
2012-10-17 12:41:24 -04:00
switch_channel_t * ochannel = NULL ;
2008-09-24 19:36:24 +00:00
2008-09-23 22:35:42 +00:00
if ( session ) {
2012-10-17 12:41:24 -04:00
ochannel = switch_core_session_get_channel ( session ) ;
switch_channel_clear_flag ( ochannel , CF_PROXY_MEDIA ) ;
switch_channel_clear_flag ( ochannel , CF_PROXY_MODE ) ;
switch_channel_pre_answer ( ochannel ) ;
2008-09-23 22:35:42 +00:00
}
2010-08-26 12:19:49 -05:00
if ( ( * new_session = switch_core_session_request ( loopback_endpoint_interface , SWITCH_CALL_DIRECTION_OUTBOUND , flags , pool ) ) ! = 0 ) {
2013-05-03 12:30:35 -05:00
loopback_private_t * tech_pvt ;
2008-09-23 21:44:18 +00:00
switch_channel_t * channel ;
switch_caller_profile_t * caller_profile ;
2012-04-17 16:13:41 -05:00
switch_event_t * clone = NULL ;
2008-10-08 18:15:00 +00:00
2008-09-23 21:44:18 +00:00
switch_core_session_add_stream ( * new_session , NULL ) ;
2017-01-06 02:10:15 -05:00
2013-05-03 12:30:35 -05:00
if ( ( tech_pvt = ( loopback_private_t * ) switch_core_session_alloc ( * new_session , sizeof ( loopback_private_t ) ) ) ! = 0 ) {
2008-09-23 21:44:18 +00:00
channel = switch_core_session_get_channel ( * new_session ) ;
2008-10-08 18:15:00 +00:00
switch_snprintf ( name , sizeof ( name ) , " loopback/%s-a " , outbound_profile - > destination_number ) ;
2008-09-24 19:36:24 +00:00
switch_channel_set_name ( channel , name ) ;
2018-04-24 04:36:01 +01:00
if ( loopback_globals . early_set_loopback_id ) {
switch_channel_set_variable ( channel , " loopback_leg " , " A " ) ;
switch_channel_set_variable ( channel , " is_loopback " , " 1 " ) ;
}
2008-09-23 21:44:18 +00:00
if ( tech_init ( tech_pvt , * new_session , session ? switch_core_session_get_read_codec ( session ) : NULL ) ! = SWITCH_STATUS_SUCCESS ) {
switch_core_session_destroy ( new_session ) ;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
} else {
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( * new_session ) , SWITCH_LOG_CRIT , " Hey where is my memory pool? \n " ) ;
2008-09-23 21:44:18 +00:00
switch_core_session_destroy ( new_session ) ;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
2010-02-06 03:38:24 +00:00
2012-04-17 16:13:41 -05:00
if ( switch_event_dup ( & clone , var_event ) = = SWITCH_STATUS_SUCCESS ) {
switch_channel_set_private ( channel , " __loopback_vars__ " , clone ) ;
}
2018-04-24 04:36:01 +01:00
if ( ochannel ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( * new_session ) , SWITCH_LOG_DEBUG , " setting loopback_from_uuid to %s \n " , switch_channel_get_uuid ( ochannel ) ) ;
switch_channel_set_variable ( channel , " loopback_from_uuid " , switch_channel_get_uuid ( ochannel ) ) ;
}
2008-09-23 21:44:18 +00:00
if ( outbound_profile ) {
2008-09-23 22:35:42 +00:00
char * dialplan = NULL , * context = NULL ;
2008-09-23 21:44:18 +00:00
caller_profile = switch_caller_profile_clone ( * new_session , outbound_profile ) ;
2008-09-24 20:20:33 +00:00
caller_profile - > source = switch_core_strdup ( caller_profile - > pool , modname ) ;
2009-10-09 00:52:25 +00:00
if ( ! strncasecmp ( caller_profile - > destination_number , " app= " , 4 ) ) {
char * dest = switch_core_session_strdup ( * new_session , caller_profile - > destination_number ) ;
char * app = dest + 4 ;
char * arg = NULL ;
if ( ( arg = strchr ( app , ' : ' ) ) ) {
* arg + + = ' \0 ' ;
}
switch_channel_set_variable ( channel , " loopback_app " , app ) ;
2012-04-18 08:24:15 -05:00
if ( clone ) {
2012-04-18 09:34:02 -05:00
switch_event_add_header_string ( clone , SWITCH_STACK_BOTTOM , " loopback_app " , app ) ;
2012-04-18 08:24:15 -05:00
}
2017-01-06 02:10:15 -05:00
2009-10-09 00:52:25 +00:00
if ( arg ) {
switch_channel_set_variable ( channel , " loopback_app_arg " , arg ) ;
2012-04-18 08:24:15 -05:00
if ( clone ) {
2012-04-18 09:34:02 -05:00
switch_event_add_header_string ( clone , SWITCH_STACK_BOTTOM , " loopback_app_arg " , arg ) ;
2012-04-18 08:24:15 -05:00
}
2009-10-09 00:52:25 +00:00
}
2010-06-02 15:14:49 -05:00
switch_set_flag ( tech_pvt , TFLAG_APP ) ;
2009-10-09 00:52:25 +00:00
caller_profile - > destination_number = switch_core_strdup ( caller_profile - > pool , app ) ;
}
2008-09-23 22:35:42 +00:00
if ( ( context = strchr ( caller_profile - > destination_number , ' / ' ) ) ) {
* context + + = ' \0 ' ;
2010-02-06 03:38:24 +00:00
2008-09-23 22:35:42 +00:00
if ( ( dialplan = strchr ( context , ' / ' ) ) ) {
* dialplan + + = ' \0 ' ;
}
2009-10-23 16:03:42 +00:00
if ( ! zstr ( context ) ) {
2008-09-23 22:35:42 +00:00
caller_profile - > context = switch_core_strdup ( caller_profile - > pool , context ) ;
}
2009-10-23 16:03:42 +00:00
if ( ! zstr ( dialplan ) ) {
2008-09-23 22:35:42 +00:00
caller_profile - > dialplan = switch_core_strdup ( caller_profile - > pool , dialplan ) ;
}
}
2010-02-06 03:38:24 +00:00
2009-10-23 16:03:42 +00:00
if ( zstr ( caller_profile - > context ) ) {
2008-09-24 19:36:24 +00:00
caller_profile - > context = switch_core_strdup ( caller_profile - > pool , " default " ) ;
}
2009-10-23 16:03:42 +00:00
if ( zstr ( caller_profile - > dialplan ) ) {
2008-09-24 19:36:24 +00:00
caller_profile - > dialplan = switch_core_strdup ( caller_profile - > pool , " xml " ) ;
}
2008-10-08 19:32:25 +00:00
switch_snprintf ( name , sizeof ( name ) , " loopback/%s-a " , caller_profile - > destination_number ) ;
2008-09-23 22:35:42 +00:00
switch_channel_set_name ( channel , name ) ;
2009-01-19 19:32:44 +00:00
switch_set_flag_locked ( tech_pvt , TFLAG_OUTBOUND ) ;
2008-09-23 21:44:18 +00:00
switch_channel_set_caller_profile ( channel , caller_profile ) ;
tech_pvt - > caller_profile = caller_profile ;
} else {
2009-08-13 21:52:05 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( * new_session ) , SWITCH_LOG_ERROR , " Doh! no caller profile \n " ) ;
2008-09-23 21:44:18 +00:00
switch_core_session_destroy ( new_session ) ;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
2010-02-06 03:38:24 +00:00
2008-09-23 21:44:18 +00:00
switch_channel_set_state ( channel , CS_INIT ) ;
2016-12-20 11:08:17 -06:00
switch_channel_set_flag ( channel , CF_AUDIO ) ;
2008-09-23 21:44:18 +00:00
return SWITCH_CAUSE_SUCCESS ;
}
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
static switch_state_handler_table_t channel_event_handlers = {
/*.on_init */ channel_on_init ,
/*.on_routing */ channel_on_routing ,
/*.on_execute */ channel_on_execute ,
/*.on_hangup */ channel_on_hangup ,
/*.on_exchange_media */ channel_on_exchange_media ,
/*.on_soft_execute */ channel_on_soft_execute ,
2008-09-24 19:36:24 +00:00
/*.on_consume_media */ channel_on_consume_media ,
/*.on_hibernate */ channel_on_hibernate ,
2009-04-10 17:43:18 +00:00
/*.on_reset */ channel_on_reset ,
2010-02-06 03:38:24 +00:00
/*.on_park */ NULL ,
/*.on_reporting */ NULL ,
/*.on_destroy */ channel_on_destroy
2008-09-23 21:44:18 +00:00
} ;
static switch_io_routines_t channel_io_routines = {
/*.outgoing_channel */ channel_outgoing_channel ,
/*.read_frame */ channel_read_frame ,
/*.write_frame */ channel_write_frame ,
/*.kill_channel */ channel_kill_channel ,
/*.send_dtmf */ channel_send_dtmf ,
/*.receive_message */ channel_receive_message
} ;
2012-10-31 12:56:09 -05:00
SWITCH_STANDARD_APP ( unloop_function ) { /* NOOP */ }
2018-09-10 14:32:10 -04:00
static switch_endpoint_interface_t * null_endpoint_interface = NULL ;
struct null_private_object {
switch_core_session_t * session ;
switch_channel_t * channel ;
switch_codec_t read_codec ;
switch_codec_t write_codec ;
switch_timer_t timer ;
switch_caller_profile_t * caller_profile ;
switch_frame_t read_frame ;
int16_t * null_buf ;
2018-12-14 10:52:00 +08:00
int rate ;
2018-09-10 14:32:10 -04:00
} ;
typedef struct null_private_object null_private_t ;
static switch_status_t null_channel_on_init ( switch_core_session_t * session ) ;
static switch_status_t null_channel_on_destroy ( switch_core_session_t * session ) ;
static switch_call_cause_t null_channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
switch_core_session_t * * new_session , switch_memory_pool_t * * pool , switch_originate_flag_t flags ,
switch_call_cause_t * cancel_cause ) ;
static switch_status_t null_channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id ) ;
static switch_status_t null_channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id ) ;
static switch_status_t null_channel_kill_channel ( switch_core_session_t * session , int sig ) ;
static switch_status_t null_tech_init ( null_private_t * tech_pvt , switch_core_session_t * session )
{
const char * iananame = " L16 " ;
uint32_t interval = 20 ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
const switch_codec_implementation_t * read_impl ;
2018-12-14 10:52:00 +08:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s setup codec %s/%d/%d \n " ,
switch_channel_get_name ( channel ) , iananame , tech_pvt - > rate , interval ) ;
2018-09-10 14:32:10 -04:00
status = switch_core_codec_init ( & tech_pvt - > read_codec ,
iananame ,
NULL ,
NULL ,
2018-12-14 10:52:00 +08:00
tech_pvt - > rate , interval , 1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , NULL , switch_core_session_get_pool ( session ) ) ;
2018-09-10 14:32:10 -04:00
if ( status ! = SWITCH_STATUS_SUCCESS | | ! tech_pvt - > read_codec . implementation | | ! switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
goto end ;
}
status = switch_core_codec_init ( & tech_pvt - > write_codec ,
iananame ,
NULL ,
NULL ,
2018-12-14 10:52:00 +08:00
tech_pvt - > rate , interval , 1 , SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE , NULL , switch_core_session_get_pool ( session ) ) ;
2018-09-10 14:32:10 -04:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
goto end ;
}
switch_core_session_set_read_codec ( session , & tech_pvt - > read_codec ) ;
switch_core_session_set_write_codec ( session , & tech_pvt - > write_codec ) ;
read_impl = tech_pvt - > read_codec . implementation ;
switch_core_timer_init ( & tech_pvt - > timer , " soft " ,
read_impl - > microseconds_per_packet / 1000 , read_impl - > samples_per_packet * 4 , switch_core_session_get_pool ( session ) ) ;
switch_core_session_set_private ( session , tech_pvt ) ;
tech_pvt - > session = session ;
tech_pvt - > channel = switch_core_session_get_channel ( session ) ;
tech_pvt - > null_buf = switch_core_session_alloc ( session , sizeof ( char ) * read_impl - > samples_per_packet * sizeof ( int16_t ) ) ;
end :
return status ;
}
static switch_status_t null_channel_on_init ( switch_core_session_t * session )
{
switch_channel_t * channel ;
null_private_t * tech_pvt = NULL ;
tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
switch_channel_set_flag ( channel , CF_ACCEPT_CNG ) ;
switch_channel_set_flag ( channel , CF_AUDIO ) ;
switch_channel_set_state ( channel , CS_ROUTING ) ;
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t null_channel_on_destroy ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
null_private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
if ( tech_pvt ) {
switch_core_timer_destroy ( & tech_pvt - > timer ) ;
if ( switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
}
if ( switch_core_codec_ready ( & tech_pvt - > write_codec ) ) {
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
}
}
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t null_channel_kill_channel ( switch_core_session_t * session , int sig )
{
switch_channel_t * channel = NULL ;
null_private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
switch ( sig ) {
case SWITCH_SIG_BREAK :
break ;
case SWITCH_SIG_KILL :
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL SWITCH_SIG_KILL - hanging up \n " ) ;
switch_channel_hangup ( channel , SWITCH_CAUSE_NORMAL_CLEARING ) ;
break ;
default :
break ;
}
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t null_channel_on_consume_media ( switch_core_session_t * session )
{
switch_channel_t * channel = NULL ;
null_private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL CONSUME_MEDIA - answering \n " ) ;
switch_channel_mark_answered ( channel ) ;
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t null_channel_send_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf )
{
null_private_t * tech_pvt = NULL ;
2019-11-19 22:17:13 +08:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
const char * dtmf_str = switch_channel_get_variable ( channel , " null_channel_dtmf_queued " ) ;
2018-09-10 14:32:10 -04:00
tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
2019-11-19 22:17:13 +08:00
if ( ! dtmf_str ) dtmf_str = " " ;
switch_channel_set_variable_printf ( channel , " null_channel_dtmf_queued " , " %s%c " , dtmf_str , dtmf - > digit ) ;
2018-09-10 14:32:10 -04:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t null_channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id )
{
switch_channel_t * channel = NULL ;
null_private_t * tech_pvt = NULL ;
switch_status_t status = SWITCH_STATUS_FALSE ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
* frame = NULL ;
if ( ! switch_channel_ready ( channel ) ) {
return SWITCH_STATUS_FALSE ;
}
switch_core_timer_next ( & tech_pvt - > timer ) ;
if ( tech_pvt - > null_buf ) {
int samples ;
memset ( & tech_pvt - > read_frame , 0 , sizeof ( switch_frame_t ) ) ;
samples = tech_pvt - > read_codec . implementation - > samples_per_packet ;
tech_pvt - > read_frame . codec = & tech_pvt - > read_codec ;
tech_pvt - > read_frame . datalen = samples * sizeof ( int16_t ) ;
tech_pvt - > read_frame . samples = samples ;
tech_pvt - > read_frame . data = tech_pvt - > null_buf ;
switch_generate_sln_silence ( ( int16_t * ) tech_pvt - > read_frame . data , tech_pvt - > read_frame . samples , tech_pvt - > read_codec . implementation - > number_of_channels , 10000 ) ;
* frame = & tech_pvt - > read_frame ;
}
if ( * frame ) {
status = SWITCH_STATUS_SUCCESS ;
} else {
status = SWITCH_STATUS_FALSE ;
}
return status ;
}
static switch_status_t null_channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id )
{
switch_channel_t * channel = NULL ;
null_private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
switch_core_timer_sync ( & tech_pvt - > timer ) ;
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t null_channel_receive_message ( switch_core_session_t * session , switch_core_session_message_t * msg )
{
switch_channel_t * channel ;
null_private_t * tech_pvt ;
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
switch ( msg - > message_id ) {
case SWITCH_MESSAGE_INDICATE_ANSWER :
switch_channel_mark_answered ( channel ) ;
break ;
case SWITCH_MESSAGE_INDICATE_BRIDGE :
case SWITCH_MESSAGE_INDICATE_UNBRIDGE :
case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC :
switch_core_timer_sync ( & tech_pvt - > timer ) ;
break ;
default :
break ;
}
return SWITCH_STATUS_SUCCESS ;
}
static switch_call_cause_t null_channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
switch_core_session_t * * new_session , switch_memory_pool_t * * pool , switch_originate_flag_t flags ,
switch_call_cause_t * cancel_cause )
{
char name [ 128 ] ;
switch_channel_t * ochannel = NULL ;
if ( session ) {
ochannel = switch_core_session_get_channel ( session ) ;
switch_channel_clear_flag ( ochannel , CF_PROXY_MEDIA ) ;
switch_channel_clear_flag ( ochannel , CF_PROXY_MODE ) ;
switch_channel_pre_answer ( ochannel ) ;
}
if ( ( * new_session = switch_core_session_request ( null_endpoint_interface , SWITCH_CALL_DIRECTION_OUTBOUND , flags , pool ) ) ! = 0 ) {
null_private_t * tech_pvt ;
switch_channel_t * channel ;
switch_caller_profile_t * caller_profile ;
switch_core_session_add_stream ( * new_session , NULL ) ;
if ( ( tech_pvt = ( null_private_t * ) switch_core_session_alloc ( * new_session , sizeof ( null_private_t ) ) ) ! = 0 ) {
2018-12-14 10:52:00 +08:00
const char * rate_ = switch_event_get_header ( var_event , " rate " ) ;
int rate = 0 ;
if ( rate_ ) {
rate = atoi ( rate_ ) ;
}
if ( ! ( rate > 0 & & rate % 8000 = = 0 ) ) {
rate = 8000 ;
}
tech_pvt - > rate = rate ;
2018-09-10 14:32:10 -04:00
channel = switch_core_session_get_channel ( * new_session ) ;
switch_snprintf ( name , sizeof ( name ) , " null/%s " , outbound_profile - > destination_number ) ;
switch_channel_set_name ( channel , name ) ;
if ( null_tech_init ( tech_pvt , * new_session ) ! = SWITCH_STATUS_SUCCESS ) {
switch_core_session_destroy ( new_session ) ;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( * new_session ) , SWITCH_LOG_CRIT , " Hey where is my memory pool? \n " ) ;
switch_core_session_destroy ( new_session ) ;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
if ( outbound_profile ) {
caller_profile = switch_caller_profile_clone ( * new_session , outbound_profile ) ;
caller_profile - > source = switch_core_strdup ( caller_profile - > pool , modname ) ;
switch_snprintf ( name , sizeof ( name ) , " null/%s " , caller_profile - > destination_number ) ;
switch_channel_set_name ( channel , name ) ;
switch_channel_set_caller_profile ( channel , caller_profile ) ;
tech_pvt - > caller_profile = caller_profile ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( * new_session ) , SWITCH_LOG_ERROR , " Doh! no caller profile \n " ) ;
switch_core_session_destroy ( new_session ) ;
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
switch_channel_set_state ( channel , CS_INIT ) ;
switch_channel_set_flag ( channel , CF_AUDIO ) ;
return SWITCH_CAUSE_SUCCESS ;
}
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
static switch_state_handler_table_t null_channel_event_handlers = {
/*.on_init */ null_channel_on_init ,
/*.on_routing */ NULL ,
/*.on_execute */ NULL ,
/*.on_hangup */ NULL ,
/*.on_exchange_media */ NULL ,
/*.on_soft_execute */ NULL ,
/*.on_consume_media */ null_channel_on_consume_media ,
/*.on_hibernate */ NULL ,
/*.on_reset */ NULL ,
/*.on_park */ NULL ,
/*.on_reporting */ NULL ,
/*.on_destroy */ null_channel_on_destroy
} ;
static switch_io_routines_t null_channel_io_routines = {
/*.outgoing_channel */ null_channel_outgoing_channel ,
/*.read_frame */ null_channel_read_frame ,
/*.write_frame */ null_channel_write_frame ,
/*.kill_channel */ null_channel_kill_channel ,
/*.send_dtmf */ null_channel_send_dtmf ,
/*.receive_message */ null_channel_receive_message
} ;
2018-04-24 04:36:01 +01:00
switch_status_t load_loopback_configuration ( switch_bool_t reload )
{
switch_xml_t xml = NULL , x_lists = NULL , x_list = NULL , cfg = NULL ;
switch_status_t status = SWITCH_STATUS_FALSE ;
memset ( & loopback_globals , 0 , sizeof ( loopback_globals ) ) ;
loopback_globals . bowout_hangup_cause = SWITCH_CAUSE_NORMAL_UNSPECIFIED ;
if ( ( xml = switch_xml_open_cfg ( " loopback.conf " , & cfg , NULL ) ) ) {
status = SWITCH_STATUS_SUCCESS ;
if ( ( x_lists = switch_xml_child ( cfg , " settings " ) ) ) {
for ( x_list = switch_xml_child ( x_lists , " param " ) ; x_list ; x_list = x_list - > next ) {
const char * name = switch_xml_attr ( x_list , " name " ) ;
const char * value = switch_xml_attr ( x_list , " value " ) ;
if ( zstr ( name ) ) {
continue ;
}
if ( zstr ( value ) ) {
continue ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s = %s \n " , name , value ) ;
if ( ! strcmp ( name , " early-set-loopback-id " ) ) {
loopback_globals . early_set_loopback_id = switch_true ( value ) ;
} else if ( ! strcmp ( name , " fire-bowout-on-bridge " ) ) {
loopback_globals . fire_bowout_event_bridge = switch_true ( value ) ;
} else if ( ! strcmp ( name , " ignore-channel-ready " ) ) {
loopback_globals . ignore_channel_ready = switch_true ( value ) ;
} else if ( ! strcmp ( name , " bowout-hangup-cause " ) ) {
loopback_globals . bowout_hangup_cause = switch_channel_str2cause ( value ) ;
} else if ( ! strcmp ( name , " bowout-controlled-hangup " ) ) {
loopback_globals . bowout_controlled_hangup = switch_true ( value ) ;
} else if ( ! strcmp ( name , " bowout-transfer-recording " ) ) {
loopback_globals . bowout_transfer_recordings = switch_true ( value ) ;
2019-04-02 17:01:36 +01:00
} else if ( ! strcmp ( name , " bowout-disable-on-inner-bridge " ) ) {
loopback_globals . bowout_disable_on_inner_bridge = switch_true ( value ) ;
2018-04-24 04:36:01 +01:00
}
}
}
switch_xml_free ( xml ) ;
}
return status ;
}
static void loopback_reload_xml_event_handler ( switch_event_t * event )
{
load_loopback_configuration ( 1 ) ;
}
2018-09-10 14:32:10 -04:00
2008-09-23 21:44:18 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_loopback_load )
{
2012-10-31 12:56:09 -05:00
switch_application_interface_t * app_interface ;
2008-09-23 21:44:18 +00:00
2015-09-21 18:00:14 -05:00
if ( switch_event_reserve_subclass ( " loopback::bowout " ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't register subclass %s! \n " , " loopback::bowout " ) ;
return SWITCH_STATUS_TERM ;
}
2018-04-24 04:36:01 +01:00
if ( switch_event_reserve_subclass ( " loopback::direct " ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't register subclass %s! \n " , " loopback::direct " ) ;
return SWITCH_STATUS_TERM ;
}
2017-01-06 02:10:15 -05:00
2018-04-24 04:36:01 +01:00
load_loopback_configuration ( 0 ) ;
2008-09-23 21:44:18 +00:00
/* connect my internal structure to the blank pointer passed to me */
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
loopback_endpoint_interface = switch_loadable_module_create_interface ( * module_interface , SWITCH_ENDPOINT_INTERFACE ) ;
loopback_endpoint_interface - > interface_name = " loopback " ;
loopback_endpoint_interface - > io_routines = & channel_io_routines ;
loopback_endpoint_interface - > state_handler = & channel_event_handlers ;
2018-09-10 14:32:10 -04:00
null_endpoint_interface = switch_loadable_module_create_interface ( * module_interface , SWITCH_ENDPOINT_INTERFACE ) ;
null_endpoint_interface - > interface_name = " null " ;
null_endpoint_interface - > io_routines = & null_channel_io_routines ;
null_endpoint_interface - > state_handler = & null_channel_event_handlers ;
2012-10-31 13:02:03 -05:00
SWITCH_ADD_APP ( app_interface , " unloop " , " Tell loopback to unfold " , " Tell loopback to unfold " , unloop_function , " " , SAF_NO_LOOPBACK ) ;
2018-04-24 04:36:01 +01:00
if ( ( switch_event_bind ( modname , SWITCH_EVENT_RELOADXML , NULL , loopback_reload_xml_event_handler , NULL ) ! = SWITCH_STATUS_SUCCESS ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't bind our reloadxml handler! \n " ) ;
/* Not such severe to prevent loading */
}
2008-09-23 21:44:18 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_loopback_shutdown )
{
2015-09-21 18:00:14 -05:00
switch_event_free_subclass ( " loopback::bowout " ) ;
2018-04-24 04:36:01 +01:00
switch_event_free_subclass ( " loopback::direct " ) ;
2019-05-16 13:52:33 +01:00
switch_event_unbind_callback ( loopback_reload_xml_event_handler ) ;
2017-01-06 02:10:15 -05:00
2008-09-23 21:44:18 +00:00
return SWITCH_STATUS_SUCCESS ;
}
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2013-06-25 11:50:17 -05:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet :
2008-09-23 21:44:18 +00:00
*/