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:
Moises Silva committed 2011-12-17 17:42:34 -05:00
commit 7bd2d154d6
615 files changed
+41286 -47127

No files matched your search

+11 -3
View File
@@ -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
View File
@@ -1 +1,2 @@
m4_include([build/ax_compiler_vendor.m4])
m4_include([build/libpcap.m4])
+5
View File
@@ -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"/>-->
+79 -2
View File
@@ -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
View File
@@ -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}
===============================================================================
])
+76
View File
@@ -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>
+316 -115
View File
@@ -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;
}
}
+25 -4
View File
@@ -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
View File
@@ -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;
+42 -19
View File
@@ -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
+3 -3
View File
@@ -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.
*
+110 -52
View File
@@ -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:
+57 -6
View File
@@ -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--;