mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-29 22:54:18 +00:00
Merge branch 'smgmaster' into releases.3.4.experimental_head
Conflicts: libs/freetdm/mod_freetdm/mod_freetdm.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_relay.c src/mod/endpoints/mod_sofia/mod_sofia.c src/mod/endpoints/mod_sofia/sofia_glue.c
This commit is contained in:
commit
7bd2d154d6
615 files changed
+41286
-47127
No files matched your search
@@ -184,9 +184,9 @@ endif
|
||||
if HAVE_LIBPRI
|
||||
mod_LTLIBRARIES += ftmod_libpri.la
|
||||
ftmod_libpri_la_SOURCES = $(SRC)/ftmod/ftmod_libpri/ftmod_libpri.c $(SRC)/ftmod/ftmod_libpri/lpwrap_pri.c
|
||||
ftmod_libpri_la_CFLAGS = $(FTDM_CFLAGS) $(AM_CFLAGS)
|
||||
ftmod_libpri_la_LDFLAGS = -shared -module -avoid-version -lpri
|
||||
ftmod_libpri_la_LIBADD = libfreetdm.la
|
||||
ftmod_libpri_la_CFLAGS = $(FTDM_CFLAGS) $(AM_CFLAGS) $(LIBPRI_CPPFLAGS)
|
||||
ftmod_libpri_la_LDFLAGS = -shared -module -avoid-version $(LIBPRI_LDFLAGS)
|
||||
ftmod_libpri_la_LIBADD = libfreetdm.la $(LIBPRI_LIBS)
|
||||
endif
|
||||
|
||||
if HAVE_PRITAP
|
||||
@@ -248,6 +248,14 @@ ftmod_r2_la_LDFLAGS = -shared -module -avoid-version -lopenr2
|
||||
ftmod_r2_la_LIBADD = libfreetdm.la
|
||||
endif
|
||||
|
||||
if HAVE_MISDN
|
||||
mod_LTLIBRARIES += ftmod_misdn.la
|
||||
ftmod_misdn_la_SOURCES = $(SRC)/ftmod/ftmod_misdn/ftmod_misdn.c
|
||||
ftmod_misdn_la_CFLAGS = $(FTDM_CFLAGS) $(AM_CFLAGS) $(MISDN_CFLAGS) -D_GNU_SOURCE
|
||||
ftmod_misdn_la_LDFLAGS = -shared -module -avoid-version
|
||||
ftmod_misdn_la_LIBADD = libfreetdm.la
|
||||
endif
|
||||
|
||||
dox doxygen:
|
||||
doxygen $(FT_SRCDIR)/docs/Doxygen.conf
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
m4_include([build/ax_compiler_vendor.m4])
|
||||
m4_include([build/libpcap.m4])
|
||||
@@ -75,6 +75,11 @@ with the signaling protocols that you can run on top of your I/O interfaces.
|
||||
<param name="polarity-delay" value="600"/>
|
||||
-->
|
||||
|
||||
<!-- Retrieve caller id on polarity reverse -->
|
||||
<!--
|
||||
<param name="polarity-callerid" value="true"/>
|
||||
-->
|
||||
|
||||
<!-- regex to stop dialing when it matches -->
|
||||
<!--<param name="dial-regex" value="5555"/>-->
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
; This file is used to generate telephony tones by FreeTDM
|
||||
|
||||
[us]
|
||||
generate-dial => v=-7;%(1000,0,350,440)
|
||||
detect-dial => 350,440
|
||||
@@ -47,19 +45,98 @@ detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 1776.7
|
||||
|
||||
|
||||
[ru]
|
||||
generate-dial => v=-7;%(1000,425)
|
||||
detect-dial => 0
|
||||
|
||||
generate-ring => v=-7;%(800,5000,425,0)
|
||||
detect-ring => 425,0
|
||||
|
||||
generate-busy => v=-7;%(350,350,425,0)
|
||||
detect-busy => 425,0
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440,480
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 1776.7
|
||||
|
||||
|
||||
[in]
|
||||
generate-dial => v=-7;%(1000,0,375,425)
|
||||
detect-dial => 375,425
|
||||
|
||||
generate-ring => v=-7;%(2000,4000,440,480)
|
||||
detect-ring => 440,480
|
||||
|
||||
generate-busy => v=-7;%(500,500,480,620)
|
||||
detect-busy => 480,620
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 776.7
|
||||
|
||||
|
||||
[th]
|
||||
generate-dial => v=-7;%(1000,0,400,400)
|
||||
detect-dial => 400,400
|
||||
|
||||
generate-ring => v=-7;%(2000,4000,400,400)
|
||||
detect-ring => 400,400
|
||||
|
||||
generate-busy => v=-7;%(500,500,480,620)
|
||||
detect-busy => 480,620
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 1776.7
|
||||
|
||||
|
||||
[au]
|
||||
generate-dial => v=-7;%(1000,0,413,438)
|
||||
detect-dial => 413,438
|
||||
|
||||
generate-ring => v=-7;%(400,200,413,438);%(400,2000,413,438)
|
||||
detect-ring => 413,438
|
||||
|
||||
generate-busy => v=-7;%(375,375,425)
|
||||
detect-busy => 425
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 776.7
|
||||
+75
-10
@@ -54,6 +54,9 @@ fi
|
||||
|
||||
AC_SUBST([confdir])
|
||||
|
||||
DEFAULT_INCLUDES="-I. -I./src/include -I\$(srcdir)"
|
||||
AC_SUBST([DEFAULT_INCLUDES])
|
||||
|
||||
# Where to install the modules
|
||||
AC_ARG_WITH([modinstdir],
|
||||
[AS_HELP_STRING([--with-modinstdir=DIR], [Install modules into this location (default: ${prefix}/mod)])],
|
||||
@@ -191,28 +194,46 @@ AM_CONDITIONAL([HAVE_OPENR2], [test "${HAVE_OPENR2}" = "yes"])
|
||||
#
|
||||
HAVE_LIBPRI="no"
|
||||
AC_ARG_WITH([libpri],
|
||||
[AS_HELP_STRING([--with-libpri], [Install ftmod_libpri])],
|
||||
[AS_HELP_STRING([--with-libpri@<:@=PREFIX@:>@], [Install ftmod_libpri])],
|
||||
[case "${withval}" in
|
||||
no) enable_libpri="no" ;;
|
||||
*) enable_libpri="yes" ;;
|
||||
no|yes) with_libpri="${withval}" ;;
|
||||
*) AS_IF([test -d "${withval}"],
|
||||
[with_libpri="${withval}"],
|
||||
[AC_MSG_ERROR([Invalid argument for --with-libpri, \"${withval}\" is not a directory])]
|
||||
) ;;
|
||||
esac],
|
||||
[enable_libpri="no"]
|
||||
[with_libpri="no"]
|
||||
)
|
||||
if test "${enable_libpri}" != "no"
|
||||
if test "x${with_libpri}" != "xno"
|
||||
then
|
||||
save_LIBS="${LIBS}"
|
||||
save_CPPFLAGS="${CPPFLAGS}"
|
||||
save_LDFLAGS="${LDFLAGS}"
|
||||
|
||||
LIBPRI_CPPFLAGS=""
|
||||
LIBPRI_LDFLAGS=""
|
||||
|
||||
AC_MSG_RESULT([${as_nl}<<>> Digium libpri])
|
||||
|
||||
save_LIBS="${LIBS}"
|
||||
AS_IF([test "x${with_libpri}" != "xyes"],
|
||||
[LIBPRI_CPPFLAGS="-I${with_libpri}/include"
|
||||
LIBPRI_LDFLAGS="-L${with_libpri}/lib"],
|
||||
)
|
||||
|
||||
LDFLAGS="${save_LDFLAGS} ${LIBPRI_LDFLAGS}"
|
||||
CPPFLAGS="${save_CPPFLAGS} ${LIBPRI_CPPFLAGS}"
|
||||
LIBS="${LIBS} -lpri"
|
||||
|
||||
AC_MSG_CHECKING([whether libpri is usable])
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include <libpri.h>],
|
||||
[const char *version = pri_get_version();]
|
||||
)],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([yes])
|
||||
HAVE_LIBPRI="yes"],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([libpri is not installed or unusable (see config.log for details)])]
|
||||
AC_MSG_ERROR([libpri not found or unusable (see config.log for details)])]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([whether libpri has BRI support])
|
||||
@@ -238,10 +259,17 @@ then
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_NOTICE([You will need libpri-1.4.12_beta1 or newer for AOC event support])]
|
||||
)
|
||||
|
||||
# libpri is available, set variables for Makefile(.am)
|
||||
AC_SUBST([LIBPRI_LIBS], [-lpri])
|
||||
AC_SUBST([LIBPRI_LDFLAGS])
|
||||
AC_SUBST([LIBPRI_CPPFLAGS])
|
||||
|
||||
LIBS="${save_LIBS}"
|
||||
LDFLAGS="${save_LDFLAGS}"
|
||||
CPPFLAGS="${save_CPPFLAGS}"
|
||||
fi
|
||||
HAVE_LIBPRI="${enable_libpri}"
|
||||
AM_CONDITIONAL([HAVE_LIBPRI],[test "${enable_libpri}" = "yes"])
|
||||
AM_CONDITIONAL([HAVE_LIBPRI],[test "x${HAVE_LIBPRI}" = "xyes"])
|
||||
|
||||
##
|
||||
# Sangoma Wanpipe
|
||||
@@ -364,6 +392,42 @@ then
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_LIBISDN], [test "${HAVE_LIBISDN}" = "yes"])
|
||||
|
||||
|
||||
##
|
||||
# mISDN dependencies
|
||||
#
|
||||
HAVE_MISDN="no"
|
||||
AC_ARG_WITH([misdn],
|
||||
[AS_HELP_STRING([--with-misdn], [Install ftmod_misdn (mISDN I/O plugin)])],
|
||||
[case "${withval}" in
|
||||
no|yes) with_misdn="${withval}" ;;
|
||||
*) AC_MSG_ERROR([Invalid value \"${with_misdn}\" for --with-misdn option]) ;;
|
||||
esac],
|
||||
[with_misdn="auto"]
|
||||
)
|
||||
AS_IF([test "${with_misdn}" != "no"],
|
||||
[AC_MSG_RESULT([${as_nl}<<>> ftmod_misdn (Linux mISDN I/O plugin)])
|
||||
AC_CHECK_FUNCS([timerfd_create],,
|
||||
[AS_IF([test "${with_misdn}" = "yes"],
|
||||
[AC_MSG_ERROR([no timerfd support in libc])],
|
||||
[AC_MSG_NOTICE([no timerfd support in libc])]
|
||||
)]
|
||||
)
|
||||
AC_CHECK_HEADER([mISDN/mISDNif.h],,
|
||||
[AS_IF([test "${with_misdn}" = "yes"],
|
||||
[AC_MSG_ERROR([mISDN/mISDNif.h not found])],
|
||||
[AC_MSG_NOTICE([mISDN/mISDNif.h not found])]
|
||||
)],
|
||||
[#include <sys/socket.h>]
|
||||
)
|
||||
AS_IF([test "${ac_cv_func_timerfd_create}" = "yes" -a "${ac_cv_header_mISDN_mISDNif_h}" = "yes"],
|
||||
[HAVE_MISDN="yes"],
|
||||
[AC_MSG_NOTICE([Some required dependencies are missing, module disabled])]
|
||||
)]
|
||||
)
|
||||
AM_CONDITIONAL([HAVE_MISDN], [test "${HAVE_MISDN}" = "yes"])
|
||||
|
||||
|
||||
AC_MSG_RESULT([${as_nl}<<>> Creating output files])
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
@@ -389,6 +453,7 @@ AC_MSG_RESULT([
|
||||
ftmod_pritap....................... ${HAVE_PRITAP}
|
||||
I/O:
|
||||
ftmod_wanpipe...................... ${HAVE_LIBSANGOMA}
|
||||
ftmod_misdn........................ ${HAVE_MISDN}
|
||||
|
||||
===============================================================================
|
||||
])
|
||||
@@ -0,0 +1,76 @@
|
||||
== This is an email sent to stkn responding to his post http://stkn.techmage.de/archives/200 ==
|
||||
|
||||
1. FreeTDM open channels immediately.
|
||||
|
||||
Yes, this seems to come from the early days of OpenZAP where probably the analog modules were implemented first and was dragged incorrectly to ISDN.
|
||||
The open API also sets the flag in use so others cannot use it. We should decouple this open and reserve operations. Does not seem very hard to do,
|
||||
I'll take a look at it on my way back to Toronto this week or earlier if possible, I'll create a git branch for it and send you the url for peer review.
|
||||
Feel free to do the opposite if you are in a hurry.
|
||||
|
||||
2. FreeTDM does not completely close the channel on hangup.
|
||||
|
||||
As long as the signaling module calls ftdm_channel_close() the fio->close API will be called where the IO module is responsible
|
||||
for turning off ec or any other operations to leave the channel unused/idle (not really closed). There was indeed a bug where ftdm_zt module
|
||||
was not properly closing the channel, if that is what you mean, then it means that was already fixed by you with your audio mode turn off patch.
|
||||
|
||||
Now, a more lengthy response ...
|
||||
|
||||
When we, Sangoma, took over openzap and renamed it to freetdm, it was not just a name change, many API cleanups were done so API users cannot access
|
||||
|
||||
the internal data structures and cannot explicitly move between channel states. Also, some order on the state transitions has been put into place.
|
||||
|
||||
We've tried to keep backwards compatibility though, so old modules may not follow all of the conventions. Some unwritten conventions are:
|
||||
|
||||
1. Signaling modules are responsible for calling ftdm_channel_close() when done with the channel. In fact, signaling modules should not
|
||||
call ftdm_channel_done unless they really know what they're doing. ftdm_channel_close will call ftdm_channel_done anyways.
|
||||
|
||||
2. When remote end hangs up a call, signaling module should go to TERMINATING state and send SIGEVENT_STOP to the user. The signaling stack
|
||||
should not acknowledge the hangup until the user implicitly moves us to HANGUP (via ftdm_channel_call_hangup()). There is a core timer
|
||||
that will ensure we move from TERMINATING to HANGUP if the user does not moves us fast enough (arbitrarely 3000ms), although that is considered
|
||||
a bug in the user application (at some point we saw that in FreeSWITCH) and we complain loudly when that happens.
|
||||
|
||||
3. Signaling modules should leave the channel with NO pending states once they unlock it. This means, whenever you have a message to process
|
||||
you must lock the channel, check its current state (the user may have already changed the state to something else), process any pending
|
||||
state set by the user, then process your message and if required move the channel to a new state and process that state before releasing the lock.
|
||||
There is a chance of a deadlock due to the callbacks we use to notify users of messages if we call those callbacks with the channel lock held and
|
||||
that is why new signaling modules should use the FTDM_SPAN_USE_SIGNALS_QUEUE to defer the notification to the user when the ftdm_channel_t is not
|
||||
locked calling ftdm_span_trigger_signals() at the end of their processing loop which delivers the callback notifications to users.
|
||||
|
||||
Having said that, there is a major architectural change coming, probably early 2011, and I'd like to have your input.
|
||||
|
||||
== Decoupling calls from IO channels ==
|
||||
|
||||
We've also found that the concept of a channel and a call are unnecesarily coupled together in FreeTDM. I've never asked Anthony the reasoning
|
||||
for this, but it seems the API was meant to be used with, or without calls. That is, a user should be able to just 'open' a channel and start
|
||||
reading and writing raw data without ever launching one of the provided signaling stacks on top, may be just because the user is using their
|
||||
own signaling stack and just needs freetdm/openzap as an I/O API. In fact, signaling modules work like this (but there are defects there).
|
||||
The problem is, as you have noticed, the way ftdm_channel_open_xx APIs has been implemented is abusing this concept.
|
||||
|
||||
Problems with current implementation.
|
||||
|
||||
1. Exclusive channel is the only way we can request channels to the ISDN network. There is no room to change the channel later on easily.
|
||||
2. Multi-rate calls cannot be done. We need to associate multiple B-channels to a single call.
|
||||
3. Low-bit-rate calls (not sure what is the proper name for them) where a single B-channel can feed media to multiple calls with a low bit-rate
|
||||
codec (I know of at least one request from a big company for this to support some Q.SIG stuff for Eurocontrol).
|
||||
|
||||
|
||||
What do we need?
|
||||
|
||||
I think there should be only one open() API that wraps calls around fio->open(), the other current open_xx functions that do hunting, should
|
||||
be eliminated and some extra arguments provided to ftdm_channel_call_place to provide information about the channel where we would like to
|
||||
place the call or group hunting information and the API would return immediately providing a ftdm_call_t reference pointer that can be used
|
||||
to further track the status of that call, or in the case where a channel exclusivity was requested and we know for a fact is not available,
|
||||
just return failure. At that point there is no I/O channel involved yet. Eventually after the signaling stack hunts the channel and
|
||||
negotiaties its availability with the network, an I/O channel can be attached to that call, or even attach multiple channels (for the case
|
||||
of multi rate calls?).
|
||||
|
||||
This involves heavy changes. The state machine should be moved out of the ftdm_channel_t structure along with probably some other members
|
||||
and stuffed into a new ftdm_call_t structure. Signaling modules would have to be updated to run their state machines with this call
|
||||
structure and then at some point attach IO channels to the call. There would be 2 type of read/write APIs, one low level ftdm_channel_read
|
||||
which receives an ftdm_channel_t as parameter and an ftdm_call_read() which receives an ftdm_call_t as parameter, for the case of multi-rate
|
||||
calls or low-bit-rate multiplexed calls in the same B-channel this API would return just the media corresponding to that call already
|
||||
demultiplexed or concatenated, or whatever needs to be done with the media from the multiple low-level IO channels.
|
||||
|
||||
This is fairly disruptive, but I believe should be done sooner or later.
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../../curl/include;../src/isdn/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@@ -126,7 +126,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../../curl/include;../src/isdn/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
@@ -210,7 +210,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../../curl/include;../src/isdn/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@@ -292,7 +292,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../src/isdn/include"
|
||||
AdditionalIncludeDirectories="../../../src/include;../src/include;../../curl/include;../src/isdn/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../../curl/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
@@ -117,7 +117,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../../curl/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
@@ -148,7 +148,7 @@
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../../curl/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
@@ -177,7 +177,7 @@
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>../../../src/include;../src/include;../../curl/include;../src/isdn/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
|
||||
@@ -34,6 +34,15 @@
|
||||
#include <switch.h>
|
||||
#include "freetdm.h"
|
||||
|
||||
//#define CUDATEL_DEBUG
|
||||
#ifdef CUDATEL_DEBUG
|
||||
#ifndef _BSD_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#endif
|
||||
#include <execinfo.h>
|
||||
#include <syscall.h>
|
||||
#endif
|
||||
|
||||
#ifndef __FUNCTION__
|
||||
#define __FUNCTION__ __SWITCH_FUNC__
|
||||
#endif
|
||||
@@ -495,15 +504,14 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
||||
switch_channel_t *channel = NULL;
|
||||
private_t *tech_pvt = NULL;
|
||||
ftdm_chan_type_t chantype;
|
||||
uint32_t tokencnt;
|
||||
char *uuid = NULL;
|
||||
uint8_t uuid_found = 0;
|
||||
uint32_t t = 0;
|
||||
const char *token = NULL;
|
||||
const char *name = NULL;
|
||||
int span_id = 0;
|
||||
int chan_id = 0;
|
||||
const char *name = NULL;
|
||||
|
||||
uint32_t t = 0;
|
||||
uint32_t tokencnt;
|
||||
char *uuid = NULL;
|
||||
const char *token = NULL;
|
||||
uint8_t uuid_found = 0;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
@@ -511,13 +519,60 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
assert(tech_pvt != NULL);
|
||||
|
||||
/* ignore any further I/O requests, we're hanging up already! */
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
/* ignore any further I/O requests, we're hanging up already! */
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
|
||||
name = switch_channel_get_name(channel);
|
||||
|
||||
span_id = tech_pvt->ftdmchan ? ftdm_channel_get_span_id(tech_pvt->ftdmchan) : 0;
|
||||
chan_id = tech_pvt->ftdmchan ? ftdm_channel_get_id(tech_pvt->ftdmchan) : 0;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%d:%d] %s CHANNEL HANGUP ENTER\n", span_id, chan_id, name);
|
||||
|
||||
/* First verify this call has a device attached */
|
||||
if (!tech_pvt->ftdmchan) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s does not have any ftdmchan attached\n", name);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now verify the device is still attached to this call :-)
|
||||
* Sometimes the FS core takes too long (more than 3 seconds) in calling
|
||||
* channel_on_hangup() and the FreeTDM core decides to take the brute
|
||||
* force approach and hangup and detach themselves from the call. Later
|
||||
* when FS finally comes around, we might end up hanging up the device
|
||||
* attached to another call, this verification avoids that. */
|
||||
uuid = switch_core_session_get_uuid(session);
|
||||
tokencnt = ftdm_channel_get_token_count(tech_pvt->ftdmchan);
|
||||
for (t = 0; t < tokencnt; t++) {
|
||||
token = ftdm_channel_get_token(tech_pvt->ftdmchan, t);
|
||||
if (!zstr(token) && !strcasecmp(uuid, token)) {
|
||||
uuid_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uuid_found) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Device [%d:%d] is no longer attached to %s. Nothing to do.\n", span_id, chan_id, name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef CUDATEL_DEBUG
|
||||
{
|
||||
pid_t tid = 0;
|
||||
size_t size = 0;
|
||||
char **symbols = NULL;
|
||||
void *stacktrace[50];
|
||||
int si = 0;
|
||||
size = backtrace(stacktrace, ftdm_array_len(stacktrace));
|
||||
symbols = backtrace_symbols(stacktrace, size);
|
||||
tid = syscall(SYS_gettid);
|
||||
for (si = 0; si < size; si++) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%d:%d][tid:%d] %s -> %s\n",
|
||||
span_id, chan_id, tid, name, symbols[si]);
|
||||
}
|
||||
free(symbols);
|
||||
}
|
||||
#endif
|
||||
|
||||
name = switch_channel_get_name(channel);
|
||||
|
||||
@@ -549,7 +604,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
||||
|
||||
ftdm_channel_clear_token(tech_pvt->ftdmchan, switch_core_session_get_uuid(session));
|
||||
|
||||
chantype = ftdm_channel_get_type(tech_pvt->ftdmchan);
|
||||
chantype = ftdm_channel_get_type(tech_pvt->ftdmchan);
|
||||
switch (chantype) {
|
||||
case FTDM_CHAN_TYPE_FXO:
|
||||
case FTDM_CHAN_TYPE_EM:
|
||||
@@ -560,7 +615,6 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
||||
case FTDM_CHAN_TYPE_FXS:
|
||||
{
|
||||
if (!ftdm_channel_call_check_busy(tech_pvt->ftdmchan) && !ftdm_channel_call_check_done(tech_pvt->ftdmchan)) {
|
||||
tokencnt = ftdm_channel_get_token_count(tech_pvt->ftdmchan);
|
||||
if (tokencnt) {
|
||||
cycle_foreground(tech_pvt->ftdmchan, 0, NULL);
|
||||
} else {
|
||||
@@ -588,9 +642,6 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
||||
|
||||
end:
|
||||
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.calls--;
|
||||
if (globals.calls < 0) {
|
||||
@@ -598,6 +649,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%d:%d] %s CHANNEL HANGUP EXIT\n", span_id, chan_id, name);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -669,6 +721,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
int total_to;
|
||||
int chunk, do_break = 0;
|
||||
uint32_t span_id, chan_id;
|
||||
const char *name = NULL;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
@@ -676,17 +729,18 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
assert(tech_pvt != NULL);
|
||||
|
||||
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "TFLAG_DEAD is set\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
name = switch_channel_get_name(channel);
|
||||
if (!tech_pvt->ftdmchan) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan);
|
||||
chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan);
|
||||
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Digium Cards sometimes timeout several times in a row here.
|
||||
Yes, we support digium cards, ain't we nice.......
|
||||
@@ -718,7 +772,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
}
|
||||
|
||||
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "TFLAG_IO is not set\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -726,7 +780,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, chunk);
|
||||
|
||||
if (status == FTDM_FAIL) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to wait for I/O\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -734,7 +788,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) {
|
||||
total_to -= chunk;
|
||||
if (total_to <= 0) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Too many timeouts while waiting for I/O\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many timeouts while waiting I/O in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -747,9 +801,9 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
|
||||
len = tech_pvt->read_frame.buflen;
|
||||
if (ftdm_channel_read(tech_pvt->ftdmchan, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "failed to read from device %d:%d\n", span_id, chan_id);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
if (++tech_pvt->read_error > FTDM_MAX_READ_WRITE_ERRORS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "too many I/O read errors on device %d:%d!\n", span_id, chan_id);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "too many I/O read errors on channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
@@ -765,23 +819,23 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
||||
}
|
||||
|
||||
while (ftdm_channel_dequeue_dtmf(tech_pvt->ftdmchan, dtmf, sizeof(dtmf))) {
|
||||
switch_dtmf_t _dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
|
||||
switch_dtmf_t _dtmf = { 0, switch_core_default_dtmf_duration(0) };
|
||||
char *p;
|
||||
for (p = dtmf; p && *p; p++) {
|
||||
if (is_dtmf(*p)) {
|
||||
_dtmf.digit = *p;
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s\n", *p, switch_channel_get_name(channel));
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id);
|
||||
switch_channel_queue_dtmf(channel, &_dtmf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "clearing IO in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
return SWITCH_STATUS_GENERR;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
|
||||
@@ -790,8 +844,9 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
private_t *tech_pvt = NULL;
|
||||
ftdm_size_t len;
|
||||
unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
|
||||
const char *name = "(none)";
|
||||
ftdm_wait_flag_t wflags = FTDM_WRITE;
|
||||
uint32_t span_id, chan_id;
|
||||
uint32_t span_id = 0, chan_id = 0;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
@@ -799,7 +854,17 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
assert(tech_pvt != NULL);
|
||||
|
||||
name = switch_channel_get_name(channel);
|
||||
if (!tech_pvt->ftdmchan) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan);
|
||||
chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan);
|
||||
|
||||
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
@@ -808,17 +873,10 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
}
|
||||
|
||||
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!tech_pvt->ftdmchan) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan);
|
||||
chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan);
|
||||
|
||||
|
||||
if (switch_test_flag(frame, SFF_CNG)) {
|
||||
frame->data = data;
|
||||
frame->buflen = sizeof(data);
|
||||
@@ -833,16 +891,16 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdmchan) * 10);
|
||||
|
||||
if (!(wflags & FTDM_WRITE)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready)\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write note ready) in channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
len = frame->datalen;
|
||||
if (ftdm_channel_write(tech_pvt->ftdmchan, frame->data, frame->buflen, &len) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "failed to write to device %d:%d\n", span_id, chan_id);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
if (++tech_pvt->write_error > FTDM_MAX_READ_WRITE_ERRORS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR, "too many I/O write errors on device %d:%d!\n", span_id, chan_id);
|
||||
SWITCH_LOG_ERROR, "Too many I/O write errors on channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
@@ -852,7 +910,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error writing to channel %s device %d:%d!\n", name, span_id, chan_id);
|
||||
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
|
||||
return SWITCH_STATUS_GENERR;
|
||||
|
||||
@@ -1854,11 +1912,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
|
||||
|
||||
switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Screen", "%d", channel_caller_data->screen);
|
||||
switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Presentation", "%d", channel_caller_data->pres);
|
||||
|
||||
var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_callref");
|
||||
if (!ftdm_strlen_zero(var_value)) {
|
||||
switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallReference", "%s", var_value);
|
||||
}
|
||||
switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-CallReference", "%d", channel_caller_data->call_reference);
|
||||
|
||||
var_value = ftdm_sigmsg_get_var(sigmsg, "ss7_opc");
|
||||
if (!ftdm_strlen_zero(var_value)) {
|
||||
@@ -2361,7 +2415,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
|
||||
switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_channel_hangup(channel, caller_data->hangup_cause);
|
||||
ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
}
|
||||
@@ -3149,6 +3202,7 @@ static switch_status_t load_config(void)
|
||||
const char *enable_callerid = "true";
|
||||
const char *answer_polarity = "false";
|
||||
const char *hangup_polarity = "false";
|
||||
const char *polarity_callerid = "false";
|
||||
int polarity_delay = 600;
|
||||
int callwaiting = 1;
|
||||
int dialtone_timeout = 5000;
|
||||
@@ -3230,6 +3284,8 @@ static switch_status_t load_config(void)
|
||||
hangup_polarity = val;
|
||||
} else if (!strcasecmp(var, "polarity-delay")) {
|
||||
polarity_delay = atoi(val);
|
||||
} else if (!strcasecmp(var, "polarity-callerid")) {
|
||||
polarity_callerid = val;
|
||||
} else if (!strcasecmp(var, "fail-dial-regex")) {
|
||||
fail_dial_regex = val;
|
||||
} else if (!strcasecmp(var, "hold-music")) {
|
||||
@@ -3292,6 +3348,7 @@ static switch_status_t load_config(void)
|
||||
"enable_callerid", enable_callerid,
|
||||
"answer_polarity_reverse", answer_polarity,
|
||||
"hangup_polarity_reverse", hangup_polarity,
|
||||
"polarity_callerid", polarity_callerid,
|
||||
"polarity_delay", &polarity_delay,
|
||||
"callwaiting", &callwaiting,
|
||||
"wait_dialtone_timeout", &dialtone_timeout,
|
||||
@@ -3918,16 +3975,151 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
|
||||
switch_channel_cause2str(caller_data->hangup_cause));
|
||||
}
|
||||
|
||||
typedef struct ftdm_cli_entry ftdm_cli_entry_t;
|
||||
typedef switch_status_t (*ftdm_cli_function_t)(ftdm_cli_entry_t *cli, const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[]);
|
||||
#define FTDM_CLI_DECLARE(name) static switch_status_t name(ftdm_cli_entry_t *cli, const char *cmd, \
|
||||
switch_core_session_t *session, switch_stream_handle_t *stream, \
|
||||
int argc, char *argv[])
|
||||
static void print_usage(switch_stream_handle_t *stream, ftdm_cli_entry_t *cli);
|
||||
|
||||
static switch_status_t ftdm_cmd_voice_detect(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
|
||||
typedef struct cmd_ioread_data {
|
||||
int num_times;
|
||||
uint32_t interval;
|
||||
ftdm_span_t *span;
|
||||
ftdm_channel_t *fchan;
|
||||
switch_memory_pool_t *pool;
|
||||
int already_open;
|
||||
} cmd_ioread_data_t;
|
||||
|
||||
static void *SWITCH_THREAD_FUNC ioread_thread(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
stream->write_function(stream, "IMPLEMENT ME!\n");
|
||||
ftdm_wait_flag_t wflags = FTDM_READ;
|
||||
ftdm_status_t status = FTDM_FAIL;
|
||||
unsigned char iobuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
cmd_ioread_data_t *data = obj;
|
||||
int span_id = ftdm_span_get_id(data->span);
|
||||
int chan_id = ftdm_channel_get_id(data->fchan);
|
||||
ftdm_size_t len = ftdm_channel_get_io_packet_len(data->fchan);
|
||||
ftdm_size_t origlen = len;
|
||||
unsigned int pbuf[5];
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Started ioread thread (times = %d, interval = %ums, len = %"FTDM_SIZE_FMT", span = %d, chan = %d\n",
|
||||
data->num_times, data->interval, len, span_id, chan_id);
|
||||
|
||||
while (ftdm_running() && data->num_times > 0) {
|
||||
data->num_times--;
|
||||
|
||||
wflags = FTDM_READ;
|
||||
|
||||
status = ftdm_channel_wait(data->fchan, &wflags, (data->interval * 10));
|
||||
|
||||
if (status == FTDM_FAIL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to wait for IO in device %d:%d!\n", span_id, chan_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status == FTDM_TIMEOUT) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Timed out while waiting I/O in device %d:%d!\n", span_id, chan_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
len = origlen;
|
||||
if (ftdm_channel_read(data->fchan, iobuf, &len) != FTDM_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from device %d:%d!\n", span_id, chan_id);
|
||||
continue;
|
||||
}
|
||||
pbuf[0] = iobuf[0];
|
||||
pbuf[1] = iobuf[1];
|
||||
pbuf[2] = iobuf[2];
|
||||
pbuf[3] = iobuf[3];
|
||||
pbuf[4] = iobuf[4];
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Read 0x%1X 0x%1X 0x%1X 0x%1X 0x%1X\n",
|
||||
pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4]);
|
||||
}
|
||||
|
||||
if (!data->already_open) {
|
||||
ftdm_channel_close(&data->fchan);
|
||||
}
|
||||
|
||||
switch_core_destroy_memory_pool(&data->pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Done ioread thread (times = %d, interval = %ums, len = %"FTDM_SIZE_FMT", span = %d, chan = %d\n",
|
||||
data->num_times, data->interval, origlen, span_id, chan_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_ioread)
|
||||
{
|
||||
char *span_name = NULL;
|
||||
int channo = 0;
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
switch_threadattr_t *attr = NULL;
|
||||
switch_thread_t *thread = NULL;
|
||||
|
||||
cmd_ioread_data_t *thdata;
|
||||
cmd_ioread_data_t data;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.num_times = 1;
|
||||
|
||||
if (argc < 3) {
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
span_name = argv[1];
|
||||
|
||||
ftdm_span_find_by_name(span_name, &data.span);
|
||||
if (!data.span) {
|
||||
stream->write_function(stream, "-ERR span %s not found\n", span_name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
channo = atoi(argv[2]);
|
||||
|
||||
status = ftdm_channel_open(ftdm_span_get_id(data.span), channo, &data.fchan);
|
||||
if (!data.fchan || (status != FTDM_SUCCESS && status != FTDM_EBUSY)) {
|
||||
stream->write_function(stream, "-ERR Failed to open channel %d in span %s\n", channo, span_name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (status == FTDM_EBUSY) {
|
||||
data.already_open = 1;
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
data.num_times = atoi(argv[3]);
|
||||
if (data.num_times < 1) {
|
||||
data.num_times = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 4) {
|
||||
data.interval = atoi(argv[4]);
|
||||
}
|
||||
|
||||
if (data.interval <= 0 || data.interval > 10000) {
|
||||
data.interval = ftdm_channel_get_io_interval(data.fchan);
|
||||
}
|
||||
|
||||
switch_core_new_memory_pool(&data.pool);
|
||||
|
||||
thdata = switch_core_alloc(data.pool, sizeof(data));
|
||||
memcpy(thdata, &data, sizeof(*thdata));
|
||||
|
||||
switch_threadattr_create(&attr, data.pool);
|
||||
switch_threadattr_detach_set(attr, 1);
|
||||
switch_threadattr_stacksize_set(attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_thread_create(&thread, attr, ioread_thread, thdata, data.pool);
|
||||
|
||||
end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_list(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_list)
|
||||
{
|
||||
int j;
|
||||
for (j = 0 ; j < FTDM_MAX_SPANS_INTERFACE; j++) {
|
||||
@@ -4004,19 +4196,20 @@ static switch_status_t ftdm_cmd_list(const char *cmd, switch_core_session_t *ses
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_start_stop(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_start_stop)
|
||||
{
|
||||
char *span_name = argv[1];
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_status_t status;
|
||||
|
||||
if (span_name) {
|
||||
ftdm_span_find_by_name(span_name, &span);
|
||||
if (argc < 2) {
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(span_name, &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR no span\n");
|
||||
stream->write_function(stream, "-ERR span %s not found\n", span_name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -4031,34 +4224,36 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_reset(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_reset)
|
||||
{
|
||||
uint32_t chan_id = 0;
|
||||
uint32_t ccount = 0;
|
||||
ftdm_channel_t *chan;
|
||||
ftdm_span_t *span = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm reset <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(argv[1], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR span %s not found\n", argv[1]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
chan_id = atoi(argv[2]);
|
||||
if (chan_id > ftdm_span_get_chan_count(span)) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel %d\n", chan_id);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan_id) {
|
||||
chan = ftdm_span_get_channel(span, chan_id);
|
||||
if (!chan) {
|
||||
stream->write_function(stream, "-ERR Could not find chan\n");
|
||||
stream->write_function(stream, "-ERR Could not find channel %d\n", chan_id);
|
||||
goto end;
|
||||
}
|
||||
stream->write_function(stream, "Resetting channel %s:%s\n", argv[1], argv[2]);
|
||||
@@ -4078,8 +4273,7 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_dump(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_dump)
|
||||
{
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
@@ -4088,12 +4282,11 @@ static switch_status_t ftdm_cmd_dump(const char *cmd, switch_core_session_t *ses
|
||||
char *as = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm dump <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(argv[1], &span);
|
||||
|
||||
if (argc > 2) {
|
||||
if (argv[3] && !strcasecmp(argv[2], "as")) {
|
||||
as = argv[3];
|
||||
@@ -4156,28 +4349,29 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_sigstatus(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_sigstatus)
|
||||
{
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_signaling_status_t sigstatus;
|
||||
|
||||
if (argc < 3) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [<span_id>] [<chan_id>] [<sigstatus>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[1], "get") && argc < 3) {
|
||||
stream->write_function(stream, "-ERR sigstatus get usage: get <span_id>\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[1], "set") && argc != 5) {
|
||||
stream->write_function(stream, "-ERR sigstatus set usage: set <span_id> <chan_id>|all <sigstatus>\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(argv[2], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR invalid span %s\n", argv[2]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -4186,21 +4380,21 @@ static switch_status_t ftdm_cmd_sigstatus(const char *cmd, switch_core_session_t
|
||||
uint32_t chan_id = atol(argv[3]);
|
||||
ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
|
||||
if (!fchan) {
|
||||
stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
|
||||
stream->write_function(stream, "-ERR invalid channel id '%d'\n", chan_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) {
|
||||
stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus));
|
||||
stream->write_function(stream, "Channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus));
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR failed to get channel sigstatus\n");
|
||||
stream->write_function(stream, "-ERR failed to get channel signaling status\n");
|
||||
}
|
||||
goto end;
|
||||
} else {
|
||||
if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) {
|
||||
stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus));
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span));
|
||||
stream->write_function(stream, "-ERR failed to read span signaling status: %s\n", ftdm_span_get_last_error(span));
|
||||
}
|
||||
}
|
||||
goto end;
|
||||
@@ -4238,8 +4432,7 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_trace(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_trace)
|
||||
{
|
||||
char tracepath[255];
|
||||
unsigned i = 0;
|
||||
@@ -4249,19 +4442,19 @@ static switch_status_t ftdm_cmd_trace(const char *cmd, switch_core_session_t *se
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_channel_t *chan = NULL;
|
||||
if (argc < 3) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm trace <path> <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
ftdm_span_find_by_name(argv[2], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]);
|
||||
goto end;
|
||||
}
|
||||
chan_count = ftdm_span_get_chan_count(span);
|
||||
if (argc > 3) {
|
||||
chan_id = atoi(argv[3]);
|
||||
if (chan_id > chan_count) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
@@ -4286,31 +4479,33 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_notrace(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_notrace)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t chan_id = 0;
|
||||
uint32_t chan_count = 0;
|
||||
ftdm_channel_t *fchan = NULL;
|
||||
ftdm_span_t *span = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm notrace <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
ftdm_span_find_by_name(argv[1], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR failed to find span %s\n", argv[1]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
chan_count = ftdm_span_get_chan_count(span);
|
||||
if (argc > 2) {
|
||||
chan_id = atoi(argv[2]);
|
||||
if (chan_id > chan_count) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan_id) {
|
||||
fchan = ftdm_span_get_channel(span, chan_id);
|
||||
ftdm_channel_command(fchan, FTDM_COMMAND_TRACE_END_ALL, NULL);
|
||||
@@ -4321,12 +4516,12 @@ static switch_status_t ftdm_cmd_notrace(const char *cmd, switch_core_session_t *
|
||||
}
|
||||
}
|
||||
stream->write_function(stream, "+OK trace disabled\n");
|
||||
|
||||
end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_gains(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_gains)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
float txgain = 0.0;
|
||||
@@ -4336,18 +4531,19 @@ static switch_status_t ftdm_cmd_gains(const char *cmd, switch_core_session_t *se
|
||||
ftdm_channel_t *chan;
|
||||
ftdm_span_t *span = NULL;
|
||||
if (argc < 4) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm gains <rxgain> <txgain> <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
ftdm_span_find_by_name(argv[3], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR failed to find span %s\n", argv[3]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (argc > 4) {
|
||||
chan_id = atoi(argv[4]);
|
||||
if (chan_id > ftdm_span_get_chan_count(span)) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
@@ -4375,8 +4571,7 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_dtmf(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_dtmf)
|
||||
{
|
||||
unsigned i = 0;
|
||||
uint32_t chan_id = 0;
|
||||
@@ -4384,8 +4579,9 @@ static switch_status_t ftdm_cmd_dtmf(const char *cmd, switch_core_session_t *ses
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_command_t fcmd = FTDM_COMMAND_ENABLE_DTMF_DETECT;
|
||||
ftdm_channel_t *fchan;
|
||||
|
||||
if (argc < 3) {
|
||||
stream->write_function(stream, "-ERR Usage: dtmf on|off <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -4397,14 +4593,15 @@ static switch_status_t ftdm_cmd_dtmf(const char *cmd, switch_core_session_t *ses
|
||||
|
||||
ftdm_span_find_by_name(argv[2], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
schan_count = ftdm_span_get_chan_count(span);
|
||||
if (argc > 3) {
|
||||
chan_id = atoi(argv[3]);
|
||||
if (chan_id > schan_count) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
@@ -4424,8 +4621,7 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_queuesize(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_queuesize)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
uint32_t rxsize = 10;
|
||||
@@ -4435,21 +4631,24 @@ static switch_status_t ftdm_cmd_queuesize(const char *cmd, switch_core_session_t
|
||||
ftdm_channel_t *chan;
|
||||
ftdm_span_t *span = NULL;
|
||||
if (argc < 4) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm queuesize <rxsize> <txsize> <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(argv[3], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR failed to find span %s\n", argv[3]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (argc > 4) {
|
||||
chan_id = atoi(argv[4]);
|
||||
if (chan_id > ftdm_span_get_chan_count(span)) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
i = sscanf(argv[1], "%u", &rxsize);
|
||||
i += sscanf(argv[2], "%u", &txsize);
|
||||
if (i != 2) {
|
||||
@@ -4503,8 +4702,7 @@ static void exec_io_command(const char *cmd, switch_stream_handle_t *stream, ftd
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t ftdm_cmd_iostats(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[])
|
||||
FTDM_CLI_DECLARE(ftdm_cmd_iostats)
|
||||
{
|
||||
uint32_t chan_id = 0;
|
||||
ftdm_channel_t *chan;
|
||||
@@ -4513,20 +4711,20 @@ static switch_status_t ftdm_cmd_iostats(const char *cmd, switch_core_session_t *
|
||||
ftdm_span_t *span = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
stream->write_function(stream, "-ERR Usage: ftdm iostats enable|disable|flush|print <span_id> [<chan_id>]\n");
|
||||
print_usage(stream, cli);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ftdm_span_find_by_name(argv[2], &span);
|
||||
if (!span) {
|
||||
stream->write_function(stream, "-ERR invalid span\n");
|
||||
stream->write_function(stream, "-ERR failed to find span %s\n", argv[2]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
chan_id = atoi(argv[3]);
|
||||
if (chan_id > ftdm_span_get_chan_count(span)) {
|
||||
stream->write_function(stream, "-ERR invalid chan\n");
|
||||
stream->write_function(stream, "-ERR invalid channel\n");
|
||||
goto end;
|
||||
}
|
||||
chan = ftdm_span_get_channel(span, chan_id);
|
||||
@@ -4544,14 +4742,12 @@ end:
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
typedef switch_status_t (*ftdm_cli_function_t)(const char *cmd, switch_core_session_t *session,
|
||||
switch_stream_handle_t *stream, int argc, char *argv[]);
|
||||
typedef struct ftdm_cli_entry {
|
||||
struct ftdm_cli_entry {
|
||||
const char *name;
|
||||
const char *args;
|
||||
const char *complete;
|
||||
ftdm_cli_function_t execute;
|
||||
} ftdm_cli_entry_t;
|
||||
};
|
||||
|
||||
static ftdm_cli_entry_t ftdm_cli_options[] =
|
||||
{
|
||||
@@ -4567,7 +4763,7 @@ static ftdm_cli_entry_t ftdm_cli_options[] =
|
||||
{ "dtmf", "on|off <span_id|span_name> [<chan_id>]", "::[on:off", ftdm_cmd_dtmf },
|
||||
{ "queuesize", "<rxsize> <txsize> <span_id|span_name> [<chan_id>]", "", ftdm_cmd_queuesize },
|
||||
{ "iostats", "enable|disable|flush|print <span_id|span_name> <chan_id>", "::[enable:disable:flush:print", ftdm_cmd_iostats },
|
||||
{ "voice_detect", "[on|off] <span_id|span_name> [<chan_id>]", "::[on:off", ftdm_cmd_voice_detect },
|
||||
{ "ioread", "<span_id|span_name> <chan_id> [num_times] [interval]", "", ftdm_cmd_ioread },
|
||||
|
||||
/* Fake handlers as they are handled within freetdm library,
|
||||
* we should provide a way inside freetdm to query for completions from signaling modules */
|
||||
@@ -4576,6 +4772,11 @@ static ftdm_cli_entry_t ftdm_cli_options[] =
|
||||
{ "core calls", "", "", NULL },
|
||||
};
|
||||
|
||||
static void print_usage(switch_stream_handle_t *stream, ftdm_cli_entry_t *cli)
|
||||
{
|
||||
stream->write_function(stream, "-ERR Usage: ftdm %s %s\n", cli->name, cli->args);
|
||||
}
|
||||
|
||||
static void print_full_usage(switch_stream_handle_t *stream)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -4608,7 +4809,7 @@ SWITCH_STANDARD_API(ft_function)
|
||||
for (i = 0 ; i < ftdm_array_len(ftdm_cli_options); i++) {
|
||||
entry = &ftdm_cli_options[i];
|
||||
if (!strcasecmp(argv[0], entry->name) && entry->execute) {
|
||||
entry->execute(cmd, session, stream, argc, argv);
|
||||
entry->execute(entry, cmd, session, stream, argc, argv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ int main(int argc, char *argv[])
|
||||
int fd, b;
|
||||
short sln[512] = {0};
|
||||
teletone_dtmf_detect_state_t dtmf_detect = {0};
|
||||
char digit_str[128] = "";
|
||||
teletone_hit_type_t hit;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Arg Error!\n");
|
||||
@@ -21,10 +21,31 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
while((b = read(fd, sln, 320)) > 0) {
|
||||
char digit_char;
|
||||
unsigned int dur;
|
||||
|
||||
teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
|
||||
teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
|
||||
if (*digit_str) {
|
||||
printf("digit: %s\n", digit_str);
|
||||
if ((hit = teletone_dtmf_get(&dtmf_detect, &digit_char, &dur))) {
|
||||
const char *hs = NULL;
|
||||
|
||||
|
||||
switch(hit) {
|
||||
case TT_HIT_BEGIN:
|
||||
hs = "begin";
|
||||
break;
|
||||
|
||||
case TT_HIT_MIDDLE:
|
||||
hs = "middle";
|
||||
break;
|
||||
|
||||
case TT_HIT_END:
|
||||
hs = "end";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("%s digit: %c\n", hs, digit_char);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
+30
-15
@@ -649,9 +649,6 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
|
||||
if (span->fio->span_destroy(span) != FTDM_SUCCESS) {
|
||||
status = FTDM_FAIL;
|
||||
}
|
||||
ftdm_safe_free(span->type);
|
||||
ftdm_safe_free(span->name);
|
||||
ftdm_safe_free(span->dtmf_hangup);
|
||||
}
|
||||
|
||||
/* destroy final basic resources of the span data structure */
|
||||
@@ -1858,7 +1855,14 @@ static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm
|
||||
goto done;
|
||||
}
|
||||
|
||||
ftdm_mutex_lock(check->mutex);
|
||||
ftdm_channel_lock(check);
|
||||
|
||||
if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
|
||||
/* let them know is already open, but return the channel anyway */
|
||||
status = FTDM_EBUSY;
|
||||
*ftdmchan = check;
|
||||
goto unlockchan;
|
||||
}
|
||||
|
||||
/* The following if's and gotos replace a big if (this || this || this || this) else { nothing; } */
|
||||
|
||||
@@ -1905,7 +1909,7 @@ openchan:
|
||||
goto done;
|
||||
|
||||
unlockchan:
|
||||
ftdm_mutex_unlock(check->mutex);
|
||||
ftdm_channel_unlock(check);
|
||||
|
||||
done:
|
||||
ftdm_mutex_unlock(globals.mutex);
|
||||
@@ -3855,7 +3859,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, v
|
||||
uint8_t sln_buf[1024] = {0};
|
||||
int16_t *sln;
|
||||
ftdm_size_t slen = 0;
|
||||
char digit_str[80] = "";
|
||||
|
||||
if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
|
||||
sln = data;
|
||||
@@ -3956,13 +3959,20 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, v
|
||||
}
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT) && !ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
|
||||
teletone_dtmf_detect(&ftdmchan->dtmf_detect, sln, (int)slen);
|
||||
teletone_dtmf_get(&ftdmchan->dtmf_detect, digit_str, sizeof(digit_str));
|
||||
teletone_hit_type_t hit;
|
||||
char digit_char;
|
||||
uint32_t dur;
|
||||
|
||||
if(*digit_str) {
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_CALLWAITING && (*digit_str == 'D' || *digit_str == 'A')) {
|
||||
if ((hit = teletone_dtmf_detect(&ftdmchan->dtmf_detect, sln, (int)slen)) == TT_HIT_END) {
|
||||
teletone_dtmf_get(&ftdmchan->dtmf_detect, &digit_char, &dur);
|
||||
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_CALLWAITING && (digit_char == 'D' || digit_char == 'A')) {
|
||||
ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
|
||||
} else {
|
||||
char digit_str[2] = { 0 };
|
||||
|
||||
digit_str[0] = digit_char;
|
||||
|
||||
if (!ftdmchan->span->sig_dtmf || (ftdmchan->span->sig_dtmf(ftdmchan, (const char*)digit_str) != FTDM_BREAK)) {
|
||||
ftdm_channel_queue_dtmf(ftdmchan, digit_str);
|
||||
}
|
||||
@@ -4568,7 +4578,7 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
|
||||
*configured = 0;
|
||||
*configured = span->fio->configure_span(span, str, chan_config->type, chan_config->name, chan_config->number);
|
||||
if (!*configured) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to configure span", span->span_id);
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to configure span\n", span->span_id);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
@@ -5469,10 +5479,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
|
||||
if (sigmsg->channel) {
|
||||
fchan = sigmsg->channel;
|
||||
ftdm_channel_lock(fchan);
|
||||
sigmsg->chan_id = fchan->chan_id;
|
||||
sigmsg->span_id = fchan->span_id;
|
||||
sigmsg->call_id = fchan->caller_data.call_id;
|
||||
sigmsg->call_priv = fchan->caller_data.priv;
|
||||
}
|
||||
|
||||
/* some core things to do on special events */
|
||||
@@ -5562,6 +5568,14 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
|
||||
|
||||
}
|
||||
|
||||
if (fchan) {
|
||||
/* set members of the sigmsg that must be present for all events */
|
||||
sigmsg->chan_id = fchan->chan_id;
|
||||
sigmsg->span_id = fchan->span_id;
|
||||
sigmsg->call_id = fchan->caller_data.call_id;
|
||||
sigmsg->call_priv = fchan->caller_data.priv;
|
||||
}
|
||||
|
||||
/* if the signaling module uses a queue for signaling notifications, then enqueue it */
|
||||
if (ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) {
|
||||
ftdm_span_queue_signal(span, sigmsg);
|
||||
@@ -5783,6 +5797,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
|
||||
}
|
||||
|
||||
hashtable_remove(globals.span_hash, (void *)cur_span->name);
|
||||
ftdm_safe_free(cur_span->dtmf_hangup);
|
||||
ftdm_safe_free(cur_span->type);
|
||||
ftdm_safe_free(cur_span->name);
|
||||
ftdm_safe_free(cur_span);
|
||||
|
||||
@@ -39,7 +39,8 @@ typedef enum {
|
||||
FTDM_ANALOG_RUNNING = (1 << 0),
|
||||
FTDM_ANALOG_CALLERID = (1 << 1),
|
||||
FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2),
|
||||
FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3)
|
||||
FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3),
|
||||
FTDM_ANALOG_POLARITY_CALLERID = (1 << 4)
|
||||
} ftdm_analog_flag_t;
|
||||
|
||||
#define FTDM_MAX_HOTLINE_STR 20
|
||||
|
||||
@@ -275,6 +275,15 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
|
||||
break;
|
||||
}
|
||||
hotline = val;
|
||||
} else if (!strcasecmp(var, "polarity_callerid")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
if (ftdm_true(val)) {
|
||||
flags |= FTDM_ANALOG_POLARITY_CALLERID;
|
||||
} else {
|
||||
flags &= ~FTDM_ANALOG_POLARITY_CALLERID;
|
||||
}
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unknown parameter %s in span %s\n", var, span->name);
|
||||
}
|
||||
@@ -1130,8 +1139,18 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
||||
break;
|
||||
}
|
||||
if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
|
||||
"Ignoring polarity reversal because this channel is down\n");
|
||||
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)
|
||||
&& ftdm_test_flag(analog_data, FTDM_ANALOG_POLARITY_CALLERID)) {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, "Polarity reversal detected while down, getting caller id now\n");
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
|
||||
event->channel->ring_count = 1;
|
||||
ftdm_mutex_unlock(event->channel->mutex);
|
||||
locked = 0;
|
||||
ftdm_thread_create_detached(ftdm_analog_channel_run, event->channel);
|
||||
} else {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
|
||||
"Ignoring polarity reversal because this channel is down\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* we have a good channel, set the polarity flag and let the channel thread deal with it */
|
||||
|
||||
@@ -204,6 +204,32 @@ static int parse_debug(const char *in, uint32_t *flags)
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Parses a change status string to flags
|
||||
* \param in change status string to parse for
|
||||
* \return Flags
|
||||
*/
|
||||
static int parse_change_status(const char *in)
|
||||
{
|
||||
int flags = 0;
|
||||
if (!in) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr(in, "in_service") || strstr(in, "in")) {
|
||||
flags = SERVICE_CHANGE_STATUS_INSERVICE;
|
||||
}
|
||||
if (strstr(in, "maintenance") || strstr(in, "maint")) {
|
||||
flags = SERVICE_CHANGE_STATUS_MAINTENANCE;
|
||||
}
|
||||
if (strstr(in, "out_of_service") || strstr(in, "out")) {
|
||||
flags = SERVICE_CHANGE_STATUS_OUTOFSERVICE;
|
||||
}
|
||||
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int print_debug(uint32_t flags, char *tmp, const int size)
|
||||
{
|
||||
int offset = 0;
|
||||
@@ -240,6 +266,9 @@ static ftdm_io_interface_t ftdm_libpri_interface;
|
||||
static const char *ftdm_libpri_usage =
|
||||
"Usage:\n"
|
||||
"libpri kill <span>\n"
|
||||
"libpri reset <span>\n"
|
||||
"libpri restart <span> <channel/all>\n"
|
||||
"libpri maintenance <span> <channel/all> <in/maint/out>\n"
|
||||
"libpri debug <span> [all|none|flag,...flagN]\n"
|
||||
"\n"
|
||||
"Possible debug flags:\n"
|
||||
@@ -281,9 +310,7 @@ static FIO_API_FUNCTION(ftdm_libpri_api)
|
||||
stream->write_function(stream, ftdm_libpri_usage);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
} else if (argc == 2) {
|
||||
if (!strcasecmp(argv[0], "kill")) {
|
||||
int span_id = atoi(argv[1]);
|
||||
ftdm_span_t *span = NULL;
|
||||
@@ -292,7 +319,8 @@ static FIO_API_FUNCTION(ftdm_libpri_api)
|
||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||
|
||||
if (span->start != ftdm_libpri_start) {
|
||||
stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
|
||||
stream->write_function(stream, "%s: -ERR '%s' is not a libpri span.\n",
|
||||
__FILE__, ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -300,13 +328,12 @@ static FIO_API_FUNCTION(ftdm_libpri_api)
|
||||
stream->write_function(stream, "%s: +OK killed.\n", __FILE__);
|
||||
goto done;
|
||||
} else {
|
||||
stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
|
||||
stream->write_function(stream, "%s: -ERR span '%s' not found.\n",
|
||||
__FILE__, argv[0]);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argc >= 2) {
|
||||
} else if (argc >= 2) {
|
||||
if (!strcasecmp(argv[0], "debug")) {
|
||||
ftdm_span_t *span = NULL;
|
||||
|
||||
@@ -315,7 +342,8 @@ static FIO_API_FUNCTION(ftdm_libpri_api)
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (span->start != ftdm_libpri_start) {
|
||||
stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
|
||||
stream->write_function(stream, "%s: -ERR '%s' is not a libpri span.\n",
|
||||
__FILE__, ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -335,12 +363,95 @@ static FIO_API_FUNCTION(ftdm_libpri_api)
|
||||
stream->write_function(stream, "%s: +OK debug %s.\n", __FILE__, (flags) ? "enabled" : "disabled");
|
||||
goto done;
|
||||
} else {
|
||||
stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
|
||||
stream->write_function(stream, "%s: -ERR span '%s' not found.\n",
|
||||
__FILE__, argv[0]);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (!strcasecmp(argv[0], "reset")) {
|
||||
ftdm_span_t *span = NULL;
|
||||
if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
|
||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||
|
||||
if (span->start != ftdm_libpri_start) {
|
||||
stream->write_function(stream, "%s: -ERR '%s' is not a libpri span.\n",
|
||||
__FILE__, ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
pri_restart(isdn_data->spri.pri);
|
||||
stream->write_function(stream, "%s: +OK reset.\n", __FILE__);
|
||||
goto done;
|
||||
} else {
|
||||
stream->write_function(stream, "%s: -ERR span '%s' not found.\n",
|
||||
__FILE__, argv[0]);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (!strcasecmp(argv[0], "restart") && argc == 3) {
|
||||
ftdm_span_t *span = NULL;
|
||||
if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
|
||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||
|
||||
if (span->start != ftdm_libpri_start) {
|
||||
stream->write_function(stream, "%s: -ERR '%s' is not a libpri span.\n",
|
||||
__FILE__, ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
if (!strcasecmp(argv[2], "all")) {
|
||||
int j;
|
||||
for(j = 1; j <= span->chan_count; j++) {
|
||||
pri_reset(isdn_data->spri.pri, j);
|
||||
ftdm_sleep(50);
|
||||
}
|
||||
} else {
|
||||
pri_reset(isdn_data->spri.pri, atoi(argv[2]));
|
||||
}
|
||||
stream->write_function(stream, "%s: +OK restart set.\n", __FILE__);
|
||||
goto done;
|
||||
} else {
|
||||
stream->write_function(stream, "%s: -ERR span '%s' not found.\n",
|
||||
__FILE__, argv[0]);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (!strcasecmp(argv[0], "maintenance") && argc > 3) {
|
||||
ftdm_span_t *span = NULL;
|
||||
if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
|
||||
ftdm_libpri_data_t *isdn_data = span->signal_data;
|
||||
|
||||
if (span->start != ftdm_libpri_start) {
|
||||
stream->write_function(stream, "%s: -ERR '%s' is not a libpri span.\n",
|
||||
__FILE__, ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
if (!isdn_data->service_message_support) {
|
||||
stream->write_function(stream, "%s: -ERR service message support is disabled\n", __FILE__);
|
||||
goto done;
|
||||
}
|
||||
if (!strcasecmp(argv[2], "all")) {
|
||||
int j;
|
||||
for(j = 1; j <= span->chan_count; j++) {
|
||||
pri_maintenance_service(isdn_data->spri.pri, atoi(argv[1]), j, parse_change_status(argv[3]));
|
||||
ftdm_sleep(50);
|
||||
}
|
||||
} else {
|
||||
pri_maintenance_service(isdn_data->spri.pri, atoi(argv[1]), atoi(argv[2]), parse_change_status(argv[3]));
|
||||
}
|
||||
stream->write_function(stream, "%s: +OK change status set.\n", __FILE__);
|
||||
goto done;
|
||||
} else {
|
||||
stream->write_function(stream, "%s: -ERR span '%s' not found.\n",
|
||||
__FILE__, argv[0]);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* zero args print usage */
|
||||
stream->write_function(stream, ftdm_libpri_usage);
|
||||
goto done;
|
||||
}
|
||||
|
||||
stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
|
||||
|
||||
done:
|
||||
@@ -1066,7 +1177,7 @@ static int on_proceeding(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_
|
||||
|
||||
if (chan) {
|
||||
/* Open channel if inband information is available */
|
||||
if (pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
|
||||
if (pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE || pevent->proceeding.progressmask & PRI_PROG_CALL_NOT_E2E_ISDN) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, B-Channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan));
|
||||
@@ -1108,7 +1219,7 @@ static int on_progress(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev
|
||||
|
||||
if (chan) {
|
||||
/* Open channel if inband information is available */
|
||||
if (pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
|
||||
if (pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE || pevent->proceeding.progressmask & PRI_PROG_CALL_NOT_E2E_ISDN) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, B-Channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan));
|
||||
@@ -1780,6 +1891,10 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
|
||||
pri_facility_enable(isdn_data->spri.pri);
|
||||
}
|
||||
#endif
|
||||
/* Support the different switch of service status */
|
||||
if (isdn_data->service_message_support) {
|
||||
pri_set_service_message_support(isdn_data->spri.pri, 1 /* True */);
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
|
||||
@@ -1835,6 +1950,14 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
|
||||
ftdm_sleep(5000);
|
||||
}
|
||||
out:
|
||||
/* close d-channel, if set */
|
||||
if (isdn_data->dchan) {
|
||||
if (ftdm_channel_close(&isdn_data->dchan) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to close D-Channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(isdn_data->dchan), ftdm_channel_get_id(isdn_data->dchan));
|
||||
}
|
||||
}
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "PRI thread ended on span %d\n", ftdm_span_get_id(span));
|
||||
|
||||
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
|
||||
@@ -2159,6 +2282,11 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
||||
isdn_data->debug_mask = 0;
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp(var, "service_message_support")) {
|
||||
if (ftdm_true(val)) {
|
||||
isdn_data->service_message_support = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unknown parameter '%s', aborting configuration\n", var);
|
||||
snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
SERVICE_CHANGE_STATUS_INSERVICE = 0,
|
||||
SERVICE_CHANGE_STATUS_MAINTENANCE = 1,
|
||||
SERVICE_CHANGE_STATUS_OUTOFSERVICE = 2
|
||||
} service_change_status_t;
|
||||
|
||||
#ifndef FTMOD_LIBPRI_H
|
||||
#define FTMOD_LIBPRI_H
|
||||
@@ -69,6 +74,7 @@ struct ftdm_libpri_data {
|
||||
int overlap; /*!< Overlap dial flags */
|
||||
unsigned int layer1;
|
||||
unsigned int ton;
|
||||
unsigned int service_message_support;
|
||||
|
||||
lpwrap_pri_t spri;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -547,7 +547,7 @@ static void handle_pri_passive_event(pritap_t *pritap, pri_event *e)
|
||||
break;
|
||||
|
||||
case PRI_EVENT_PROGRESS:
|
||||
crv = tap_pri_get_crv(pritap->pri, e->ring.call);
|
||||
crv = tap_pri_get_crv(pritap->pri, e->proceeding.call);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Progress on channel %s:%d:%d with callref %d\n",
|
||||
pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv);
|
||||
break;
|
||||
|
||||
@@ -1155,6 +1155,77 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (span_data->cid_name_method == SNGISDN_CID_NAME_AUTO) {
|
||||
switch (span_data->switchtype) {
|
||||
case SNGISDN_SWITCH_EUROISDN:
|
||||
if (FTDM_SPAN_IS_BRI(span)) {
|
||||
span_data->cid_name_method = SNGISDN_CID_NAME_USR_USR_IE;
|
||||
} else {
|
||||
span_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE;
|
||||
}
|
||||
break;
|
||||
case SNGISDN_SWITCH_DMS100:
|
||||
span_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE;
|
||||
break;
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
span_data->cid_name_method = SNGISDN_CID_NAME_FACILITY_IE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (span_data->send_cid_name == SNGISDN_OPT_DEFAULT) {
|
||||
switch (span_data->switchtype) {
|
||||
case SNGISDN_SWITCH_EUROISDN:
|
||||
#ifdef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
#endif
|
||||
if (span_data->signalling == SNGISDN_SIGNALING_NET) {
|
||||
span_data->send_cid_name = SNGISDN_OPT_TRUE;
|
||||
} else {
|
||||
span_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
}
|
||||
break;
|
||||
case SNGISDN_SWITCH_DMS100:
|
||||
span_data->send_cid_name = SNGISDN_OPT_TRUE;
|
||||
break;
|
||||
#ifndef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
span_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
span_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
break;
|
||||
}
|
||||
} else if (span_data->send_cid_name == SNGISDN_OPT_TRUE) {
|
||||
switch (span_data->switchtype) {
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
#ifndef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
|
||||
ftdm_log(FTDM_LOG_WARNING, "Sending Calling Name in Facility IE not supported, please update your libsng_isdn library\n");
|
||||
span_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
#endif
|
||||
break;
|
||||
case SNGISDN_SWITCH_INSNET: /* Don't know how to transmit caller ID name on INSNET */
|
||||
case SNGISDN_SWITCH_QSIG: /* It seems like QSIG does not support Caller ID */
|
||||
span_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
break;
|
||||
case SNGISDN_SWITCH_EUROISDN:
|
||||
break;
|
||||
default:
|
||||
span_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
span->start = ftdm_sangoma_isdn_start;
|
||||
span->stop = ftdm_sangoma_isdn_stop;
|
||||
|
||||
@@ -132,6 +132,13 @@ typedef enum {
|
||||
SNGISDN_AVAIL_UP = 10,
|
||||
} sngisdn_avail_t;
|
||||
|
||||
typedef enum {
|
||||
SNGISDN_CID_NAME_AUTO,
|
||||
SNGISDN_CID_NAME_DISPLAY_IE,
|
||||
SNGISDN_CID_NAME_USR_USR_IE,
|
||||
SNGISDN_CID_NAME_FACILITY_IE,
|
||||
} sngisdn_cid_name_t;
|
||||
|
||||
typedef enum {
|
||||
SNGISDN_EVENT_CON_IND = 1,
|
||||
SNGISDN_EVENT_CON_CFM,
|
||||
@@ -264,6 +271,8 @@ typedef struct sngisdn_span_data {
|
||||
uint8_t restart_opt;
|
||||
uint8_t restart_timeout;
|
||||
uint8_t force_sending_complete;
|
||||
uint8_t cid_name_method;
|
||||
uint8_t send_cid_name;
|
||||
char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS];
|
||||
ftdm_timer_id_t timers[SNGISDN_NUM_SPAN_TIMERS];
|
||||
ftdm_sched_t *sched;
|
||||
|
||||
@@ -289,6 +289,9 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
||||
signal_data->att_remove_dtmf = SNGISDN_OPT_DEFAULT;
|
||||
signal_data->force_sending_complete = SNGISDN_OPT_DEFAULT;
|
||||
|
||||
signal_data->cid_name_method = SNGISDN_CID_NAME_AUTO;
|
||||
signal_data->send_cid_name = SNGISDN_OPT_DEFAULT;
|
||||
|
||||
span->default_caller_data.dnis.plan = FTDM_NPI_INVALID;
|
||||
span->default_caller_data.dnis.type = FTDM_TON_INVALID;
|
||||
span->default_caller_data.cid_num.plan = FTDM_NPI_INVALID;
|
||||
@@ -361,7 +364,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
||||
parse_yesno(var, val, &signal_data->restart_opt);
|
||||
} else if (!strcasecmp(var, "channel-restart-timeout")) {
|
||||
signal_data->restart_timeout = atoi(val);
|
||||
} else if (!strcasecmp(var, "local-number")) {
|
||||
} else if (!strcasecmp(var, "local-number")) {
|
||||
if (add_local_number(val, span) != FTDM_SUCCESS) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
@@ -401,6 +404,30 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
|
||||
#else
|
||||
ftdm_log(FTDM_LOG_WARNING, "chan-id-invert-extend-bit is not supported in your version of libsng_isdn\n");
|
||||
#endif
|
||||
} else if (!strcasecmp(var, "cid-name-transmit-method")) {
|
||||
if (!strcasecmp(val, "display-ie")) {
|
||||
signal_data->cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE;
|
||||
} else if (!strcasecmp(val, "user-user-ie")) {
|
||||
signal_data->cid_name_method = SNGISDN_CID_NAME_USR_USR_IE;
|
||||
} else if (!strcasecmp(val, "facility-ie")) {
|
||||
signal_data->cid_name_method = SNGISDN_CID_NAME_FACILITY_IE;
|
||||
} else if (!strcasecmp(val, "auto") || !strcasecmp(val, "automatic") || !strcasecmp(val, "default")) {
|
||||
signal_data->cid_name_method = SNGISDN_CID_NAME_AUTO;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Invalid option %s for parameter %s\n", val, var);
|
||||
signal_data->cid_name_method = SNGISDN_CID_NAME_AUTO;
|
||||
}
|
||||
} else if (!strcasecmp(var, "send-cid-name")) {
|
||||
if (!strcasecmp(val, "yes")) {
|
||||
signal_data->send_cid_name = SNGISDN_OPT_TRUE;
|
||||
} else if (!strcasecmp(val, "no")) {
|
||||
signal_data->send_cid_name = SNGISDN_OPT_FALSE;
|
||||
} else if (!strcasecmp(val, "auto") || !strcasecmp(val, "automatic") || !strcasecmp(val, "default")) {
|
||||
signal_data->send_cid_name = SNGISDN_OPT_DEFAULT;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Invalid option %s for parameter %s\n", val, var);
|
||||
signal_data->send_cid_name = SNGISDN_OPT_DEFAULT;
|
||||
}
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
|
||||
}
|
||||
|
||||
@@ -681,7 +681,11 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inDLSAP.clrGlr = FALSE; /* in case of glare, do not clear local call */
|
||||
cfg.t.cfg.s.inDLSAP.statEnqOpt = TRUE;
|
||||
|
||||
cfg.t.cfg.s.inDLSAP.rstOpt = TRUE;
|
||||
if (signal_data->ftdm_span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
|
||||
cfg.t.cfg.s.inDLSAP.rstOpt = FALSE;
|
||||
} else {
|
||||
cfg.t.cfg.s.inDLSAP.rstOpt = TRUE;
|
||||
}
|
||||
} else {
|
||||
cfg.t.cfg.s.inDLSAP.ackOpt = FALSE;
|
||||
cfg.t.cfg.s.inDLSAP.intType = USER;
|
||||
@@ -772,15 +776,13 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t307.val = 35;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t308.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t308.val = 4;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.val = 120;
|
||||
|
||||
if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.val = 10;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.val = cfg.t.cfg.s.inDLSAP.tmr.t303.val+2;
|
||||
} else {
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.enb = TRUE;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t310.val = 120;
|
||||
cfg.t.cfg.s.inDLSAP.tmr.t312.enb = FALSE;
|
||||
}
|
||||
|
||||
@@ -846,7 +848,7 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
|
||||
cfg.t.cfg.s.inDLSAP.dChannelNum = 0; /* Unused for BRI */
|
||||
cfg.t.cfg.s.inDLSAP.nmbBearChan = NUM_BRI_CHANNELS_PER_SPAN;
|
||||
cfg.t.cfg.s.inDLSAP.firstBChanNum = 1;
|
||||
cfg.t.cfg.s.inDLSAP.callRefLen = 1;
|
||||
cfg.t.cfg.s.inDLSAP.callRefLen = 1;
|
||||
cfg.t.cfg.s.inDLSAP.teiAlloc = IN_STATIC;
|
||||
cfg.t.cfg.s.inDLSAP.intCfg = IN_INTCFG_PTPT;
|
||||
break;
|
||||
@@ -902,7 +904,14 @@ ftdm_status_t sngisdn_stack_cfg_q931_lce(ftdm_span_t *span)
|
||||
|
||||
cfg.t.cfg.s.inLCe.sapId = signal_data->dchan_id;
|
||||
|
||||
cfg.t.cfg.s.inLCe.lnkUpDwnInd = TRUE;
|
||||
if (span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
|
||||
/* Stack will send Restart CFM's each time link is established (TEI negotiated),
|
||||
and we do not want thi s event */
|
||||
cfg.t.cfg.s.inLCe.lnkUpDwnInd = FALSE;
|
||||
} else {
|
||||
cfg.t.cfg.s.inLCe.lnkUpDwnInd = TRUE;
|
||||
}
|
||||
|
||||
cfg.t.cfg.s.inLCe.tCon.enb = TRUE;
|
||||
cfg.t.cfg.s.inLCe.tCon.val = 35;
|
||||
cfg.t.cfg.s.inLCe.tDisc.enb = TRUE;
|
||||
|
||||
@@ -1178,7 +1178,16 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
|
||||
ftdm_log(FTDM_LOG_CRIT, "Received RESTART CFM on unconfigured span (suId:%d)\n", suId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "%s: Processing RESTART CFM (suId:%u dChan:%d ces:%d %s(%d))\n",
|
||||
signal_data->ftdm_span->name,
|
||||
suId, dChan, ces,
|
||||
(evntType == IN_LNK_DWN)?"LNK_DOWN":
|
||||
(evntType == IN_LNK_UP)?"LNK_UP":
|
||||
(evntType == IN_INDCHAN)?"b-channel":
|
||||
(evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures":
|
||||
(evntType == IN_SWCHD_BU_DCHAN)?"NFAS switchover to backup":"Unknown", evntType);
|
||||
|
||||
if (rstEvnt->rstInd.eh.pres == PRSNT_NODEF && rstEvnt->rstInd.rstClass.pres == PRSNT_NODEF) {
|
||||
switch(rstEvnt->rstInd.rstClass.val) {
|
||||
case IN_CL_INDCHAN: /* Indicated b-channel */
|
||||
@@ -1212,19 +1221,29 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
|
||||
}
|
||||
|
||||
if (chan_no) { /* For a single channel */
|
||||
if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Received RESTART on invalid channel:%d\n", chan_no);
|
||||
} else {
|
||||
ftdm_channel_t *ftdmchan = ftdm_span_get_channel(signal_data->ftdm_span, chan_no);
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
|
||||
if (sngisdn_info->ces == ces && ftdmchan->physical_chan_id == chan_no) {
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
}
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
} else { /* for all channels */
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
sngisdn_bring_down((ftdm_channel_t*)ftdm_iterator_current(curr));
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
|
||||
if (sngisdn_info->ces == ces) {
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
}
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
}
|
||||
@@ -1305,28 +1324,29 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
|
||||
}
|
||||
|
||||
if (chan_no) { /* For a single channel */
|
||||
if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Received RESTART IND on invalid channel:%d\n", chan_no);
|
||||
} else {
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
if (ftdmchan->physical_chan_id == chan_no) {
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
}
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
|
||||
if (sngisdn_info->ces == ces && ftdmchan->physical_chan_id == chan_no) {
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
} else { /* for all channels */
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *curr = NULL;
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
|
||||
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
|
||||
sngisdn_bring_down((ftdm_channel_t*)ftdm_iterator_current(curr));
|
||||
ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
|
||||
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
|
||||
if (sngisdn_info->ces == ces) {
|
||||
sngisdn_bring_down(ftdmchan);
|
||||
}
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,8 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
|
||||
set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad);
|
||||
set_redir_num(ftdmchan, &conEvnt.redirNmb);
|
||||
set_calling_name(ftdmchan, &conEvnt);
|
||||
|
||||
/* set_facility_ie will overwrite Calling Name for NI-2 if user specifies custom Facility IE */
|
||||
set_facility_ie(ftdmchan, &conEvnt.facilityStr);
|
||||
set_prog_ind_ie(ftdmchan, &conEvnt.progInd, prog_ind);
|
||||
|
||||
|
||||
@@ -897,12 +897,19 @@ int16_t sngisdn_rcv_l1_data_req(uint16_t spId, sng_l1_frame_t *l1_frame)
|
||||
do {
|
||||
flags = FTDM_WRITE;
|
||||
status = signal_data->dchan->fio->wait(signal_data->dchan, &flags, 1000);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_WARNING, "transmit timed-out\n");
|
||||
return -1;
|
||||
switch(status) {
|
||||
case FTDM_SUCCESS:
|
||||
break;
|
||||
case FTDM_TIMEOUT:
|
||||
continue;
|
||||
case FTDM_FAIL:
|
||||
default:
|
||||
ftdm_log_chan_msg(signal_data->dchan, FTDM_LOG_WARNING, "failed to poll for channel\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* status = FTDM_SUCCESS */
|
||||
if ((flags & FTDM_WRITE)) {
|
||||
#if 0
|
||||
int i;
|
||||
@@ -990,27 +997,29 @@ void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...)
|
||||
|
||||
switch (level) {
|
||||
case SNG_LOGLEVEL_DEBUG:
|
||||
ftdm_log(FTDM_LOG_DEBUG, "sng_isdn->%s", data);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "sng_isdn->%s\n", data);
|
||||
break;
|
||||
case SNG_LOGLEVEL_WARN:
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
|
||||
if ( strncmp(data, "Invalid Q.921/Q.931 frame", 25) ) {
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
|
||||
}
|
||||
break;
|
||||
case SNG_LOGLEVEL_INFO:
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s\n", data);
|
||||
break;
|
||||
case SNG_LOGLEVEL_STATS:
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s\n", data);
|
||||
break;
|
||||
case SNG_LOGLEVEL_ERROR:
|
||||
ftdm_log(FTDM_LOG_ERROR, "sng_isdn->%s", data);
|
||||
ftdm_log(FTDM_LOG_ERROR, "sng_isdn->%s\n", data);
|
||||
/*ftdm_assert(0, "Got an error from stack");*/
|
||||
break;
|
||||
case SNG_LOGLEVEL_CRIT:
|
||||
ftdm_log(FTDM_LOG_CRIT, "sng_isdn->%s", data);
|
||||
ftdm_log(FTDM_LOG_CRIT, "sng_isdn->%s\n", data);
|
||||
/* ftdm_assert(0, "Got an error from stack"); */
|
||||
break;
|
||||
default:
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data);
|
||||
ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s\n", data);
|
||||
break;
|
||||
}
|
||||
ftdm_safe_free(data);
|
||||
|
||||
@@ -567,7 +567,7 @@ ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
|
||||
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
||||
|
||||
string = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.cg_pty2.digits");
|
||||
if ((string == NULL) || !(*string)) {
|
||||
if (ftdm_strlen_zero(string)) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
@@ -696,63 +696,71 @@ ftdm_status_t set_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb)
|
||||
ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt)
|
||||
{
|
||||
uint8_t len;
|
||||
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
||||
/* sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; */
|
||||
const char *string = NULL;
|
||||
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_bool_t force_send_cid_name = FTDM_FALSE;
|
||||
|
||||
len = strlen(caller_data->cid_name);
|
||||
if (!len) {
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
|
||||
ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
|
||||
|
||||
conEvnt->usrUsr.eh.pres = PRSNT_NODEF;
|
||||
conEvnt->usrUsr.protocolDisc.pres = PRSNT_NODEF;
|
||||
conEvnt->usrUsr.protocolDisc.val = PD_IA5; /* IA5 chars */
|
||||
conEvnt->usrUsr.usrInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->usrUsr.usrInfo.len = len;
|
||||
/* in sangoma_brid we used to send usr-usr info as <cid_name>!<calling_number>,
|
||||
change to previous style if current one does not work */
|
||||
memcpy(conEvnt->usrUsr.usrInfo.val, caller_data->cid_name, len);
|
||||
} else {
|
||||
switch (signal_data->switchtype) {
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
/* TODO: Need to send the caller ID as a facility IE */
|
||||
|
||||
break;
|
||||
case SNGISDN_SWITCH_EUROISDN:
|
||||
if (signal_data->signalling != SNGISDN_SIGNALING_NET) {
|
||||
break;
|
||||
}
|
||||
/* follow through */
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
case SNGISDN_SWITCH_4ESS:
|
||||
conEvnt->display.dispInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->display.dispInfo.len = len;
|
||||
memcpy(conEvnt->display.dispInfo.val, caller_data->cid_name, len);
|
||||
break;
|
||||
case SNGISDN_SWITCH_DMS100:
|
||||
conEvnt->ntDisplay[0].eh.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispTypeNt.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispTypeNt.val = 0x01; /* Calling Party Name */
|
||||
conEvnt->ntDisplay[0].assocInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].assocInfo.val = 0x03; /* Included */
|
||||
conEvnt->ntDisplay[0].eh.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].eh.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispInfo.len = len;
|
||||
memcpy(conEvnt->ntDisplay[0].dispInfo.val, caller_data->cid_name, len);
|
||||
break;
|
||||
case SNGISDN_SWITCH_QSIG:
|
||||
/* It seems like QSIG does not support Caller ID Name */
|
||||
break;
|
||||
case SNGISDN_SWITCH_INSNET:
|
||||
/* Don't know how to transmit caller ID name on INSNET */
|
||||
break;
|
||||
string = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.send_cid_name");
|
||||
if (!ftdm_strlen_zero(string)) {
|
||||
if (!strcasecmp(string, "no")) {
|
||||
return FTDM_SUCCESS;
|
||||
} else if (!strcasecmp(string, "yes")) {
|
||||
force_send_cid_name = FTDM_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (force_send_cid_name == FTDM_FALSE && signal_data->send_cid_name == SNGISDN_OPT_FALSE) {
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
switch(signal_data->cid_name_method) {
|
||||
case SNGISDN_CID_NAME_FACILITY_IE:
|
||||
#ifdef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
|
||||
/* Note: The Facility IE will be overwritten if user chose to transmit a Raw Facility IE */
|
||||
sng_isdn_encode_facility_caller_name(caller_data->cid_name, conEvnt->facilityStr.facilityStr.val, &conEvnt->facilityStr.facilityStr.len);
|
||||
conEvnt->facilityStr.eh.pres = PRSNT_NODEF;
|
||||
conEvnt->facilityStr.facilityStr.pres = PRSNT_NODEF;
|
||||
#endif
|
||||
break;
|
||||
case SNGISDN_CID_NAME_USR_USR_IE:
|
||||
conEvnt->usrUsr.eh.pres = PRSNT_NODEF;
|
||||
conEvnt->usrUsr.protocolDisc.pres = PRSNT_NODEF;
|
||||
conEvnt->usrUsr.protocolDisc.val = PD_IA5; /* IA5 chars */
|
||||
conEvnt->usrUsr.usrInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->usrUsr.usrInfo.len = len;
|
||||
/* in sangoma_brid we used to send usr-usr info as <cid_name>!<calling_number>,
|
||||
change to previous style if current one does not work */
|
||||
memcpy(conEvnt->usrUsr.usrInfo.val, caller_data->cid_name, len);
|
||||
break;
|
||||
case SNGISDN_CID_NAME_DISPLAY_IE:
|
||||
if (signal_data->switchtype == SNGISDN_SWITCH_DMS100) {
|
||||
conEvnt->ntDisplay[0].eh.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispTypeNt.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispTypeNt.val = 0x01; /* Calling Party Name */
|
||||
conEvnt->ntDisplay[0].assocInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].assocInfo.val = 0x03; /* Included */
|
||||
conEvnt->ntDisplay[0].eh.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].eh.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->ntDisplay[0].dispInfo.len = len;
|
||||
memcpy(conEvnt->ntDisplay[0].dispInfo.val, caller_data->cid_name, len);
|
||||
} else {
|
||||
conEvnt->display.eh.pres = PRSNT_NODEF;
|
||||
conEvnt->display.dispInfo.pres = PRSNT_NODEF;
|
||||
conEvnt->display.dispInfo.len = len;
|
||||
memcpy(conEvnt->display.dispInfo.val, caller_data->cid_name, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -760,7 +768,7 @@ ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
|
||||
{
|
||||
const char* clg_subaddr = NULL;
|
||||
clg_subaddr = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "isdn.calling_subaddr");
|
||||
if ((clg_subaddr != NULL) && (*clg_subaddr)) {
|
||||
if (!ftdm_strlen_zero(clg_subaddr)) {
|
||||
unsigned len = strlen (clg_subaddr);
|
||||
cgPtySad->eh.pres = PRSNT_NODEF;
|
||||
cgPtySad->typeSad.pres = 1;
|
||||
|
||||
@@ -249,6 +249,34 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
||||
SS7_DEBUG_CHAN(ftdmchan, "No Location Number information in IAM%s\n", " ");
|
||||
}
|
||||
|
||||
/* Retrieve the Location Number if present (see ITU Q.763, 3.30) */
|
||||
if (siConEvnt->cgPtyNum1.eh.pres) {
|
||||
if (siConEvnt->cgPtyNum1.addrSig.pres) {
|
||||
/* fill in the ss7 location address number */
|
||||
copy_tknStr_from_sngss7(siConEvnt->cgPtyNum1.addrSig, var, siConEvnt->cgPtyNum1.oddEven);
|
||||
sngss7_add_var(sngss7_info, "ss7_loc_digits", var);
|
||||
}
|
||||
|
||||
if (siConEvnt->cgPtyNum1.scrnInd.pres) {
|
||||
/* fill in the screening indication value */
|
||||
sprintf(var, "%d", siConEvnt->cgPtyNum1.scrnInd.val);
|
||||
sngss7_add_var(sngss7_info, "ss7_loc_screen_ind", var);
|
||||
}
|
||||
|
||||
if (siConEvnt->cgPtyNum1.presRest.pres) {
|
||||
/* fill in the presentation value */
|
||||
sprintf(var, "%d", siConEvnt->cgPtyNum1.presRest.val);
|
||||
sngss7_add_var(sngss7_info, "ss7_loc_pres_ind", var);
|
||||
}
|
||||
|
||||
if (siConEvnt->cgPtyNum1.natAddrInd.pres) {
|
||||
sprintf(var, "%d", siConEvnt->cgPtyNum1.natAddrInd.val);
|
||||
sngss7_add_var(sngss7_info, "ss7_loc_nadi", var);
|
||||
}
|
||||
} else {
|
||||
SS7_DEBUG_CHAN(ftdmchan, "No Location Number information in IAM%s\n", " ");
|
||||
}
|
||||
|
||||
sprintf(var, "%d", sngss7_info->circuit->cic);
|
||||
sngss7_add_var(sngss7_info, "ss7_cic", var);
|
||||
|
||||
@@ -256,11 +284,10 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
|
||||
sngss7_add_var(sngss7_info, "ss7_opc", var);
|
||||
|
||||
if (siConEvnt->callRef.callId.pres) {
|
||||
/* %x expect an unsigned int so as callId is a U32, casting to uint32_t
|
||||
* is safe */
|
||||
sprintf(var, "%x", (uint32_t)siConEvnt->callRef.callId.val);
|
||||
sngss7_add_var(sngss7_info, "ss7_callref", var);
|
||||
}
|
||||
ftdmchan->caller_data.call_reference = (unsigned int)siConEvnt->callRef.callId.val;
|
||||
} else {
|
||||
ftdmchan->caller_data.call_reference = 0;
|
||||
}
|
||||
|
||||
if (sngss7_info->circuit->transparent_iam) {
|
||||
sngss7_save_iam(ftdmchan, siConEvnt);
|
||||
|
||||
@@ -39,6 +39,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef WP_DEBUG_IO
|
||||
#define _BSD_SOURCE
|
||||
#include <syscall.h>
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
#include <unistd.h>
|
||||
#include <stropts.h>
|
||||
@@ -99,6 +104,17 @@ static struct {
|
||||
uint32_t ring_off_ms;
|
||||
} wp_globals;
|
||||
|
||||
typedef struct {
|
||||
sangoma_wait_obj_t *waitobj;
|
||||
#ifdef WP_DEBUG_IO
|
||||
/* record the last reader threads */
|
||||
pid_t readers[10];
|
||||
int rindex;
|
||||
ftdm_time_t last_read;
|
||||
#endif
|
||||
} wp_channel_t;
|
||||
#define WP_GET_WAITABLE(fchan) ((wp_channel_t *)((fchan)->io_data))->waitobj
|
||||
|
||||
/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
|
||||
|
||||
FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
|
||||
@@ -123,7 +139,7 @@ static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout
|
||||
int err;
|
||||
uint32_t inflags = *flags;
|
||||
uint32_t outflags = 0;
|
||||
sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->io_data;
|
||||
sangoma_wait_obj_t *sangoma_wait_obj = WP_GET_WAITABLE(ftdmchan);
|
||||
|
||||
if (timeout == -1) {
|
||||
timeout = SANGOMA_WAIT_INFINITE;
|
||||
@@ -254,9 +270,13 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
|
||||
}
|
||||
|
||||
if (ftdm_span_add_channel(span, sockfd, type, &chan) == FTDM_SUCCESS) {
|
||||
wp_channel_t *wpchan = NULL;
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
wpchan = ftdm_calloc(1, sizeof(*wpchan));
|
||||
ftdm_assert(wpchan != NULL, "wpchan alloc failed\n");
|
||||
chan->io_data = wpchan;
|
||||
/* we need SANGOMA_DEVICE_WAIT_OBJ_SIG and not SANGOMA_DEVICE_WAIT_OBJ alone because we need to call
|
||||
* sangoma_wait_obj_sig to wake up any I/O waiters when closing the channel (typically on ftdm shutdown)
|
||||
* this adds an extra pair of file descriptors to the waitable object
|
||||
@@ -266,7 +286,7 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
|
||||
ftdm_log(FTDM_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
|
||||
continue;
|
||||
}
|
||||
chan->io_data = sangoma_wait_obj;
|
||||
WP_GET_WAITABLE(chan) = sangoma_wait_obj;
|
||||
#endif
|
||||
|
||||
chan->physical_span_id = spanno;
|
||||
@@ -580,9 +600,16 @@ static FIO_OPEN_FUNCTION(wanpipe_open)
|
||||
static FIO_CLOSE_FUNCTION(wanpipe_close)
|
||||
{
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
sangoma_wait_obj_t *waitobj = ftdmchan->io_data;
|
||||
sangoma_wait_obj_t *waitobj = WP_GET_WAITABLE(ftdmchan);
|
||||
/* kick any I/O waiters */
|
||||
sangoma_wait_obj_signal(waitobj);
|
||||
#ifdef WP_DEBUG_IO
|
||||
{
|
||||
wp_channel_t *wchan = ftdmchan->io_data;
|
||||
memset(wchan->readers, 0, sizeof(wchan->readers));
|
||||
wchan->rindex = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
@@ -944,10 +971,44 @@ static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx
|
||||
static FIO_READ_FUNCTION(wanpipe_read)
|
||||
{
|
||||
int rx_len = 0;
|
||||
int rq_len = (int)*datalen;
|
||||
wp_tdm_api_rx_hdr_t hdrframe;
|
||||
|
||||
memset(&hdrframe, 0, sizeof(hdrframe));
|
||||
#ifdef WP_DEBUG_IO
|
||||
wp_channel_t *wchan = ftdmchan->io_data;
|
||||
ftdm_time_t time_diff = 0;
|
||||
pid_t previous_thread = 1;
|
||||
pid_t current_thread = 0;
|
||||
int previous_thread_index = 0;
|
||||
|
||||
previous_thread_index = wchan->rindex == 0 ? (ftdm_array_len(wchan->readers) - 1) : wchan->rindex - 1;
|
||||
previous_thread = wchan->readers[previous_thread_index];
|
||||
current_thread = syscall(SYS_gettid);
|
||||
if (current_thread && current_thread != wchan->readers[wchan->rindex]) {
|
||||
if (!wchan->readers[wchan->rindex]) {
|
||||
wchan->readers[wchan->rindex] = current_thread;
|
||||
/* first read */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Initial reader thread is %d\n", current_thread);
|
||||
previous_thread = current_thread;
|
||||
} else {
|
||||
previous_thread = wchan->readers[wchan->rindex];
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Changed reader thread from %d to %d (rindex = %d)\n",
|
||||
previous_thread, current_thread, wchan->rindex);
|
||||
if (wchan->rindex == (ftdm_array_len(wchan->readers) - 1)) {
|
||||
wchan->rindex = 0;
|
||||
} else {
|
||||
wchan->rindex++;
|
||||
}
|
||||
wchan->readers[wchan->rindex] = current_thread;
|
||||
}
|
||||
}
|
||||
ftdm_time_t curr = ftdm_current_time_in_ms();
|
||||
if (wchan->last_read) {
|
||||
time_diff = curr - wchan->last_read;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&hdrframe, 0, sizeof(hdrframe));
|
||||
rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen, 0);
|
||||
*datalen = rx_len;
|
||||
|
||||
@@ -957,14 +1018,20 @@ static FIO_READ_FUNCTION(wanpipe_read)
|
||||
}
|
||||
|
||||
if (rx_len < 0) {
|
||||
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read from sangoma device: %s (%d)\n", strerror(errno), rx_len);
|
||||
#ifdef WP_DEBUG_IO
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read %d bytes from sangoma device: %s (%d) "
|
||||
"(read time diff = %llums, prev thread = %d, curr thread = %d)\n", rq_len, strerror(errno), rx_len,
|
||||
time_diff, previous_thread, current_thread);
|
||||
#else
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read %d bytes from sangoma device: %s (%d)\n", rq_len, strerror(errno), rx_len);
|
||||
#endif
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
|
||||
wanpipe_read_stats(ftdmchan, &hdrframe);
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1110,7 +1177,7 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
|
||||
if (!ftdmchan->io_data) {
|
||||
continue; /* should never happen but happens when shutting down */
|
||||
}
|
||||
pfds[j] = ftdmchan->io_data;
|
||||
pfds[j] = WP_GET_WAITABLE(ftdmchan);
|
||||
inflags[j] = chan_events;
|
||||
#else
|
||||
memset(&pfds[j], 0, sizeof(pfds[j]));
|
||||
@@ -1572,10 +1639,10 @@ static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
|
||||
{
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
if (ftdmchan->io_data) {
|
||||
sangoma_wait_obj_t *sangoma_wait_obj;
|
||||
sangoma_wait_obj = ftdmchan->io_data;
|
||||
ftdmchan->io_data = NULL;
|
||||
sangoma_wait_obj_t *sangoma_wait_obj = WP_GET_WAITABLE(ftdmchan);
|
||||
sangoma_wait_obj_delete(&sangoma_wait_obj);
|
||||
ftdm_safe_free(ftdmchan->io_data);
|
||||
ftdmchan->io_data = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1606,7 +1673,8 @@ static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
|
||||
*/
|
||||
static FIO_IO_LOAD_FUNCTION(wanpipe_init)
|
||||
{
|
||||
assert(fio != NULL);
|
||||
ftdm_assert(fio != NULL, "fio should not be null\n");
|
||||
|
||||
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
|
||||
|
||||
wp_globals.codec_ms = 20;
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
*
|
||||
* Moises Silva <moy@sangoma.com>
|
||||
* W McRoberts <fs@whmcr.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "private/ftdm_core.h"
|
||||
@@ -94,6 +100,7 @@ struct ioctl_codes {
|
||||
ioctlcmd ECHOTRAIN;
|
||||
ioctlcmd SETTXBITS;
|
||||
ioctlcmd GETRXBITS;
|
||||
ioctlcmd SETPOLARITY;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -169,7 +176,8 @@ static struct ioctl_codes dahdi_ioctl_codes = {
|
||||
.GETCONFMUTE = DAHDI_GETCONFMUTE,
|
||||
.ECHOTRAIN = DAHDI_ECHOTRAIN,
|
||||
.SETTXBITS = DAHDI_SETTXBITS,
|
||||
.GETRXBITS = DAHDI_GETRXBITS
|
||||
.GETRXBITS = DAHDI_GETRXBITS,
|
||||
.SETPOLARITY = DAHDI_SETPOLARITY
|
||||
};
|
||||
|
||||
#define ZT_INVALID_SOCKET -1
|
||||
@@ -248,7 +256,7 @@ static void zt_build_gains(struct zt_gains *g, float rxgain, float txgain, int c
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialises a range of ftdmtel channels
|
||||
* \brief Initialises a range of Zaptel/DAHDI channels
|
||||
* \param span FreeTDM span
|
||||
* \param start Initial wanpipe channel number
|
||||
* \param end Final wanpipe channel number
|
||||
@@ -341,7 +349,7 @@ static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, f
|
||||
}
|
||||
|
||||
if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "this ioctl fails on older ftdmtel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
|
||||
ftdm_log(FTDM_LOG_WARNING, "this ioctl fails in older zaptel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +453,7 @@ static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, f
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialises an freetdm ftdmtel span from a configuration string
|
||||
* \brief Initialises a freetdm Zaptel/DAHDI span from a configuration string
|
||||
* \param span FreeTDM span
|
||||
* \param str Configuration string
|
||||
* \param type FreeTDM span type
|
||||
@@ -515,7 +523,7 @@ static FIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Process configuration variable for a ftdmtel profile
|
||||
* \brief Process configuration variable for a Zaptel/DAHDI profile
|
||||
* \param category Wanpipe profile name
|
||||
* \param var Variable name
|
||||
* \param val Variable value
|
||||
@@ -593,7 +601,7 @@ static FIO_CONFIGURE_FUNCTION(zt_configure)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opens a ftdmtel channel
|
||||
* \brief Opens a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to open
|
||||
* \return Success or failure
|
||||
*/
|
||||
@@ -663,7 +671,7 @@ static FIO_OPEN_FUNCTION(zt_open)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Closes ftdmtel channel
|
||||
* \brief Closes Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to close
|
||||
* \return Success
|
||||
*/
|
||||
@@ -681,7 +689,7 @@ static FIO_CLOSE_FUNCTION(zt_close)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Executes an FreeTDM command on a ftdmtel channel
|
||||
* \brief Executes a FreeTDM command on a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to execute command on
|
||||
* \param command FreeTDM command to execute
|
||||
* \param obj Object (unused)
|
||||
@@ -826,6 +834,15 @@ static FIO_COMMAND_FUNCTION(zt_command)
|
||||
err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
|
||||
}
|
||||
break;
|
||||
case FTDM_COMMAND_SET_POLARITY:
|
||||
{
|
||||
ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT;
|
||||
err = ioctl(ftdmchan->sockfd, codes.SETPOLARITY, polarity);
|
||||
if (!err) {
|
||||
ftdmchan->polarity = polarity;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FTDM_COMMAND_FLUSH_RX_BUFFERS:
|
||||
{
|
||||
int flushmode = ZT_FLUSH_READ;
|
||||
@@ -853,7 +870,7 @@ static FIO_COMMAND_FUNCTION(zt_command)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Gets alarms from a ftdmtel Channel
|
||||
* \brief Gets alarms from a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to get alarms from
|
||||
* \return Success or failure
|
||||
*/
|
||||
@@ -876,7 +893,7 @@ static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Waits for an event on a ftdmtel channel
|
||||
* \brief Waits for an event on a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to open
|
||||
* \param flags Type of event to wait for
|
||||
* \param to Time to wait (in ms)
|
||||
@@ -950,7 +967,7 @@ pollagain:
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks for events on a ftdmtel span
|
||||
* \brief Checks for events on a Zaptel/DAHDI span
|
||||
* \param span Span to check for events
|
||||
* \param ms Time to wait for event
|
||||
* \return Success if event is waiting or failure if not
|
||||
@@ -1088,6 +1105,12 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan,
|
||||
*event_id = FTDM_OOB_NOOP; /* What else could we do? */
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_POLARITY:
|
||||
{
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Got polarity reverse (ZT_EVENT_POLARITY)\n");
|
||||
*event_id = FTDM_OOB_POLARITY_REVERSE;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_NONE:
|
||||
{
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "No event\n");
|
||||
@@ -1141,7 +1164,7 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves an event from a ftdmtel span
|
||||
* \brief Retrieves an event from a Zaptel/DAHDI span
|
||||
* \param span Span to retrieve event from
|
||||
* \param event FreeTDM event to return
|
||||
* \return Success or failure
|
||||
@@ -1181,7 +1204,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reads data from a ftdmtel channel
|
||||
* \brief Reads data from a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to read from
|
||||
* \param data Data buffer
|
||||
* \param datalen Size of data buffer
|
||||
@@ -1223,7 +1246,7 @@ static FIO_READ_FUNCTION(zt_read)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Writes data to a ftdmtel channel
|
||||
* \brief Writes data to a Zaptel/DAHDI channel
|
||||
* \param ftdmchan Channel to write to
|
||||
* \param data Data buffer
|
||||
* \param datalen Size of data buffer
|
||||
@@ -1262,7 +1285,7 @@ tryagain:
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroys a ftdmtel Channel
|
||||
* \brief Destroys a Zaptel/DAHDI Channel
|
||||
* \param ftdmchan Channel to destroy
|
||||
* \return Success
|
||||
*/
|
||||
@@ -1275,12 +1298,12 @@ static FIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Global FreeTDM IO interface for ftdmtel
|
||||
* \brief Global FreeTDM IO interface for Zaptel/DAHDI
|
||||
*/
|
||||
static ftdm_io_interface_t zt_interface;
|
||||
|
||||
/**
|
||||
* \brief Loads ftdmtel IO module
|
||||
* \brief Loads Zaptel/DAHDI IO module
|
||||
* \param fio FreeTDM IO interface
|
||||
* \return Success or failure
|
||||
*/
|
||||
@@ -1335,7 +1358,7 @@ static FIO_IO_LOAD_FUNCTION(zt_init)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Unloads ftdmtel IO module
|
||||
* \brief Unloads Zaptel/DAHDI IO module
|
||||
* \return Success
|
||||
*/
|
||||
static FIO_IO_UNLOAD_FUNCTION(zt_destroy)
|
||||
@@ -1346,7 +1369,7 @@ static FIO_IO_UNLOAD_FUNCTION(zt_destroy)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief FreeTDM ftdmtel IO module definition
|
||||
* \brief FreeTDM Zaptel/DAHDI IO module definition
|
||||
*/
|
||||
ftdm_module_t ftdm_module = {
|
||||
"zt",
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
*
|
||||
* Moises Silva <moy@sangoma.com>
|
||||
* W McRoberts <fs@whmcr.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FTDM_ZT_H
|
||||
@@ -349,6 +355,7 @@ ZT_ABIT = 8
|
||||
#define DAHDI_SETTXBITS _IOW (DAHDI_CODE, 43, int)
|
||||
#define DAHDI_GETRXBITS _IOR (DAHDI_CODE, 43, int)
|
||||
|
||||
#define DAHDI_SETPOLARITY _IOW (DAHDI_CODE, 92, int) /* Polarity setting for FXO lines */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -928,20 +928,20 @@ typedef enum {
|
||||
/*! \brief IO statistics */
|
||||
typedef struct {
|
||||
struct {
|
||||
uint64_t packets;
|
||||
uint32_t errors;
|
||||
uint16_t flags;
|
||||
uint8_t queue_size; /*!< max queue size configured */
|
||||
uint8_t queue_len; /*!< Current number of elements in queue */
|
||||
uint64_t packets;
|
||||
} rx;
|
||||
|
||||
struct {
|
||||
uint64_t idle_packets;
|
||||
uint64_t packets;
|
||||
uint32_t errors;
|
||||
uint16_t flags;
|
||||
uint8_t idle_packets;
|
||||
uint8_t queue_size; /*!< max queue size configured */
|
||||
uint8_t queue_len; /*!< Current number of elements in queue */
|
||||
uint64_t packets;
|
||||
} tx;
|
||||
} ftdm_channel_iostats_t;
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mftilla Public License Version
|
||||
* 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.mftilla.org/MPL/
|
||||
* 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
|
||||
@@ -33,8 +33,8 @@
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the freetdm library. Any use or distribution of this
|
||||
* source code outside the scope of the freetdm library will nullify the
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
|
||||
@@ -2,13 +2,60 @@
|
||||
* libteletone
|
||||
* 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 tone_detect.c - General telephony tone detection, and specific detection of DTMF.
|
||||
*
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Stephen Underwood <steveu@coppice.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* The the original interface designed by Steve Underwood was preserved to retain
|
||||
*the optimizations when considering DTMF tones though the names were changed in the interest
|
||||
* of namespace.
|
||||
*
|
||||
* Much less efficient expansion interface was added to allow for the detection of
|
||||
* a single arbitrary tone combination which may also exceed 2 simultaneous tones.
|
||||
* (controlled by compile time constant TELETONE_MAX_TONES)
|
||||
*
|
||||
* Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone_detect.c Tone Detection Code
|
||||
*
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.h - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the freetdm library. Any use or distribution of this
|
||||
* source code outside the scope of the freetdm library will nullify the
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
@@ -41,20 +88,6 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.h - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBTELETONE_DETECT_H
|
||||
@@ -101,6 +134,14 @@ extern "C" {
|
||||
#define BLOCK_LEN 102
|
||||
#define M_TWO_PI 2.0*M_PI
|
||||
|
||||
typedef enum {
|
||||
TT_HIT_NONE = 0,
|
||||
TT_HIT_BEGIN = 1,
|
||||
TT_HIT_MIDDLE = 2,
|
||||
TT_HIT_END = 3
|
||||
} teletone_hit_type_t;
|
||||
|
||||
|
||||
/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
|
||||
typedef struct {
|
||||
float v2;
|
||||
@@ -114,16 +155,19 @@ extern "C" {
|
||||
int hit2;
|
||||
int hit3;
|
||||
int hit4;
|
||||
int mhit;
|
||||
int dur;
|
||||
int zc;
|
||||
|
||||
|
||||
teletone_goertzel_state_t row_out[GRID_FACTOR];
|
||||
teletone_goertzel_state_t col_out[GRID_FACTOR];
|
||||
teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
|
||||
teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
|
||||
float energy;
|
||||
float lenergy;
|
||||
|
||||
int current_sample;
|
||||
char digits[TELETONE_MAX_DTMF_DIGITS + 1];
|
||||
char digit;
|
||||
int current_digits;
|
||||
int detected_digits;
|
||||
int lost_digits;
|
||||
@@ -196,7 +240,7 @@ TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf
|
||||
\param samples the number of samples present in sample_buffer
|
||||
\return true when DTMF was detected or false when it is not
|
||||
*/
|
||||
TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
int16_t sample_buffer[],
|
||||
int samples);
|
||||
/*!
|
||||
@@ -206,9 +250,7 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
\param max the maximum length of buf
|
||||
\return the number of characters written to buf
|
||||
*/
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
char *buf,
|
||||
int max);
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur);
|
||||
|
||||
/*!
|
||||
\brief Step through the Goertzel Algorithm for each sample in a buffer
|
||||
|
||||
@@ -2,6 +2,41 @@
|
||||
* libteletone
|
||||
* 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 libteletone
|
||||
*
|
||||
* 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):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone.h -- Tone Generator
|
||||
*
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -2,14 +2,62 @@
|
||||
* libteletone
|
||||
* 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 tone_detect.c - General telephony tone detection, and specific detection of DTMF.
|
||||
*
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Stephen Underwood <steveu@coppice.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* The the original interface designed by Steve Underwood was preserved to retain
|
||||
*the optimizations when considering DTMF tones though the names were changed in the interest
|
||||
* of namespace.
|
||||
*
|
||||
* Much less efficient expansion interface was added to allow for the detection of
|
||||
* a single arbitrary tone combination which may also exceed 2 simultaneous tones.
|
||||
* (controlled by compile time constant TELETONE_MAX_TONES)
|
||||
*
|
||||
* Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone_detect.c Tone Detection Code
|
||||
*
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.c - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -40,21 +88,6 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.c - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libteletone_detect.h>
|
||||
@@ -67,7 +100,8 @@
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#define LOW_ENG 10000000
|
||||
#define ZC 2
|
||||
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
|
||||
static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
|
||||
static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
|
||||
@@ -132,8 +166,8 @@ TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf
|
||||
dtmf_detect_state->current_sample = 0;
|
||||
dtmf_detect_state->detected_digits = 0;
|
||||
dtmf_detect_state->lost_digits = 0;
|
||||
dtmf_detect_state->digits[0] = '\0';
|
||||
dtmf_detect_state->mhit = 0;
|
||||
dtmf_detect_state->digit = 0;
|
||||
dtmf_detect_state->dur = 0;
|
||||
}
|
||||
|
||||
TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
|
||||
@@ -266,7 +300,7 @@ TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
|
||||
}
|
||||
|
||||
|
||||
TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
int16_t sample_buffer[],
|
||||
int samples)
|
||||
{
|
||||
@@ -281,6 +315,7 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
int best_col;
|
||||
char hit;
|
||||
int limit;
|
||||
teletone_hit_type_t r = 0;
|
||||
|
||||
hit = 0;
|
||||
for (sample = 0; sample < samples; sample = limit) {
|
||||
@@ -317,6 +352,32 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
|
||||
}
|
||||
|
||||
if (dtmf_detect_state->zc > 0) {
|
||||
if (dtmf_detect_state->energy < LOW_ENG && dtmf_detect_state->lenergy < LOW_ENG) {
|
||||
if (!--dtmf_detect_state->zc) {
|
||||
/* Reinitialise the detector for the next block */
|
||||
dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
|
||||
for (i = 0; i < GRID_FACTOR; i++) {
|
||||
goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
|
||||
goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
|
||||
}
|
||||
dtmf_detect_state->dur -= samples;
|
||||
return TT_HIT_END;
|
||||
}
|
||||
}
|
||||
|
||||
dtmf_detect_state->dur += samples;
|
||||
dtmf_detect_state->lenergy = dtmf_detect_state->energy;
|
||||
dtmf_detect_state->energy = 0.0;
|
||||
dtmf_detect_state->current_sample = 0;
|
||||
return TT_HIT_MIDDLE;
|
||||
} else if (dtmf_detect_state->digit) {
|
||||
return TT_HIT_END;
|
||||
}
|
||||
|
||||
|
||||
dtmf_detect_state->current_sample += (limit - sample);
|
||||
if (dtmf_detect_state->current_sample < BLOCK_LEN) {
|
||||
continue;
|
||||
@@ -361,58 +422,55 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
back to back differing digits. More importantly, it
|
||||
can work with nasty phones that give a very wobbly start
|
||||
to a digit. */
|
||||
if (hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
|
||||
dtmf_detect_state->mhit = hit;
|
||||
if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
|
||||
dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
|
||||
dtmf_detect_state->detected_digits++;
|
||||
if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
|
||||
dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit;
|
||||
dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0';
|
||||
dtmf_detect_state->digit = hit;
|
||||
} else {
|
||||
dtmf_detect_state->lost_digits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dtmf_detect_state->lost_digits++;
|
||||
}
|
||||
|
||||
if (!dtmf_detect_state->zc) {
|
||||
dtmf_detect_state->zc = ZC;
|
||||
dtmf_detect_state->dur = 0;
|
||||
r = TT_HIT_BEGIN;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
|
||||
dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
|
||||
dtmf_detect_state->hit3 = hit;
|
||||
/* Reinitialise the detector for the next block */
|
||||
for (i = 0; i < GRID_FACTOR; i++) {
|
||||
goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
|
||||
goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
|
||||
}
|
||||
|
||||
dtmf_detect_state->energy = 0.0;
|
||||
dtmf_detect_state->current_sample = 0;
|
||||
|
||||
}
|
||||
if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) {
|
||||
dtmf_detect_state->mhit = 0;
|
||||
return(0);
|
||||
}
|
||||
return (hit);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
char *buf,
|
||||
int max)
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
|
||||
{
|
||||
teletone_assert(dtmf_detect_state->current_digits <= TELETONE_MAX_DTMF_DIGITS);
|
||||
if (!dtmf_detect_state->digit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max > dtmf_detect_state->current_digits) {
|
||||
max = dtmf_detect_state->current_digits;
|
||||
*buf = dtmf_detect_state->digit;
|
||||
|
||||
*dur = dtmf_detect_state->dur;
|
||||
|
||||
if (!dtmf_detect_state->zc) {
|
||||
dtmf_detect_state->dur = 0;
|
||||
dtmf_detect_state->digit = 0;
|
||||
}
|
||||
if (max > 0) {
|
||||
memcpy (buf, dtmf_detect_state->digits, max);
|
||||
memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max);
|
||||
dtmf_detect_state->current_digits -= max;
|
||||
}
|
||||
buf[max] = '\0';
|
||||
return max;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
/*
|
||||
* libteletone_generate.c -- Tone Generator
|
||||
* libteletone
|
||||
* 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 libteletone
|
||||
*
|
||||
* 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):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone.c -- Tone Generator
|
||||
*
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
@@ -34,7 +70,6 @@
|
||||
*/
|
||||
|
||||
#include <libteletone.h>
|
||||
#include "private/ftdm_core.h"
|
||||
|
||||
#define SMAX 32767
|
||||
#define SMIN -32768
|
||||
@@ -111,7 +146,7 @@ TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int b
|
||||
ts->decay_step = 0;
|
||||
ts->decay_factor = 1;
|
||||
if (buflen) {
|
||||
if ((ts->buffer = ftdm_calloc(buflen, sizeof(teletone_audio_t))) == 0) {
|
||||
if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
|
||||
return -1;
|
||||
}
|
||||
ts->datalen = buflen;
|
||||
@@ -142,7 +177,7 @@ TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int b
|
||||
TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts)
|
||||
{
|
||||
if (ts->buffer) {
|
||||
ftdm_safe_free(ts->buffer);
|
||||
free(ts->buffer);
|
||||
ts->buffer = NULL;
|
||||
ts->samples = 0;
|
||||
}
|
||||
@@ -270,6 +305,19 @@ TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone
|
||||
return ts->samples / ts->channels;
|
||||
}
|
||||
|
||||
/* don't ask */
|
||||
static char *my_strdup (const char *s)
|
||||
{
|
||||
size_t len = strlen (s) + 1;
|
||||
void *new = malloc (len);
|
||||
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *) memcpy (new, s, len);
|
||||
}
|
||||
|
||||
TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd)
|
||||
{
|
||||
char *data = NULL, *cur = NULL, *end = NULL;
|
||||
@@ -280,7 +328,7 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
|
||||
}
|
||||
|
||||
do {
|
||||
if (!(data = ftdm_strdup(cmd))) {
|
||||
if (!(data = my_strdup(cmd))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -363,6 +411,9 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
|
||||
*e++ = '\0';
|
||||
}
|
||||
do {
|
||||
if (!p) {
|
||||
break;
|
||||
}
|
||||
if ((next = strchr(p, ',')) != 0) {
|
||||
*next++ = '\0';
|
||||
}
|
||||
@@ -427,7 +478,7 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
|
||||
}
|
||||
}
|
||||
bottom:
|
||||
ftdm_safe_free(data);
|
||||
free(data);
|
||||
data = NULL;
|
||||
if (ts->LOOPS > 0) {
|
||||
ts->LOOPS--;
|
||||
|
||||
Reference in new issue
Block a user