ioctlcmd SETTXBITS;
ioctlcmd GETRXBITS;
ioctlcmd SETPOLARITY;
+ ioctlcmd TONEDETECT;
};
/**
.GETCONFMUTE = ZT_GETCONFMUTE,
.ECHOTRAIN = ZT_ECHOTRAIN,
.SETTXBITS = ZT_SETTXBITS,
- .GETRXBITS = ZT_GETRXBITS
+ .GETRXBITS = ZT_GETRXBITS,
+ .TONEDETECT = ZT_TONEDETECT,
};
/**
.ECHOTRAIN = DAHDI_ECHOTRAIN,
.SETTXBITS = DAHDI_SETTXBITS,
.GETRXBITS = DAHDI_GETRXBITS,
- .SETPOLARITY = DAHDI_SETPOLARITY
+ .SETPOLARITY = DAHDI_SETPOLARITY,
+ .TONEDETECT = DAHDI_TONEDETECT,
};
#define ZT_INVALID_SOCKET -1
cc.sigtype = ZT_SIG_CAS;
cc.idlebits = cas_bits;
if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
- ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
+ ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
close(sockfd);
continue;
}
continue;
}
+ zt_tone_mode_t mode = ZT_TONEDETECT_ON | ZT_TONEDETECT_MUTE;
+ if (ioctl(sockfd, codes.TONEDETECT, &mode)) {
+ ftdm_log(FTDM_LOG_DEBUG, "HW DTMF not available on FreeTDM device %d:%d fd:%d\n", ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "HW DTMF available on FreeTDM device %d:%d fd:%d\n", ftdmchan->span_id, ftdmchan->chan_id, sockfd);
+ ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT);
+ mode = 0;
+ ioctl(sockfd, codes.TONEDETECT, &mode);
+ }
+
if (!ftdm_strlen_zero(name)) {
ftdm_copy_string(ftdmchan->chan_name, name, sizeof(ftdmchan->chan_name));
}
if (!ftdm_strlen_zero(number)) {
ftdm_copy_string(ftdmchan->chan_number, number, sizeof(ftdmchan->chan_number));
}
+
configured++;
} else {
ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s\n", chanpath);
}
}
}
-
}
return FTDM_SUCCESS;
}
and this is only used by some sig modules such as ftmod_r2 to behave bettter under load */
err = 0;
break;
+ case FTDM_COMMAND_ENABLE_DTMF_DETECT:
+ {
+ zt_tone_mode_t mode = ZT_TONEDETECT_ON | ZT_TONEDETECT_MUTE;
+ err = ioctl(ftdmchan->sockfd, codes.TONEDETECT, &mode);
+ }
+ break;
+ case FTDM_COMMAND_DISABLE_DTMF_DETECT:
+ {
+ zt_tone_mode_t mode = 0;
+ err = ioctl(ftdmchan->sockfd, codes.TONEDETECT, &mode);
+ }
+ break;
default:
err = FTDM_NOTIMPL;
break;
pfds[0].fd = ftdmchan->sockfd;
pfds[0].events = inflags;
result = poll(pfds, 1, to);
- *flags = 0;
+ *flags = FTDM_NO_FLAGS;
if (result < 0 && errno == EINTR) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "DAHDI wait got interrupted, trying again\n");
inflags = pfds[0].revents;
}
- *flags = FTDM_NO_FLAGS;
-
if (result < 0){
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to poll DAHDI device: %s\n", strerror(errno));
return k ? FTDM_SUCCESS : FTDM_FAIL;
}
+static __inline__ int handle_dtmf_event(ftdm_channel_t *fchan, zt_event_t zt_event_id)
+{
+ if ((zt_event_id & ZT_EVENT_DTMFUP)) {
+ int digit = (zt_event_id & (~ZT_EVENT_DTMFUP));
+ char tmp_dtmf[2] = { digit, 0 };
+ ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "DTMF UP [%d]\n", digit);
+ ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
+ return 0;
+ } else if ((zt_event_id & ZT_EVENT_DTMFDOWN)) {
+ int digit = (zt_event_id & (~ZT_EVENT_DTMFDOWN));
+ ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "DTMF DOWN [%d]\n", digit);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
/**
* \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked.
* \param fchan Channel to retrieve event from
break;
default:
{
- ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
- *event_id = FTDM_OOB_INVALID;
+ if (handle_dtmf_event(fchan, zt_event_id)) {
+ ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
+ *event_id = FTDM_OOB_INVALID;
+ } else {
+ *event_id = FTDM_OOB_NOOP;
+ }
}
break;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
return FTDM_FAIL;
}
- /* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
- ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
+
+ if (handle_dtmf_event(ftdmchan, zt_event_id)) {
+ /* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
+ }
+
goto tryagain;
}
{
close(ftdmchan->sockfd);
ftdmchan->sockfd = ZT_INVALID_SOCKET;
-
return FTDM_SUCCESS;
}
ZT_EVENT_TIMER_EXPIRED = 15,
ZT_EVENT_TIMER_PING = 16,
ZT_EVENT_POLARITY = 17,
- ZT_EVENT_RINGBEGIN = 18
+ ZT_EVENT_RINGBEGIN = 18,
+ ZT_EVENT_DTMFDOWN = (1 << 17),
+ ZT_EVENT_DTMFUP = (1 << 18),
} zt_event_t;
typedef enum {
ZT_ABIT = 8
} zt_cas_bit_t;
+typedef enum {
+/* Tone Detection */
+ZT_TONEDETECT_ON = (1 << 0), /* Detect tones */
+ZT_TONEDETECT_MUTE = (1 << 1) /* Mute audio in received channel */
+} zt_tone_mode_t;
+
/* Defines */
#define ZT_MAX_BLOCKSIZE 8192
#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+/*
+ * Enable tone detection -- implemented by low level driver
+ */
+#define ZT_TONEDETECT _IOW(ZT_CODE, 91, int)
+
#define DAHDI_GET_BLOCKSIZE _IOR (DAHDI_CODE, 1, int) /* Get Transfer Block Size. */
#define DAHDI_SET_BLOCKSIZE _IOW (DAHDI_CODE, 1, int) /* Set Transfer Block Size. */
#define DAHDI_FLUSH _IOW (DAHDI_CODE, 3, int) /* Flush Buffer(s) and stop I/O */
#define DAHDI_SETPOLARITY _IOW (DAHDI_CODE, 92, int) /* Polarity setting for FXO lines */
+/*
+ * Enable tone detection -- implemented by low level driver
+ */
+#define DAHDI_TONEDETECT _IOW(DAHDI_CODE, 91, int)
+
#endif
/* For Emacs: