freetdm: ftmod_zt - Integrated HW DTMF support
This commit is contained in:
parent
c7e8dce247
commit
db673a043f
|
@ -102,6 +102,7 @@ struct ioctl_codes {
|
||||||
ioctlcmd SETTXBITS;
|
ioctlcmd SETTXBITS;
|
||||||
ioctlcmd GETRXBITS;
|
ioctlcmd GETRXBITS;
|
||||||
ioctlcmd SETPOLARITY;
|
ioctlcmd SETPOLARITY;
|
||||||
|
ioctlcmd TONEDETECT;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,7 +140,8 @@ static struct ioctl_codes zt_ioctl_codes = {
|
||||||
.GETCONFMUTE = ZT_GETCONFMUTE,
|
.GETCONFMUTE = ZT_GETCONFMUTE,
|
||||||
.ECHOTRAIN = ZT_ECHOTRAIN,
|
.ECHOTRAIN = ZT_ECHOTRAIN,
|
||||||
.SETTXBITS = ZT_SETTXBITS,
|
.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,
|
.ECHOTRAIN = DAHDI_ECHOTRAIN,
|
||||||
.SETTXBITS = DAHDI_SETTXBITS,
|
.SETTXBITS = DAHDI_SETTXBITS,
|
||||||
.GETRXBITS = DAHDI_GETRXBITS,
|
.GETRXBITS = DAHDI_GETRXBITS,
|
||||||
.SETPOLARITY = DAHDI_SETPOLARITY
|
.SETPOLARITY = DAHDI_SETPOLARITY,
|
||||||
|
.TONEDETECT = DAHDI_TONEDETECT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ZT_INVALID_SOCKET -1
|
#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.sigtype = ZT_SIG_CAS;
|
||||||
cc.idlebits = cas_bits;
|
cc.idlebits = cas_bits;
|
||||||
if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
|
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);
|
close(sockfd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -436,12 +439,23 @@ static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, f
|
||||||
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)) {
|
if (!ftdm_strlen_zero(name)) {
|
||||||
ftdm_copy_string(ftdmchan->chan_name, name, sizeof(ftdmchan->chan_name));
|
ftdm_copy_string(ftdmchan->chan_name, name, sizeof(ftdmchan->chan_name));
|
||||||
}
|
}
|
||||||
if (!ftdm_strlen_zero(number)) {
|
if (!ftdm_strlen_zero(number)) {
|
||||||
ftdm_copy_string(ftdmchan->chan_number, number, sizeof(ftdmchan->chan_number));
|
ftdm_copy_string(ftdmchan->chan_number, number, sizeof(ftdmchan->chan_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
configured++;
|
configured++;
|
||||||
} else {
|
} else {
|
||||||
ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s\n", chanpath);
|
ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s\n", chanpath);
|
||||||
|
@ -666,7 +680,6 @@ static FIO_OPEN_FUNCTION(zt_open)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return FTDM_SUCCESS;
|
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 */
|
and this is only used by some sig modules such as ftmod_r2 to behave bettter under load */
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
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:
|
default:
|
||||||
err = FTDM_NOTIMPL;
|
err = FTDM_NOTIMPL;
|
||||||
break;
|
break;
|
||||||
|
@ -955,7 +980,7 @@ pollagain:
|
||||||
pfds[0].fd = ftdmchan->sockfd;
|
pfds[0].fd = ftdmchan->sockfd;
|
||||||
pfds[0].events = inflags;
|
pfds[0].events = inflags;
|
||||||
result = poll(pfds, 1, to);
|
result = poll(pfds, 1, to);
|
||||||
*flags = 0;
|
*flags = FTDM_NO_FLAGS;
|
||||||
|
|
||||||
if (result < 0 && errno == EINTR) {
|
if (result < 0 && errno == EINTR) {
|
||||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "DAHDI wait got interrupted, trying again\n");
|
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "DAHDI wait got interrupted, trying again\n");
|
||||||
|
@ -971,8 +996,6 @@ pollagain:
|
||||||
inflags = pfds[0].revents;
|
inflags = pfds[0].revents;
|
||||||
}
|
}
|
||||||
|
|
||||||
*flags = FTDM_NO_FLAGS;
|
|
||||||
|
|
||||||
if (result < 0){
|
if (result < 0){
|
||||||
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
|
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));
|
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;
|
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.
|
* \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
|
* \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;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
|
if (handle_dtmf_event(fchan, zt_event_id)) {
|
||||||
*event_id = FTDM_OOB_INVALID;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1314,8 +1358,12 @@ tryagain:
|
||||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
|
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
|
||||||
return FTDM_FAIL;
|
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;
|
goto tryagain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1331,7 +1379,6 @@ static FIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
|
||||||
{
|
{
|
||||||
close(ftdmchan->sockfd);
|
close(ftdmchan->sockfd);
|
||||||
ftdmchan->sockfd = ZT_INVALID_SOCKET;
|
ftdmchan->sockfd = ZT_INVALID_SOCKET;
|
||||||
|
|
||||||
return FTDM_SUCCESS;
|
return FTDM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,9 @@ typedef enum {
|
||||||
ZT_EVENT_TIMER_EXPIRED = 15,
|
ZT_EVENT_TIMER_EXPIRED = 15,
|
||||||
ZT_EVENT_TIMER_PING = 16,
|
ZT_EVENT_TIMER_PING = 16,
|
||||||
ZT_EVENT_POLARITY = 17,
|
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;
|
} zt_event_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -258,6 +260,12 @@ ZT_BBIT = 4,
|
||||||
ZT_ABIT = 8
|
ZT_ABIT = 8
|
||||||
} zt_cas_bit_t;
|
} 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 */
|
/* Defines */
|
||||||
|
|
||||||
#define ZT_MAX_BLOCKSIZE 8192
|
#define ZT_MAX_BLOCKSIZE 8192
|
||||||
|
@ -312,6 +320,11 @@ ZT_ABIT = 8
|
||||||
#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
|
#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
|
||||||
#define ZT_GETRXBITS _IOR (ZT_CODE, 45, 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_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_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_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 */
|
#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
|
#endif
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
|
|
Loading…
Reference in New Issue