#define zap_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); zap_mutex_unlock(obj->mutex);
+#define zap_log_chan(zchan, level, format, ...) zap_log(level, "[s%dc%d][%d:%d] " format, zchan->span_id, zchan->chan_id, zchan->physical_span_id, zchan->physical_chan_id, __VA_ARGS__)
+
+#define zap_log_chan_msg(zchan, level, msg) zap_log(level, "[s%dc%d][%d:%d] " msg, zchan->span_id, zchan->chan_id, zchan->physical_span_id, zchan->physical_chan_id)
#define zap_set_state_locked(obj, s) if ( obj->state == s ) { \
if (s != ZAP_CHANNEL_STATE_HANGUP) zap_log(ZAP_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(obj->state), zap_channel_state2str(s)); \
ZAP_TYPE_CHANNEL
} zap_data_type_t;
+#ifdef ZAP_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;
+ zap_mutex_t *mutex;
+} zap_dtmf_debug_t;
+#endif
+
/* 2^8 table size, one for each byte value */
#define ZAP_GAINS_TABLE_SIZE 256
struct zap_channel {
unsigned char txgain_table[ZAP_GAINS_TABLE_SIZE];
float rxgain;
float txgain;
+#ifdef ZAP_DEBUG_DTMF
+ zap_dtmf_debug_t dtmfdbg;
+#endif
};
zap_sleep(500);
}
+#ifdef ZAP_DEBUG_DTMF
+ zap_mutex_destroy(&zchan->dtmfdbg.mutex);
+#endif
zap_mutex_lock(zchan->pre_buffer_mutex);
zap_buffer_destroy(&zchan->pre_buffer);
zap_mutex_unlock(zchan->pre_buffer_mutex);
memset(new_span, 0, sizeof(*new_span));
status = zap_mutex_create(&new_span->mutex);
assert(status == ZAP_SUCCESS);
-
+
zap_set_flag(new_span, ZAP_SPAN_CONFIGURED);
new_span->span_id = ++globals.span_index;
new_span->zio = zio;
zap_mutex_create(&new_chan->mutex);
zap_mutex_create(&new_chan->pre_buffer_mutex);
+#ifdef ZAP_DEBUG_DTMF
+ zap_mutex_create(&new_chan->dtmfdbg.mutex);
+#endif
zap_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
zap_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0);
return ZAP_FAIL;
}
+#ifdef ZAP_DEBUG_DTMF
+static void close_dtmf_debug(zap_channel_t *zchan)
+{
+ zap_mutex_lock(zchan->dtmfdbg.mutex);
+
+ if (zchan->dtmfdbg.file) {
+ zap_log_chan_msg(zchan, ZAP_LOG_DEBUG, "closing debug dtmf file\n");
+ fclose(zchan->dtmfdbg.file);
+ zchan->dtmfdbg.file = NULL;
+ }
+ zchan->dtmfdbg.windex = 0;
+ zchan->dtmfdbg.wrapped = 0;
+
+ zap_mutex_unlock(zchan->dtmfdbg.mutex);
+}
+#endif
+
OZ_DECLARE(zap_status_t) zap_channel_done(zap_channel_t *zchan)
{
assert(zchan != NULL);
zap_buffer_destroy(&zchan->pre_buffer);
zchan->pre_buffer_size = 0;
zap_mutex_unlock(zchan->pre_buffer_mutex);
+#ifdef ZAP_DEBUG_DTMF
+ close_dtmf_debug(zchan);
+#endif
zap_channel_flush_dtmf(zchan);
assert(zchan != NULL);
+ zap_log_chan(zchan, ZAP_LOG_DEBUG, "Queuing DTMF %s\n", dtmf);
+
+#ifdef ZAP_DEBUG_DTMF
+ zap_mutex_lock(zchan->dtmfdbg.mutex);
+ if (!zchan->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",
+ zchan->span_id, zchan->chan_id,
+ currtime.tm_year-100, currtime.tm_mon+1, currtime.tm_mday,
+ currtime.tm_hour, currtime.tm_min, currtime.tm_sec, zchan->native_codec == ZAP_CODEC_ULAW ? "ulaw" : zchan->native_codec == ZAP_CODEC_ALAW ? "alaw" : "sln");
+ zchan->dtmfdbg.file = fopen(dfile, "w");
+ if (!zchan->dtmfdbg.file) {
+ zap_log_chan(zchan, ZAP_LOG_ERROR, "failed to open debug dtmf file %s\n", dfile);
+ } else {
+ /* write the saved audio buffer */
+ int rc = 0;
+ int towrite = sizeof(zchan->dtmfdbg.buffer) - zchan->dtmfdbg.windex;
+
+ zap_log_chan(zchan, ZAP_LOG_DEBUG, "created debug DTMF file %s\n", dfile);
+ zchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT;
+ if (zchan->dtmfdbg.wrapped) {
+ rc = fwrite(&zchan->dtmfdbg.buffer[zchan->dtmfdbg.windex], 1, towrite, zchan->dtmfdbg.file);
+ if (rc != towrite) {
+ zap_log_chan(zchan, ZAP_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
+ }
+ }
+ if (zchan->dtmfdbg.windex) {
+ towrite = zchan->dtmfdbg.windex;
+ rc = fwrite(&zchan->dtmfdbg.buffer[0], 1, towrite, zchan->dtmfdbg.file);
+ if (rc != towrite) {
+ zap_log_chan(zchan, ZAP_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
+ }
+ }
+ zchan->dtmfdbg.windex = 0;
+ zchan->dtmfdbg.wrapped = 0;
+ }
+ } else {
+ zchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT;
+ }
+ zap_mutex_unlock(zchan->dtmfdbg.mutex);
+#endif
+
if (zchan->pre_buffer) {
zap_buffer_zero(zchan->pre_buffer);
}
}
}
+#ifdef ZAP_DEBUG_DTMF
+ if (status == ZAP_SUCCESS) {
+ int dlen = (int) *datalen;
+ int rc = 0;
+ zap_mutex_lock(zchan->dtmfdbg.mutex);
+ if (!zchan->dtmfdbg.file) {
+ /* no file yet, write to our circular buffer */
+ int windex = zchan->dtmfdbg.windex;
+ int avail = sizeof(zchan->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(&zchan->dtmfdbg.buffer[windex], dataptr, avail);
+ memcpy(&zchan->dtmfdbg.buffer[0], &dataptr[avail], diff);
+ windex = diff;
+ /*zap_log_chan(zchan, ZAP_LOG_DEBUG, "wrapping around dtmf read buffer up to index %d\n\n", windex);*/
+ zchan->dtmfdbg.wrapped = 1;
+ } else {
+ memcpy(&zchan->dtmfdbg.buffer[windex], dataptr, dlen);
+ windex += dlen;
+ }
+ if (windex == sizeof(zchan->dtmfdbg.buffer)) {
+ /*zap_log_chan_msg(zchan, ZAP_LOG_DEBUG, "wrapping around dtmf read buffer\n");*/
+ windex = 0;
+ zchan->dtmfdbg.wrapped = 1;
+ }
+ zchan->dtmfdbg.windex = windex;
+ } else {
+ rc = fwrite(data, 1, dlen, zchan->dtmfdbg.file);
+ if (rc != dlen) {
+ zap_log(ZAP_LOG_WARNING, "DTMF debugger wrote only %d out of %d bytes: %s\n", rc, datalen, strerror(errno));
+ }
+ zchan->dtmfdbg.closetimeout--;
+ if (!zchan->dtmfdbg.closetimeout) {
+ close_dtmf_debug(zchan);
+ }
+ }
+ zap_mutex_unlock(zchan->dtmfdbg.mutex);
+ }
+#endif
+
if (status == ZAP_SUCCESS) {
if (zap_test_flag(zchan, ZAP_CHANNEL_USE_RX_GAIN)
&& (zchan->native_codec == ZAP_CODEC_ALAW || zchan->native_codec == ZAP_CODEC_ULAW)) {