From 9f9c4541cdf633ab840c2e7ff9e0d20c7339021f Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 29 Jul 2010 17:26:03 -0400 Subject: [PATCH] freetdm: added dtmf recording feature for debugging --- libs/freetdm/Makefile.am | 9 ++ libs/freetdm/configure.ac | 7 ++ libs/freetdm/src/ftdm_io.c | 118 +++++++++++++++++++ libs/freetdm/src/include/private/ftdm_core.h | 18 +++ 4 files changed, 152 insertions(+) diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 1c878e6cb4..54c44f8169 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -41,11 +41,16 @@ INCS += -I$(FT_SRCDIR)/$(SRC)/ftmod/ftmod_sangoma_boost if SNGSS7 INCS += -I/usr/include/sng_ss7/ endif + MY_CFLAGS = $(INCS) $(FTDM_CFLAGS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@ COMPILE = $(CC) $(MY_CFLAGS) $(INCS) LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE) LINK = $(LIBTOOL) --mode=link --tag=CC $(CC) $(MY_CFLAGS) $(LDFLAGS) -o $@ +if DEBUGDTMF +MY_CFLAGS += -DFTDM_DEBUG_DTMF +endif + # # GNU pkgconfig file @@ -171,6 +176,10 @@ if SNGSS7 mod_LTLIBRARIES += ftmod_sangoma_ss7.la endif +if SNGISDN +mod_LTLIBRARIES += ftmod_sangoma_isdn.la +endif + if OPENR2 mod_LTLIBRARIES += ftmod_r2.la endif diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 567be44587..17b063a361 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -165,11 +165,18 @@ AC_ARG_WITH([libpri], [AS_HELP_STRING([--with-libpri], [Install ftmod_libpri])], [enable_libpri="yes"], [enable_libpri="no"]) AC_SUBST(enable_libpri) +# debug dtmf? +AC_ARG_WITH([debugdtmf], + [AS_HELP_STRING([--with-debugdtmf], [Debug DTMF])], [enable_debugdtmf="yes"], [enable_debugdtmf="no"]) +AC_SUBST(enable_debugdtmf) + AC_CHECK_LIB([sangoma], [sangoma_span_chan_toif], [have_libsangoma="yes"]) AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"]) AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"]) +AM_CONDITIONAL([DEBUGDTMF],[test "${enable_debugdtmf}" = "yes"]) + AC_CHECK_LIB([sng_ss7], [sng_isup_init], [have_sng_ss7="yes"]) AM_CONDITIONAL([SNGSS7],[test "${have_sng_ss7}" = "yes"]) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 6c90f0d174..738c657f21 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -372,6 +372,10 @@ static ftdm_status_t ftdm_channel_destroy(ftdm_channel_t *ftdmchan) ftdm_sleep(500); } +#ifdef FTDM_DEBUG_DTMF + ftdm_mutex_destroy(&ftdmchan->dtmfdbg.mutex); +#endif + ftdm_mutex_lock(ftdmchan->pre_buffer_mutex); ftdm_buffer_destroy(&ftdmchan->pre_buffer); ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex); @@ -771,6 +775,9 @@ FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t ftdm_mutex_create(&new_chan->mutex); ftdm_mutex_create(&new_chan->pre_buffer_mutex); +#ifdef FTDM_DEBUG_DTMF + ftdm_mutex_create(&new_chan->dtmfdbg.mutex); +#endif ftdm_buffer_create(&new_chan->digit_buffer, 128, 128, 0); ftdm_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0); @@ -2166,6 +2173,23 @@ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signa } } +#ifdef FTDM_DEBUG_DTMF +static void close_dtmf_debug(ftdm_channel_t *ftdmchan) +{ + ftdm_mutex_lock(ftdmchan->dtmfdbg.mutex); + + if (ftdmchan->dtmfdbg.file) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "closing debug dtmf file\n"); + fclose(ftdmchan->dtmfdbg.file); + ftdmchan->dtmfdbg.file = NULL; + } + ftdmchan->dtmfdbg.windex = 0; + ftdmchan->dtmfdbg.wrapped = 0; + + ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex); +} +#endif + FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) { assert(ftdmchan != NULL); @@ -2193,6 +2217,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_buffer_destroy(&ftdmchan->pre_buffer); ftdmchan->pre_buffer_size = 0; ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex); +#ifdef FTDM_DEBUG_DTMF + close_dtmf_debug(ftdmchan); +#endif ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN; ftdmchan->state = FTDM_CHANNEL_STATE_DOWN; @@ -2831,6 +2858,54 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons assert(ftdmchan != NULL); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing DTMF %s\n", dtmf); + +#ifdef FTDM_DEBUG_DTMF + ftdm_mutex_lock(ftdmchan->dtmfdbg.mutex); + if (!ftdmchan->dtmfdbg.file) { + struct tm currtime; + time_t currsec; + char dfile[512]; + + currsec = time(NULL); + localtime_r(&currsec, &currtime); + + snprintf(dfile, sizeof(dfile), "dtmf-s%dc%d-20%d-%d-%d-%d:%d:%d.%s", + ftdmchan->span_id, ftdmchan->chan_id, + currtime.tm_year-100, currtime.tm_mon+1, currtime.tm_mday, + currtime.tm_hour, currtime.tm_min, currtime.tm_sec, ftdmchan->native_codec == FTDM_CODEC_ULAW ? "ulaw" : ftdmchan->native_codec == FTDM_CODEC_ALAW ? "alaw" : "sln"); + ftdmchan->dtmfdbg.file = fopen(dfile, "w"); + if (!ftdmchan->dtmfdbg.file) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to open debug dtmf file %s\n", dfile); + } else { + /* write the saved audio buffer */ + int rc = 0; + int towrite = sizeof(ftdmchan->dtmfdbg.buffer) - ftdmchan->dtmfdbg.windex; + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "created debug DTMF file %s\n", dfile); + ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT; + if (ftdmchan->dtmfdbg.wrapped) { + rc = fwrite(&ftdmchan->dtmfdbg.buffer[ftdmchan->dtmfdbg.windex], 1, towrite, ftdmchan->dtmfdbg.file); + if (rc != towrite) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite); + } + } + if (ftdmchan->dtmfdbg.windex) { + towrite = ftdmchan->dtmfdbg.windex; + rc = fwrite(&ftdmchan->dtmfdbg.buffer[0], 1, towrite, ftdmchan->dtmfdbg.file); + if (rc != towrite) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite); + } + } + ftdmchan->dtmfdbg.windex = 0; + ftdmchan->dtmfdbg.wrapped = 0; + } + } else { + ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT; + } + ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex); +#endif + if (ftdmchan->pre_buffer) { ftdm_buffer_zero(ftdmchan->pre_buffer); } @@ -2883,6 +2958,7 @@ static FIO_WRITE_FUNCTION(ftdm_raw_write) return ftdmchan->fio->write(ftdmchan, data, datalen); } + static FIO_READ_FUNCTION(ftdm_raw_read) { ftdm_status_t status = ftdmchan->fio->read(ftdmchan, data, datalen); @@ -2892,6 +2968,48 @@ static FIO_READ_FUNCTION(ftdm_raw_read) ftdm_log(FTDM_LOG_WARNING, "Raw input trace failed to write all of the %zd bytes\n", dlen); } } +#ifdef FTDM_DEBUG_DTMF + if (status == FTDM_SUCCESS) { + int dlen = (int) *datalen; + int rc = 0; + ftdm_mutex_lock(ftdmchan->dtmfdbg.mutex); + if (!ftdmchan->dtmfdbg.file) { + /* no file yet, write to our circular buffer */ + int windex = ftdmchan->dtmfdbg.windex; + int avail = sizeof(ftdmchan->dtmfdbg.buffer) - windex; + char *dataptr = data; + + if (dlen > avail) { + int diff = dlen - avail; + /* write only what we can and the rest at the beginning of the buffer */ + memcpy(&ftdmchan->dtmfdbg.buffer[windex], dataptr, avail); + memcpy(&ftdmchan->dtmfdbg.buffer[0], &dataptr[avail], diff); + windex = diff; + /*ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "wrapping around dtmf read buffer up to index %d\n\n", windex);*/ + ftdmchan->dtmfdbg.wrapped = 1; + } else { + memcpy(&ftdmchan->dtmfdbg.buffer[windex], dataptr, dlen); + windex += dlen; + } + if (windex == sizeof(ftdmchan->dtmfdbg.buffer)) { + /*ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "wrapping around dtmf read buffer\n");*/ + windex = 0; + ftdmchan->dtmfdbg.wrapped = 1; + } + ftdmchan->dtmfdbg.windex = windex; + } else { + rc = fwrite(data, 1, dlen, ftdmchan->dtmfdbg.file); + if (rc != dlen) { + ftdm_log(FTDM_LOG_WARNING, "DTMF debugger wrote only %d out of %d bytes: %s\n", rc, datalen, strerror(errno)); + } + ftdmchan->dtmfdbg.closetimeout--; + if (!ftdmchan->dtmfdbg.closetimeout) { + close_dtmf_debug(ftdmchan); + } + } + ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex); + } +#endif return status; } diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index a99ad79f54..eff62bb58e 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -340,6 +340,21 @@ typedef enum { FTDM_TYPE_CHANNEL } ftdm_data_type_t; +#ifdef FTDM_DEBUG_DTMF +/* number of bytes for the circular buffer (5 seconds worth of audio) */ +#define DTMF_DEBUG_SIZE 8 * 5000 +/* number of 20ms cycles before timeout and close the debug dtmf file (5 seconds) */ +#define DTMF_DEBUG_TIMEOUT 250 +typedef struct { + FILE *file; + char buffer[DTMF_DEBUG_SIZE]; + int windex; + int wrapped; + int closetimeout; + ftdm_mutex_t *mutex; +} ftdm_dtmf_debug_t; +#endif + /* 2^8 table size, one for each byte (sample) value */ #define FTDM_GAINS_TABLE_SIZE 256 struct ftdm_channel { @@ -409,6 +424,9 @@ struct ftdm_channel { float txgain; int availability_rate; void *user_private; +#ifdef FTDM_DEBUG_DTMF + ftdm_dtmf_debug_t dtmfdbg; +#endif }; struct ftdm_span {