From db673a043f2438ff127b16a4465333926b9efd70 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Sun, 18 Nov 2012 23:55:54 -0500 Subject: [PATCH] freetdm: ftmod_zt - Integrated HW DTMF support --- libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c | 71 ++++++++++++++++++---- libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h | 20 +++++- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c index ac3fcf2417..8d4ee8ab6f 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -102,6 +102,7 @@ struct ioctl_codes { ioctlcmd SETTXBITS; ioctlcmd GETRXBITS; ioctlcmd SETPOLARITY; + ioctlcmd TONEDETECT; }; /** @@ -139,7 +140,8 @@ static struct ioctl_codes zt_ioctl_codes = { .GETCONFMUTE = ZT_GETCONFMUTE, .ECHOTRAIN = ZT_ECHOTRAIN, .SETTXBITS = ZT_SETTXBITS, - .GETRXBITS = ZT_GETRXBITS + .GETRXBITS = ZT_GETRXBITS, + .TONEDETECT = ZT_TONEDETECT, }; /** @@ -178,7 +180,8 @@ static struct ioctl_codes dahdi_ioctl_codes = { .ECHOTRAIN = DAHDI_ECHOTRAIN, .SETTXBITS = DAHDI_SETTXBITS, .GETRXBITS = DAHDI_GETRXBITS, - .SETPOLARITY = DAHDI_SETPOLARITY + .SETPOLARITY = DAHDI_SETPOLARITY, + .TONEDETECT = DAHDI_TONEDETECT, }; #define ZT_INVALID_SOCKET -1 @@ -361,7 +364,7 @@ static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, f 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; } @@ -436,12 +439,23 @@ static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, f 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); @@ -666,7 +680,6 @@ static FIO_OPEN_FUNCTION(zt_open) } } } - } return FTDM_SUCCESS; } @@ -864,6 +877,18 @@ static FIO_COMMAND_FUNCTION(zt_command) 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; @@ -955,7 +980,7 @@ pollagain: 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"); @@ -971,8 +996,6 @@ pollagain: 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)); @@ -1048,6 +1071,23 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) 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 @@ -1157,8 +1197,12 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, 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; } @@ -1314,8 +1358,12 @@ tryagain: 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; } @@ -1331,7 +1379,6 @@ static FIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy) { close(ftdmchan->sockfd); ftdmchan->sockfd = ZT_INVALID_SOCKET; - return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h index c9bb171b55..9d680668d2 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h @@ -195,7 +195,9 @@ typedef enum { 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 { @@ -258,6 +260,12 @@ ZT_BBIT = 4, 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 @@ -312,6 +320,11 @@ ZT_ABIT = 8 #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 */ @@ -361,6 +374,11 @@ ZT_ABIT = 8 #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: