Merge branch 'master' of git://git.freeswitch.org/freeswitch into netborder
This commit is contained in:
commit
14e931ffbb
|
@ -33,6 +33,12 @@
|
|||
*.ilk
|
||||
*.bsc
|
||||
*.pch
|
||||
*.tar
|
||||
*.gz
|
||||
*.tgz
|
||||
*.xz
|
||||
*.bz2
|
||||
*.tbz2
|
||||
core.*
|
||||
/Path
|
||||
/w32/Library/lastversion
|
||||
|
@ -79,7 +85,6 @@ configure.lineno
|
|||
/scripts/fsxs
|
||||
/scripts/gentls_cert
|
||||
/a.out.dSYM
|
||||
/freeswitch-sounds-*
|
||||
src/mod/applications/mod_easyroute/Makefile
|
||||
src/mod/applications/mod_lcr/Makefile
|
||||
src/mod/applications/mod_nibblebill/Makefile
|
||||
|
|
|
@ -349,7 +349,7 @@ scripts/fsxs: scripts/fsxs.in
|
|||
-e "s|@INCLUDES\@|-I$(prefix)/include|" \
|
||||
-e "s|@SOLINK\@|$(SOLINK)|" \
|
||||
-e "s|@LDFLAGS\@|-L$(prefix)/lib|" \
|
||||
-e "s|@LIBS\@|`./libs/apr/apr-1-config --libs` `./libs/apr-util/apu-1-config --libs`|" \
|
||||
-e "s|@LIBS\@||" \
|
||||
$(top_srcdir)/scripts/fsxs.in > scripts/fsxs
|
||||
|
||||
##
|
||||
|
|
|
@ -78,6 +78,7 @@ event_handlers/mod_cdr_sqlite
|
|||
#event_handlers/mod_cdr_pg_csv
|
||||
#event_handlers/mod_radius_cdr
|
||||
#event_handlers/mod_erlang_event
|
||||
#event_handlers/mod_snmp
|
||||
formats/mod_native_file
|
||||
formats/mod_sndfile
|
||||
#formats/mod_shout
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
<!-- IP or Hostname of Default Route -->
|
||||
<param name="default-gateway" value="192.168.66.6"/>
|
||||
|
||||
<!-- Number of times to retry ODBC connection on connection problems, default is 120 -->
|
||||
<param name="odbc-retries" value="120"/>
|
||||
|
||||
<!-- Customer Query. Use this with Care!!! We are not responsible if you mess
|
||||
This up!!! Query *MUST* return columns in the following order!
|
||||
gateway varchar(128) - contains destination gateway host:port pair (ex: 192.168.1.1:5060 )
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<load module="mod_event_socket"/>
|
||||
<!-- <load module="mod_zeroconf"/> -->
|
||||
<!-- <load module="mod_erlang_event"/> -->
|
||||
<!-- <load module="mod_snmp"/> -->
|
||||
|
||||
<!-- Directory Interfaces -->
|
||||
<!-- <load module="mod_ldap"/> -->
|
||||
|
|
|
@ -11,3 +11,12 @@
|
|||
cannot be shown to end users, we already provide extensive logging for problem
|
||||
troubleshooting.
|
||||
|
||||
- Implement threaded IO.
|
||||
Currently IO modules only work on-demand, where the user (ie, FreeSWITCH) drives the read/write
|
||||
of media. If the user stops reading, some functions are not possible
|
||||
(DTMF detection or Hangup tone detection). It would be useful to implement a FreeTDM mode
|
||||
where the media is driven by a group of threads that are always reading (and possibly writing)
|
||||
then when the user does ftdm_channel_read(), the media would be read from the buffers filled
|
||||
by the media thread and not from the underlying IO device, this gives a chance to FreeTDM to
|
||||
still perform hangup detection or other media services even if the application is not reading.
|
||||
|
||||
|
|
|
@ -188,6 +188,7 @@
|
|||
<ClInclude Include="..\src\include\ftdm_os.h" />
|
||||
<ClInclude Include="..\src\include\private\ftdm_sched.h" />
|
||||
<ClInclude Include="..\src\include\ftdm_threadmutex.h" />
|
||||
<ClInclude Include="..\src\include\private\ftdm_state.h" />
|
||||
<ClInclude Include="..\src\include\private\ftdm_types.h" />
|
||||
<ClInclude Include="..\src\include\private\g711.h" />
|
||||
<ClInclude Include="..\src\include\private\hashtable.h" />
|
||||
|
@ -209,6 +210,7 @@
|
|||
<ClCompile Include="..\src\ftdm_io.c" />
|
||||
<ClCompile Include="..\src\ftdm_queue.c" />
|
||||
<ClCompile Include="..\src\ftdm_sched.c" />
|
||||
<ClCompile Include="..\src\ftdm_state.c" />
|
||||
<ClCompile Include="..\src\ftdm_threadmutex.c" />
|
||||
<ClCompile Include="..\src\g711.c" />
|
||||
<ClCompile Include="..\src\hashtable.c" />
|
||||
|
|
|
@ -71,6 +71,9 @@
|
|||
<ClInclude Include="..\src\include\private\uart.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\include\private\ftdm_state.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\fsk.c">
|
||||
|
@ -124,5 +127,8 @@
|
|||
<ClCompile Include="..\src\uart.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\ftdm_state.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -676,6 +676,9 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
|
|||
/*OUTBOUND...so we were told by the line of this so noifiy the user*/
|
||||
sigev.event_id = FTDM_SIGEVENT_PROCEED;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
|
||||
}
|
||||
} else {
|
||||
if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
|
||||
/* By default, we do not send a progress indicator in the proceed */
|
||||
|
|
|
@ -112,6 +112,11 @@ typedef enum {
|
|||
SNGISDN_OPT_FALSE = 2,
|
||||
} sngisdn_opt_t;
|
||||
|
||||
typedef enum {
|
||||
SNGISDN_EARLY_MEDIA_ON_PROCEED = (1 << 0),
|
||||
SNGISDN_EARLY_MEDIA_ON_PROGRESS = (1 << 1),
|
||||
SNGISDN_EARLY_MEDIA_ON_ALERT= (1 << 2),
|
||||
} sngisdn_early_media_opt_t;
|
||||
|
||||
typedef enum {
|
||||
SNGISDN_AVAIL_DOWN = 1,
|
||||
|
@ -188,7 +193,8 @@ typedef struct sngisdn_span_data {
|
|||
uint8_t span_id;
|
||||
uint8_t tei;
|
||||
uint8_t min_digits;
|
||||
uint8_t trace_flags; /* TODO: change to flags, so we can use ftdm_test_flag etc.. */
|
||||
uint8_t trace_flags; /* TODO change to bit map of sngisdn_tracetype_t */
|
||||
uint8_t early_media_flags; /* bit map of ftdm_sngisdn_early_media_opt_t */
|
||||
uint8_t overlap_dial;
|
||||
uint8_t setup_arb;
|
||||
uint8_t facility_ie_decode;
|
||||
|
@ -196,10 +202,10 @@ typedef struct sngisdn_span_data {
|
|||
int8_t facility_timeout;
|
||||
uint8_t num_local_numbers;
|
||||
uint8_t ignore_cause_value;
|
||||
uint8_t raw_trace_q931;
|
||||
uint8_t raw_trace_q921;
|
||||
uint8_t raw_trace_q931; /* TODO: combine with trace_flags */
|
||||
uint8_t raw_trace_q921; /* TODO: combine with trace_flags */
|
||||
uint8_t timer_t3;
|
||||
uint8_t restart_opt;
|
||||
uint8_t restart_opt;
|
||||
char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS];
|
||||
ftdm_sched_t *sched;
|
||||
ftdm_queue_t *event_queue;
|
||||
|
|
|
@ -192,6 +192,24 @@ static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span)
|
|||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static ftdm_status_t parse_early_media(const char* opt, ftdm_span_t *span)
|
||||
{
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
|
||||
if (!strcasecmp(opt, "on-proceed")) {
|
||||
signal_data->early_media_flags |= SNGISDN_EARLY_MEDIA_ON_PROCEED;
|
||||
} else if (!strcasecmp(opt, "on-progress")) {
|
||||
signal_data->early_media_flags |= SNGISDN_EARLY_MEDIA_ON_PROGRESS;
|
||||
} else if (!strcasecmp(opt, "on-alert")) {
|
||||
signal_data->early_media_flags |= SNGISDN_EARLY_MEDIA_ON_ALERT;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unsupported early-media option %s\n", opt);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Early media opt:0x%x\n", signal_data->early_media_flags);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static ftdm_status_t set_switchtype_defaults(ftdm_span_t *span)
|
||||
{
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
|
||||
|
@ -249,6 +267,7 @@ static ftdm_status_t set_switchtype_defaults(ftdm_span_t *span)
|
|||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span)
|
||||
{
|
||||
unsigned paramindex;
|
||||
|
@ -351,10 +370,14 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
|||
parse_yesno(var, val, &signal_data->raw_trace_q931);
|
||||
} else if (!strcasecmp(var, "q921-raw-trace")) {
|
||||
parse_yesno(var, val, &signal_data->raw_trace_q921);
|
||||
} else if (!strcasecmp(var, "early-media-override")) {
|
||||
if (parse_early_media(val, span) != FTDM_SUCCESS) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
|
||||
}
|
||||
}
|
||||
} /* for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) */
|
||||
|
||||
if (signal_data->switchtype == SNGISDN_SWITCH_INVALID) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%s: switchtype not specified", span->name);
|
||||
|
@ -366,10 +389,11 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
|||
}
|
||||
|
||||
if (span->default_caller_data.bearer_layer1 == FTDM_INVALID_INT_PARM) {
|
||||
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
|
||||
span->default_caller_data.bearer_layer1 = IN_UIL1_G711ULAW;
|
||||
} else {
|
||||
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN ||
|
||||
signal_data->switchtype == SNGISDN_SWITCH_QSIG) {
|
||||
span->default_caller_data.bearer_layer1 = IN_UIL1_G711ALAW;
|
||||
} else {
|
||||
span->default_caller_data.bearer_layer1 = IN_UIL1_G711ULAW;
|
||||
}
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
|
|
|
@ -167,12 +167,12 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
|
|||
char retrieved_str[255];
|
||||
|
||||
ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
|
||||
/*
|
||||
return values for "sng_isdn_retrieve_facility_information_following":
|
||||
If there will be no information following, or fails to decode IE, returns -1
|
||||
If there will be no information following, but current FACILITY IE contains a caller name, returns 0
|
||||
If there will be information following, returns 1
|
||||
*/
|
||||
/*
|
||||
return values for "sng_isdn_retrieve_facility_information_following":
|
||||
If there will be no information following, or fails to decode IE, returns -1
|
||||
If there will be no information following, but current FACILITY IE contains a caller name, returns 0
|
||||
If there will be information following, returns 1
|
||||
*/
|
||||
|
||||
if (ret_val == 1) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
|
||||
|
@ -346,6 +346,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
|
|||
|
||||
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
|
||||
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
|
||||
|
||||
CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt;
|
||||
|
||||
|
@ -384,7 +385,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
|
|||
case FTDM_CHANNEL_STATE_DIALING:
|
||||
case FTDM_CHANNEL_STATE_PROCEED:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media available\n");
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
|
||||
|
@ -393,16 +394,34 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
|
|||
}
|
||||
switch (evntType) {
|
||||
case MI_CALLPROC:
|
||||
if (!sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY) &&
|
||||
(signal_data->early_media_flags & SNGISDN_EARLY_MEDIA_ON_PROCEED)) {
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media override on proceed\n");
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
|
||||
}
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED);
|
||||
}
|
||||
break;
|
||||
case MI_ALERTING:
|
||||
if (!sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY) &&
|
||||
(signal_data->early_media_flags & SNGISDN_EARLY_MEDIA_ON_ALERT)) {
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media override on alert\n");
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
|
||||
}
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_PROCEED) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RINGING);
|
||||
}
|
||||
break;
|
||||
case MI_PROGRESS:
|
||||
if (!sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY) &&
|
||||
(signal_data->early_media_flags & SNGISDN_EARLY_MEDIA_ON_PROGRESS)) {
|
||||
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media override on progress\n");
|
||||
sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
|
||||
}
|
||||
if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
|
||||
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_PROGRESS) {
|
||||
|
|
|
@ -873,29 +873,32 @@ ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap)
|
|||
bearCap->tranMode.pres = PRSNT_NODEF;
|
||||
bearCap->tranMode.val = IN_TM_CIRCUIT;
|
||||
|
||||
if (!FTDM_SPAN_IS_BRI(ftdmchan->span)) {
|
||||
/* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it.
|
||||
Check with Trillium if this ever causes calls to fail in the field */
|
||||
bearCap->usrInfoLyr1Prot.pres = PRSNT_NODEF;
|
||||
bearCap->usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1);
|
||||
|
||||
/* PRI only params */
|
||||
bearCap->usrInfoLyr1Prot.pres = PRSNT_NODEF;
|
||||
bearCap->usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1);
|
||||
|
||||
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN &&
|
||||
bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) {
|
||||
|
||||
/* We are bridging a call from T1 */
|
||||
bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
|
||||
|
||||
} else if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) {
|
||||
|
||||
/* We are bridging a call from E1 */
|
||||
bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
|
||||
}
|
||||
|
||||
bearCap->lyr1Ident.pres = PRSNT_NODEF;
|
||||
bearCap->lyr1Ident.val = IN_L1_IDENT;
|
||||
switch (signal_data->switchtype) {
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_DMS100:
|
||||
case SNGISDN_SWITCH_INSNET:
|
||||
if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Overriding bearer cap to u-law\n");
|
||||
bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
|
||||
}
|
||||
break;
|
||||
case SNGISDN_SWITCH_EUROISDN:
|
||||
case SNGISDN_SWITCH_QSIG:
|
||||
if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Overriding bearer cap to a-law\n");
|
||||
bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bearCap->lyr1Ident.pres = PRSNT_NODEF;
|
||||
bearCap->lyr1Ident.val = IN_L1_IDENT;
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -664,6 +664,8 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case FTDM_COMMAND_DISABLE_ECHOTRAIN: { err = 0; }
|
||||
break;
|
||||
case FTDM_COMMAND_ENABLE_DTMF_DETECT:
|
||||
{
|
||||
#ifdef WP_API_FEATURE_DTMF_EVENTS
|
||||
|
|
|
@ -83,11 +83,18 @@ AC_ARG_ENABLE(64,
|
|||
|
||||
if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
|
||||
if test "${enable_64}" = "yes"; then
|
||||
CFLAGS="$CFLAGS -m64"
|
||||
CXXFLAGS="$CXXFLAGS -m64 -lgpg-error"
|
||||
CFLAGS="$CFLAGS -xc99=all -mt -m64 -lgpg-error"
|
||||
CXXFLAGS="$CXXFLAGS -xc99=all -mt -m64 -lgpg-error"
|
||||
SUNFLAGS="-xc99=all -mt -m64 -lgpg-error"
|
||||
else
|
||||
CFLAGS="$CFLAGS -xc99=all -mt -lgpg-error"
|
||||
CXXFLAGS="$CXXFLAGS -xc99=all -mt -lgpg-error"
|
||||
SUNFLAGS="-xc99=all -mt -lgpg-error"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(SUNCFLAGS)
|
||||
|
||||
dnl Generating makefiles
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
|
|
|
@ -25,5 +25,5 @@ libiksemel_la_SOURCES = \
|
|||
base64.c
|
||||
|
||||
libiksemel_la_LDFLAGS = -version-info 4:0:1 -no-undefined
|
||||
libiksemel_la_CFLAGS = $(CFLAGS) $(LIBGNUTLS_CFLAGS)
|
||||
libiksemel_la_LIBADD = $(LIBGNUTLS_LIBS)
|
||||
libiksemel_la_CFLAGS = $(CFLAGS) $(LIBGNUTLS_CFLAGS)
|
||||
libiksemel_la_LIBADD = $(LIBGNUTLS_LIBS)
|
||||
|
|
|
@ -8,11 +8,11 @@ bin_PROGRAMS = ikslint iksroster iksperf
|
|||
|
||||
noinst_HEADERS = perf.h
|
||||
|
||||
ikslint_LDADD = $(top_builddir)/src/libiksemel.la
|
||||
ikslint_LDADD = $(top_builddir)/src/libiksemel.la @SUNCFLAGS@
|
||||
ikslint_SOURCES = ikslint.c hash.c
|
||||
|
||||
iksroster_LDADD = $(top_builddir)/src/libiksemel.la
|
||||
iksroster_LDADD = $(top_builddir)/src/libiksemel.la @SUNCFLAGS@
|
||||
iksroster_SOURCES = iksroster.c
|
||||
|
||||
iksperf_LDADD = $(top_builddir)/src/libiksemel.la
|
||||
iksperf_LDADD = $(top_builddir)/src/libiksemel.la @SUNCFLAGS@
|
||||
iksperf_SOURCES = iksperf.c perf.c
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
exec_prefix=@prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
|
|
|
@ -61,12 +61,7 @@ while ($sock->recv($newmsg, 1024)) {
|
|||
}
|
||||
print "Sending option 66 as $opt_u\n";
|
||||
|
||||
$handle = IO::Socket::INET->new(Proto => 'udp',
|
||||
PeerPort => '68',
|
||||
LocalPort => '67',
|
||||
ReuseAddr => 1,
|
||||
PeerAddr => $dhcpreq->ciaddr(),
|
||||
) or die "socket: $@";
|
||||
$handle->send($dhcpresp->serialize())
|
||||
|
||||
$sock->send($dhcpresp->serialize())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ static inline char switch_itodtmf(char i)
|
|||
r = i + 55;
|
||||
}
|
||||
|
||||
return r;
|
||||
return r + 48;
|
||||
}
|
||||
|
||||
static inline int switch_dtmftoi(char *s)
|
||||
|
|
|
@ -2372,7 +2372,7 @@ SWITCH_STANDARD_API(uuid_media_function)
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BROADCAST_SYNTAX "<uuid> <path> [aleg|bleg|both]"
|
||||
#define BROADCAST_SYNTAX "<uuid> <path> [aleg|bleg|holdb|both]"
|
||||
SWITCH_STANDARD_API(uuid_broadcast_function)
|
||||
{
|
||||
char *mycmd = NULL, *argv[4] = { 0 };
|
||||
|
@ -2389,15 +2389,26 @@ SWITCH_STANDARD_API(uuid_broadcast_function)
|
|||
switch_media_flag_t flags = SMF_NONE;
|
||||
|
||||
if (argv[2]) {
|
||||
if (!strcasecmp(argv[2], "both")) {
|
||||
if (switch_stristr("both", (argv[2]))) {
|
||||
flags |= (SMF_ECHO_ALEG | SMF_ECHO_BLEG);
|
||||
} else if (!strcasecmp(argv[2], "aleg")) {
|
||||
}
|
||||
|
||||
if (switch_stristr("aleg", argv[2])) {
|
||||
flags |= SMF_ECHO_ALEG;
|
||||
} else if (!strcasecmp(argv[2], "bleg")) {
|
||||
}
|
||||
|
||||
if (switch_stristr("bleg", argv[2])) {
|
||||
flags &= ~SMF_HOLD_BLEG;
|
||||
flags |= SMF_ECHO_BLEG;
|
||||
}
|
||||
|
||||
if (switch_stristr("holdb", argv[2])) {
|
||||
flags &= ~SMF_ECHO_BLEG;
|
||||
flags |= SMF_HOLD_BLEG;
|
||||
}
|
||||
|
||||
} else {
|
||||
flags |= SMF_ECHO_ALEG;
|
||||
flags = SMF_ECHO_ALEG | SMF_HOLD_BLEG;
|
||||
}
|
||||
|
||||
status = switch_ivr_broadcast(argv[0], argv[1], flags);
|
||||
|
|
|
@ -152,7 +152,8 @@ typedef enum {
|
|||
CFLAG_BRIDGE_TO = (1 << 6),
|
||||
CFLAG_WAIT_MOD = (1 << 7),
|
||||
CFLAG_VID_FLOOR = (1 << 8),
|
||||
CFLAG_WASTE_BANDWIDTH = (1 << 9)
|
||||
CFLAG_WASTE_BANDWIDTH = (1 << 9),
|
||||
CFLAG_OUTCALL = (1 << 10)
|
||||
} conf_flag_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -288,6 +289,8 @@ typedef struct conference_obj {
|
|||
uint32_t avg_tally;
|
||||
switch_time_t run_time;
|
||||
char *uuid_str;
|
||||
uint32_t originating;
|
||||
switch_call_cause_t cancel_cause;
|
||||
} conference_obj_t;
|
||||
|
||||
/* Relationship with another member */
|
||||
|
@ -395,11 +398,16 @@ SWITCH_STANDARD_API(conf_api_main);
|
|||
static switch_status_t conference_outcall(conference_obj_t *conference,
|
||||
char *conference_name,
|
||||
switch_core_session_t *session,
|
||||
char *bridgeto, uint32_t timeout, char *flags, char *cid_name, char *cid_num, switch_call_cause_t *cause);
|
||||
char *bridgeto, uint32_t timeout,
|
||||
char *flags,
|
||||
char *cid_name,
|
||||
char *cid_num,
|
||||
switch_call_cause_t *cause,
|
||||
switch_call_cause_t *cancel_cause);
|
||||
static switch_status_t conference_outcall_bg(conference_obj_t *conference,
|
||||
char *conference_name,
|
||||
switch_core_session_t *session, char *bridgeto, uint32_t timeout, const char *flags, const char *cid_name,
|
||||
const char *cid_num, const char *call_uuid);
|
||||
const char *cid_num, const char *call_uuid, switch_call_cause_t *cancel_cause);
|
||||
SWITCH_STANDARD_APP(conference_function);
|
||||
static void launch_conference_thread(conference_obj_t *conference);
|
||||
static void launch_conference_video_thread(conference_obj_t *conference);
|
||||
|
@ -477,6 +485,7 @@ static switch_status_t conference_add_event_member_data(conference_member_t *mem
|
|||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" );
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-ID", "%u", member->id);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Type", "%s", switch_test_flag(member, MFLAG_MOD) ? "moderator" : "member");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Energy-Level", "%d", member->energy_level);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -1380,6 +1389,14 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
|||
/* Rinse ... Repeat */
|
||||
end:
|
||||
|
||||
if (switch_test_flag(conference, CFLAG_OUTCALL)) {
|
||||
conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Ending pending outcall channels for Conference: '%s'\n", conference->name);
|
||||
while(conference->originating) {
|
||||
switch_yield(200000);
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", CONF_CHAT_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", conference->name);
|
||||
|
@ -2403,6 +2420,8 @@ static void conference_loop_output(conference_member_t *member)
|
|||
|
||||
switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
|
||||
|
||||
switch_set_flag(member->conference, CFLAG_OUTCALL);
|
||||
|
||||
if (toval) {
|
||||
to = atoi(toval);
|
||||
if (to < 10 || to > 500) {
|
||||
|
@ -2421,7 +2440,8 @@ static void conference_loop_output(conference_member_t *member)
|
|||
for (x = 0; x < argc; x++) {
|
||||
char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
|
||||
switch_assert(dial_str);
|
||||
conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL);
|
||||
conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL,
|
||||
&member->conference->cancel_cause);
|
||||
switch_safe_free(dial_str);
|
||||
}
|
||||
switch_safe_free(cpstr);
|
||||
|
@ -4243,9 +4263,9 @@ static switch_status_t conf_api_sub_dial(conference_obj_t *conference, switch_st
|
|||
}
|
||||
|
||||
if (conference) {
|
||||
conference_outcall(conference, NULL, NULL, argv[2], 60, NULL, argv[4], argv[3], &cause);
|
||||
conference_outcall(conference, NULL, NULL, argv[2], 60, NULL, argv[4], argv[3], &cause, NULL);
|
||||
} else {
|
||||
conference_outcall(NULL, argv[0], NULL, argv[2], 60, NULL, argv[4], argv[3], &cause);
|
||||
conference_outcall(NULL, argv[0], NULL, argv[2], 60, NULL, argv[4], argv[3], &cause, NULL);
|
||||
}
|
||||
stream->write_function(stream, "Call Requested: result: [%s]\n", switch_channel_cause2str(cause));
|
||||
|
||||
|
@ -4268,9 +4288,9 @@ static switch_status_t conf_api_sub_bgdial(conference_obj_t *conference, switch_
|
|||
switch_uuid_format(uuid_str, &uuid);
|
||||
|
||||
if (conference) {
|
||||
conference_outcall_bg(conference, NULL, NULL, argv[2], 60, NULL, argv[4], argv[3], uuid_str);
|
||||
conference_outcall_bg(conference, NULL, NULL, argv[2], 60, NULL, argv[4], argv[3], uuid_str, NULL);
|
||||
} else {
|
||||
conference_outcall_bg(NULL, argv[0], NULL, argv[2], 60, NULL, argv[4], argv[3], uuid_str);
|
||||
conference_outcall_bg(NULL, argv[0], NULL, argv[2], 60, NULL, argv[4], argv[3], uuid_str, NULL);
|
||||
}
|
||||
|
||||
stream->write_function(stream, "OK Job-UUID: %s\n", uuid_str);
|
||||
|
@ -4784,7 +4804,11 @@ SWITCH_STANDARD_API(conf_api_main)
|
|||
static switch_status_t conference_outcall(conference_obj_t *conference,
|
||||
char *conference_name,
|
||||
switch_core_session_t *session,
|
||||
char *bridgeto, uint32_t timeout, char *flags, char *cid_name, char *cid_num, switch_call_cause_t *cause)
|
||||
char *bridgeto, uint32_t timeout,
|
||||
char *flags, char *cid_name,
|
||||
char *cid_num,
|
||||
switch_call_cause_t *cause,
|
||||
switch_call_cause_t *cancel_cause)
|
||||
{
|
||||
switch_core_session_t *peer_session = NULL;
|
||||
switch_channel_t *peer_channel;
|
||||
|
@ -4830,8 +4854,15 @@ static switch_status_t conference_outcall(conference_obj_t *conference,
|
|||
|
||||
/* establish an outbound call leg */
|
||||
|
||||
if (switch_ivr_originate(session, &peer_session, cause, bridgeto, timeout, NULL, cid_name, cid_num, NULL, NULL, SOF_NO_LIMITS, NULL) !=
|
||||
SWITCH_STATUS_SUCCESS) {
|
||||
switch_mutex_lock(conference->mutex);
|
||||
conference->originating++;
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
status = switch_ivr_originate(session, &peer_session, cause, bridgeto, timeout, NULL, cid_name, cid_num, NULL, NULL, SOF_NO_LIMITS, cancel_cause);
|
||||
switch_mutex_lock(conference->mutex);
|
||||
conference->originating--;
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot create outgoing channel, cause: %s\n",
|
||||
switch_channel_cause2str(*cause));
|
||||
if (caller_channel) {
|
||||
|
@ -4908,6 +4939,7 @@ struct bg_call {
|
|||
char *cid_num;
|
||||
char *conference_name;
|
||||
char *uuid;
|
||||
switch_call_cause_t *cancel_cause;
|
||||
switch_memory_pool_t *pool;
|
||||
};
|
||||
|
||||
|
@ -4920,7 +4952,7 @@ static void *SWITCH_THREAD_FUNC conference_outcall_run(switch_thread_t *thread,
|
|||
switch_event_t *event;
|
||||
|
||||
conference_outcall(call->conference, call->conference_name,
|
||||
call->session, call->bridgeto, call->timeout, call->flags, call->cid_name, call->cid_num, &cause);
|
||||
call->session, call->bridgeto, call->timeout, call->flags, call->cid_name, call->cid_num, &cause, call->cancel_cause);
|
||||
|
||||
if (call->conference && test_eflag(call->conference, EFLAG_BGDIAL_RESULT) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
|
@ -4948,7 +4980,7 @@ static void *SWITCH_THREAD_FUNC conference_outcall_run(switch_thread_t *thread,
|
|||
static switch_status_t conference_outcall_bg(conference_obj_t *conference,
|
||||
char *conference_name,
|
||||
switch_core_session_t *session, char *bridgeto, uint32_t timeout, const char *flags, const char *cid_name,
|
||||
const char *cid_num, const char *call_uuid)
|
||||
const char *cid_num, const char *call_uuid, switch_call_cause_t *cancel_cause)
|
||||
{
|
||||
struct bg_call *call = NULL;
|
||||
switch_thread_t *thread;
|
||||
|
@ -4962,6 +4994,7 @@ static switch_status_t conference_outcall_bg(conference_obj_t *conference,
|
|||
call->conference = conference;
|
||||
call->session = session;
|
||||
call->timeout = timeout;
|
||||
call->cancel_cause = cancel_cause;
|
||||
|
||||
if (conference) {
|
||||
pool = conference->pool;
|
||||
|
@ -5664,8 +5697,9 @@ SWITCH_STANDARD_APP(conference_function)
|
|||
|
||||
/* more friendliness */
|
||||
if (conference->bad_pin_sound) {
|
||||
conference_local_play_file(conference, session, conference->bad_pin_sound, 20, pin_buf, sizeof(pin_buf));
|
||||
conference_local_play_file(conference, session, conference->bad_pin_sound, 20, NULL, 0);
|
||||
}
|
||||
switch_channel_flush_dtmf(channel);
|
||||
}
|
||||
pin_retries--;
|
||||
}
|
||||
|
@ -5715,7 +5749,7 @@ SWITCH_STANDARD_APP(conference_function)
|
|||
/* if we're using "bridge:" make an outbound call and bridge it in */
|
||||
if (!zstr(bridgeto) && strcasecmp(bridgeto, "none")) {
|
||||
switch_call_cause_t cause;
|
||||
if (conference_outcall(conference, NULL, session, bridgeto, 60, NULL, NULL, NULL, &cause) != SWITCH_STATUS_SUCCESS) {
|
||||
if (conference_outcall(conference, NULL, session, bridgeto, 60, NULL, NULL, NULL, &cause, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -2982,6 +2982,8 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
|
|||
}
|
||||
}
|
||||
}
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", user);
|
||||
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain);
|
||||
|
||||
if (!dest) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No dial-string available, please check your user directory.\n");
|
||||
|
|
|
@ -65,6 +65,7 @@ static struct {
|
|||
switch_mutex_t *mutex;
|
||||
char *custom_query;
|
||||
switch_odbc_handle_t *master_odbc;
|
||||
int odbc_num_retries;
|
||||
} globals;
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_easyroute_load);
|
||||
|
@ -120,6 +121,8 @@ static switch_status_t load_config(void)
|
|||
set_global_default_gateway(val);
|
||||
} else if (!strcasecmp(var, "custom-query")) {
|
||||
set_global_custom_query(val);
|
||||
} else if (!strcasecmp(var, "odbc-retries")) {
|
||||
globals.odbc_num_retries = atoi(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +146,9 @@ static switch_status_t load_config(void)
|
|||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opened ODBC Database!\n");
|
||||
}
|
||||
if (globals.odbc_num_retries) {
|
||||
switch_odbc_set_num_retries(globals.master_odbc, globals.odbc_num_retries);
|
||||
}
|
||||
if (switch_odbc_handle_connect(globals.master_odbc) != SWITCH_ODBC_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
|
@ -205,7 +211,7 @@ static switch_status_t route_lookup(char *dn, easyroute_results_t *results, int
|
|||
switch_mutex_lock(globals.mutex);
|
||||
}
|
||||
/* Do the Query */
|
||||
if (switch_odbc_handle_callback_exec(globals.master_odbc, sql, route_callback, &pdata, NULL) == SWITCH_ODBC_SUCCESS) {
|
||||
if (globals.master_odbc && switch_odbc_handle_callback_exec(globals.master_odbc, sql, route_callback, &pdata, NULL) == SWITCH_ODBC_SUCCESS) {
|
||||
char tmp_profile[129];
|
||||
char tmp_gateway[129];
|
||||
|
||||
|
@ -418,7 +424,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_easyroute_load)
|
|||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_easyroute_shutdown)
|
||||
{
|
||||
switch_odbc_handle_disconnect(globals.master_odbc);
|
||||
if (globals.master_odbc) {
|
||||
switch_odbc_handle_disconnect(globals.master_odbc);
|
||||
switch_odbc_handle_destroy(&globals.master_odbc);
|
||||
}
|
||||
switch_safe_free(globals.db_username);
|
||||
switch_safe_free(globals.db_password);
|
||||
switch_safe_free(globals.db_dsn);
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#define MAX_FEC_ENTRIES 4
|
||||
#define MAX_FEC_SPAN 4
|
||||
|
||||
#define SPANDSP_EVENT_TXFAXRESULT "spandsp::txfaxresult"
|
||||
#define SPANDSP_EVENT_RXFAXRESULT "spandsp::rxfaxresult"
|
||||
|
||||
/*****************************************************************************
|
||||
OUR DEFINES AND STRUCTS
|
||||
*****************************************************************************/
|
||||
|
@ -305,7 +308,14 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
|
|||
switch_core_session_t *session;
|
||||
switch_channel_t *channel;
|
||||
pvt_t *pvt;
|
||||
char *tmp;
|
||||
char *fax_document_transferred_pages = NULL;
|
||||
char *fax_document_total_pages = NULL;
|
||||
char *fax_image_resolution = NULL;
|
||||
char *fax_image_size = NULL;
|
||||
char *fax_bad_rows = NULL;
|
||||
char *fax_transfer_rate = NULL;
|
||||
char *fax_result_code = NULL;
|
||||
switch_event_t *event;
|
||||
|
||||
pvt = (pvt_t *) user_data;
|
||||
switch_assert(pvt);
|
||||
|
@ -353,13 +363,12 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
|
|||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "==============================================================================\n");
|
||||
|
||||
/*
|
||||
Set our channel variables
|
||||
Set our channel variables, variables are also used in event
|
||||
*/
|
||||
|
||||
tmp = switch_mprintf("%i", result);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_result_code", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_result_code = switch_core_session_sprintf(session, "%i", result);
|
||||
if (fax_result_code) {
|
||||
switch_channel_set_variable(channel, "fax_result_code", fax_result_code);
|
||||
}
|
||||
|
||||
switch_channel_set_variable(channel, "fax_result_text", t30_completion_code_to_str(result));
|
||||
|
@ -368,49 +377,56 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
|
|||
switch_channel_set_variable(channel, "fax_local_station_id", local_ident);
|
||||
switch_channel_set_variable(channel, "fax_remote_station_id", far_ident);
|
||||
|
||||
tmp = switch_mprintf("%i", pvt->app_mode == FUNCTION_TX ? t.pages_tx : t.pages_rx);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_document_transferred_pages", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_document_transferred_pages = switch_core_session_sprintf(session, "%i", pvt->app_mode == FUNCTION_TX ? t.pages_tx : t.pages_rx);
|
||||
if (fax_document_transferred_pages) {
|
||||
switch_channel_set_variable(channel, "fax_document_transferred_pages", fax_document_transferred_pages);
|
||||
}
|
||||
|
||||
tmp = switch_mprintf("%i", t.pages_in_file);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_document_total_pages", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_document_total_pages = switch_core_session_sprintf(session, "%i", t.pages_in_file);
|
||||
if (fax_document_total_pages) {
|
||||
switch_channel_set_variable(channel, "fax_document_total_pages", fax_document_total_pages);
|
||||
}
|
||||
|
||||
tmp = switch_mprintf("%ix%i", t.x_resolution, t.y_resolution);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_image_resolution", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_image_resolution = switch_core_session_sprintf(session, "%ix%i", t.x_resolution, t.y_resolution);
|
||||
if (fax_image_resolution) {
|
||||
switch_channel_set_variable(channel, "fax_image_resolution", fax_image_resolution);
|
||||
}
|
||||
|
||||
tmp = switch_mprintf("%d", t.image_size);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_image_size", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_image_size = switch_core_session_sprintf(session, "%d", t.image_size);
|
||||
if (fax_image_size) {
|
||||
switch_channel_set_variable(channel, "fax_image_size", fax_image_size);
|
||||
}
|
||||
|
||||
tmp = switch_mprintf("%d", t.bad_rows);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_bad_rows", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_bad_rows = switch_core_session_sprintf(session, "%d", t.bad_rows);
|
||||
if (fax_bad_rows) {
|
||||
switch_channel_set_variable(channel, "fax_bad_rows", fax_bad_rows);
|
||||
}
|
||||
|
||||
tmp = switch_mprintf("%i", t.bit_rate);
|
||||
if (tmp) {
|
||||
switch_channel_set_variable(channel, "fax_transfer_rate", tmp);
|
||||
switch_safe_free(tmp);
|
||||
fax_transfer_rate = switch_core_session_sprintf(session, "%i", t.bit_rate);
|
||||
if (fax_transfer_rate) {
|
||||
switch_channel_set_variable(channel, "fax_transfer_rate", fax_transfer_rate);
|
||||
}
|
||||
|
||||
/* switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); */
|
||||
|
||||
pvt->done = 1;
|
||||
|
||||
/*
|
||||
TODO Fire events
|
||||
*/
|
||||
/* Fire event */
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, pvt->app_mode == FUNCTION_TX ? SPANDSP_EVENT_TXFAXRESULT : SPANDSP_EVENT_RXFAXRESULT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-document-transferred-pages", fax_document_transferred_pages);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-document-total-pages", fax_document_total_pages);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-image-resolution", fax_image_resolution);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-image-size", fax_image_size);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-bad-rows", fax_bad_rows);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-transfer-rate", fax_transfer_rate);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-result-code", fax_result_code);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-result-text", t30_completion_code_to_str(result));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-ecm-used", (t.error_correcting_mode) ? "on" : "off");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-local-station-id", local_ident);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-station-id", far_ident);
|
||||
switch_core_session_queue_private_event(session, &event, SWITCH_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
|
||||
|
@ -1026,7 +1042,6 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
|
|||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Fax TX filename not set.\n");
|
||||
goto done;
|
||||
} else if (pvt->app_mode == FUNCTION_RX) {
|
||||
char *fname;
|
||||
const char *prefix;
|
||||
switch_time_t time;
|
||||
|
||||
|
@ -1036,11 +1051,7 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
|
|||
prefix = globals.prepend_string;
|
||||
}
|
||||
|
||||
fname = switch_mprintf("%s/%s-%ld-%ld.tif", globals.spool, prefix, globals.total_sessions, time);
|
||||
if (fname) {
|
||||
pvt->filename = switch_core_session_strdup(session, fname);
|
||||
switch_safe_free(fname);
|
||||
} else {
|
||||
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%ld.tif", globals.spool, prefix, globals.total_sessions, time))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot automatically set fax RX destination file\n");
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ static switch_status_t switch_celt_init(switch_codec_t *codec, switch_codec_flag
|
|||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
context->mode_object = celt_mode_create(codec->implementation->actual_samples_per_second, codec->implementation->samples_per_packet, NULL);
|
||||
|
||||
context->frame_size = codec->implementation->samples_per_packet;
|
||||
context->mode_object = celt_mode_create(codec->implementation->actual_samples_per_second, context->frame_size, NULL);
|
||||
context->bytes_per_packet = (codec->implementation->bits_per_second * context->frame_size / codec->implementation->actual_samples_per_second + 4) / 8;
|
||||
|
||||
/*
|
||||
|
@ -106,15 +106,22 @@ static switch_status_t switch_celt_encode(switch_codec_t *codec,
|
|||
unsigned int *flag)
|
||||
{
|
||||
struct celt_context *context = codec->private_info;
|
||||
int bytes = 0;
|
||||
|
||||
if (!context) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
*encoded_data_len = (uint32_t) celt_encode(context->encoder_object, (void *) decoded_data, codec->implementation->samples_per_packet,
|
||||
(unsigned char *) encoded_data, context->bytes_per_packet);
|
||||
bytes = (uint32_t) celt_encode(context->encoder_object, (void *) decoded_data, codec->implementation->samples_per_packet,
|
||||
(unsigned char *) encoded_data, context->bytes_per_packet);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
if (bytes > 0) {
|
||||
*encoded_data_len = (uint32_t) bytes;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
static switch_status_t switch_celt_decode(switch_codec_t *codec,
|
||||
|
@ -152,23 +159,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_celt_load)
|
|||
|
||||
SWITCH_ADD_CODEC(codec_interface, "CELT ultra-low delay");
|
||||
|
||||
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
|
||||
114, /* the IANA code number */
|
||||
"CELT", /* the IANA code name */
|
||||
NULL, /* default fmtp to send (can be overridden by the init function) */
|
||||
32000, /* samples transferred per second */
|
||||
32000, /* actual samples transferred per second */
|
||||
32000, /* bits transferred per second */
|
||||
10000, /* number of microseconds per frame */
|
||||
320, /* number of samples per frame */
|
||||
640, /* number of bytes per frame decompressed */
|
||||
0, /* number of bytes per frame compressed */
|
||||
1, /* number of channels represented */
|
||||
1, /* number of frames per network packet */
|
||||
switch_celt_init, /* function to initialize a codec handle using this implementation */
|
||||
switch_celt_encode, /* function to encode raw data into encoded data */
|
||||
switch_celt_decode, /* function to decode encoded data into raw data */
|
||||
switch_celt_destroy); /* deinitalize a codec handle using this implementation */
|
||||
ms_per_frame = 2000;
|
||||
samples_per_frame = 96;
|
||||
bytes_per_frame = 192;
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
!/gsmlib/gsmlib-*/aclocal.m4
|
||||
!/gsmlib/gsmlib-*/configure
|
||||
!/gsmlib/gsmlib-1.10.tar.gz
|
||||
!/gsmlib/gsmlib_1.10-12ubuntu1.diff.gz
|
||||
|
|
|
@ -77,11 +77,11 @@ struct private_object {
|
|||
|
||||
switch_frame_t cng_frame;
|
||||
unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
switch_timer_t timer;
|
||||
switch_caller_profile_t *caller_profile;
|
||||
int32_t bowout_frame_count;
|
||||
char *other_uuid;
|
||||
switch_queue_t *frame_queue;
|
||||
switch_codec_implementation_t read_impl;
|
||||
};
|
||||
|
||||
typedef struct private_object private_t;
|
||||
|
@ -111,7 +111,6 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
|
|||
int 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;
|
||||
|
||||
if (codec) {
|
||||
iananame = codec->implementation->iananame;
|
||||
|
@ -166,15 +165,7 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
|
|||
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
|
||||
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
|
||||
|
||||
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));
|
||||
|
||||
tech_pvt->read_impl = *tech_pvt->read_codec.implementation;
|
||||
|
||||
if (!tech_pvt->flag_mutex) {
|
||||
switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
|
||||
|
@ -376,7 +367,6 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
|
|||
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);
|
||||
|
@ -568,12 +558,10 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
|||
goto end;
|
||||
}
|
||||
|
||||
switch_core_timer_next(&tech_pvt->timer);
|
||||
|
||||
mutex = tech_pvt->mutex;
|
||||
switch_mutex_lock(mutex);
|
||||
|
||||
if (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
|
||||
if (switch_queue_pop_timeout(tech_pvt->frame_queue, &pop, tech_pvt->read_impl.microseconds_per_packet) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
if (tech_pvt->write_frame) {
|
||||
switch_frame_free(&tech_pvt->write_frame);
|
||||
}
|
||||
|
@ -585,6 +573,8 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
|||
switch_set_flag(tech_pvt, TFLAG_CNG);
|
||||
}
|
||||
|
||||
switch_mutex_lock(mutex);
|
||||
|
||||
if (switch_test_flag(tech_pvt, TFLAG_CNG)) {
|
||||
unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
uint32_t flag = 0;
|
||||
|
@ -775,8 +765,6 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
|
|||
switch_frame_free(&frame);
|
||||
}
|
||||
|
||||
switch_core_timer_sync(&tech_pvt->timer);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -4850,7 +4850,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
|||
sofia_endpoint_interface->state_handler = &sofia_event_handlers;
|
||||
|
||||
management_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_MANAGEMENT_INTERFACE);
|
||||
management_interface->relative_oid = "1";
|
||||
management_interface->relative_oid = "1001";
|
||||
management_interface->management_function = sofia_manage;
|
||||
|
||||
SWITCH_ADD_API(api_interface, "sofia", "Sofia Controls", sofia_function, "<cmd> <args>");
|
||||
|
|
|
@ -808,6 +808,18 @@ void sofia_event_callback(nua_event_t event,
|
|||
}
|
||||
}
|
||||
|
||||
if ((event == nua_i_invite) && (!session)) {
|
||||
uint32_t sess_count = switch_core_session_count();
|
||||
uint32_t sess_max = switch_core_session_limit(0);
|
||||
|
||||
if (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready()) {
|
||||
nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No more sessions allowed at this time.\n");
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
|
||||
sip_authorization_t const *authorization = NULL;
|
||||
|
|
|
@ -630,6 +630,11 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
|
|||
char *probe_user = NULL, *probe_euser, *probe_host, *p;
|
||||
struct dialog_helper dh = { { 0 } };
|
||||
|
||||
if (strcasecmp(proto, SOFIA_CHAT_PROTO) != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
if (!to || !(probe_user = strdup(to))) {
|
||||
goto done;
|
||||
}
|
||||
|
@ -2405,6 +2410,20 @@ void sofia_presence_handle_sip_i_subscribe(int status,
|
|||
switch_event_fire(&sevent);
|
||||
}
|
||||
|
||||
} else if (to_user && (strcasecmp(proto, SOFIA_CHAT_PROTO) != 0)) {
|
||||
if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", proto);
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "long", profile->name);
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s%s%s@%s", proto, "+", to_user, to_host);
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event);
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
|
||||
switch_event_fire(&sevent);
|
||||
|
||||
}
|
||||
} else {
|
||||
if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
|
|
|
@ -111,6 +111,7 @@ void ei_encode_switch_event_headers(ei_x_buff * ebuf, switch_event_t *event)
|
|||
for (hp = event->headers; hp; hp = hp->next) {
|
||||
ei_x_encode_tuple_header(ebuf, 2);
|
||||
_ei_x_encode_string(ebuf, hp->name);
|
||||
switch_url_decode(hp->value);
|
||||
_ei_x_encode_string(ebuf, hp->value);
|
||||
}
|
||||
|
||||
|
|
|
@ -778,7 +778,7 @@ static switch_status_t handle_msg_bind(listener_t *listener, erlang_msg * msg, e
|
|||
binding->process.pid = msg->from;
|
||||
binding->listener = listener;
|
||||
|
||||
switch_thread_rwlock_wrlock(globals.listener_rwlock);
|
||||
switch_thread_rwlock_wrlock(globals.bindings_rwlock);
|
||||
|
||||
for (ptr = bindings.head; ptr && ptr->next; ptr = ptr->next);
|
||||
|
||||
|
@ -789,7 +789,7 @@ static switch_status_t handle_msg_bind(listener_t *listener, erlang_msg * msg, e
|
|||
}
|
||||
|
||||
switch_xml_set_binding_sections(bindings.search_binding, switch_xml_get_binding_sections(bindings.search_binding) | section);
|
||||
switch_thread_rwlock_unlock(globals.listener_rwlock);
|
||||
switch_thread_rwlock_unlock(globals.bindings_rwlock);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sections %d\n", switch_xml_get_binding_sections(bindings.search_binding));
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ static void remove_binding(listener_t *listener, erlang_pid * pid)
|
|||
{
|
||||
struct erlang_binding *ptr, *lst = NULL;
|
||||
|
||||
switch_thread_rwlock_wrlock(globals.listener_rwlock);
|
||||
switch_thread_rwlock_wrlock(globals.bindings_rwlock);
|
||||
|
||||
switch_xml_set_binding_sections(bindings.search_binding, SWITCH_XML_SECTION_MAX);
|
||||
|
||||
|
@ -100,7 +100,7 @@ static void remove_binding(listener_t *listener, erlang_pid * pid)
|
|||
if (ptr->next) {
|
||||
bindings.head = ptr->next;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed all (only?) listeners\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed all (only?) binding\n");
|
||||
bindings.head = NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -111,13 +111,13 @@ static void remove_binding(listener_t *listener, erlang_pid * pid)
|
|||
lst->next = NULL;
|
||||
}
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed listener\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed binding\n");
|
||||
} else {
|
||||
switch_xml_set_binding_sections(bindings.search_binding, switch_xml_get_binding_sections(bindings.search_binding) | ptr->section);
|
||||
}
|
||||
}
|
||||
|
||||
switch_thread_rwlock_unlock(globals.listener_rwlock);
|
||||
switch_thread_rwlock_unlock(globals.bindings_rwlock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -381,6 +381,8 @@ static switch_xml_t erlang_fetch(const char *sectionstr, const char *tag_name, c
|
|||
|
||||
section = switch_xml_parse_section_string((char *) sectionstr);
|
||||
|
||||
switch_thread_rwlock_rdlock(globals.bindings_rwlock);
|
||||
|
||||
for (ptr = bindings.head; ptr; ptr = ptr->next) {
|
||||
if (ptr->section != section)
|
||||
continue;
|
||||
|
@ -417,6 +419,8 @@ static switch_xml_t erlang_fetch(const char *sectionstr, const char *tag_name, c
|
|||
switch_mutex_unlock(ptr->listener->sock_mutex);
|
||||
}
|
||||
|
||||
switch_thread_rwlock_unlock(globals.bindings_rwlock);
|
||||
|
||||
ei_x_free(&buf);
|
||||
|
||||
if (!p) {
|
||||
|
@ -532,6 +536,7 @@ static switch_status_t notify_new_session(listener_t *listener, session_elem_t *
|
|||
session_element->uuid_str);
|
||||
}
|
||||
|
||||
switch_event_destroy(&call_event);
|
||||
ei_x_free(&lbuf);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -1637,6 +1642,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_erlang_event_load)
|
|||
memset(&prefs, 0, sizeof(prefs));
|
||||
|
||||
switch_thread_rwlock_create(&globals.listener_rwlock, pool);
|
||||
switch_thread_rwlock_create(&globals.bindings_rwlock, pool);
|
||||
switch_mutex_init(&globals.fetch_reply_mutex, SWITCH_MUTEX_DEFAULT, pool);
|
||||
switch_mutex_init(&globals.listener_count_mutex, SWITCH_MUTEX_UNNESTED, pool);
|
||||
switch_core_hash_init(&globals.fetch_reply_hash, pool);
|
||||
|
|
|
@ -161,6 +161,7 @@ struct api_command_struct {
|
|||
|
||||
struct globals_struct {
|
||||
switch_thread_rwlock_t *listener_rwlock;
|
||||
switch_thread_rwlock_t *bindings_rwlock;
|
||||
switch_event_node_t *node;
|
||||
switch_mutex_t *ref_mutex;
|
||||
switch_mutex_t *fetch_reply_mutex;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <switch.h>
|
||||
#define CMD_BUFLEN 1024 * 1000
|
||||
#define MAX_QUEUE_LEN 25000
|
||||
#define MAX_MISSED 2000
|
||||
#define MAX_MISSED 500
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_event_socket_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_event_socket_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime);
|
||||
|
@ -143,7 +143,7 @@ static const char *format2str(event_format_t format)
|
|||
}
|
||||
|
||||
static void remove_listener(listener_t *listener);
|
||||
static void kill_listener(listener_t *l);
|
||||
static void kill_listener(listener_t *l, const char *message);
|
||||
static void kill_all_listeners(void);
|
||||
|
||||
static uint32_t next_id(void)
|
||||
|
@ -170,7 +170,7 @@ static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_l
|
|||
if (switch_test_flag(l, LFLAG_LOG) && l->level >= node->level) {
|
||||
switch_log_node_t *dnode = switch_log_node_dup(node);
|
||||
|
||||
if (switch_queue_push(l->log_queue, dnode) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_trypush(l->log_queue, dnode) == SWITCH_STATUS_SUCCESS) {
|
||||
if (l->lost_logs) {
|
||||
int ll = l->lost_logs;
|
||||
switch_event_t *event;
|
||||
|
@ -184,7 +184,7 @@ static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_l
|
|||
} else {
|
||||
switch_log_node_free(&dnode);
|
||||
if (++l->lost_logs > MAX_MISSED) {
|
||||
kill_listener(l);
|
||||
kill_listener(l, "Disconnected due to log queue failure.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ static void event_handler(switch_event_t *event)
|
|||
|
||||
if (send) {
|
||||
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_push(l->event_queue, clone) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_trypush(l->event_queue, clone) == SWITCH_STATUS_SUCCESS) {
|
||||
if (l->lost_events) {
|
||||
int le = l->lost_events;
|
||||
l->lost_events = 0;
|
||||
|
@ -379,7 +379,7 @@ static void event_handler(switch_event_t *event)
|
|||
}
|
||||
} else {
|
||||
if (++l->lost_events > MAX_MISSED) {
|
||||
kill_listener(l);
|
||||
kill_listener(l, "Disconnected due to event queue failure.\n");
|
||||
}
|
||||
switch_event_destroy(&clone);
|
||||
}
|
||||
|
@ -579,8 +579,41 @@ static void remove_listener(listener_t *listener)
|
|||
switch_mutex_unlock(globals.listener_mutex);
|
||||
}
|
||||
|
||||
static void kill_listener(listener_t *l)
|
||||
static void send_disconnect(listener_t *listener, const char *message)
|
||||
{
|
||||
|
||||
char disco_buf[512] = "";
|
||||
switch_size_t len, mlen;
|
||||
|
||||
if (zstr(message)) {
|
||||
message = "Disconnected.\n";
|
||||
}
|
||||
|
||||
mlen = strlen(message);
|
||||
|
||||
if (listener->session) {
|
||||
switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\n"
|
||||
"Controlled-Session-UUID: %s\n"
|
||||
"Content-Disposition: disconnect\n" "Content-Length: %d\n\n", switch_core_session_get_uuid(listener->session), mlen);
|
||||
} else {
|
||||
switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\nContent-Length: %d\n\n", mlen);
|
||||
}
|
||||
|
||||
len = strlen(disco_buf);
|
||||
switch_socket_send(listener->sock, disco_buf, &len);
|
||||
if (len > 0) {
|
||||
len = mlen;
|
||||
switch_socket_send(listener->sock, message, &len);
|
||||
}
|
||||
}
|
||||
|
||||
static void kill_listener(listener_t *l, const char *message)
|
||||
{
|
||||
|
||||
if (message) {
|
||||
send_disconnect(l, message);
|
||||
}
|
||||
|
||||
switch_clear_flag(l, LFLAG_RUNNING);
|
||||
if (l->sock) {
|
||||
switch_socket_shutdown(l->sock, SWITCH_SHUTDOWN_READWRITE);
|
||||
|
@ -595,7 +628,7 @@ static void kill_all_listeners(void)
|
|||
|
||||
switch_mutex_lock(globals.listener_mutex);
|
||||
for (l = listen_list.listeners; l; l = l->next) {
|
||||
kill_listener(l);
|
||||
kill_listener(l, "The system is being shut down.\n");
|
||||
}
|
||||
switch_mutex_unlock(globals.listener_mutex);
|
||||
}
|
||||
|
@ -1233,7 +1266,7 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event,
|
|||
if (switch_channel_get_state(chan) < CS_HANGUP && switch_channel_test_flag(chan, CF_DIVERT_EVENTS)) {
|
||||
switch_event_t *e = NULL;
|
||||
while (switch_core_session_dequeue_event(listener->session, &e, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_push(listener->event_queue, e) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_queue_trypush(listener->event_queue, e) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_session_queue_event(listener->session, &e);
|
||||
break;
|
||||
}
|
||||
|
@ -2540,22 +2573,7 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
|||
}
|
||||
|
||||
if (listener->sock) {
|
||||
char disco_buf[512] = "";
|
||||
const char message[] = "Disconnected, goodbye.\nSee you at ClueCon! http://www.cluecon.com/\n";
|
||||
int mlen = strlen(message);
|
||||
|
||||
if (listener->session) {
|
||||
switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\n"
|
||||
"Controlled-Session-UUID: %s\n"
|
||||
"Content-Disposition: disconnect\n" "Content-Length: %d\n\n", switch_core_session_get_uuid(listener->session), mlen);
|
||||
} else {
|
||||
switch_snprintf(disco_buf, sizeof(disco_buf), "Content-Type: text/disconnect-notice\nContent-Length: %d\n\n", mlen);
|
||||
}
|
||||
|
||||
len = strlen(disco_buf);
|
||||
switch_socket_send(listener->sock, disco_buf, &len);
|
||||
len = mlen;
|
||||
switch_socket_send(listener->sock, message, &len);
|
||||
send_disconnect(listener, "Disconnected, goodbye.\nSee you at ClueCon! http://www.cluecon.com/\n");
|
||||
close_socket(&listener->sock);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
FREESWITCH-MIB DEFINITIONS ::= BEGIN
|
||||
|
||||
IMPORTS
|
||||
OBJECT-TYPE, MODULE-IDENTITY,
|
||||
Integer32, Gauge32, Counter32, Counter64, TimeTicks,
|
||||
enterprises,
|
||||
FROM SNMPv2-SMI
|
||||
|
||||
DisplayString
|
||||
FROM SNMPv2-TC
|
||||
;
|
||||
|
||||
|
||||
freeswitch MODULE-IDENTITY
|
||||
LAST-UPDATED "201101170000Z"
|
||||
ORGANIZATION "www.freeswitch.org"
|
||||
CONTACT-INFO
|
||||
"Primary contact: Anthony Minessale II
|
||||
Email: anthm@freeswitch.org"
|
||||
DESCRIPTION
|
||||
"This file defines the private FreeSWITCH SNMP MIB extensions."
|
||||
REVISION "201101170000Z"
|
||||
DESCRIPTION
|
||||
"First draft by daniel.swarbrick@seventhsignal.de"
|
||||
::= { enterprises 27880 }
|
||||
|
||||
|
||||
core OBJECT IDENTIFIER ::= { freeswitch 1 }
|
||||
mod-sofia OBJECT IDENTIFIER ::= { freeswitch 1001 }
|
||||
mod-skinny OBJECT IDENTIFIER ::= { freeswitch 1002 }
|
||||
|
||||
|
||||
identity OBJECT IDENTIFIER ::= { core 1 }
|
||||
|
||||
versionString OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"FreeSWITCH version as a string"
|
||||
::= { identity 1 }
|
||||
|
||||
uuid OBJECT-TYPE
|
||||
SYNTAX DisplayString
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"FreeSWITCH core UUID"
|
||||
::= { identity 2 }
|
||||
|
||||
|
||||
systemStats OBJECT IDENTIFIER ::= { core 2 }
|
||||
|
||||
uptime OBJECT-TYPE
|
||||
SYNTAX TimeTicks
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"FreeSWITCH process uptime in hundredths of seconds"
|
||||
::= { systemStats 1 }
|
||||
|
||||
sessionsSinceStartup OBJECT-TYPE
|
||||
SYNTAX Counter32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Number of sessions since FreeSWITCH process was started"
|
||||
::= { systemStats 2 }
|
||||
|
||||
currentSessions OBJECT-TYPE
|
||||
SYNTAX Gauge32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Currently active sessions"
|
||||
::= { systemStats 3 }
|
||||
|
||||
maxSessions OBJECT-TYPE
|
||||
SYNTAX Gauge32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Maximum permissible active sessions"
|
||||
::= { systemStats 4 }
|
||||
|
||||
currentCalls OBJECT-TYPE
|
||||
SYNTAX Gauge32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Currently active calls"
|
||||
::= { systemStats 5 }
|
||||
|
||||
sessionsPerSecond OBJECT-TYPE
|
||||
SYNTAX Gauge32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Current sessions per second"
|
||||
::= { systemStats 6 }
|
||||
|
||||
maxSessionsPerSecond OBJECT-TYPE
|
||||
SYNTAX Gauge32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"Maximum permissible sessions per second"
|
||||
::= { systemStats 7 }
|
||||
|
||||
END
|
|
@ -0,0 +1,7 @@
|
|||
include ../../../../build/modmake.rules
|
||||
|
||||
LOCAL_CFLAGS=-I `net-snmp-config --cflags`
|
||||
LOCAL_LDFLAGS=`net-snmp-config --agent-libs`
|
||||
LOCAL_OBJS=subagent.o
|
||||
|
||||
local_depend: $(LOCAL_OBJS)
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* 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
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Daniel Swarbrick <daniel.swarbrick@seventhsignal.de>
|
||||
* Stefan Knoblich <s.knoblich@axsentis.de>
|
||||
*
|
||||
* mod_snmp.c -- SNMP AgentX Subagent Module
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
|
||||
#include "subagent.h"
|
||||
|
||||
static struct {
|
||||
switch_memory_pool_t *pool;
|
||||
switch_mutex_t *mutex;
|
||||
int shutdown;
|
||||
} globals;
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_snmp_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_snmp_shutdown);
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_snmp_runtime);
|
||||
SWITCH_MODULE_DEFINITION(mod_snmp, mod_snmp_load, mod_snmp_shutdown, mod_snmp_runtime);
|
||||
|
||||
|
||||
static switch_status_t snmp_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
|
||||
{
|
||||
if (action == SMA_GET) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Mutex lock request from relative OID %s.\n", relative_oid);
|
||||
switch_mutex_lock(globals.mutex);
|
||||
} else if (action == SMA_SET) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Mutex unlock request from relative OID %s.\n", relative_oid);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int snmp_callback_log(int major, int minor, void *serverarg, void *clientarg)
|
||||
{
|
||||
struct snmp_log_message *slm = (struct snmp_log_message *) serverarg;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, slm->priority, "%s", slm->msg);
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t load_config(switch_memory_pool_t *pool)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
globals.pool = pool;
|
||||
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_snmp_load)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_management_interface_t *management_interface;
|
||||
|
||||
load_config(pool);
|
||||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
management_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_MANAGEMENT_INTERFACE);
|
||||
management_interface->relative_oid = "1000";
|
||||
management_interface->management_function = snmp_manage;
|
||||
|
||||
/* Register callback function so we get Net-SNMP logging handled by FreeSWITCH */
|
||||
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, snmp_callback_log, NULL);
|
||||
snmp_enable_calllog();
|
||||
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
|
||||
|
||||
init_agent("mod_snmp");
|
||||
|
||||
/*
|
||||
* Override master/subagent ping interval to 2s, to ensure that
|
||||
* agent_check_and_process() never blocks for longer than that.
|
||||
*/
|
||||
netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL, 2);
|
||||
|
||||
init_subagent();
|
||||
init_snmp("mod_snmp");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_RUNTIME_FUNCTION(mod_snmp_runtime)
|
||||
{
|
||||
if (!globals.shutdown) {
|
||||
switch_mutex_lock(globals.mutex);
|
||||
/* Block on select() */
|
||||
agent_check_and_process(1);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
}
|
||||
|
||||
switch_yield(5000);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_snmp_shutdown)
|
||||
{
|
||||
globals.shutdown = 1;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
snmp_shutdown("mod_snmp");
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_mutex_destroy(globals.mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
||||
*/
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* 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
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Daniel Swarbrick <daniel.swarbrick@seventhsignal.de>
|
||||
* Stefan Knoblich <s.knoblich@axsentis.de>
|
||||
*
|
||||
* mod_snmp.c -- SNMP AgentX Subagent Module
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include <switch_version.h>
|
||||
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
#include "subagent.h"
|
||||
|
||||
|
||||
void init_subagent(void)
|
||||
{
|
||||
static oid identity_oid[] = { 1,3,6,1,4,1,27880,1,1 };
|
||||
static oid systemStats_oid[] = { 1,3,6,1,4,1,27880,1,2 };
|
||||
|
||||
DEBUGMSGTL(("init_subagent", "Initializing\n"));
|
||||
|
||||
netsnmp_register_scalar_group(netsnmp_create_handler_registration("identity", handle_identity, identity_oid, OID_LENGTH(identity_oid), HANDLER_CAN_RONLY), 1, 2);
|
||||
netsnmp_register_scalar_group(netsnmp_create_handler_registration("systemStats", handle_systemStats, systemStats_oid, OID_LENGTH(systemStats_oid), HANDLER_CAN_RONLY), 1, 7);
|
||||
}
|
||||
|
||||
|
||||
int handle_identity(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests)
|
||||
{
|
||||
netsnmp_request_info *request = NULL;
|
||||
oid subid;
|
||||
static char const version[] = SWITCH_VERSION_FULL;
|
||||
char uuid[40] = "";
|
||||
|
||||
switch(reqinfo->mode) {
|
||||
case MODE_GET:
|
||||
subid = requests->requestvb->name[reginfo->rootoid_len - 2];
|
||||
|
||||
switch (subid) {
|
||||
case ID_VERSION_STR:
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &version, strlen(version));
|
||||
break;
|
||||
case ID_UUID:
|
||||
strncpy(uuid, switch_core_get_uuid(), sizeof(uuid));
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &uuid, strlen(uuid));
|
||||
break;
|
||||
default:
|
||||
snmp_log(LOG_WARNING, "Unregistered OID-suffix requested (%d)\n", (int) subid);
|
||||
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* we should never get here, so this is a really bad error */
|
||||
snmp_log(LOG_ERR, "Unknown mode (%d) in handle_identity\n", reqinfo->mode );
|
||||
return SNMP_ERR_GENERR;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
int handle_systemStats(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests)
|
||||
{
|
||||
netsnmp_request_info *request = NULL;
|
||||
oid subid;
|
||||
switch_time_t uptime;
|
||||
uint32_t int_val;
|
||||
|
||||
switch(reqinfo->mode) {
|
||||
case MODE_GET:
|
||||
subid = requests->requestvb->name[reginfo->rootoid_len - 2];
|
||||
|
||||
switch (subid) {
|
||||
case SS_UPTIME:
|
||||
uptime = switch_core_uptime() / 10000;
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_TIMETICKS, (u_char *) &uptime, sizeof(uptime));
|
||||
break;
|
||||
case SS_SESSIONS_SINCE_STARTUP:
|
||||
int_val = switch_core_session_id() - 1;
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &int_val, sizeof(int_val));
|
||||
break;
|
||||
case SS_CURRENT_SESSIONS:
|
||||
int_val = switch_core_session_count();
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
|
||||
break;
|
||||
case SS_MAX_SESSIONS:
|
||||
switch_core_session_ctl(SCSC_MAX_SESSIONS, &int_val);;
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
|
||||
break;
|
||||
case SS_CURRENT_CALLS:
|
||||
/*
|
||||
* This is zero for now, since there is no convenient way to get total call
|
||||
* count (not to be confused with session count), without touching the
|
||||
* database.
|
||||
*/
|
||||
int_val = 0;
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
|
||||
break;
|
||||
case SS_SESSIONS_PER_SECOND:
|
||||
switch_core_session_ctl(SCSC_LAST_SPS, &int_val);
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
|
||||
break;
|
||||
case SS_MAX_SESSIONS_PER_SECOND:
|
||||
switch_core_session_ctl(SCSC_SPS, &int_val);
|
||||
snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
|
||||
break;
|
||||
default:
|
||||
snmp_log(LOG_WARNING, "Unregistered OID-suffix requested (%d)\n", (int) subid);
|
||||
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* we should never get here, so this is a really bad error */
|
||||
snmp_log(LOG_ERR, "Unknown mode (%d) in handle_systemStats\n", reqinfo->mode);
|
||||
return SNMP_ERR_GENERR;
|
||||
}
|
||||
|
||||
return SNMP_ERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
||||
*/
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef subagent_H
|
||||
#define subagent_H
|
||||
|
||||
/* .1.3.6.1.4.1.27880.1.1 */
|
||||
#define ID_VERSION_STR 1
|
||||
#define ID_UUID 2
|
||||
|
||||
/* .1.3.6.1.4.1.27880.1.2 */
|
||||
#define SS_UPTIME 1
|
||||
#define SS_SESSIONS_SINCE_STARTUP 2
|
||||
#define SS_CURRENT_SESSIONS 3
|
||||
#define SS_MAX_SESSIONS 4
|
||||
#define SS_CURRENT_CALLS 5
|
||||
#define SS_SESSIONS_PER_SECOND 6
|
||||
#define SS_MAX_SESSIONS_PER_SECOND 7
|
||||
|
||||
|
||||
void init_subagent(void);
|
||||
Netsnmp_Node_Handler handle_identity;
|
||||
Netsnmp_Node_Handler handle_systemStats;
|
||||
|
||||
#endif /* subagent_H */
|
|
@ -584,7 +584,11 @@ static void launch_write_stream_thread(shout_context_t *context)
|
|||
}
|
||||
|
||||
#define TC_BUFFER_SIZE 1024 * 32
|
||||
#define MPGERROR() {err = "MPG123 Error at __FILE__:__LINE__."; mpg123err = mpg123_strerror(context->mh); goto error; }
|
||||
|
||||
#define CONCAT_LOCATION(_x,_y) _x ":" #_y
|
||||
#define MAKE_LOCATION(_x,_y) CONCAT_LOCATION(_x,_y)
|
||||
#define HERE MAKE_LOCATION(__FILE__, __LINE__)
|
||||
#define MPGERROR() {err = "MPG123 Error at " HERE "."; mpg123err = mpg123_strerror(context->mh); goto error; }
|
||||
static switch_status_t shout_file_open(switch_file_handle_t *handle, const char *path)
|
||||
{
|
||||
shout_context_t *context;
|
||||
|
|
|
@ -89,6 +89,7 @@ class Dbh {
|
|||
~Dbh();
|
||||
bool release();
|
||||
bool connected();
|
||||
bool test_reactive(char *test_sql, char *drop_sql = NULL, char *reactive_sql = NULL);
|
||||
bool query(char *sql, SWIGLUA_FN lua_fun);
|
||||
int affected_rows();
|
||||
};
|
||||
|
|
|
@ -312,15 +312,21 @@ switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t ityp
|
|||
Dbh::Dbh(char *dsn, char *user, char *pass)
|
||||
{
|
||||
switch_cache_db_connection_options_t options = { {0} };
|
||||
const char *prefix = "core:";
|
||||
m_connected = false;
|
||||
|
||||
options.odbc_options.dsn = dsn;
|
||||
options.odbc_options.user = user;
|
||||
options.odbc_options.pass = pass;
|
||||
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) == SWITCH_STATUS_SUCCESS) {
|
||||
m_connected = true;
|
||||
if (strstr(dsn, prefix) == dsn) {
|
||||
options.core_db_options.db_path = &dsn[strlen(prefix)];
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_CORE_DB, &options) == SWITCH_STATUS_SUCCESS) {
|
||||
m_connected = true;
|
||||
}
|
||||
} else {
|
||||
m_connected = false;
|
||||
options.odbc_options.dsn = dsn;
|
||||
options.odbc_options.user = user;
|
||||
options.odbc_options.pass = pass;
|
||||
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) == SWITCH_STATUS_SUCCESS) {
|
||||
m_connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,6 +350,16 @@ bool Dbh::connected()
|
|||
return m_connected;
|
||||
}
|
||||
|
||||
bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql)
|
||||
{
|
||||
if (m_connected) {
|
||||
if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
|
||||
{
|
||||
SWIGLUA_FN *lua_fun = (SWIGLUA_FN *)pArg;
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace LUA {
|
|||
~Dbh();
|
||||
bool release();
|
||||
bool connected();
|
||||
bool test_reactive(char *test_sql, char *drop_sql = NULL, char *reactive_sql = NULL);
|
||||
bool query(char *sql, SWIGLUA_FN lua_fun);
|
||||
int affected_rows();
|
||||
};
|
||||
|
|
|
@ -7254,6 +7254,184 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_test_reactive__SWIG_0(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
LUA::Dbh *arg1 = (LUA::Dbh *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
char *arg4 = (char *) 0 ;
|
||||
bool result;
|
||||
|
||||
SWIG_check_num_args("test_reactive",4,4)
|
||||
if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("test_reactive",1,"LUA::Dbh *");
|
||||
if(!lua_isstring(L,2)) SWIG_fail_arg("test_reactive",2,"char *");
|
||||
if(!lua_isstring(L,3)) SWIG_fail_arg("test_reactive",3,"char *");
|
||||
if(!lua_isstring(L,4)) SWIG_fail_arg("test_reactive",4,"char *");
|
||||
|
||||
if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,0))){
|
||||
SWIG_fail_ptr("Dbh_test_reactive",1,SWIGTYPE_p_LUA__Dbh);
|
||||
}
|
||||
|
||||
arg2 = (char *)lua_tostring(L, 2);
|
||||
arg3 = (char *)lua_tostring(L, 3);
|
||||
arg4 = (char *)lua_tostring(L, 4);
|
||||
result = (bool)(arg1)->test_reactive(arg2,arg3,arg4);
|
||||
SWIG_arg=0;
|
||||
lua_pushboolean(L,(int)(result==true)); SWIG_arg++;
|
||||
return SWIG_arg;
|
||||
|
||||
if(0) SWIG_fail;
|
||||
|
||||
fail:
|
||||
lua_error(L);
|
||||
return SWIG_arg;
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_test_reactive__SWIG_1(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
LUA::Dbh *arg1 = (LUA::Dbh *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
char *arg3 = (char *) 0 ;
|
||||
bool result;
|
||||
|
||||
SWIG_check_num_args("test_reactive",3,3)
|
||||
if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("test_reactive",1,"LUA::Dbh *");
|
||||
if(!lua_isstring(L,2)) SWIG_fail_arg("test_reactive",2,"char *");
|
||||
if(!lua_isstring(L,3)) SWIG_fail_arg("test_reactive",3,"char *");
|
||||
|
||||
if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,0))){
|
||||
SWIG_fail_ptr("Dbh_test_reactive",1,SWIGTYPE_p_LUA__Dbh);
|
||||
}
|
||||
|
||||
arg2 = (char *)lua_tostring(L, 2);
|
||||
arg3 = (char *)lua_tostring(L, 3);
|
||||
result = (bool)(arg1)->test_reactive(arg2,arg3);
|
||||
SWIG_arg=0;
|
||||
lua_pushboolean(L,(int)(result==true)); SWIG_arg++;
|
||||
return SWIG_arg;
|
||||
|
||||
if(0) SWIG_fail;
|
||||
|
||||
fail:
|
||||
lua_error(L);
|
||||
return SWIG_arg;
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_test_reactive__SWIG_2(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
LUA::Dbh *arg1 = (LUA::Dbh *) 0 ;
|
||||
char *arg2 = (char *) 0 ;
|
||||
bool result;
|
||||
|
||||
SWIG_check_num_args("test_reactive",2,2)
|
||||
if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("test_reactive",1,"LUA::Dbh *");
|
||||
if(!lua_isstring(L,2)) SWIG_fail_arg("test_reactive",2,"char *");
|
||||
|
||||
if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_LUA__Dbh,0))){
|
||||
SWIG_fail_ptr("Dbh_test_reactive",1,SWIGTYPE_p_LUA__Dbh);
|
||||
}
|
||||
|
||||
arg2 = (char *)lua_tostring(L, 2);
|
||||
result = (bool)(arg1)->test_reactive(arg2);
|
||||
SWIG_arg=0;
|
||||
lua_pushboolean(L,(int)(result==true)); SWIG_arg++;
|
||||
return SWIG_arg;
|
||||
|
||||
if(0) SWIG_fail;
|
||||
|
||||
fail:
|
||||
lua_error(L);
|
||||
return SWIG_arg;
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_test_reactive(lua_State* L) {
|
||||
int argc;
|
||||
int argv[5]={
|
||||
1,2,3,4,5
|
||||
};
|
||||
|
||||
argc = lua_gettop(L);
|
||||
if (argc == 2) {
|
||||
int _v;
|
||||
{
|
||||
void *ptr;
|
||||
if (SWIG_isptrtype(L,argv[0])==0 || SWIG_ConvertPtr(L,argv[0], (void **) &ptr, SWIGTYPE_p_LUA__Dbh, 0)) {
|
||||
_v = 0;
|
||||
} else {
|
||||
_v = 1;
|
||||
}
|
||||
}
|
||||
if (_v) {
|
||||
{
|
||||
_v = lua_isstring(L,argv[1]);
|
||||
}
|
||||
if (_v) {
|
||||
return _wrap_Dbh_test_reactive__SWIG_2(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (argc == 3) {
|
||||
int _v;
|
||||
{
|
||||
void *ptr;
|
||||
if (SWIG_isptrtype(L,argv[0])==0 || SWIG_ConvertPtr(L,argv[0], (void **) &ptr, SWIGTYPE_p_LUA__Dbh, 0)) {
|
||||
_v = 0;
|
||||
} else {
|
||||
_v = 1;
|
||||
}
|
||||
}
|
||||
if (_v) {
|
||||
{
|
||||
_v = lua_isstring(L,argv[1]);
|
||||
}
|
||||
if (_v) {
|
||||
{
|
||||
_v = lua_isstring(L,argv[2]);
|
||||
}
|
||||
if (_v) {
|
||||
return _wrap_Dbh_test_reactive__SWIG_1(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (argc == 4) {
|
||||
int _v;
|
||||
{
|
||||
void *ptr;
|
||||
if (SWIG_isptrtype(L,argv[0])==0 || SWIG_ConvertPtr(L,argv[0], (void **) &ptr, SWIGTYPE_p_LUA__Dbh, 0)) {
|
||||
_v = 0;
|
||||
} else {
|
||||
_v = 1;
|
||||
}
|
||||
}
|
||||
if (_v) {
|
||||
{
|
||||
_v = lua_isstring(L,argv[1]);
|
||||
}
|
||||
if (_v) {
|
||||
{
|
||||
_v = lua_isstring(L,argv[2]);
|
||||
}
|
||||
if (_v) {
|
||||
{
|
||||
_v = lua_isstring(L,argv[3]);
|
||||
}
|
||||
if (_v) {
|
||||
return _wrap_Dbh_test_reactive__SWIG_0(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushstring(L,"No matching function for overloaded 'Dbh_test_reactive'");
|
||||
lua_error(L);return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _wrap_Dbh_query(lua_State* L) {
|
||||
int SWIG_arg = -1;
|
||||
LUA::Dbh *arg1 = (LUA::Dbh *) 0 ;
|
||||
|
@ -7328,6 +7506,7 @@ delete arg1;
|
|||
static swig_lua_method swig_LUA_Dbh_methods[] = {
|
||||
{"release", _wrap_Dbh_release},
|
||||
{"connected", _wrap_Dbh_connected},
|
||||
{"test_reactive", _wrap_Dbh_test_reactive},
|
||||
{"query", _wrap_Dbh_query},
|
||||
{"affected_rows", _wrap_Dbh_affected_rows},
|
||||
{0,0}
|
||||
|
|
|
@ -7413,6 +7413,20 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_switch_core_session_get_dmachine(void * jar
|
|||
}
|
||||
|
||||
|
||||
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_set_codec_slin(void * jarg1, void * jarg2) {
|
||||
int jresult ;
|
||||
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
|
||||
switch_slin_data_t *arg2 = (switch_slin_data_t *) 0 ;
|
||||
switch_status_t result;
|
||||
|
||||
arg1 = (switch_core_session_t *)jarg1;
|
||||
arg2 = (switch_slin_data_t *)jarg2;
|
||||
result = (switch_status_t)switch_core_session_set_codec_slin(arg1,arg2);
|
||||
jresult = result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_core_get_uuid() {
|
||||
char * jresult ;
|
||||
char *result = 0 ;
|
||||
|
@ -22794,6 +22808,119 @@ SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_api_interface(void * jarg1) {
|
|||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_slin_data_session_set(void * jarg1, void * jarg2) {
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
switch_core_session_t *arg2 = (switch_core_session_t *) 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
arg2 = (switch_core_session_t *)jarg2;
|
||||
if (arg1) (arg1)->session = arg2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_switch_slin_data_session_get(void * jarg1) {
|
||||
void * jresult ;
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
switch_core_session_t *result = 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
result = (switch_core_session_t *) ((arg1)->session);
|
||||
jresult = (void *)result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_slin_data_write_frame_set(void * jarg1, void * jarg2) {
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
switch_frame_t *arg2 = (switch_frame_t *) 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
arg2 = (switch_frame_t *)jarg2;
|
||||
if (arg1) (arg1)->write_frame = *arg2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_switch_slin_data_write_frame_get(void * jarg1) {
|
||||
void * jresult ;
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
switch_frame_t *result = 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
result = (switch_frame_t *)& ((arg1)->write_frame);
|
||||
jresult = (void *)result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_slin_data_codec_set(void * jarg1, void * jarg2) {
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
switch_codec_t *arg2 = (switch_codec_t *) 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
arg2 = (switch_codec_t *)jarg2;
|
||||
if (arg1) (arg1)->codec = *arg2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_switch_slin_data_codec_get(void * jarg1) {
|
||||
void * jresult ;
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
switch_codec_t *result = 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
result = (switch_codec_t *)& ((arg1)->codec);
|
||||
jresult = (void *)result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_slin_data_frame_data_set(void * jarg1, char * jarg2) {
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
char *arg2 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
arg2 = (char *)jarg2;
|
||||
{
|
||||
if (arg2) strncpy((char *)arg1->frame_data, (const char *)arg2, 4096);
|
||||
else arg1->frame_data[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_slin_data_frame_data_get(void * jarg1) {
|
||||
char * jresult ;
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
char *result = 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
result = (char *)(char *) ((arg1)->frame_data);
|
||||
jresult = SWIG_csharp_string_callback((const char *)result);
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_slin_data() {
|
||||
void * jresult ;
|
||||
switch_slin_data *result = 0 ;
|
||||
|
||||
result = (switch_slin_data *)new switch_slin_data();
|
||||
jresult = (void *)result;
|
||||
return jresult;
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_slin_data(void * jarg1) {
|
||||
switch_slin_data *arg1 = (switch_slin_data *) 0 ;
|
||||
|
||||
arg1 = (switch_slin_data *)jarg1;
|
||||
delete arg1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_timetable_profile_created_set(void * jarg1, void * jarg2) {
|
||||
switch_channel_timetable *arg1 = (switch_channel_timetable *) 0 ;
|
||||
switch_time_t arg2 ;
|
||||
|
|
|
@ -1357,6 +1357,11 @@ public class freeswitch {
|
|||
return ret;
|
||||
}
|
||||
|
||||
public static switch_status_t switch_core_session_set_codec_slin(SWIGTYPE_p_switch_core_session session, switch_slin_data data) {
|
||||
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_set_codec_slin(SWIGTYPE_p_switch_core_session.getCPtr(session), switch_slin_data.getCPtr(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string switch_core_get_uuid() {
|
||||
string ret = freeswitchPINVOKE.switch_core_get_uuid();
|
||||
return ret;
|
||||
|
@ -7504,6 +7509,9 @@ class freeswitchPINVOKE {
|
|||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_get_dmachine")]
|
||||
public static extern IntPtr switch_core_session_get_dmachine(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_set_codec_slin")]
|
||||
public static extern int switch_core_session_set_codec_slin(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_get_uuid")]
|
||||
public static extern string switch_core_get_uuid();
|
||||
|
||||
|
@ -11188,6 +11196,36 @@ class freeswitchPINVOKE {
|
|||
[DllImport("mod_managed", EntryPoint="CSharp_delete_switch_api_interface")]
|
||||
public static extern void delete_switch_api_interface(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_session_set")]
|
||||
public static extern void switch_slin_data_session_set(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_session_get")]
|
||||
public static extern IntPtr switch_slin_data_session_get(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_write_frame_set")]
|
||||
public static extern void switch_slin_data_write_frame_set(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_write_frame_get")]
|
||||
public static extern IntPtr switch_slin_data_write_frame_get(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_codec_set")]
|
||||
public static extern void switch_slin_data_codec_set(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_codec_get")]
|
||||
public static extern IntPtr switch_slin_data_codec_get(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_frame_data_set")]
|
||||
public static extern void switch_slin_data_frame_data_set(HandleRef jarg1, string jarg2);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_slin_data_frame_data_get")]
|
||||
public static extern string switch_slin_data_frame_data_get(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_new_switch_slin_data")]
|
||||
public static extern IntPtr new_switch_slin_data();
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_delete_switch_slin_data")]
|
||||
public static extern void delete_switch_slin_data(HandleRef jarg1);
|
||||
|
||||
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_timetable_profile_created_set")]
|
||||
public static extern void switch_channel_timetable_profile_created_set(HandleRef jarg1, HandleRef jarg2);
|
||||
|
||||
|
@ -28401,7 +28439,8 @@ public enum switch_rtp_bug_flag_t {
|
|||
RTP_BUG_IGNORE_MARK_BIT = (1 << 2),
|
||||
RTP_BUG_SEND_LINEAR_TIMESTAMPS = (1 << 3),
|
||||
RTP_BUG_START_SEQ_AT_ZERO = (1 << 4),
|
||||
RTP_BUG_NEVER_SEND_MARKER = (1 << 5)
|
||||
RTP_BUG_NEVER_SEND_MARKER = (1 << 5),
|
||||
RTP_BUG_IGNORE_DTMF_DURATION = (1 << 6)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29437,6 +29476,96 @@ public enum switch_signal_t {
|
|||
|
||||
namespace FreeSWITCH.Native {
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class switch_slin_data : IDisposable {
|
||||
private HandleRef swigCPtr;
|
||||
protected bool swigCMemOwn;
|
||||
|
||||
internal switch_slin_data(IntPtr cPtr, bool cMemoryOwn) {
|
||||
swigCMemOwn = cMemoryOwn;
|
||||
swigCPtr = new HandleRef(this, cPtr);
|
||||
}
|
||||
|
||||
internal static HandleRef getCPtr(switch_slin_data obj) {
|
||||
return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr;
|
||||
}
|
||||
|
||||
~switch_slin_data() {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public virtual void Dispose() {
|
||||
lock(this) {
|
||||
if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) {
|
||||
swigCMemOwn = false;
|
||||
freeswitchPINVOKE.delete_switch_slin_data(swigCPtr);
|
||||
}
|
||||
swigCPtr = new HandleRef(null, IntPtr.Zero);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public SWIGTYPE_p_switch_core_session session {
|
||||
set {
|
||||
freeswitchPINVOKE.switch_slin_data_session_set(swigCPtr, SWIGTYPE_p_switch_core_session.getCPtr(value));
|
||||
}
|
||||
get {
|
||||
IntPtr cPtr = freeswitchPINVOKE.switch_slin_data_session_get(swigCPtr);
|
||||
SWIGTYPE_p_switch_core_session ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_switch_core_session(cPtr, false);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public switch_frame write_frame {
|
||||
set {
|
||||
freeswitchPINVOKE.switch_slin_data_write_frame_set(swigCPtr, switch_frame.getCPtr(value));
|
||||
}
|
||||
get {
|
||||
IntPtr cPtr = freeswitchPINVOKE.switch_slin_data_write_frame_get(swigCPtr);
|
||||
switch_frame ret = (cPtr == IntPtr.Zero) ? null : new switch_frame(cPtr, false);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public switch_codec codec {
|
||||
set {
|
||||
freeswitchPINVOKE.switch_slin_data_codec_set(swigCPtr, switch_codec.getCPtr(value));
|
||||
}
|
||||
get {
|
||||
IntPtr cPtr = freeswitchPINVOKE.switch_slin_data_codec_get(swigCPtr);
|
||||
switch_codec ret = (cPtr == IntPtr.Zero) ? null : new switch_codec(cPtr, false);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public string frame_data {
|
||||
set {
|
||||
freeswitchPINVOKE.switch_slin_data_frame_data_set(swigCPtr, value);
|
||||
}
|
||||
get {
|
||||
string ret = freeswitchPINVOKE.switch_slin_data_frame_data_get(swigCPtr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public switch_slin_data() : this(freeswitchPINVOKE.new_switch_slin_data(), true) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/* ----------------------------------------------------------------------------
|
||||
* This file was automatically generated by SWIG (http://www.swig.org).
|
||||
* Version 1.3.35
|
||||
*
|
||||
* Do not make changes to this file unless you know what you are doing--modify
|
||||
* the SWIG interface file instead.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
namespace FreeSWITCH.Native {
|
||||
|
||||
[System.Flags] public enum switch_speech_flag_enum_t {
|
||||
SWITCH_SPEECH_FLAG_NONE = 0,
|
||||
SWITCH_SPEECH_FLAG_HASTEXT = (1 << 0),
|
||||
|
@ -30146,7 +30275,7 @@ public enum switch_status_t {
|
|||
SWITCH_STATUS_FALSE,
|
||||
SWITCH_STATUS_TIMEOUT,
|
||||
SWITCH_STATUS_RESTART,
|
||||
SWITCH_STATUS_TERM,
|
||||
SWITCH_STATUS_INTR,
|
||||
SWITCH_STATUS_NOTIMPL,
|
||||
SWITCH_STATUS_MEMERR,
|
||||
SWITCH_STATUS_NOOP,
|
||||
|
@ -30163,6 +30292,7 @@ public enum switch_status_t {
|
|||
SWITCH_STATUS_TOO_SMALL,
|
||||
SWITCH_STATUS_FOUND,
|
||||
SWITCH_STATUS_CONTINUE,
|
||||
SWITCH_STATUS_TERM,
|
||||
SWITCH_STATUS_NOT_INITALIZED
|
||||
}
|
||||
|
||||
|
|
|
@ -833,7 +833,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_recvfrom(switch_sockaddr_t *from,
|
|||
*/
|
||||
}
|
||||
|
||||
if (r == 35) {
|
||||
if (r == 35 || r == 730035) {
|
||||
r = SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2564,8 +2564,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(swi
|
|||
char *app;
|
||||
switch_event_t *event;
|
||||
|
||||
if (!switch_channel_test_flag(channel, CF_RING_READY) && !switch_channel_test_flag(channel, CF_EARLY_MEDIA &&
|
||||
!switch_channel_test_flag(channel, CF_ANSWERED))) {
|
||||
if (!switch_channel_test_flag(channel, CF_RING_READY) &&
|
||||
!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Ring-Ready %s!\n", channel->name);
|
||||
switch_channel_set_flag_value(channel, CF_RING_READY, rv);
|
||||
if (channel->caller_profile && channel->caller_profile->times) {
|
||||
|
|
|
@ -151,13 +151,21 @@ static void check_ip(void)
|
|||
SWITCH_STANDARD_SCHED_FUNC(heartbeat_callback)
|
||||
{
|
||||
send_heartbeat();
|
||||
check_ip();
|
||||
|
||||
/* reschedule this task */
|
||||
task->runtime = switch_epoch_time_now(NULL) + 20;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_STANDARD_SCHED_FUNC(check_ip_callback)
|
||||
{
|
||||
check_ip();
|
||||
|
||||
/* reschedule this task */
|
||||
task->runtime = switch_epoch_time_now(NULL) + 60;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_set_console(const char *console)
|
||||
{
|
||||
if ((runtime.console = fopen(console, "a")) == 0) {
|
||||
|
@ -1357,6 +1365,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc
|
|||
|
||||
switch_scheduler_add_task(switch_epoch_time_now(NULL), heartbeat_callback, "heartbeat", "core", 0, NULL, SSHF_NONE | SSHF_NO_DEL);
|
||||
|
||||
switch_scheduler_add_task(switch_epoch_time_now(NULL), check_ip_callback, "check_ip", "core", 0, NULL, SSHF_NONE | SSHF_NO_DEL | SSHF_OWN_THREAD);
|
||||
|
||||
switch_uuid_get(&uuid);
|
||||
switch_uuid_format(runtime.uuid_str, &uuid);
|
||||
|
||||
|
|
|
@ -391,10 +391,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh,
|
|||
if ((status = fh->file_interface->file_write(fh, fh->pre_buffer_data, &blen)) != SWITCH_STATUS_SUCCESS) {
|
||||
*len = 0;
|
||||
}
|
||||
fh->samples_out += blen;
|
||||
}
|
||||
}
|
||||
|
||||
fh->samples_out += orig_len;
|
||||
return status;
|
||||
} else {
|
||||
switch_status_t status;
|
||||
|
|
|
@ -224,7 +224,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
|
|||
switch_ivr_parse_all_events(session);
|
||||
|
||||
|
||||
if (args && (args->input_callback || args->buf || args->buflen || args->dmachine)) {
|
||||
if (args) {
|
||||
switch_dtmf_t dtmf;
|
||||
|
||||
/*
|
||||
|
|
|
@ -3129,6 +3129,7 @@ static void *SWITCH_THREAD_FUNC speech_thread(switch_thread_t *thread, void *obj
|
|||
switch_event_t *dup;
|
||||
|
||||
if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data(channel, dup);
|
||||
switch_event_fire(&dup);
|
||||
}
|
||||
|
||||
|
|
|
@ -2755,6 +2755,26 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (session) {
|
||||
switch_channel_set_variable(originate_status[i].peer_channel, "originating_leg_uuid", switch_core_session_get_uuid(session));
|
||||
}
|
||||
|
||||
if ((vvar = switch_channel_get_variable_dup(originate_status[i].peer_channel, "execute_on_originate", SWITCH_FALSE))) {
|
||||
char *app = switch_core_session_strdup(originate_status[i].peer_session, vvar);
|
||||
char *arg = NULL;
|
||||
|
||||
if (strstr(app, "::")) {
|
||||
switch_core_session_execute_application_async(originate_status[i].peer_session, app, arg);
|
||||
} else {
|
||||
if ((arg = strchr(app, ' '))) {
|
||||
*arg++ = '\0';
|
||||
}
|
||||
|
||||
switch_core_session_execute_application(originate_status[i].peer_session, app, arg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (table) {
|
||||
|
@ -2773,7 +2793,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
|||
*cause = SWITCH_CAUSE_SUCCESS;
|
||||
goto outer_for;
|
||||
}
|
||||
|
||||
|
||||
if (!switch_core_session_running(originate_status[i].peer_session)) {
|
||||
if (originate_status[i].per_channel_delay_start) {
|
||||
switch_channel_set_flag(originate_status[i].peer_channel, CF_BLOCK_STATE);
|
||||
|
|
|
@ -372,6 +372,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
|
|||
switch_event_t *event;
|
||||
int divisor = 0;
|
||||
int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT;
|
||||
int restart_limit_on_dtmf = 0;
|
||||
const char *prefix;
|
||||
|
||||
prefix = switch_channel_get_variable(channel, "sound_prefix");
|
||||
|
@ -528,6 +529,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
|
|||
if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
|
||||
asis = 1;
|
||||
}
|
||||
|
||||
restart_limit_on_dtmf = switch_true(switch_channel_get_variable(channel, "record_restart_limit_on_dtmf"));
|
||||
|
||||
if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) {
|
||||
vval = switch_core_session_strdup(session, p);
|
||||
|
@ -631,12 +634,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
|
|||
break;
|
||||
}
|
||||
|
||||
if (args && (args->input_callback || args->buf || args->buflen || args->dmachine)) {
|
||||
if (args) {
|
||||
/*
|
||||
dtmf handler function you can hook up to be executed when a digit is dialed during playback
|
||||
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
|
||||
*/
|
||||
if (switch_channel_has_dtmf(channel)) {
|
||||
|
||||
if (limit && restart_limit_on_dtmf) {
|
||||
start = switch_epoch_time_now(NULL);
|
||||
}
|
||||
|
||||
if (!args->input_callback && !args->buf && !args->dmachine) {
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
break;
|
||||
|
@ -854,7 +862,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi
|
|||
|
||||
switch_ivr_parse_all_events(session);
|
||||
|
||||
if (args && (args->input_callback || args->buf || args->buflen || args->dmachine)) {
|
||||
if (args) {
|
||||
/*
|
||||
dtmf handler function you can hook up to be executed when a digit is dialed during gentones
|
||||
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
|
||||
|
@ -1306,7 +1314,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
|
|||
|
||||
switch_ivr_parse_all_events(session);
|
||||
|
||||
if (args && (args->input_callback || args->buf || args->buflen || args->dmachine)) {
|
||||
if (args) {
|
||||
/*
|
||||
dtmf handler function you can hook up to be executed when a digit is dialed during playback
|
||||
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
|
||||
|
@ -1867,7 +1875,7 @@ SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t
|
|||
switch_status_t status;
|
||||
|
||||
memset(digit_buffer, 0, digit_buffer_length);
|
||||
switch_channel_flush_dtmf(channel);
|
||||
|
||||
status = switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, var_name,
|
||||
digit_buffer, digit_buffer_length, timeout, valid_terminators, digit_timeout);
|
||||
if (status == SWITCH_STATUS_TIMEOUT && strlen(digit_buffer) >= min_digits) {
|
||||
|
@ -2029,7 +2037,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session
|
|||
switch_event_destroy(&event);
|
||||
}
|
||||
|
||||
if (args && (args->input_callback || args->buf || args->buflen || args->dmachine)) {
|
||||
if (args) {
|
||||
/* dtmf handler function you can hook up to be executed when a digit is dialed during playback
|
||||
* if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
|
||||
*/
|
||||
|
|
|
@ -1047,20 +1047,24 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir,
|
|||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Module is not unloadable.\n");
|
||||
*err = "Module is not unloadable";
|
||||
status = SWITCH_STATUS_NOUNLOAD;
|
||||
goto end;
|
||||
goto unlock;
|
||||
} else {
|
||||
if ((status = do_shutdown(module, SWITCH_TRUE, SWITCH_TRUE, !force, err) != SWITCH_STATUS_SUCCESS)) {
|
||||
goto end;
|
||||
/* Prevent anything from using the module while it's shutting down */
|
||||
switch_core_hash_delete(loadable_modules.module_hash, fname);
|
||||
switch_mutex_unlock(loadable_modules.mutex);
|
||||
if ((status = do_shutdown(module, SWITCH_TRUE, SWITCH_TRUE, !force, err)) != SWITCH_STATUS_SUCCESS) {
|
||||
/* Something went wrong in the module's shutdown function, add it again */
|
||||
switch_core_hash_insert_locked(loadable_modules.module_hash, fname, module, loadable_modules.mutex);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
switch_core_hash_delete(loadable_modules.module_hash, fname);
|
||||
} else {
|
||||
*err = "No such module!";
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
end:
|
||||
unlock:
|
||||
switch_mutex_unlock(loadable_modules.mutex);
|
||||
|
||||
end:
|
||||
if (force) {
|
||||
switch_yield(1000000);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "PHEW!\n");
|
||||
|
|
425
src/switch_rtp.c
425
src/switch_rtp.c
|
@ -32,6 +32,7 @@
|
|||
*/
|
||||
//#define DEBUG_2833
|
||||
//#define RTP_DEBUG_WRITE_DELTA
|
||||
//#define DEBUG_MISSED_SEQ
|
||||
#include <switch.h>
|
||||
#include <switch_stun.h>
|
||||
#undef PACKAGE_NAME
|
||||
|
@ -245,6 +246,9 @@ struct switch_rtp {
|
|||
switch_time_t send_time;
|
||||
switch_byte_t auto_adj_used;
|
||||
uint8_t pause_jb;
|
||||
uint16_t last_seq;
|
||||
switch_time_t last_read_time;
|
||||
switch_size_t last_flush_packet_count;
|
||||
};
|
||||
|
||||
struct switch_rtcp_senderinfo {
|
||||
|
@ -256,6 +260,180 @@ struct switch_rtcp_senderinfo {
|
|||
unsigned oc:32;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
RESULT_CONTINUE,
|
||||
RESULT_GOTO_END,
|
||||
RESULT_GOTO_RECVFROM,
|
||||
RESULT_GOTO_TIMERCHECK
|
||||
} handle_rfc2833_result_t;
|
||||
|
||||
static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_size_t bytes, int *do_cng)
|
||||
{
|
||||
#ifdef DEBUG_2833
|
||||
if (rtp_session->dtmf_data.in_digit_sanity && !(rtp_session->dtmf_data.in_digit_sanity % 100)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sanity %d\n", rtp_session->dtmf_data.in_digit_sanity);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rtp_session->dtmf_data.in_digit_sanity && !--rtp_session->dtmf_data.in_digit_sanity) {
|
||||
rtp_session->dtmf_data.last_digit = 0;
|
||||
rtp_session->dtmf_data.in_digit_ts = 0;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF sanity check.\n");
|
||||
}
|
||||
|
||||
/* RFC2833 ... like all RFC RE: VoIP, guaranteed to drive you to insanity!
|
||||
We know the real rules here, but if we enforce them, it's an interop nightmare so,
|
||||
we put up with as much as we can so we don't have to deal with being punished for
|
||||
doing it right. Nice guys finish last!
|
||||
*/
|
||||
if (bytes > rtp_header_len && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) &&
|
||||
!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
|
||||
switch_size_t len = bytes - rtp_header_len;
|
||||
unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body;
|
||||
int end;
|
||||
uint16_t duration;
|
||||
char key;
|
||||
uint16_t in_digit_seq;
|
||||
uint32_t ts;
|
||||
|
||||
if (!(packet[0] || packet[1] || packet[2] || packet[3]) && len >= 8) {
|
||||
packet += 4;
|
||||
len -= 4;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "DTMF payload offset by 4 bytes.\n");
|
||||
}
|
||||
|
||||
if (!(packet[0] || packet[1] || packet[2] || packet[3])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF payload check.\n");
|
||||
rtp_session->dtmf_data.last_digit = 0;
|
||||
rtp_session->dtmf_data.in_digit_ts = 0;
|
||||
}
|
||||
|
||||
end = packet[1] & 0x80 ? 1 : 0;
|
||||
duration = (packet[2] << 8) + packet[3];
|
||||
key = switch_rfc2833_to_char(packet[0]);
|
||||
in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
|
||||
ts = htonl(rtp_session->recv_msg.header.ts);
|
||||
|
||||
if (in_digit_seq < rtp_session->dtmf_data.in_digit_seq) {
|
||||
if (rtp_session->dtmf_data.in_digit_seq - in_digit_seq > 100) {
|
||||
rtp_session->dtmf_data.in_digit_seq = 0;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "packet[%d]: %02x %02x %02x %02x\n", (int) len, (unsigned) packet[0], (unsigned)
|
||||
packet[1], (unsigned) packet[2], (unsigned) packet[3]);
|
||||
#endif
|
||||
|
||||
if (in_digit_seq > rtp_session->dtmf_data.in_digit_seq) {
|
||||
|
||||
rtp_session->dtmf_data.in_digit_seq = in_digit_seq;
|
||||
#ifdef DEBUG_2833
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read: %c %u %u %u %u %d %d %s\n",
|
||||
key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq,
|
||||
ts, duration, rtp_session->recv_msg.header.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : "");
|
||||
#endif
|
||||
|
||||
if (!rtp_session->dtmf_data.in_digit_queued && (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) &&
|
||||
rtp_session->dtmf_data.in_digit_ts) {
|
||||
switch_dtmf_t dtmf = { key, switch_core_min_dtmf_duration(0) };
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Early Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
|
||||
#endif
|
||||
switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
|
||||
rtp_session->dtmf_data.in_digit_queued = 1;
|
||||
}
|
||||
|
||||
/* only set sanity if we do NOT ignore the packet */
|
||||
if (rtp_session->dtmf_data.in_digit_ts) {
|
||||
rtp_session->dtmf_data.in_digit_sanity = 2000;
|
||||
}
|
||||
|
||||
if (rtp_session->dtmf_data.last_duration > duration &&
|
||||
rtp_session->dtmf_data.last_duration > 0xFC17 && ts == rtp_session->dtmf_data.in_digit_ts) {
|
||||
rtp_session->dtmf_data.flip++;
|
||||
}
|
||||
|
||||
if (end) {
|
||||
if (rtp_session->dtmf_data.in_digit_ts) {
|
||||
switch_dtmf_t dtmf = { key, duration };
|
||||
|
||||
if (ts > rtp_session->dtmf_data.in_digit_ts) {
|
||||
dtmf.duration += (ts - rtp_session->dtmf_data.in_digit_ts);
|
||||
}
|
||||
if (rtp_session->dtmf_data.flip) {
|
||||
dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF;
|
||||
rtp_session->dtmf_data.flip = 0;
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "you're welcome!\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n",
|
||||
dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration);
|
||||
#endif
|
||||
|
||||
if (!(rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) && !rtp_session->dtmf_data.in_digit_queued) {
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
|
||||
#endif
|
||||
switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
|
||||
}
|
||||
|
||||
rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit;
|
||||
|
||||
rtp_session->dtmf_data.in_digit_ts = 0;
|
||||
rtp_session->dtmf_data.in_digit_sanity = 0;
|
||||
rtp_session->dtmf_data.in_digit_queued = 0;
|
||||
*do_cng = 1;
|
||||
} else {
|
||||
if (!switch_rtp_ready(rtp_session)) {
|
||||
return RESULT_GOTO_END;
|
||||
}
|
||||
switch_cond_next();
|
||||
return RESULT_GOTO_RECVFROM;
|
||||
}
|
||||
|
||||
} else if (!rtp_session->dtmf_data.in_digit_ts) {
|
||||
rtp_session->dtmf_data.in_digit_ts = ts;
|
||||
rtp_session->dtmf_data.first_digit = key;
|
||||
rtp_session->dtmf_data.in_digit_sanity = 2000;
|
||||
}
|
||||
|
||||
rtp_session->dtmf_data.last_duration = duration;
|
||||
} else {
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "drop: %c %u %u %u %u %d %d\n",
|
||||
key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end);
|
||||
#endif
|
||||
switch_cond_next();
|
||||
return RESULT_GOTO_RECVFROM;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes && rtp_session->dtmf_data.in_digit_ts) {
|
||||
if (!switch_rtp_ready(rtp_session)) {
|
||||
return RESULT_GOTO_END;
|
||||
}
|
||||
|
||||
if (!rtp_session->dtmf_data.in_interleaved && rtp_session->recv_msg.header.pt != rtp_session->recv_te) {
|
||||
/* Drat, they are sending audio still as well as DTMF ok fine..... *sigh* */
|
||||
rtp_session->dtmf_data.in_interleaved = 1;
|
||||
}
|
||||
|
||||
if (rtp_session->dtmf_data.in_interleaved || (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION)) {
|
||||
if (rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
|
||||
return RESULT_GOTO_RECVFROM;
|
||||
}
|
||||
} else {
|
||||
*do_cng = 1;
|
||||
return RESULT_GOTO_TIMERCHECK;
|
||||
}
|
||||
}
|
||||
|
||||
return RESULT_CONTINUE;
|
||||
}
|
||||
|
||||
static int global_init = 0;
|
||||
static int rtp_common_write(switch_rtp_t *rtp_session,
|
||||
rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags);
|
||||
|
@ -2157,6 +2335,15 @@ static void do_flush(switch_rtp_t *rtp_session)
|
|||
bytes = sizeof(rtp_msg_t);
|
||||
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, &bytes);
|
||||
if (bytes) {
|
||||
int do_cng = 0;
|
||||
|
||||
/* Make sure to handle RFC2833 packets, even if we're flushing the packets */
|
||||
if (bytes > rtp_header_len && rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
|
||||
handle_rfc2833(rtp_session, bytes, &do_cng);
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "*** RTP packet handled in flush loop ***\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
flushed++;
|
||||
|
||||
|
@ -2195,7 +2382,52 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
|
|||
*bytes = sizeof(rtp_msg_t);
|
||||
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes);
|
||||
ts = ntohl(rtp_session->recv_msg.header.ts);
|
||||
|
||||
|
||||
if (*bytes ) {
|
||||
uint16_t seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
|
||||
|
||||
if (rtp_session->last_seq && rtp_session->last_seq+1 != seq) {
|
||||
#ifdef DEBUG_MISSED_SEQ
|
||||
switch_size_t flushed_packets_diff = rtp_session->stats.inbound.flush_packet_count - rtp_session->last_flush_packet_count;
|
||||
switch_size_t num_missed = (switch_size_t)seq - (rtp_session->last_seq+1);
|
||||
|
||||
if (num_missed == 1) { /* We missed one packet */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missed one RTP frame with sequence [%d]%s. Time since last read [%d]\n",
|
||||
rtp_session->last_seq+1, (flushed_packets_diff == 1) ? " (flushed by FS)" : " (missed)",
|
||||
rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
|
||||
} else { /* We missed multiple packets */
|
||||
if (flushed_packets_diff == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Missed %d RTP frames from sequence [%d] to [%d] (missed). Time since last read [%d]\n",
|
||||
num_missed, rtp_session->last_seq+1, seq-1,
|
||||
rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
|
||||
} else if (flushed_packets_diff == num_missed) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Missed %d RTP frames from sequence [%d] to [%d] (flushed by FS). Time since last read [%d]\n",
|
||||
num_missed, rtp_session->last_seq+1, seq-1,
|
||||
rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
|
||||
} else if (num_missed > flushed_packets_diff) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Missed %d RTP frames from sequence [%d] to [%d] (%d packets flushed by FS, %d packets missed)."
|
||||
" Time since last read [%d]\n",
|
||||
num_missed, rtp_session->last_seq+1, seq-1,
|
||||
flushed_packets_diff, num_missed-flushed_packets_diff,
|
||||
rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Missed %d RTP frames from sequence [%d] to [%d] (%d packets flushed by FS). Time since last read [%d]\n",
|
||||
num_missed, rtp_session->last_seq+1, seq-1,
|
||||
flushed_packets_diff, rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
rtp_session->last_seq = seq;
|
||||
}
|
||||
|
||||
rtp_session->last_flush_packet_count = rtp_session->stats.inbound.flush_packet_count;
|
||||
rtp_session->last_read_time = switch_micro_time_now();
|
||||
|
||||
if (*bytes && (!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) &&
|
||||
ts && !rtp_session->jb && !rtp_session->pause_jb && ts == rtp_session->last_cng_ts) {
|
||||
/* we already sent this frame..... */
|
||||
|
@ -2494,13 +2726,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||
}
|
||||
}
|
||||
|
||||
if (rtp_session->recv_msg.header.pt != 13 &&
|
||||
rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
|
||||
(!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&
|
||||
rtp_session->recv_msg.header.pt != rtp_session->payload) {
|
||||
/* drop frames of incorrect payload number and return CNG frame instead */
|
||||
return_cng_frame();
|
||||
}
|
||||
|
||||
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && rtp_session->rtcp_read_pollfd) {
|
||||
rtcp_poll_status = switch_poll(rtp_session->rtcp_read_pollfd, 1, &rtcp_fdr, 0);
|
||||
|
@ -2579,6 +2804,15 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL) &&
|
||||
rtp_session->recv_msg.header.pt != 13 &&
|
||||
rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
|
||||
(!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&
|
||||
rtp_session->recv_msg.header.pt != rtp_session->payload) {
|
||||
/* drop frames of incorrect payload number and return CNG frame instead */
|
||||
return_cng_frame();
|
||||
}
|
||||
|
||||
if (!bytes && (io_flags & SWITCH_IO_FLAG_NOBLOCK)) {
|
||||
rtp_session->missed_count = 0;
|
||||
ret = 0;
|
||||
|
@ -2835,173 +3069,20 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||
|
||||
bytes = sbytes;
|
||||
}
|
||||
#ifdef DEBUG_2833
|
||||
if (rtp_session->dtmf_data.in_digit_sanity && !(rtp_session->dtmf_data.in_digit_sanity % 100)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sanity %d\n", rtp_session->dtmf_data.in_digit_sanity);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rtp_session->dtmf_data.in_digit_sanity && !--rtp_session->dtmf_data.in_digit_sanity) {
|
||||
rtp_session->dtmf_data.last_digit = 0;
|
||||
rtp_session->dtmf_data.in_digit_ts = 0;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF sanity check.\n");
|
||||
}
|
||||
|
||||
/* RFC2833 ... like all RFC RE: VoIP, guaranteed to drive you to insanity!
|
||||
We know the real rules here, but if we enforce them, it's an interop nightmare so,
|
||||
we put up with as much as we can so we don't have to deal with being punished for
|
||||
doing it right. Nice guys finish last!
|
||||
*/
|
||||
if (bytes > rtp_header_len && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) &&
|
||||
!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
|
||||
switch_size_t len = bytes - rtp_header_len;
|
||||
unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body;
|
||||
int end;
|
||||
uint16_t duration;
|
||||
char key;
|
||||
uint16_t in_digit_seq;
|
||||
uint32_t ts;
|
||||
|
||||
|
||||
if (!(packet[0] || packet[1] || packet[2] || packet[3]) && len >= 8) {
|
||||
packet += 4;
|
||||
len -= 4;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "DTMF payload offset by 4 bytes.\n");
|
||||
}
|
||||
|
||||
if (!(packet[0] || packet[1] || packet[2] || packet[3])) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF payload check.\n");
|
||||
rtp_session->dtmf_data.last_digit = 0;
|
||||
rtp_session->dtmf_data.in_digit_ts = 0;
|
||||
}
|
||||
|
||||
end = packet[1] & 0x80 ? 1 : 0;
|
||||
duration = (packet[2] << 8) + packet[3];
|
||||
key = switch_rfc2833_to_char(packet[0]);
|
||||
in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
|
||||
ts = htonl(rtp_session->recv_msg.header.ts);
|
||||
|
||||
if (in_digit_seq < rtp_session->dtmf_data.in_digit_seq) {
|
||||
if (rtp_session->dtmf_data.in_digit_seq - in_digit_seq > 100) {
|
||||
rtp_session->dtmf_data.in_digit_seq = 0;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "packet[%d]: %02x %02x %02x %02x\n", (int) len, (unsigned) packet[0], (unsigned)
|
||||
packet[1], (unsigned) packet[2], (unsigned) packet[3]);
|
||||
#endif
|
||||
|
||||
if (in_digit_seq > rtp_session->dtmf_data.in_digit_seq) {
|
||||
|
||||
rtp_session->dtmf_data.in_digit_seq = in_digit_seq;
|
||||
#ifdef DEBUG_2833
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read: %c %u %u %u %u %d %d %s\n",
|
||||
key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq,
|
||||
ts, duration, rtp_session->recv_msg.header.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : "");
|
||||
#endif
|
||||
|
||||
if (!rtp_session->dtmf_data.in_digit_queued && (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) &&
|
||||
rtp_session->dtmf_data.in_digit_ts) {
|
||||
switch_dtmf_t dtmf = { key, switch_core_min_dtmf_duration(0) };
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Early Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
|
||||
#endif
|
||||
switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
|
||||
rtp_session->dtmf_data.in_digit_queued = 1;
|
||||
}
|
||||
|
||||
/* only set sanity if we do NOT ignore the packet */
|
||||
if (rtp_session->dtmf_data.in_digit_ts) {
|
||||
rtp_session->dtmf_data.in_digit_sanity = 2000;
|
||||
}
|
||||
|
||||
if (rtp_session->dtmf_data.last_duration > duration &&
|
||||
rtp_session->dtmf_data.last_duration > 0xFC17 && ts == rtp_session->dtmf_data.in_digit_ts) {
|
||||
rtp_session->dtmf_data.flip++;
|
||||
}
|
||||
|
||||
if (end) {
|
||||
if (rtp_session->dtmf_data.in_digit_ts) {
|
||||
switch_dtmf_t dtmf = { key, duration };
|
||||
|
||||
if (ts > rtp_session->dtmf_data.in_digit_ts) {
|
||||
dtmf.duration += (ts - rtp_session->dtmf_data.in_digit_ts);
|
||||
}
|
||||
if (rtp_session->dtmf_data.flip) {
|
||||
dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF;
|
||||
rtp_session->dtmf_data.flip = 0;
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "you're welcome!\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n",
|
||||
dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration);
|
||||
#endif
|
||||
|
||||
if (!(rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) && !rtp_session->dtmf_data.in_digit_queued) {
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
|
||||
#endif
|
||||
switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
|
||||
}
|
||||
|
||||
rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit;
|
||||
|
||||
rtp_session->dtmf_data.in_digit_ts = 0;
|
||||
rtp_session->dtmf_data.in_digit_sanity = 0;
|
||||
rtp_session->dtmf_data.in_digit_queued = 0;
|
||||
do_cng = 1;
|
||||
} else {
|
||||
if (!switch_rtp_ready(rtp_session)) {
|
||||
goto end;
|
||||
}
|
||||
switch_cond_next();
|
||||
goto recvfrom;
|
||||
}
|
||||
|
||||
} else if (!rtp_session->dtmf_data.in_digit_ts) {
|
||||
rtp_session->dtmf_data.in_digit_ts = ts;
|
||||
rtp_session->dtmf_data.first_digit = key;
|
||||
rtp_session->dtmf_data.in_digit_sanity = 2000;
|
||||
}
|
||||
|
||||
rtp_session->dtmf_data.last_duration = duration;
|
||||
} else {
|
||||
#ifdef DEBUG_2833
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "drop: %c %u %u %u %u %d %d\n",
|
||||
key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end);
|
||||
#endif
|
||||
switch_cond_next();
|
||||
goto recvfrom;
|
||||
}
|
||||
}
|
||||
|
||||
if (rtp_session->dtmf_data.in_digit_ts) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (bytes && rtp_session->dtmf_data.in_digit_ts) {
|
||||
if (!switch_rtp_ready(rtp_session)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!rtp_session->dtmf_data.in_interleaved && rtp_session->recv_msg.header.pt != rtp_session->recv_te) {
|
||||
/* Drat, they are sending audio still as well as DTMF ok fine..... *sigh* */
|
||||
rtp_session->dtmf_data.in_interleaved = 1;
|
||||
}
|
||||
|
||||
if (rtp_session->dtmf_data.in_interleaved || (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION)) {
|
||||
if (rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
|
||||
goto recvfrom;
|
||||
}
|
||||
} else {
|
||||
return_cng_frame();
|
||||
}
|
||||
/* Handle incoming RFC2833 packets */
|
||||
switch (handle_rfc2833(rtp_session, bytes, &do_cng)) {
|
||||
case RESULT_GOTO_END:
|
||||
goto end;
|
||||
case RESULT_GOTO_RECVFROM:
|
||||
goto recvfrom;
|
||||
case RESULT_GOTO_TIMERCHECK:
|
||||
goto timer_check;
|
||||
case RESULT_CONTINUE:
|
||||
goto result_continue;
|
||||
}
|
||||
|
||||
result_continue:
|
||||
timer_check:
|
||||
|
||||
if (do_cng) {
|
||||
|
|
Loading…
Reference in New Issue