#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;
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);
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);
}
}
-#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)
{
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);
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;
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;
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);
{
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);
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;
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)) {
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;
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);
return ftdmchan->fio->write(ftdmchan, data, datalen);
}
-
static FIO_READ_FUNCTION(ftdm_raw_read)
{
ftdm_status_t status = ftdmchan->fio->read(ftdmchan, data, datalen);
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;
}