]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: ftmod_zt - Integrated HW DTMF support
authorMoises Silva <moy@sangoma.com>
Mon, 19 Nov 2012 04:55:54 +0000 (23:55 -0500)
committerMoises Silva <moy@sangoma.com>
Mon, 19 Nov 2012 04:57:52 +0000 (23:57 -0500)
libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c
libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.h

index ac3fcf241720530f1cd77e9d73b503b1112897a6..8d4ee8ab6fe97d6495603c7b268d1b90d5ea8cbd 100644 (file)
@@ -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;
 }
 
index c9bb171b55467d7410eacf20ba94adce4d917ad8..9d680668d2c85b9971cb5e0157524ba9cb9eb0af 100644 (file)
@@ -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: