mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-11-09 04:49:05 +00:00
Merge remote-tracking branch 'fsorig/master'
Conflicts: src/mod/endpoints/mod_sofia/mod_sofia.c src/mod/endpoints/mod_sofia/sofia_glue.c
This commit is contained in:
commit
b004bcfc6d
407 files changed
+25813
-41133
No files matched your search
@@ -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)
|
||||
ftmod_misdn_la_LDFLAGS = -shared -module -avoid-version
|
||||
ftmod_misdn_la_LIBADD = libfreetdm.la
|
||||
endif
|
||||
|
||||
dox doxygen:
|
||||
doxygen $(FT_SRCDIR)/docs/Doxygen.conf
|
||||
|
||||
|
||||
@@ -75,6 +75,11 @@ with the signaling protocols that you can run on top of your I/O interfaces.
|
||||
<param name="polarity-delay" value="600"/>
|
||||
-->
|
||||
|
||||
<!-- Retrieve caller id on polarity reverse -->
|
||||
<!--
|
||||
<param name="polarity-callerid" value="true"/>
|
||||
-->
|
||||
|
||||
<!-- regex to stop dialing when it matches -->
|
||||
<!--<param name="dial-regex" value="5555"/>-->
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
; This file is used to generate telephony tones by FreeTDM
|
||||
|
||||
[us]
|
||||
generate-dial => v=-7;%(1000,0,350,440)
|
||||
detect-dial => 350,440
|
||||
@@ -47,19 +45,98 @@ detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 1776.7
|
||||
|
||||
|
||||
[ru]
|
||||
generate-dial => v=-7;%(1000,425)
|
||||
detect-dial => 0
|
||||
|
||||
generate-ring => v=-7;%(800,5000,425,0)
|
||||
detect-ring => 425,0
|
||||
|
||||
generate-busy => v=-7;%(350,350,425,0)
|
||||
detect-busy => 425,0
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440,480
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 1776.7
|
||||
|
||||
|
||||
[in]
|
||||
generate-dial => v=-7;%(1000,0,375,425)
|
||||
detect-dial => 375,425
|
||||
|
||||
generate-ring => v=-7;%(2000,4000,440,480)
|
||||
detect-ring => 440,480
|
||||
|
||||
generate-busy => v=-7;%(500,500,480,620)
|
||||
detect-busy => 480,620
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 776.7
|
||||
|
||||
|
||||
[th]
|
||||
generate-dial => v=-7;%(1000,0,400,400)
|
||||
detect-dial => 400,400
|
||||
|
||||
generate-ring => v=-7;%(2000,4000,400,400)
|
||||
detect-ring => 400,400
|
||||
|
||||
generate-busy => v=-7;%(500,500,480,620)
|
||||
detect-busy => 480,620
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 1776.7
|
||||
|
||||
|
||||
[au]
|
||||
generate-dial => v=-7;%(1000,0,413,438)
|
||||
detect-dial => 413,438
|
||||
|
||||
generate-ring => v=-7;%(400,200,413,438);%(400,2000,413,438)
|
||||
detect-ring => 413,438
|
||||
|
||||
generate-busy => v=-7;%(375,375,425)
|
||||
detect-busy => 425
|
||||
|
||||
generate-attn => v=0;%(100,100,1400,2060,2450,2600)
|
||||
detect-attn => 1400,2060,2450,2600
|
||||
|
||||
generate-callwaiting-sas => v=0;%(300,0,440)
|
||||
detect-callwaiting-sas => 440
|
||||
|
||||
generate-callwaiting-cas => v=0;%(80,0,2750,2130)
|
||||
detect-callwaiting-cas => 2750,2130
|
||||
|
||||
detect-fail1 => 913.8
|
||||
detect-fail2 => 1370.6
|
||||
detect-fail3 => 776.7
|
||||
@@ -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)])],
|
||||
@@ -364,6 +367,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 +428,7 @@ AC_MSG_RESULT([
|
||||
ftmod_pritap....................... ${HAVE_PRITAP}
|
||||
I/O:
|
||||
ftmod_wanpipe...................... ${HAVE_LIBSANGOMA}
|
||||
ftmod_misdn........................ ${HAVE_MISDN}
|
||||
|
||||
===============================================================================
|
||||
])
|
||||
@@ -0,0 +1,76 @@
|
||||
== This is an email sent to stkn responding to his post http://stkn.techmage.de/archives/200 ==
|
||||
|
||||
1. FreeTDM open channels immediately.
|
||||
|
||||
Yes, this seems to come from the early days of OpenZAP where probably the analog modules were implemented first and was dragged incorrectly to ISDN.
|
||||
The open API also sets the flag in use so others cannot use it. We should decouple this open and reserve operations. Does not seem very hard to do,
|
||||
I'll take a look at it on my way back to Toronto this week or earlier if possible, I'll create a git branch for it and send you the url for peer review.
|
||||
Feel free to do the opposite if you are in a hurry.
|
||||
|
||||
2. FreeTDM does not completely close the channel on hangup.
|
||||
|
||||
As long as the signaling module calls ftdm_channel_close() the fio->close API will be called where the IO module is responsible
|
||||
for turning off ec or any other operations to leave the channel unused/idle (not really closed). There was indeed a bug where ftdm_zt module
|
||||
was not properly closing the channel, if that is what you mean, then it means that was already fixed by you with your audio mode turn off patch.
|
||||
|
||||
Now, a more lengthy response ...
|
||||
|
||||
When we, Sangoma, took over openzap and renamed it to freetdm, it was not just a name change, many API cleanups were done so API users cannot access
|
||||
|
||||
the internal data structures and cannot explicitly move between channel states. Also, some order on the state transitions has been put into place.
|
||||
|
||||
We've tried to keep backwards compatibility though, so old modules may not follow all of the conventions. Some unwritten conventions are:
|
||||
|
||||
1. Signaling modules are responsible for calling ftdm_channel_close() when done with the channel. In fact, signaling modules should not
|
||||
call ftdm_channel_done unless they really know what they're doing. ftdm_channel_close will call ftdm_channel_done anyways.
|
||||
|
||||
2. When remote end hangs up a call, signaling module should go to TERMINATING state and send SIGEVENT_STOP to the user. The signaling stack
|
||||
should not acknowledge the hangup until the user implicitly moves us to HANGUP (via ftdm_channel_call_hangup()). There is a core timer
|
||||
that will ensure we move from TERMINATING to HANGUP if the user does not moves us fast enough (arbitrarely 3000ms), although that is considered
|
||||
a bug in the user application (at some point we saw that in FreeSWITCH) and we complain loudly when that happens.
|
||||
|
||||
3. Signaling modules should leave the channel with NO pending states once they unlock it. This means, whenever you have a message to process
|
||||
you must lock the channel, check its current state (the user may have already changed the state to something else), process any pending
|
||||
state set by the user, then process your message and if required move the channel to a new state and process that state before releasing the lock.
|
||||
There is a chance of a deadlock due to the callbacks we use to notify users of messages if we call those callbacks with the channel lock held and
|
||||
that is why new signaling modules should use the FTDM_SPAN_USE_SIGNALS_QUEUE to defer the notification to the user when the ftdm_channel_t is not
|
||||
locked calling ftdm_span_trigger_signals() at the end of their processing loop which delivers the callback notifications to users.
|
||||
|
||||
Having said that, there is a major architectural change coming, probably early 2011, and I'd like to have your input.
|
||||
|
||||
== Decoupling calls from IO channels ==
|
||||
|
||||
We've also found that the concept of a channel and a call are unnecesarily coupled together in FreeTDM. I've never asked Anthony the reasoning
|
||||
for this, but it seems the API was meant to be used with, or without calls. That is, a user should be able to just 'open' a channel and start
|
||||
reading and writing raw data without ever launching one of the provided signaling stacks on top, may be just because the user is using their
|
||||
own signaling stack and just needs freetdm/openzap as an I/O API. In fact, signaling modules work like this (but there are defects there).
|
||||
The problem is, as you have noticed, the way ftdm_channel_open_xx APIs has been implemented is abusing this concept.
|
||||
|
||||
Problems with current implementation.
|
||||
|
||||
1. Exclusive channel is the only way we can request channels to the ISDN network. There is no room to change the channel later on easily.
|
||||
2. Multi-rate calls cannot be done. We need to associate multiple B-channels to a single call.
|
||||
3. Low-bit-rate calls (not sure what is the proper name for them) where a single B-channel can feed media to multiple calls with a low bit-rate
|
||||
codec (I know of at least one request from a big company for this to support some Q.SIG stuff for Eurocontrol).
|
||||
|
||||
|
||||
What do we need?
|
||||
|
||||
I think there should be only one open() API that wraps calls around fio->open(), the other current open_xx functions that do hunting, should
|
||||
be eliminated and some extra arguments provided to ftdm_channel_call_place to provide information about the channel where we would like to
|
||||
place the call or group hunting information and the API would return immediately providing a ftdm_call_t reference pointer that can be used
|
||||
to further track the status of that call, or in the case where a channel exclusivity was requested and we know for a fact is not available,
|
||||
just return failure. At that point there is no I/O channel involved yet. Eventually after the signaling stack hunts the channel and
|
||||
negotiaties its availability with the network, an I/O channel can be attached to that call, or even attach multiple channels (for the case
|
||||
of multi rate calls?).
|
||||
|
||||
This involves heavy changes. The state machine should be moved out of the ftdm_channel_t structure along with probably some other members
|
||||
and stuffed into a new ftdm_call_t structure. Signaling modules would have to be updated to run their state machines with this call
|
||||
structure and then at some point attach IO channels to the call. There would be 2 type of read/write APIs, one low level ftdm_channel_read
|
||||
which receives an ftdm_channel_t as parameter and an ftdm_call_read() which receives an ftdm_call_t as parameter, for the case of multi-rate
|
||||
calls or low-bit-rate multiplexed calls in the same B-channel this API would return just the media corresponding to that call already
|
||||
demultiplexed or concatenated, or whatever needs to be done with the media from the multiple low-level IO channels.
|
||||
|
||||
This is fairly disruptive, but I believe should be done sooner or later.
|
||||
|
||||
|
||||
@@ -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,7 +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;
|
||||
const char *name = NULL;
|
||||
int span_id = 0;
|
||||
int chan_id = 0;
|
||||
int 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);
|
||||
@@ -503,13 +519,64 @@ 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);
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
@@ -520,7 +587,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 {
|
||||
@@ -548,9 +614,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) {
|
||||
@@ -558,6 +621,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;
|
||||
}
|
||||
|
||||
@@ -629,6 +693,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);
|
||||
@@ -636,17 +701,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.......
|
||||
@@ -678,7 +744,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;
|
||||
}
|
||||
|
||||
@@ -686,7 +752,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;
|
||||
}
|
||||
|
||||
@@ -694,7 +760,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;
|
||||
}
|
||||
}
|
||||
@@ -707,9 +773,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 {
|
||||
@@ -725,23 +791,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)
|
||||
@@ -750,8 +816,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);
|
||||
@@ -759,7 +826,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;
|
||||
}
|
||||
|
||||
@@ -768,17 +845,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);
|
||||
@@ -793,16 +863,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 {
|
||||
@@ -812,7 +882,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;
|
||||
|
||||
@@ -2374,7 +2444,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_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);
|
||||
}
|
||||
}
|
||||
@@ -3025,6 +3094,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;
|
||||
@@ -3106,6 +3176,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")) {
|
||||
@@ -3168,6 +3240,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,
|
||||
@@ -3794,16 +3867,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++) {
|
||||
@@ -3880,19 +4088,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;
|
||||
}
|
||||
|
||||
@@ -3907,34 +4116,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]);
|
||||
@@ -3954,8 +4165,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;
|
||||
@@ -3964,12 +4174,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];
|
||||
@@ -4032,28 +4241,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;
|
||||
}
|
||||
|
||||
@@ -4062,21 +4272,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;
|
||||
@@ -4114,8 +4324,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;
|
||||
@@ -4125,19 +4334,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;
|
||||
}
|
||||
}
|
||||
@@ -4162,31 +4371,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);
|
||||
@@ -4197,12 +4408,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;
|
||||
@@ -4212,18 +4423,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;
|
||||
}
|
||||
}
|
||||
@@ -4251,8 +4463,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;
|
||||
@@ -4260,8 +4471,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;
|
||||
}
|
||||
|
||||
@@ -4273,14 +4485,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;
|
||||
}
|
||||
}
|
||||
@@ -4300,8 +4513,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;
|
||||
@@ -4311,21 +4523,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) {
|
||||
@@ -4379,8 +4594,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;
|
||||
@@ -4389,20 +4603,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);
|
||||
@@ -4420,14 +4634,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[] =
|
||||
{
|
||||
@@ -4443,7 +4655,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 */
|
||||
@@ -4452,6 +4664,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;
|
||||
@@ -4484,7 +4701,7 @@ SWITCH_STANDARD_API(ft_function)
|
||||
for (i = 0 ; i < ftdm_array_len(ftdm_cli_options); i++) {
|
||||
entry = &ftdm_cli_options[i];
|
||||
if (!strcasecmp(argv[0], entry->name) && entry->execute) {
|
||||
entry->execute(cmd, session, stream, argc, argv);
|
||||
entry->execute(entry, cmd, session, stream, argc, argv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ int main(int argc, char *argv[])
|
||||
int fd, b;
|
||||
short sln[512] = {0};
|
||||
teletone_dtmf_detect_state_t dtmf_detect = {0};
|
||||
char digit_str[128] = "";
|
||||
teletone_hit_type_t hit;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Arg Error!\n");
|
||||
@@ -21,10 +21,31 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
while((b = read(fd, sln, 320)) > 0) {
|
||||
char digit_char;
|
||||
unsigned int dur;
|
||||
|
||||
teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
|
||||
teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
|
||||
if (*digit_str) {
|
||||
printf("digit: %s\n", digit_str);
|
||||
if ((hit = teletone_dtmf_get(&dtmf_detect, &digit_char, &dur))) {
|
||||
const char *hs = NULL;
|
||||
|
||||
|
||||
switch(hit) {
|
||||
case TT_HIT_BEGIN:
|
||||
hs = "begin";
|
||||
break;
|
||||
|
||||
case TT_HIT_MIDDLE:
|
||||
hs = "middle";
|
||||
break;
|
||||
|
||||
case TT_HIT_END:
|
||||
hs = "end";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("%s digit: %c\n", hs, digit_char);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
+28
-15
@@ -649,9 +649,6 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
|
||||
if (span->fio->span_destroy(span) != FTDM_SUCCESS) {
|
||||
status = FTDM_FAIL;
|
||||
}
|
||||
ftdm_safe_free(span->type);
|
||||
ftdm_safe_free(span->name);
|
||||
ftdm_safe_free(span->dtmf_hangup);
|
||||
}
|
||||
|
||||
/* destroy final basic resources of the span data structure */
|
||||
@@ -1858,7 +1855,14 @@ static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm
|
||||
goto done;
|
||||
}
|
||||
|
||||
ftdm_mutex_lock(check->mutex);
|
||||
ftdm_channel_lock(check);
|
||||
|
||||
if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
|
||||
/* let them know is already open, but return the channel anyway */
|
||||
status = FTDM_EBUSY;
|
||||
*ftdmchan = check;
|
||||
goto unlockchan;
|
||||
}
|
||||
|
||||
/* The following if's and gotos replace a big if (this || this || this || this) else { nothing; } */
|
||||
|
||||
@@ -1905,7 +1909,7 @@ openchan:
|
||||
goto done;
|
||||
|
||||
unlockchan:
|
||||
ftdm_mutex_unlock(check->mutex);
|
||||
ftdm_channel_unlock(check);
|
||||
|
||||
done:
|
||||
ftdm_mutex_unlock(globals.mutex);
|
||||
@@ -3855,7 +3859,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_process_media(ftdm_channel_t *ftdmchan, v
|
||||
uint8_t sln_buf[1024] = {0};
|
||||
int16_t *sln;
|
||||
ftdm_size_t slen = 0;
|
||||
char digit_str[80] = "";
|
||||
|
||||
if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
|
||||
sln = data;
|
||||
@@ -3956,13 +3959,18 @@ 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] = { digit_char, 0};
|
||||
|
||||
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 +4576,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;
|
||||
}
|
||||
|
||||
@@ -5468,10 +5476,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 */
|
||||
@@ -5561,6 +5565,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);
|
||||
@@ -5774,6 +5786,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"
|
||||
@@ -339,8 +368,78 @@ static FIO_API_FUNCTION(ftdm_libpri_api)
|
||||
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 invalid span.\n", __FILE__);
|
||||
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 invalid span.\n", __FILE__);
|
||||
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 invalid span.\n", __FILE__);
|
||||
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 invalid span.\n", __FILE__);
|
||||
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 invalid span.\n", __FILE__);
|
||||
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 invalid span.\n", __FILE__);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
|
||||
|
||||
done:
|
||||
@@ -1780,6 +1879,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 +1938,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 +2270,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
@@ -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);
|
||||
|
||||
|
||||
@@ -719,12 +719,19 @@ ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt)
|
||||
} else {
|
||||
switch (signal_data->switchtype) {
|
||||
case SNGISDN_SWITCH_NI2:
|
||||
/* TODO: Need to send the caller ID as a facility IE */
|
||||
|
||||
#ifdef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
|
||||
{
|
||||
if (signal_data->signalling == SNGISDN_SIGNALING_NET) {
|
||||
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_SWITCH_EUROISDN:
|
||||
if (signal_data->signalling != SNGISDN_SIGNALING_NET) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
/* follow through */
|
||||
case SNGISDN_SWITCH_5ESS:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -950,10 +977,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;
|
||||
|
||||
@@ -963,14 +1024,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;
|
||||
}
|
||||
|
||||
@@ -1116,7 +1183,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]));
|
||||
@@ -1578,10 +1645,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
|
||||
|
||||
@@ -1612,7 +1679,8 @@ static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
|
||||
*/
|
||||
static FIO_IO_LOAD_FUNCTION(wanpipe_init)
|
||||
{
|
||||
assert(fio != NULL);
|
||||
ftdm_assert(fio != NULL, "fio should not be null\n");
|
||||
|
||||
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
|
||||
|
||||
wp_globals.codec_ms = 20;
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
*
|
||||
* Moises Silva <moy@sangoma.com>
|
||||
* W McRoberts <fs@whmcr.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "private/ftdm_core.h"
|
||||
@@ -94,6 +100,7 @@ struct ioctl_codes {
|
||||
ioctlcmd ECHOTRAIN;
|
||||
ioctlcmd SETTXBITS;
|
||||
ioctlcmd GETRXBITS;
|
||||
ioctlcmd SETPOLARITY;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -169,7 +176,8 @@ static struct ioctl_codes dahdi_ioctl_codes = {
|
||||
.GETCONFMUTE = DAHDI_GETCONFMUTE,
|
||||
.ECHOTRAIN = DAHDI_ECHOTRAIN,
|
||||
.SETTXBITS = DAHDI_SETTXBITS,
|
||||
.GETRXBITS = DAHDI_GETRXBITS
|
||||
.GETRXBITS = DAHDI_GETRXBITS,
|
||||
.SETPOLARITY = DAHDI_SETPOLARITY
|
||||
};
|
||||
|
||||
#define ZT_INVALID_SOCKET -1
|
||||
@@ -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;
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -926,20 +926,20 @@ typedef enum {
|
||||
/*! \brief IO statistics */
|
||||
typedef struct {
|
||||
struct {
|
||||
uint64_t packets;
|
||||
uint32_t errors;
|
||||
uint16_t flags;
|
||||
uint8_t queue_size; /*!< max queue size configured */
|
||||
uint8_t queue_len; /*!< Current number of elements in queue */
|
||||
uint64_t packets;
|
||||
} rx;
|
||||
|
||||
struct {
|
||||
uint64_t idle_packets;
|
||||
uint64_t packets;
|
||||
uint32_t errors;
|
||||
uint16_t flags;
|
||||
uint8_t idle_packets;
|
||||
uint8_t queue_size; /*!< max queue size configured */
|
||||
uint8_t queue_len; /*!< Current number of elements in queue */
|
||||
uint64_t packets;
|
||||
} tx;
|
||||
} ftdm_channel_iostats_t;
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mftilla Public License Version
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mftilla.org/MPL/
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
@@ -33,8 +33,8 @@
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the freetdm library. Any use or distribution of this
|
||||
* source code outside the scope of the freetdm library will nullify the
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
|
||||
@@ -2,13 +2,60 @@
|
||||
* libteletone
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is tone_detect.c - General telephony tone detection, and specific detection of DTMF.
|
||||
*
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Stephen Underwood <steveu@coppice.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* The the original interface designed by Steve Underwood was preserved to retain
|
||||
*the optimizations when considering DTMF tones though the names were changed in the interest
|
||||
* of namespace.
|
||||
*
|
||||
* Much less efficient expansion interface was added to allow for the detection of
|
||||
* a single arbitrary tone combination which may also exceed 2 simultaneous tones.
|
||||
* (controlled by compile time constant TELETONE_MAX_TONES)
|
||||
*
|
||||
* Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone_detect.c Tone Detection Code
|
||||
*
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.h - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the freetdm library. Any use or distribution of this
|
||||
* source code outside the scope of the freetdm library will nullify the
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
@@ -41,20 +88,6 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.h - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBTELETONE_DETECT_H
|
||||
@@ -101,6 +134,14 @@ extern "C" {
|
||||
#define BLOCK_LEN 102
|
||||
#define M_TWO_PI 2.0*M_PI
|
||||
|
||||
typedef enum {
|
||||
TT_HIT_NONE = 0,
|
||||
TT_HIT_BEGIN = 1,
|
||||
TT_HIT_MIDDLE = 2,
|
||||
TT_HIT_END = 3
|
||||
} teletone_hit_type_t;
|
||||
|
||||
|
||||
/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
|
||||
typedef struct {
|
||||
float v2;
|
||||
@@ -114,16 +155,19 @@ extern "C" {
|
||||
int hit2;
|
||||
int hit3;
|
||||
int hit4;
|
||||
int mhit;
|
||||
int dur;
|
||||
int zc;
|
||||
|
||||
|
||||
teletone_goertzel_state_t row_out[GRID_FACTOR];
|
||||
teletone_goertzel_state_t col_out[GRID_FACTOR];
|
||||
teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
|
||||
teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
|
||||
float energy;
|
||||
float lenergy;
|
||||
|
||||
int current_sample;
|
||||
char digits[TELETONE_MAX_DTMF_DIGITS + 1];
|
||||
char digit;
|
||||
int current_digits;
|
||||
int detected_digits;
|
||||
int lost_digits;
|
||||
@@ -196,7 +240,7 @@ TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf
|
||||
\param samples the number of samples present in sample_buffer
|
||||
\return true when DTMF was detected or false when it is not
|
||||
*/
|
||||
TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
int16_t sample_buffer[],
|
||||
int samples);
|
||||
/*!
|
||||
@@ -206,9 +250,7 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
\param max the maximum length of buf
|
||||
\return the number of characters written to buf
|
||||
*/
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
char *buf,
|
||||
int max);
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur);
|
||||
|
||||
/*!
|
||||
\brief Step through the Goertzel Algorithm for each sample in a buffer
|
||||
|
||||
@@ -2,6 +2,41 @@
|
||||
* libteletone
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libteletone
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone.h -- Tone Generator
|
||||
*
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
|
||||
@@ -2,14 +2,62 @@
|
||||
* libteletone
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is tone_detect.c - General telephony tone detection, and specific detection of DTMF.
|
||||
*
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Stephen Underwood <steveu@coppice.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* The the original interface designed by Steve Underwood was preserved to retain
|
||||
*the optimizations when considering DTMF tones though the names were changed in the interest
|
||||
* of namespace.
|
||||
*
|
||||
* Much less efficient expansion interface was added to allow for the detection of
|
||||
* a single arbitrary tone combination which may also exceed 2 simultaneous tones.
|
||||
* (controlled by compile time constant TELETONE_MAX_TONES)
|
||||
*
|
||||
* Copyright (C) 2006 Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone_detect.c Tone Detection Code
|
||||
*
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.c - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -40,21 +88,6 @@
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*********************************************************************************
|
||||
*
|
||||
* Derived from tone_detect.c - General telephony tone detection, and specific
|
||||
* detection of DTMF.
|
||||
*
|
||||
* Copyright (C) 2001 Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Despite my general liking of the GPL, I place this code in the
|
||||
* public domain for the benefit of all mankind - even the slimy
|
||||
* ones who might try to proprietize my work and use it to my
|
||||
* detriment.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libteletone_detect.h>
|
||||
@@ -67,7 +100,8 @@
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#define LOW_ENG 10000000
|
||||
#define ZC 2
|
||||
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
|
||||
static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];
|
||||
static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR];
|
||||
@@ -132,8 +166,8 @@ TELETONE_API(void) teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf
|
||||
dtmf_detect_state->current_sample = 0;
|
||||
dtmf_detect_state->detected_digits = 0;
|
||||
dtmf_detect_state->lost_digits = 0;
|
||||
dtmf_detect_state->digits[0] = '\0';
|
||||
dtmf_detect_state->mhit = 0;
|
||||
dtmf_detect_state->digit = 0;
|
||||
dtmf_detect_state->dur = 0;
|
||||
}
|
||||
|
||||
TELETONE_API(void) teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map)
|
||||
@@ -266,7 +300,7 @@ TELETONE_API(int) teletone_multi_tone_detect (teletone_multi_tone_t *mt,
|
||||
}
|
||||
|
||||
|
||||
TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
int16_t sample_buffer[],
|
||||
int samples)
|
||||
{
|
||||
@@ -281,6 +315,7 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
int best_col;
|
||||
char hit;
|
||||
int limit;
|
||||
teletone_hit_type_t r = 0;
|
||||
|
||||
hit = 0;
|
||||
for (sample = 0; sample < samples; sample = limit) {
|
||||
@@ -317,6 +352,32 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
|
||||
}
|
||||
|
||||
if (dtmf_detect_state->zc > 0) {
|
||||
if (dtmf_detect_state->energy < LOW_ENG && dtmf_detect_state->lenergy < LOW_ENG) {
|
||||
if (!--dtmf_detect_state->zc) {
|
||||
/* Reinitialise the detector for the next block */
|
||||
dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0;
|
||||
for (i = 0; i < GRID_FACTOR; i++) {
|
||||
goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
|
||||
goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
|
||||
}
|
||||
dtmf_detect_state->dur -= samples;
|
||||
return TT_HIT_END;
|
||||
}
|
||||
}
|
||||
|
||||
dtmf_detect_state->dur += samples;
|
||||
dtmf_detect_state->lenergy = dtmf_detect_state->energy;
|
||||
dtmf_detect_state->energy = 0.0;
|
||||
dtmf_detect_state->current_sample = 0;
|
||||
return TT_HIT_MIDDLE;
|
||||
} else if (dtmf_detect_state->digit) {
|
||||
return TT_HIT_END;
|
||||
}
|
||||
|
||||
|
||||
dtmf_detect_state->current_sample += (limit - sample);
|
||||
if (dtmf_detect_state->current_sample < BLOCK_LEN) {
|
||||
continue;
|
||||
@@ -361,58 +422,55 @@ TELETONE_API(int) teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detec
|
||||
back to back differing digits. More importantly, it
|
||||
can work with nasty phones that give a very wobbly start
|
||||
to a digit. */
|
||||
if (hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
|
||||
dtmf_detect_state->mhit = hit;
|
||||
if (! r && hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) {
|
||||
dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++;
|
||||
dtmf_detect_state->detected_digits++;
|
||||
if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) {
|
||||
dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit;
|
||||
dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0';
|
||||
dtmf_detect_state->digit = hit;
|
||||
} else {
|
||||
dtmf_detect_state->lost_digits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dtmf_detect_state->lost_digits++;
|
||||
}
|
||||
|
||||
if (!dtmf_detect_state->zc) {
|
||||
dtmf_detect_state->zc = ZC;
|
||||
dtmf_detect_state->dur = 0;
|
||||
r = TT_HIT_BEGIN;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dtmf_detect_state->hit1 = dtmf_detect_state->hit2;
|
||||
dtmf_detect_state->hit2 = dtmf_detect_state->hit3;
|
||||
dtmf_detect_state->hit3 = hit;
|
||||
/* Reinitialise the detector for the next block */
|
||||
for (i = 0; i < GRID_FACTOR; i++) {
|
||||
goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]);
|
||||
goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]);
|
||||
goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]);
|
||||
}
|
||||
|
||||
dtmf_detect_state->energy = 0.0;
|
||||
dtmf_detect_state->current_sample = 0;
|
||||
|
||||
}
|
||||
if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) {
|
||||
dtmf_detect_state->mhit = 0;
|
||||
return(0);
|
||||
}
|
||||
return (hit);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
|
||||
char *buf,
|
||||
int max)
|
||||
TELETONE_API(int) teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, char *buf, unsigned int *dur)
|
||||
{
|
||||
teletone_assert(dtmf_detect_state->current_digits <= TELETONE_MAX_DTMF_DIGITS);
|
||||
if (!dtmf_detect_state->digit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max > dtmf_detect_state->current_digits) {
|
||||
max = dtmf_detect_state->current_digits;
|
||||
*buf = dtmf_detect_state->digit;
|
||||
|
||||
*dur = dtmf_detect_state->dur;
|
||||
|
||||
if (!dtmf_detect_state->zc) {
|
||||
dtmf_detect_state->dur = 0;
|
||||
dtmf_detect_state->digit = 0;
|
||||
}
|
||||
if (max > 0) {
|
||||
memcpy (buf, dtmf_detect_state->digits, max);
|
||||
memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max);
|
||||
dtmf_detect_state->current_digits -= max;
|
||||
}
|
||||
buf[max] = '\0';
|
||||
return max;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
/*
|
||||
* libteletone_generate.c -- Tone Generator
|
||||
* libteletone
|
||||
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is libteletone
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* libteletone.c -- Tone Generator
|
||||
*
|
||||
*
|
||||
*
|
||||
* Exception:
|
||||
* The author hereby grants the use of this source code under the
|
||||
* following license if and only if the source code is distributed
|
||||
* as part of the OpenZAP or FreeTDM library. Any use or distribution of this
|
||||
* source code outside the scope of the OpenZAP or FreeTDM library will nullify the
|
||||
* following license and reinact the MPL 1.1 as stated above.
|
||||
*
|
||||
* Copyright (c) 2007, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
@@ -34,7 +70,6 @@
|
||||
*/
|
||||
|
||||
#include <libteletone.h>
|
||||
#include "private/ftdm_core.h"
|
||||
|
||||
#define SMAX 32767
|
||||
#define SMIN -32768
|
||||
@@ -111,7 +146,7 @@ TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int b
|
||||
ts->decay_step = 0;
|
||||
ts->decay_factor = 1;
|
||||
if (buflen) {
|
||||
if ((ts->buffer = ftdm_calloc(buflen, sizeof(teletone_audio_t))) == 0) {
|
||||
if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
|
||||
return -1;
|
||||
}
|
||||
ts->datalen = buflen;
|
||||
@@ -142,7 +177,7 @@ TELETONE_API(int) teletone_init_session(teletone_generation_session_t *ts, int b
|
||||
TELETONE_API(int) teletone_destroy_session(teletone_generation_session_t *ts)
|
||||
{
|
||||
if (ts->buffer) {
|
||||
ftdm_safe_free(ts->buffer);
|
||||
free(ts->buffer);
|
||||
ts->buffer = NULL;
|
||||
ts->samples = 0;
|
||||
}
|
||||
@@ -270,6 +305,19 @@ TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone
|
||||
return ts->samples / ts->channels;
|
||||
}
|
||||
|
||||
/* don't ask */
|
||||
static char *my_strdup (const char *s)
|
||||
{
|
||||
size_t len = strlen (s) + 1;
|
||||
void *new = malloc (len);
|
||||
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *) memcpy (new, s, len);
|
||||
}
|
||||
|
||||
TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd)
|
||||
{
|
||||
char *data = NULL, *cur = NULL, *end = NULL;
|
||||
@@ -280,7 +328,7 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
|
||||
}
|
||||
|
||||
do {
|
||||
if (!(data = ftdm_strdup(cmd))) {
|
||||
if (!(data = my_strdup(cmd))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -363,6 +411,9 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
|
||||
*e++ = '\0';
|
||||
}
|
||||
do {
|
||||
if (!p) {
|
||||
break;
|
||||
}
|
||||
if ((next = strchr(p, ',')) != 0) {
|
||||
*next++ = '\0';
|
||||
}
|
||||
@@ -427,7 +478,7 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
|
||||
}
|
||||
}
|
||||
bottom:
|
||||
ftdm_safe_free(data);
|
||||
free(data);
|
||||
data = NULL;
|
||||
if (ts->LOOPS > 0) {
|
||||
ts->LOOPS--;
|
||||
|
||||
Reference in new issue
Block a user