diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 3dd1aa9ece..92302c5071 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -86,6 +86,110 @@ FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void) #endif } +static void write_chan_io_dump(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, char *dataptr, int dlen) +{ + int windex = dump->windex; + int avail = dump->size - windex; + + if (dlen > avail) { + int diff = dlen - avail; + + ftdm_assert(diff < dump->size, "Very small buffer or very big IO chunk!\n"); + + /* write only what we can and the rest at the beginning of the buffer */ + memcpy(&dump->buffer[windex], dataptr, avail); + memcpy(&dump->buffer[0], &dataptr[avail], diff); + windex = diff; + + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p up to index %d\n\n", dump, windex); + dump->wrapped = 1; + } else { + memcpy(&dump->buffer[windex], dataptr, dlen); + windex += dlen; + } + + if (windex == dump->size) { + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p\n", dump); + windex = 0; + dump->wrapped = 1; + } + + dump->windex = windex; +} + +static void dump_chan_io_to_file(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, FILE *file) +{ + /* write the saved audio buffer */ + int rc = 0; + int towrite = dump->size - dump->windex; + if (dump->wrapped) { + rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file); + if (rc != towrite) { + ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite); + } + } + if (dump->windex) { + towrite = dump->windex; + rc = fwrite(&dump->buffer[0], 1, towrite, file); + if (rc != towrite) { + ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite); + } + } + dump->windex = 0; + dump->wrapped = 0; +} + +static void stop_chan_io_dump(ftdm_io_dump_t *dump) +{ + if (!dump->buffer) { + return; + } + ftdm_safe_free(dump->buffer); + memset(dump, 0, sizeof(dump)); +} + +static int start_chan_io_dump(ftdm_channel_t *chan, ftdm_io_dump_t *dump, ftdm_size_t size) +{ + if (dump->buffer) { + ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "IO dump is already started\n"); + return -1; + } + memset(dump, 0, sizeof(*dump)); + dump->buffer = ftdm_malloc(size); + if (!dump->buffer) { + return -1; + } + dump->size = size; + return 0; +} + + +static void close_dtmf_debug_file(ftdm_channel_t *ftdmchan) +{ + 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; + } +} + +static int disable_dtmf_debug(ftdm_channel_t *ftdmchan) +{ + if (!ftdmchan->dtmfdbg.enabled) { + return 0; + } + + if (!ftdmchan->rxdump.buffer) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "DTMF debug enabled but no rx dump?\n"); + return -1; + } + + close_dtmf_debug_file(ftdmchan); + stop_chan_io_dump(&ftdmchan->rxdump); + ftdmchan->dtmfdbg.enabled = 0; + return 0; +} + typedef struct { uint8_t enabled; uint8_t running; @@ -448,10 +552,6 @@ 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); @@ -870,9 +970,6 @@ 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); @@ -2355,23 +2452,6 @@ 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 - static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan); FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) { @@ -2400,9 +2480,7 @@ 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 + disable_dtmf_debug(ftdmchan); ftdm_channel_clear_vars(ftdmchan); if (ftdmchan->hangup_timer) { ftdm_sched_cancel_timer(globals.timingsched, ftdmchan->hangup_timer); @@ -2411,7 +2489,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN; ftdmchan->state = FTDM_CHANNEL_STATE_DOWN; - ftdm_log(FTDM_LOG_DEBUG, "channel done %u:%u\n", ftdmchan->span_id, ftdmchan->chan_id); + stop_chan_io_dump(&ftdmchan->txdump); + stop_chan_io_dump(&ftdmchan->rxdump); if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) { ftdm_sigmsg_t sigmsg; @@ -2423,6 +2502,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_span_send_signal(ftdmchan->span, &sigmsg); } + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n"); + ftdm_mutex_unlock(ftdmchan->mutex); return FTDM_SUCCESS; @@ -2431,7 +2512,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan) { - assert(ftdmchan != NULL); + ftdm_assert(ftdmchan != NULL, "Null channel\n"); ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE); @@ -2505,8 +2586,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co { ftdm_status_t status = FTDM_FAIL; - assert(ftdmchan != NULL); - assert(ftdmchan->fio != NULL); + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n"); + ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No IO attached to channel\n"); ftdm_mutex_lock(ftdmchan->mutex); @@ -2533,7 +2614,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co break; case FTDM_COMMAND_TRACE_INPUT: { - char *path = (char *) obj; + char *path = FTDM_COMMAND_OBJ_CHAR_P; if (ftdmchan->fds[FTDM_READ_TRACE_INDEX] > 0) { close(ftdmchan->fds[FTDM_READ_TRACE_INDEX]); ftdmchan->fds[FTDM_READ_TRACE_INDEX] = -1; @@ -2576,6 +2657,109 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co GOTO_STATUS(done, FTDM_SUCCESS); } break; + + /*!< Enable DTMF debugging */ + case FTDM_COMMAND_ENABLE_DEBUG_DTMF: + { + if (ftdmchan->dtmfdbg.enabled) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot enable debug DTMF again\n"); + GOTO_STATUS(done, FTDM_FAIL); + } + if (ftdmchan->rxdump.buffer) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot debug DTMF if Rx dumping is already enabled\n"); + GOTO_STATUS(done, FTDM_FAIL); + } + if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, FTDM_IO_DUMP_DEFAULT_BUFF_SIZE)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable rx dump for DTMF debugging\n"); + } + ftdmchan->dtmfdbg.enabled = 1; + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Disable DTMF debugging (if not disabled explicitly, it is disabled automatically when calls hangup) */ + case FTDM_COMMAND_DISABLE_DEBUG_DTMF: + { + if (!ftdmchan->dtmfdbg.enabled) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "DTMF debug is already disabled\n"); + GOTO_STATUS(done, FTDM_SUCCESS); + } + if (disable_dtmf_debug(ftdmchan)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to disable DTMF debug\n"); + GOTO_STATUS(done, FTDM_FAIL); + } + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Start dumping all input to a circular buffer. The size of the circular buffer can be specified, default used otherwise */ + case FTDM_COMMAND_ENABLE_INPUT_DUMP: + { + ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE; + if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, size)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump\n"); + GOTO_STATUS(done, FTDM_FAIL); + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled input dump with size %zd\n", size); + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Stop dumping all input to a circular buffer. */ + case FTDM_COMMAND_DISABLE_INPUT_DUMP: + { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %zd\n", ftdmchan->rxdump.size); + stop_chan_io_dump(&ftdmchan->rxdump); + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Start dumping all output to a circular buffer. The size of the circular buffer can be specified, default used otherwise */ + case FTDM_COMMAND_ENABLE_OUTPUT_DUMP: + { + ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE; + if (start_chan_io_dump(ftdmchan, &ftdmchan->txdump, size)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump\n"); + GOTO_STATUS(done, FTDM_FAIL); + } + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %zd\n", size); + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Stop dumping all output to a circular buffer. */ + case FTDM_COMMAND_DISABLE_OUTPUT_DUMP: + { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %zd\n", ftdmchan->rxdump.size); + stop_chan_io_dump(&ftdmchan->txdump); + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Dump the current input circular buffer to the specified FILE* structure */ + case FTDM_COMMAND_DUMP_INPUT: + { + if (!obj) { + GOTO_STATUS(done, FTDM_FAIL); + } + dump_chan_io_to_file(ftdmchan, &ftdmchan->rxdump, obj); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %zd to file %p\n", ftdmchan->rxdump.size, obj); + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + + /*!< Dump the current output circular buffer to the specified FILE* structure */ + case FTDM_COMMAND_DUMP_OUTPUT: + { + if (!obj) { + GOTO_STATUS(done, FTDM_FAIL); + } + dump_chan_io_to_file(ftdmchan, &ftdmchan->txdump, obj); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %zd to file %p\n", ftdmchan->txdump.size, obj); + GOTO_STATUS(done, FTDM_SUCCESS); + } + break; + case FTDM_COMMAND_SET_INTERVAL: { if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL)) { @@ -3044,12 +3228,14 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons ftdm_size_t wr = 0; const char *p; - assert(ftdmchan != NULL); + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n"); 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.enabled) { + goto skipdebug; + } + if (!ftdmchan->dtmfdbg.file) { struct tm currtime; time_t currsec; @@ -3062,37 +3248,18 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons 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"); + 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; + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, ftdmchan->dtmfdbg.file); } } else { - ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT; + ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT; } - ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex); -#endif + +skipdebug: if (ftdmchan->pre_buffer) { ftdm_buffer_zero(ftdmchan->pre_buffer); @@ -3146,7 +3313,6 @@ 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); @@ -3161,48 +3327,24 @@ static FIO_READ_FUNCTION(ftdm_raw_read) ftdmchan->span->sig_read(ftdmchan, data, *datalen); } -#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 { + write_chan_io_dump(ftdmchan, &ftdmchan->rxdump, data, dlen); + + /* if dtmf debug is enabled and initialized, write there too */ + if (ftdmchan->dtmfdbg.file) { 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); + close_dtmf_debug_file(ftdmchan); } } - ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex); } -#endif return status; } diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 45254e817f..1adbaa819a 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -431,9 +431,38 @@ typedef enum { FTDM_COMMAND_WINK, FTDM_COMMAND_ENABLE_PROGRESS_DETECT, FTDM_COMMAND_DISABLE_PROGRESS_DETECT, + + /*!< Start tracing input and output from channel to the given file */ FTDM_COMMAND_TRACE_INPUT, FTDM_COMMAND_TRACE_OUTPUT, + + /*!< Stop both Input and Output trace, closing the files */ FTDM_COMMAND_TRACE_END_ALL, + + /*!< Enable DTMF debugging */ + FTDM_COMMAND_ENABLE_DEBUG_DTMF, + + /*!< Disable DTMF debugging (if not disabled explicitly, it is disabled automatically when calls hangup) */ + FTDM_COMMAND_DISABLE_DEBUG_DTMF, + + /*!< Start dumping all input to a circular buffer. The size of the circular buffer can be specified, default used otherwise */ + FTDM_COMMAND_ENABLE_INPUT_DUMP, + + /*!< Stop dumping all input to a circular buffer. */ + FTDM_COMMAND_DISABLE_INPUT_DUMP, + + /*!< Start dumping all output to a circular buffer. The size of the circular buffer can be specified, default used otherwise */ + FTDM_COMMAND_ENABLE_OUTPUT_DUMP, + + /*!< Stop dumping all output to a circular buffer. */ + FTDM_COMMAND_DISABLE_OUTPUT_DUMP, + + /*!< Dump the current input circular buffer to the specified FILE* structure */ + FTDM_COMMAND_DUMP_INPUT, + + /*!< Dump the current output circular buffer to the specified FILE* structure */ + FTDM_COMMAND_DUMP_OUTPUT, + FTDM_COMMAND_ENABLE_CALLERID_DETECT, FTDM_COMMAND_DISABLE_CALLERID_DETECT, FTDM_COMMAND_ENABLE_ECHOCANCEL, diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 7683ec7145..04458adda1 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -342,21 +342,23 @@ 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 +/* number of bytes for the IO dump circular buffer (5 seconds worth of audio by default) */ +#define FTDM_IO_DUMP_DEFAULT_BUFF_SIZE 8 * 5000 typedef struct { - FILE *file; - char buffer[DTMF_DEBUG_SIZE]; + char *buffer; + ftdm_size_t size; int windex; int wrapped; - int closetimeout; +} ftdm_io_dump_t; + +/* number of interval cycles before timeout and close the debug dtmf file (5 seconds if interval is 20) */ +#define DTMF_DEBUG_TIMEOUT 250 +typedef struct { + uint8_t enabled; + FILE *file; + int32_t closetimeout; ftdm_mutex_t *mutex; } ftdm_dtmf_debug_t; -#endif - typedef struct { const char *file; @@ -471,9 +473,9 @@ struct ftdm_channel { void *user_private; ftdm_timer_id_t hangup_timer; ftdm_channel_iostats_t iostats; -#ifdef FTDM_DEBUG_DTMF ftdm_dtmf_debug_t dtmfdbg; -#endif + ftdm_io_dump_t rxdump; + ftdm_io_dump_t txdump; }; struct ftdm_span { diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index f265cb1a3d..db1428c962 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -58,6 +58,7 @@ typedef int ftdm_filehandle_t; extern "C" { #endif +#define FTDM_COMMAND_OBJ_SIZE *((ftdm_size_t *)obj) #define FTDM_COMMAND_OBJ_INT *((int *)obj) #define FTDM_COMMAND_OBJ_CHAR_P (char *)obj #define FTDM_COMMAND_OBJ_FLOAT *(float *)obj