Blocked revisions 36725 via svnmerge
[asterisk/asterisk.git] / channels / chan_vpb.c
old mode 100755 (executable)
new mode 100644 (file)
index a65411b..d615e60
@@ -1,11 +1,9 @@
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
- * VoiceTronix Interface driver
- * 
  * Copyright (C) 2003, Paul Bagyenda
  * Paul Bagyenda <bagyenda@dsmagic.com>
- * Copyright (C) 2004, Ben Kramer
+ * Copyright (C) 2004 - 2005, Ben Kramer
  * Ben Kramer <ben@voicetronix.com.au>
  *
  * Daniel Bichara <daniel@bichara.com.br> - Brazilian CallerID detection (c)2004 
  * Welber Silveira - welberms@magiclink.com.br - (c)2004
  * Copying CLID string to propper structure after detection
  *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
  * This program is free software, distributed under the terms of
- * the GNU General Public License
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief VoiceTronix Interface driver
+ * 
+ * \ingroup channel_drivers
  */
 
+/*** MODULEINFO
+       <depend>vpbapi</depend>
+ ***/
 
 extern "C" {
 
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
 #include <stdio.h>
 #include <string.h>
-#include <asterisk/lock.h>
-#include <asterisk/utils.h>
-#include <asterisk/channel.h>
-#include <asterisk/channel_pvt.h>
-#include <asterisk/config.h>
-#include <asterisk/logger.h>
-#include <asterisk/module.h>
-#include <asterisk/pbx.h>
-#include <asterisk/options.h>
-#include <asterisk/callerid.h>
 
+#include "asterisk/lock.h"
+#include "asterisk/utils.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/options.h"
+#include "asterisk/callerid.h"
+#include "asterisk/dsp.h"
+#include "asterisk/features.h"
 }
 
 #include <sys/socket.h>
@@ -63,6 +83,7 @@ extern "C" {
 #define VPB_WAIT_TIMEOUT 4000
 
 #define MAX_VPB_GAIN 12.0
+#define MIN_VPB_GAIN -12.0
 
 #define DTMF_CALLERID  
 #define DTMF_CID_START 'D'
@@ -74,10 +95,9 @@ extern "C" {
 #endif
 /**/
 
-static char *desc = "VoiceTronix V6PCI/V12PCI/V4PCI  API Support";
-static char *type = "vpb";
-static char *tdesc = "Standard VoiceTronix API Driver";
-static char *config = "vpb.conf";
+static const char desc[] = "VoiceTronix V6PCI/V12PCI/V4PCI  API Support";
+static const char tdesc[] = "Standard VoiceTronix API Driver";
+static const char config[] = "vpb.conf";
 
 /* Default context for dialtone mode */
 static char context[AST_MAX_EXTENSION] = "default";
@@ -132,9 +152,14 @@ static VPB_TONE Ringbacktone = {440, 480,   0, -20,   -20, -100,  2000, 4000};
 #endif
 
 /* grunt tone defn's */
+#if 0
 static VPB_DETECT toned_grunt = { 3, VPB_GRUNT, 1, 2000, 3000, 0, 0, -40, 0, 0, 0, 40, { { VPB_DELAY, 1000, 0, 0 }, { VPB_RISING, 0, 40, 0 }, { 0, 100, 0, 0 } } };
+#endif
 static VPB_DETECT toned_ungrunt = { 2, VPB_GRUNT, 1, 2000, 1, 0, 0, -40, 0, 0, 30, 40, { { 0, 0, 0, 0 } } };
 
+/* Use loop polarity detection for CID */
+static int UsePolarityCID=0;
+
 /* Use loop drop detection */
 static int UseLoopDrop=1;
 
@@ -144,8 +169,27 @@ static int UseNativeBridge=1;
 /* Use Asterisk Indication or VPB */
 static int use_ast_ind=0;
 
+/* Use Asterisk DTMF detection or VPB */
+static int use_ast_dtmfdet=0;
+
+static int relaxdtmf=0;
+
+/* Use Asterisk DTMF play back or VPB */
+static int use_ast_dtmf=0;
+
+/* Break for DTMF on native bridge ? */
+static int break_for_dtmf=1;
+
+/* Set EC suppression threshold */
+static int ec_supp_threshold=-1;
+
+/* Inter Digit Delay for collecting DTMF's */
+static int dtmf_idd = 3000;
+
 #define TIMER_PERIOD_RINGBACK 2000
 #define TIMER_PERIOD_BUSY 700
+#define TIMER_PERIOD_RING 4000
+static int timer_period_ring = TIMER_PERIOD_RING;
          
 #define VPB_EVENTS_ALL (VPB_MRING|VPB_MDIGIT|VPB_MDTMF|VPB_MTONEDETECT|VPB_MTIMEREXP|VPB_MPLAY_UNDERFLOW \
                        |VPB_MRECORD_OVERFLOW|VPB_MSTATION_OFFHOOK|VPB_MSTATION_ONHOOK \
@@ -187,6 +231,10 @@ VPB_TONE_MAP DialToneMap[] = {     { VPB_BUSY_AUST, VPB_CALL_DISCONNECT, 0 },
 #define VPB_STATE_PLAYBUSY     6
 #define VPB_STATE_PLAYRING     7
 
+#define VPB_GOT_RXHWG          1
+#define VPB_GOT_TXHWG          2
+#define VPB_GOT_RXSWG          4
+#define VPB_GOT_TXSWG          8
 
 typedef struct  {
        int inuse;
@@ -194,7 +242,7 @@ typedef struct  {
        struct ast_frame **fo;
        int flags;
        ast_mutex_t lock;
-       pthread_cond_t cond;
+       ast_cond_t cond;
        int endbridge;
 } vpb_bridge_t;
 
@@ -222,6 +270,9 @@ static struct vpb_pvt {
        int state;                              /* used to keep port state (internal to driver) */
 
        int group;                              /* Which group this port belongs to */
+       ast_group_t callgroup;                  /* Call group */
+       ast_group_t pickupgroup;                /* Pickup group */
+
 
        char dev[256];                          /* Device name, eg vpb/1-1 */
        vpb_model_t vpb_model;                  /* card model */
@@ -239,6 +290,9 @@ static struct vpb_pvt {
        char ext[AST_MAX_EXTENSION];            /* DTMF buffer for the ext[ens] */
        char language[MAX_LANGUAGE];            /* language being used */
        char callerid[AST_MAX_EXTENSION];       /* CallerId used for directly connected phone */
+       int  callerid_type;                     /* Caller ID type: 0=>none 1=>vpb 2=>AstV23 3=>AstBell */
+       char cid_num[AST_MAX_EXTENSION];
+       char cid_name[AST_MAX_EXTENSION];
 
        int dtmf_caller_pos;                    /* DTMF CallerID detection (Brazil)*/
 
@@ -252,7 +306,15 @@ static struct vpb_pvt {
        void *ringback_timer;                   /* Void pointer for ringback vpb_timer */
        int ringback_timer_id;                  /* unique timer ID for ringback timer */
 
-       double lastgrunt;                       /* time stamp (secs since epoc) of last grunt event */
+       void *ring_timer;                       /* Void pointer for ring vpb_timer */
+       int ring_timer_id;                      /* unique timer ID for ring timer */
+
+       void *dtmfidd_timer;                    /* Void pointer for DTMF IDD vpb_timer */
+       int dtmfidd_timer_id;                   /* unique timer ID for DTMF IDD timer */
+
+       struct ast_dsp *vad;                    /* AST  Voice Activation Detection dsp */
+
+       struct timeval lastgrunt;                       /* time stamp of last grunt event */
 
        ast_mutex_t lock;                       /* This one just protects bridge ptr below */
        vpb_bridge_t *bridge;
@@ -265,10 +327,13 @@ static struct vpb_pvt {
        ast_mutex_t record_lock;                /* This one prevents reentering a record_buf block */
        ast_mutex_t play_lock;                  /* This one prevents reentering a play_buf block */
        int  play_buf_time;                     /* How long the last play_buf took */
+       struct timeval lastplay;                /* Last play time */
 
        ast_mutex_t play_dtmf_lock;
        char play_dtmf[16];
 
+       int faxhandled;                         /* has a fax tone been handled ? */
+
        struct vpb_pvt *next;                   /* Next channel in list */
 
 } *iflist = NULL;
@@ -276,7 +341,76 @@ static struct vpb_pvt {
 static struct ast_channel *vpb_new(struct vpb_pvt *i, int state, char *context);
 static void *do_chanreads(void *pvt);
 
-/* Can't get vpb_bridge() working on v4pci without either a horrible 
+static struct ast_channel *vpb_request(const char *type, int format, void *data, int *cause);
+static int vpb_digit(struct ast_channel *ast, char digit);
+static int vpb_call(struct ast_channel *ast, char *dest, int timeout);
+static int vpb_hangup(struct ast_channel *ast);
+static int vpb_answer(struct ast_channel *ast);
+static struct ast_frame *vpb_read(struct ast_channel *ast);
+static int vpb_write(struct ast_channel *ast, struct ast_frame *frame);
+static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
+static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+
+static struct ast_channel_tech vpb_tech = {
+       type: "vpb",
+       description: tdesc,
+       capabilities: AST_FORMAT_SLINEAR,
+       properties: 0,
+       requester: vpb_request,
+       devicestate: NULL,
+       send_digit: vpb_digit,
+       send_digit_begin: NULL,
+       send_digit_end: NULL,
+       call: vpb_call,
+       hangup: vpb_hangup,
+       answer: vpb_answer,
+       read: vpb_read,
+       write: vpb_write,
+       send_text: NULL,
+       send_image: NULL,
+       send_html: NULL,
+       exception: NULL,
+       bridge: ast_vpb_bridge,
+       indicate: vpb_indicate,
+       fixup: vpb_fixup,
+       setoption: NULL,
+       queryoption: NULL,
+       transfer: NULL,
+       write_video: NULL,
+       bridged_channel: NULL
+};
+
+static struct ast_channel_tech vpb_tech_indicate = {
+       type: "vpb",
+       description: tdesc,
+       capabilities: AST_FORMAT_SLINEAR,
+       properties: 0,
+       requester: vpb_request,
+       devicestate: NULL,
+       send_digit: vpb_digit,
+       send_digit_begin: NULL,
+       send_digit_end: NULL,
+       call: vpb_call,
+       hangup: vpb_hangup,
+       answer: vpb_answer,
+       read: vpb_read,
+       write: vpb_write,
+       send_text: NULL,
+       send_image: NULL,
+       send_html: NULL,
+       exception: NULL,
+       bridge: ast_vpb_bridge,
+       indicate: NULL,
+       fixup: vpb_fixup,
+       setoption: NULL,
+       queryoption: NULL,
+       transfer: NULL,
+       write_video: NULL,
+       bridged_channel: NULL
+};
+
+/* Can't get ast_vpb_bridge() working on v4pci without either a horrible 
 *  high pitched feedback noise or bad hiss noise depending on gain settings
 *  Get asterisk to do the bridging
 */
@@ -288,15 +422,14 @@ static void *do_chanreads(void *pvt);
 /* #define HALF_DUPLEX_BRIDGE */
 
 /* This is the Native bridge code, which Asterisk will try before using its own bridging code */
-static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
+static enum ast_bridge_result ast_vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
-       struct vpb_pvt *p0 = (struct vpb_pvt *)c0->pvt->pvt;
-       struct vpb_pvt *p1 = (struct vpb_pvt *)c1->pvt->pvt;
-       int i, res;
-
+       struct vpb_pvt *p0 = (struct vpb_pvt *)c0->tech_pvt;
+       struct vpb_pvt *p1 = (struct vpb_pvt *)c1->tech_pvt;
+       int i;
+       int res;
        struct ast_channel *cs[3];
        struct ast_channel *who;
-       int to = -1;
        struct ast_frame *f;
 
        cs[0] = c0;
@@ -304,10 +437,10 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
 
        #ifdef BAD_V4PCI_BRIDGE
        if(p0->vpb_model==vpb_model_v4pci)
-               return -2;
+               return AST_BRIDGE_FAILED_NOWARN;
        #endif
        if ( UseNativeBridge != 1){
-               return -2;
+               return AST_BRIDGE_FAILED_NOWARN;
        }
 
 /*
@@ -333,10 +466,10 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
        } ast_mutex_unlock(&bridge_lock); 
 
        if (i == max_bridges) {
-               ast_log(LOG_WARNING, "vpb_bridge: Failed to bridge %s and %s!\n", c0->name, c1->name);
+               ast_log(LOG_WARNING, "%s: vpb_bridge: Failed to bridge %s and %s!\n", p0->dev, c0->name, c1->name);
                ast_mutex_unlock(&p0->lock);
                ast_mutex_unlock(&p1->lock);
-               return -2;
+               return AST_BRIDGE_FAILED_NOWARN;
        } else {
                /* Set bridge pointers. You don't want to take these locks while holding bridge lock.*/
                ast_mutex_lock(&p0->lock); {
@@ -348,13 +481,16 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
                } ast_mutex_unlock(&p1->lock);
 
                if (option_verbose>1) 
-                       ast_verbose(VERBOSE_PREFIX_2 "vpb_bridge: Bridging call entered with [%s, %s]\n", c0->name, c1->name);
+                       ast_verbose(VERBOSE_PREFIX_2 "%s: vpb_bridge: Bridging call entered with [%s, %s]\n",p0->dev, c0->name, c1->name);
        }
 
+       if (option_verbose > 2) 
+               ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
+
        #ifdef HALF_DUPLEX_BRIDGE
 
        if (option_verbose>1) 
-               ast_verbose(VERBOSE_PREFIX_2 "vpb_bridge: Starting half-duplex bridge [%s, %s]\n", c0->name, c1->name);
+               ast_verbose(VERBOSE_PREFIX_2 "%s: vpb_bridge: Starting half-duplex bridge [%s, %s]\n",p0->dev, c0->name, c1->name);
 
        int dir = 0;
 
@@ -387,7 +523,7 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
        vpb_play_buf_finish(p1->handle);
 
        if (option_verbose>1) 
-               ast_verbose(VERBOSE_PREFIX_2 "vpb_bridge: Finished half-duplex bridge [%s, %s]\n", c0->name, c1->name);
+               ast_verbose(VERBOSE_PREFIX_2 "%s: vpb_bridge: Finished half-duplex bridge [%s, %s]\n",p0->dev, c0->name, c1->name);
 
        res = VPB_OK;
 
@@ -398,9 +534,13 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
                /* pthread_cond_wait(&bridges[i].cond, &bridges[i].lock);*/ /* Wait for condition signal. */
                while( !bridges[i].endbridge ) {
                        /* Are we really ment to be doing nothing ?!?! */
-                       who = ast_waitfor_n(cs, 2, &to);
+                       who = ast_waitfor_n(cs, 2, &timeoutms);
                        if (!who) {
-                               ast_log(LOG_DEBUG, "vpb_bridge: Empty frame read...\n");
+                               if (!timeoutms) {
+                                       res = AST_BRIDGE_RETRY;
+                                       break;
+                               }
+                               ast_log(LOG_DEBUG, "%s: vpb_bridge: Empty frame read...\n",p0->dev);
                                /* check for hangup / whentohangup */
                                if (ast_check_hangup(c0) || ast_check_hangup(c1))
                                        break;
@@ -412,20 +552,26 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
                                       ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
                                *fo = f;
                                *rc = who;
-                               ast_log(LOG_DEBUG, "vpb_bridge: Got a [%s]\n", f ? "digit" : "hangup");
+                               ast_log(LOG_DEBUG, "%s: vpb_bridge: Got a [%s]\n",p0->dev, f ? "digit" : "hangup");
 /*
-                               if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
+                               if ((c0->tech_pvt == pvt0) && (!c0->_softhangup)) {
                                        if (pr0->set_rtp_peer(c0, NULL, NULL, 0)) 
                                                ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
                                }
-                               if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
+                               if ((c1->tech_pvt == pvt1) && (!c1->_softhangup)) {
                                        if (pr1->set_rtp_peer(c1, NULL, NULL, 0)) 
                                                ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
                                }
 */
                                /* That's all we needed */
                                /*return 0; */
-                               break;
+                               /* Check if we need to break */
+                               if (break_for_dtmf){
+                                       break;
+                               }
+                               else if ((f->frametype == AST_FRAME_DTMF) && ((f->subclass == '#')||(f->subclass == '*'))){
+                                       break;
+                               }
                        } else {
                                if ((f->frametype == AST_FRAME_DTMF) || 
                                        (f->frametype == AST_FRAME_VOICE) || 
@@ -467,14 +613,7 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
        ast_mutex_unlock(&p0->lock);
        ast_mutex_unlock(&p1->lock);
 */
-       return (res==VPB_OK)?0:-1;
-}
-
-static double get_time_in_ms()
-{
-       struct timeval tv;
-       gettimeofday(&tv, NULL);
-       return ((double)tv.tv_sec*1000)+((double)tv.tv_usec/1000);
+       return (res==VPB_OK) ? AST_BRIDGE_COMPLETE : AST_BRIDGE_FAILED;
 }
 
 /* Caller ID can be located in different positions between the rings depending on your Telco
@@ -482,48 +621,53 @@ static double get_time_in_ms()
  * Use ANALYSE_CID to record rings and determine location of callerid
  */
 /* #define ANALYSE_CID */
-#define RING_SKIP 600
-#define CID_MSECS 1700
+#define RING_SKIP 300
+#define CID_MSECS 2000
 
 static void get_callerid(struct vpb_pvt *p)
 {
        short buf[CID_MSECS*8]; /* 8kHz sampling rate */
-       double cid_record_time;
+       struct timeval cid_record_time;
        int rc;
        struct ast_channel *owner = p->owner;
+/*
+       char callerid[AST_MAX_EXTENSION] = ""; 
+*/
+#ifdef ANALYSE_CID
        void * ws;
        char * file="cidsams.wav";
+#endif
 
 
        if( ast_mutex_trylock(&p->record_lock) == 0 ) {
 
-               char callerid[AST_MAX_EXTENSION] = ""; 
-
-               cid_record_time = get_time_in_ms();
+               cid_record_time = ast_tvnow();
                if (option_verbose>3) 
                        ast_verbose(VERBOSE_PREFIX_4 "CID record - start\n");
 
                /* Skip any trailing ringtone */
-               vpb_sleep(RING_SKIP);
+               if (UsePolarityCID != 1){
+                       vpb_sleep(RING_SKIP);
+               }
 
                if (option_verbose>3) 
-                       ast_verbose(VERBOSE_PREFIX_4 "CID record - skipped %fms trailing ring\n",
-                                get_time_in_ms() - cid_record_time);
-               cid_record_time = get_time_in_ms();
+                       ast_verbose(VERBOSE_PREFIX_4 "CID record - skipped %dms trailing ring\n",
+                                ast_tvdiff_ms(ast_tvnow(), cid_record_time));
+               cid_record_time = ast_tvnow();
 
                /* Record bit between the rings which contains the callerid */
                vpb_record_buf_start(p->handle, VPB_LINEAR);
                rc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
                vpb_record_buf_finish(p->handle);
-/*
+#ifdef ANALYSE_CID
                vpb_wave_open_write(&ws, file, VPB_LINEAR);
                vpb_wave_write(ws,(char*)buf,sizeof(buf));
                vpb_wave_close_write(ws);
-*/
+#endif
 
                if (option_verbose>3) 
-                       ast_verbose(VERBOSE_PREFIX_4 "CID record - recorded %fms between rings\n", 
-                               get_time_in_ms() - cid_record_time);
+                       ast_verbose(VERBOSE_PREFIX_4 "CID record - recorded %dms between rings\n", 
+                                ast_tvdiff_ms(ast_tvnow(), cid_record_time));
 
                ast_mutex_unlock(&p->record_lock);
 
@@ -537,18 +681,30 @@ static void get_callerid(struct vpb_pvt *p)
                cli_struct->ra_cn[0]=0;
                /* This decodes FSK 1200baud type callerid */
                if ((rc=vpb_cid_decode2(cli_struct, buf, CID_MSECS*8)) == VPB_OK ) {
+                       /*
                        if (owner->cid.cid_num)
                                free(owner->cid.cid_num);
                        owner->cid.cid_num=NULL;
                        if (owner->cid.cid_name)
                                free(owner->cid.cid_name);
                        owner->cid.cid_name=NULL;
+                       */
                        
                        if (cli_struct->ra_cldn[0]=='\0'){
+                               /*
                                owner->cid.cid_num = strdup(cli_struct->cldn);
                                owner->cid.cid_name = strdup(cli_struct->cn);
+                               */
+                               if (owner){
+                                       ast_set_callerid(owner, cli_struct->cldn, cli_struct->cn, cli_struct->cldn);
+                               } else {
+                                       strcpy(p->cid_num, cli_struct->cldn);
+                                       strcpy(p->cid_name, cli_struct->cn);
+
+                               }
                                if (option_verbose>3) 
                                        ast_verbose(VERBOSE_PREFIX_4 "CID record - got [%s] [%s]\n",owner->cid.cid_num,owner->cid.cid_name );
+                               snprintf(p->callerid,sizeof(p->callerid)-1,"%s %s",cli_struct->cldn,cli_struct->cn);
                        }
                        else {
                                ast_log(LOG_ERROR,"CID record - No caller id avalable on %s \n", p->dev);
@@ -556,13 +712,14 @@ static void get_callerid(struct vpb_pvt *p)
 
                } else {
                        ast_log(LOG_ERROR, "CID record - Failed to decode caller id on %s - %s\n", p->dev, vpb_strerror(rc) );
-                       strncpy(callerid,"unknown", sizeof(callerid) - 1);
+                       strncpy(p->callerid,"unknown", sizeof(p->callerid) - 1);
                }
                delete cli_struct;
 
        } else 
                ast_log(LOG_ERROR, "CID record - Failed to set record mode for caller id on %s\n", p->dev );
 }
+
 static void get_callerid_ast(struct vpb_pvt *p)
 {
        struct callerid_state *cs;
@@ -572,48 +729,57 @@ static void get_callerid_ast(struct vpb_pvt *p)
        int rc=0,vrc;
        int sam_count=0;
        struct ast_channel *owner = p->owner;
-       float old_gain;
        int which_cid;
+/*
+       float old_gain;
+*/
+#ifdef ANALYSE_CID
        void * ws;
        char * file="cidsams.wav";
+#endif
 
-       if(!strcasecmp(p->callerid, "on")) {
+       if(p->callerid_type == 1) {
        if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collected caller ID already\n");
                return;
        }
-       else if(!strcasecmp(p->callerid, "v23")) {
+       else if(p->callerid_type == 2 ) {
                which_cid=CID_SIG_V23;
-       if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID v23[%s/%d]...\n",p->callerid,which_cid);
+       if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID v23...\n");
        }
-       else if(!strcasecmp(p->callerid, "bell")) {
+       else if(p->callerid_type == 3) {
                which_cid=CID_SIG_BELL;
-       if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID bell[%s/%d]...\n",p->callerid,which_cid);
+       if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID bell...\n");
        }
        else {
                if (option_verbose>3) 
                        ast_verbose(VERBOSE_PREFIX_4 "Caller ID disabled\n");
                return;
        }
-       if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID type[%s/%d]...\n",p->callerid,which_cid);
 /*     vpb_sleep(RING_SKIP); */
 /*     vpb_record_get_gain(p->handle, &old_gain); */
        cs = callerid_new(which_cid);
        if (cs){
-/*             vpb_wave_open_write(&ws, file, VPB_MULAW); */
-/*             vpb_record_set_gain(p->handle, 3.0); */
-/*             vpb_record_set_hw_gain(p->handle,12.0); */
+#ifdef ANALYSE_CID
+               vpb_wave_open_write(&ws, file, VPB_MULAW); 
+               vpb_record_set_gain(p->handle, 3.0); 
+               vpb_record_set_hw_gain(p->handle,12.0); 
+#endif
                vpb_record_buf_start(p->handle, VPB_MULAW);
                while((rc == 0)&&(sam_count<8000*3)){
                        vrc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf));
                        if (vrc != VPB_OK)
                                ast_log(LOG_ERROR, "%s: Caller ID couldnt read audio buffer!\n",p->dev);
                        rc = callerid_feed(cs,(unsigned char *)buf,sizeof(buf),AST_FORMAT_ULAW);
-/*                     vpb_wave_write(ws,(char*)buf,sizeof(buf)); */
+#ifdef ANALYSE_CID
+                       vpb_wave_write(ws,(char*)buf,sizeof(buf)); 
+#endif
                        sam_count+=sizeof(buf);
                        if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collecting Caller ID samples [%d][%d]...\n",sam_count,rc);
                }
                vpb_record_buf_finish(p->handle);
-/*             vpb_wave_close_write(ws); */
+#ifdef ANALYSE_CID
+               vpb_wave_close_write(ws); 
+#endif
                if (rc == 1){
                        callerid_get(cs, &name, &number, &flags);
                        if (option_verbose>0) 
@@ -638,13 +804,14 @@ static void get_callerid_ast(struct vpb_pvt *p)
        }
        if (number)
                ast_shrink_phone_number(number);
-       if (number && !ast_strlen_zero(number)) {
-               owner->cid.cid_num = strdup(number);
-               owner->cid.cid_ani = strdup(number);
+       ast_set_callerid(owner,
+               number, name,
+               owner->cid.cid_ani ? NULL : number);
+       if (!ast_strlen_zero(name)){
+               snprintf(p->callerid,(sizeof(p->callerid)-1),"%s %s",number,name);
+       } else {
+               snprintf(p->callerid,(sizeof(p->callerid)-1),"%s",number);
        }
-       if (name && !ast_strlen_zero(name))
-               owner->cid.cid_name = strdup(name);
-                                                                                                                    
        if (cs)
                callerid_free(cs);
 }
@@ -685,14 +852,15 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
        int res=0;
 
        if (option_verbose > 3) 
-               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_owned: got event: [%d=>%d]\n",
-                       p->dev, e->type, e->data);
+               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_owned: got event: [%d=>%d]\n", p->dev, e->type, e->data);
 
-       f.src = type;
+       f.src = "vpb";
        switch (e->type) {
                case VPB_RING:
                        if (p->mode == MODE_FXO) {
                                f.subclass = AST_CONTROL_RING;
+                               vpb_timer_stop(p->ring_timer);
+                               vpb_timer_start(p->ring_timer);
                        } else
                                f.frametype = -1; /* ignore ring on station port. */
                        break;
@@ -713,13 +881,27 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                vpb_timer_stop(p->ringback_timer);
                                vpb_timer_start(p->ringback_timer);
                                f.frametype = -1;
+                       } else if (e->data == p->ring_timer_id) {
+                               /* We didnt get another ring in time! */
+                               if (p->owner->_state != AST_STATE_UP)  {
+                                        /* Assume caller has hung up */
+                                       vpb_timer_stop(p->ring_timer);
+                                       f.subclass = AST_CONTROL_HANGUP;
+                               } else {
+                                       vpb_timer_stop(p->ring_timer);
+                                       f.frametype = -1;
+                               }
+                               
                        } else {
                                f.frametype = -1; /* Ignore. */
                        }
                        break;
 
+               case VPB_DTMF_DOWN:
                case VPB_DTMF:
-                       if (p->owner->_state == AST_STATE_UP) {
+                       if (use_ast_dtmfdet){
+                               f.frametype = -1;
+                       } else if (p->owner->_state == AST_STATE_UP) {
                                        f.frametype = AST_FRAME_DTMF;
                                        f.subclass = e->data;
                        } else
@@ -736,8 +918,29 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                else {
                                        f.subclass = AST_CONTROL_BUSY;
                                }
-                       } else if (e->data == VPB_GRUNT) {
-                               if( ( get_time_in_ms() - p->lastgrunt ) > gruntdetect_timeout ) {
+                       } 
+                       else if (e->data == VPB_FAX){
+                               if (!p->faxhandled){
+                                       if (strcmp(p->owner->exten, "fax")) {
+                                               const char *target_context = S_OR(p->owner->macrocontext, p->owner->context);
+                                               
+                                               if (ast_exists_extension(p->owner, target_context, "fax", 1, p->owner->cid.cid_num)) {
+                                                       if (option_verbose > 2)
+                                                               ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", p->owner->name);
+                                                       /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+                                                       pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
+                                                       if (ast_async_goto(p->owner, target_context, "fax", 1))
+                                                               ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, target_context);
+                                               } else
+                                                       ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+                                       } else
+                                               ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
+                               } else
+                                       ast_log(LOG_DEBUG, "Fax already handled\n");
+
+                       } 
+                       else if (e->data == VPB_GRUNT) {
+                               if ( ast_tvdiff_ms(ast_tvnow(), p->lastgrunt) > gruntdetect_timeout ) {
                                        /* Nothing heard on line for a very long time
                                         * Timeout connection */
                                        if (option_verbose > 2) 
@@ -745,11 +948,13 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                        ast_log(LOG_NOTICE,"%s: Line hangup due of lack of conversation\n",p->dev); 
                                        f.subclass = AST_CONTROL_HANGUP;
                                } else {
-                                       p->lastgrunt = get_time_in_ms();
+                                       p->lastgrunt = ast_tvnow();
                                        f.frametype = -1;
                                }
-                       } else
+                       } 
+                       else {
                                f.frametype = -1;
+                       }
                        break;
 
                case VPB_CALLEND:
@@ -780,6 +985,12 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                                        f.frametype = -1;
                        }
                        break;
+               case VPB_LOOP_ONHOOK:
+                       if (p->owner->_state == AST_STATE_UP)
+                               f.subclass = AST_CONTROL_HANGUP;
+                       else
+                               f.frametype = -1;
+                       break;
                case VPB_STATION_ONHOOK:
                        f.subclass = AST_CONTROL_HANGUP;
                        break;
@@ -855,7 +1066,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
 
                                ast_mutex_lock(&p->bridge->lock); {
                                        p->bridge->endbridge = 1;
-                                       pthread_cond_signal(&p->bridge->cond);
+                                       ast_cond_signal(&p->bridge->cond);
                                } ast_mutex_unlock(&p->bridge->lock);                      
                        }         
                }
@@ -900,6 +1111,11 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
 {
        char s[2] = {0};
        struct ast_channel *owner = p->owner;
+       char cid_num[256];
+       char cid_name[256];
+/*
+       struct ast_channel *c;
+*/
 
        if (option_verbose > 3) {
                char str[VPB_MAX_STR];
@@ -909,15 +1125,39 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
        }
 
        switch(e->type) {
+               case VPB_LOOP_ONHOOK:
+               case VPB_LOOP_POLARITY:
+                       if (UsePolarityCID == 1){
+                               if (option_verbose>3)
+                                       ast_verbose(VERBOSE_PREFIX_4 "Polarity reversal\n");
+                               if(p->callerid_type == 1) {
+                                       if (option_verbose>3)
+                                               ast_verbose(VERBOSE_PREFIX_4 "Using VPB Caller ID\n");
+                                       get_callerid(p);        /* UK CID before 1st ring*/
+                               }
+/*                             get_callerid_ast(p); */   /* Caller ID using the ast functions */
+                       }
+                       break;
                case VPB_RING:
                        if (p->mode == MODE_FXO) /* FXO port ring, start * */ {
                                vpb_new(p, AST_STATE_RING, p->context);
-                               if(!strcasecmp(p->callerid, "on")) {
-                                       if (option_verbose>3) 
-                                               ast_verbose(VERBOSE_PREFIX_4 "Using VPB Caller ID\n");
-                                       get_callerid(p);        /* Australian Caller ID only between 1st and 2nd ring  */
+                               if (UsePolarityCID != 1){
+                                       if(p->callerid_type == 1) {
+                                               if (option_verbose>3)
+                                                       ast_verbose(VERBOSE_PREFIX_4 "Using VPB Caller ID\n");
+                                               get_callerid(p);        /* Australian CID only between 1st and 2nd ring  */
+                                       }
+                                       get_callerid_ast(p);    /* Caller ID using the ast functions */
                                }
-                               get_callerid_ast(p);    /* Caller ID using the ast functions */
+                               else {
+                                       ast_log(LOG_ERROR, "Setting caller ID: %s %s\n",p->cid_num, p->cid_name);
+                                       ast_set_callerid(p->owner, p->cid_num, p->cid_name, p->cid_num);
+                                       p->cid_num[0]=0;
+                                       p->cid_name[0]=0;
+                               }
+
+                               vpb_timer_stop(p->ring_timer);
+                               vpb_timer_start(p->ring_timer);
                        }
                        break;
 
@@ -966,6 +1206,27 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
                        p->ext[0] = 0;
                        p->state=VPB_STATE_ONHOOK;
                        break;
+               case VPB_TIMEREXP:
+                       if (e->data == p->dtmfidd_timer_id) {
+                               if (ast_exists_extension(NULL, p->context, p->ext, 1, p->callerid)){
+                                       if (option_verbose > 3)
+                                               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: DTMF IDD timer out, matching on [%s] in [%s]\n", p->dev,p->ext , p->context);
+
+                                       vpb_new(p,AST_STATE_RING, p->context);
+                               }
+                       } else if (e->data == p->ring_timer_id) {
+                               /* We didnt get another ring in time! */
+                               if (p->owner){
+                                       if (p->owner->_state != AST_STATE_UP)  {
+                                                /* Assume caller has hung up */
+                                               vpb_timer_stop(p->ring_timer);
+                                       }
+                               } else {
+                                        /* No owner any more, Assume caller has hung up */
+                                       vpb_timer_stop(p->ring_timer);
+                               }
+                       } 
+                       break;
 
                case VPB_DTMF:
                        if (p->state == VPB_STATE_ONHOOK){
@@ -979,13 +1240,26 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
                                                p->callerid[p->dtmf_caller_pos] = '\0';
                                                if (option_verbose > 2)
                                                        ast_verbose(VERBOSE_PREFIX_3 " %s: DTMF CallerID %s\n",p->dev,p->callerid);
-                                               if (owner->cid.cid_num)
-                                                       free(owner->cid.cid_num);
-                                               owner->cid.cid_num=NULL;
-                                               if (owner->cid.cid_name)
-                                                       free(owner->cid.cid_name);
-                                               owner->cid.cid_name=NULL;
-                                               owner->cid.cid_num = strdup(p->callerid);
+                                               if (owner){
+                                                       /*
+                                                       if (owner->cid.cid_num)
+                                                               free(owner->cid.cid_num);
+                                                       owner->cid.cid_num=NULL;
+                                                       if (owner->cid.cid_name)
+                                                               free(owner->cid.cid_name);
+                                                       owner->cid.cid_name=NULL;
+                                                       owner->cid.cid_num = strdup(p->callerid);
+                                                       */
+                                                       cid_name[0] = '\0';
+                                                       cid_num[0] = '\0';
+                                                       ast_callerid_split(p->callerid, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
+                                                       ast_set_callerid(owner, cid_num, cid_name, cid_num);
+
+                                               }
+                                               else {
+                                                       if (option_verbose > 2)
+                                                               ast_verbose(VERBOSE_PREFIX_3 " %s: DTMF CallerID: no owner to assign CID \n",p->dev);
+                                               }
                                        } else if ( p->dtmf_caller_pos < AST_MAX_EXTENSION ) {
                                                if ( p->dtmf_caller_pos >= 0 )
                                                        p->callerid[p->dtmf_caller_pos] = e->data;
@@ -1001,18 +1275,34 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
                        p->state=VPB_STATE_GETDTMF;
                        s[0] = e->data;
                        strncat(p->ext, s, sizeof(p->ext) - strlen(p->ext) - 1);
+                       #if 0
+                       if (!strcmp(p->ext,ast_pickup_ext())) {
+                               /* Call pickup has been dialled! */
+                               if (ast_pickup_call(c)) {
+                                       /* Call pickup wasnt possible */
+                               }
+                       }
+                       else 
+                       #endif
                        if (ast_exists_extension(NULL, p->context, p->ext, 1, p->callerid)){
-                               if (option_verbose > 3) {
-                                       ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: Matched on [%s] in [%s]\n", p->dev,p->ext , p->context);
+                               if ( ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)){
+                                       if (option_verbose > 3)
+                                               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: Multiple matches on [%s] in [%s]\n", p->dev,p->ext , p->context);
+                                       /* Start DTMF IDD timer */
+                                       vpb_timer_stop(p->dtmfidd_timer);
+                                       vpb_timer_start(p->dtmfidd_timer);
+                               }
+                               else {
+                                       if (option_verbose > 3)
+                                               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: Matched on [%s] in [%s]\n", p->dev,p->ext , p->context);
+                                       vpb_new(p,AST_STATE_UP, p->context);
                                }
-                               vpb_new(p,AST_STATE_RING, p->context);
                        } else if (!ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)){
                                if (ast_exists_extension(NULL, "default", p->ext, 1, p->callerid)) {
-                                       vpb_new(p,AST_STATE_RING, "default");         
+                                       vpb_new(p,AST_STATE_UP, "default");           
                                } else if (!ast_canmatch_extension(NULL, "default", p->ext, 1, p->callerid)) {
                                        if (option_verbose > 3) {
-                                               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: can't match anything in %s or default\n",
-                                                        p->dev, p->context);
+                                               ast_verbose(VERBOSE_PREFIX_4 "%s: handle_notowned: can't match anything in %s or default\n", p->dev, p->context);
                                        }
                                        playtone(p->handle, &Busytone);
                                        vpb_timer_stop(p->busy_timer);
@@ -1220,7 +1510,7 @@ static void mkbrd(vpb_model_t model, int echo_cancel)
                        memset(bridges,0,max_bridges * sizeof(vpb_bridge_t));
                        for(int i = 0; i < max_bridges; i++ ) {
                                ast_mutex_init(&bridges[i].lock);
-                               pthread_cond_init(&bridges[i].cond, NULL);
+                               ast_cond_init(&bridges[i].cond, NULL);
                        }
                }
        }
@@ -1236,6 +1526,14 @@ static void mkbrd(vpb_model_t model, int echo_cancel)
                if (model==vpb_model_v4pci) {
                        vpb_echo_canc_enable();
                        ast_log(LOG_NOTICE, "Voicetronix echo cancellation ON\n");
+                       if (ec_supp_threshold > -1){
+                               #ifdef VPB_PRI
+                               vpb_echo_canc_set_sup_thresh(0,(short *)&ec_supp_threshold);
+                               #else
+                               vpb_echo_canc_set_sup_thresh((short *)&ec_supp_threshold);
+                               #endif
+                               ast_log(LOG_NOTICE, "Voicetronix EC Sup Thres set\n");
+                       }
                }
                else {
                /* need to it port by port for OpenSwitch*/
@@ -1243,9 +1541,9 @@ static void mkbrd(vpb_model_t model, int echo_cancel)
        }
 }
 
-struct vpb_pvt *mkif(int board, int channel, int mode, float txgain, float rxgain,
+static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float txgain, float rxgain,
                         float txswgain, float rxswgain, int bal1, int bal2, int bal3,
-                        char * callerid, int echo_cancel, int group )
+                        char * callerid, int echo_cancel, int group, ast_group_t callgroup, ast_group_t pickupgroup )
 {
        struct vpb_pvt *tmp;
        char buf[64];
@@ -1269,14 +1567,32 @@ struct vpb_pvt *mkif(int board, int channel, int mode, float txgain, float rxgai
        tmp->mode = mode;
 
        tmp->group = group;
+       tmp->callgroup = callgroup;
+       tmp->pickupgroup = pickupgroup;
 
+       /* Initilize dtmf caller ID position variable */
+       tmp->dtmf_caller_pos=0;
 
        strncpy(tmp->language, language, sizeof(tmp->language) - 1);
        strncpy(tmp->context, context, sizeof(tmp->context) - 1);
 
+       tmp->callerid_type=0;
        if(callerid) { 
-               strncpy(tmp->callerid, callerid, sizeof(tmp->callerid) - 1);
-               free(callerid);
+               if (strcasecmp(callerid,"on")==0){
+                       tmp->callerid_type =1;
+                       strncpy(tmp->callerid, "unknown", sizeof(tmp->callerid) - 1);
+               }
+               else if (strcasecmp(callerid,"v23")==0){
+                       tmp->callerid_type =2;
+                       strncpy(tmp->callerid, "unknown", sizeof(tmp->callerid) - 1);
+               }
+               else if (strcasecmp(callerid,"bell")==0){
+                       tmp->callerid_type =3;
+                       strncpy(tmp->callerid, "unknown", sizeof(tmp->callerid) - 1);
+               }
+               else {
+                       strncpy(tmp->callerid, callerid, sizeof(tmp->callerid) - 1);
+               }
        } else {
                strncpy(tmp->callerid, "unknown", sizeof(tmp->callerid) - 1);
        }
@@ -1289,17 +1605,46 @@ struct vpb_pvt *mkif(int board, int channel, int mode, float txgain, float rxgai
        if(bal1>=0) vpb_set_codec_reg(tmp->handle, 0x32, bal1);
        if(bal2>=0) vpb_set_codec_reg(tmp->handle, 0x3a, bal2);
 
-       tmp->txgain = txgain;
-       vpb_play_set_hw_gain(tmp->handle, (txgain > MAX_VPB_GAIN) ? MAX_VPB_GAIN : txgain);
+       if (gains & VPB_GOT_TXHWG){
+               if (txgain > MAX_VPB_GAIN){
+                       tmp->txgain = MAX_VPB_GAIN;
+               }
+               else if (txgain < MIN_VPB_GAIN){
+                       tmp->txgain = MIN_VPB_GAIN;
+               }
+               else {
+                       tmp->txgain = txgain;
+               }
+               
+               ast_log(LOG_NOTICE,"VPB setting Tx Hw gain to [%f]\n",tmp->txgain);
+               vpb_play_set_hw_gain(tmp->handle, tmp->txgain);
+       }
 
-       tmp->rxgain = rxgain;
-       vpb_record_set_hw_gain(tmp->handle, (rxgain > MAX_VPB_GAIN) ? MAX_VPB_GAIN : rxgain);
+       if (gains & VPB_GOT_RXHWG){
+               if (rxgain > MAX_VPB_GAIN){
+                       tmp->rxgain = MAX_VPB_GAIN;
+               }
+               else if (rxgain < MIN_VPB_GAIN){
+                       tmp->rxgain = MIN_VPB_GAIN;
+               }
+               else {
+                       tmp->rxgain = rxgain;
+               }
+               ast_log(LOG_NOTICE,"VPB setting Rx Hw gain to [%f]\n",tmp->rxgain);
+               vpb_record_set_hw_gain(tmp->handle,tmp->rxgain);
+       }
 
-       tmp->txswgain = txswgain;
-       vpb_play_set_gain(tmp->handle, (txswgain > MAX_VPB_GAIN) ? MAX_VPB_GAIN : txswgain);
+       if (gains & VPB_GOT_TXSWG){
+               tmp->txswgain = txswgain;
+               ast_log(LOG_NOTICE,"VPB setting Tx Sw gain to [%f]\n",tmp->txswgain);
+               vpb_play_set_gain(tmp->handle, tmp->txswgain);
+       }
 
-       tmp->rxswgain = rxswgain;
-       vpb_record_set_gain(tmp->handle, (rxswgain > MAX_VPB_GAIN) ? MAX_VPB_GAIN : rxswgain);
+       if (gains & VPB_GOT_RXSWG){
+               tmp->rxswgain = rxswgain;
+               ast_log(LOG_NOTICE,"VPB setting Rx Sw gain to [%f]\n",tmp->rxswgain);
+               vpb_record_set_gain(tmp->handle, tmp->rxswgain);
+       }
 
        tmp->vpb_model = vpb_model_unknown;
        if( vpb_get_model(buf) == VPB_OK ) {
@@ -1325,35 +1670,64 @@ struct vpb_pvt *mkif(int board, int channel, int mode, float txgain, float rxgai
 
        tmp->ringback_timer_id = vpb_timer_get_unique_timer_id();
        vpb_timer_open(&tmp->ringback_timer, tmp->handle, tmp->ringback_timer_id, TIMER_PERIOD_RINGBACK);
+
+       tmp->ring_timer_id = vpb_timer_get_unique_timer_id();
+       vpb_timer_open(&tmp->ring_timer, tmp->handle, tmp->ring_timer_id, timer_period_ring);
+             
+       tmp->dtmfidd_timer_id = vpb_timer_get_unique_timer_id();
+       vpb_timer_open(&tmp->dtmfidd_timer, tmp->handle, tmp->dtmfidd_timer_id, dtmf_idd);
              
        if (mode == MODE_FXO){
-               vpb_set_event_mask(tmp->handle, VPB_EVENTS_ALL );
+               if (use_ast_dtmfdet)
+                       vpb_set_event_mask(tmp->handle, VPB_EVENTS_NODTMF );
+               else
+                       vpb_set_event_mask(tmp->handle, VPB_EVENTS_ALL );
        }
        else {
-               vpb_set_event_mask(tmp->handle, VPB_EVENTS_STAT );
+/*
+               if (use_ast_dtmfdet)
+                       vpb_set_event_mask(tmp->handle, VPB_EVENTS_NODTMF );
+               else
+*/
+                       vpb_set_event_mask(tmp->handle, VPB_EVENTS_STAT );
        }
 
        if ((tmp->vpb_model == vpb_model_v12pci) && (echo_cancel)){
                vpb_hostecho_on(tmp->handle);
        }
+       if (use_ast_dtmfdet) {
+               tmp->vad = ast_dsp_new();
+               ast_dsp_set_features(tmp->vad, DSP_FEATURE_DTMF_DETECT);
+               ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF);
+               if (relaxdtmf)
+                       ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF|DSP_DIGITMODE_RELAXDTMF);
+       }
+       else {
+               tmp->vad = NULL;
+       }
 
        /* define grunt tone */
        vpb_settonedet(tmp->handle,&toned_ungrunt);
 
-       ast_log(LOG_NOTICE,"Voicetronix %s channel %s initialized (rxgain=%f txgain=%f) (%f/%f/0x%X/0x%X/0x%X)\n",
-               (tmp->vpb_model==vpb_model_v4pci)?"V4PCI":
-               (tmp->vpb_model==vpb_model_v12pci)?"V12PCI":"[Unknown model]",
+       ast_log(LOG_NOTICE,"Voicetronix %s channel %s initialized (rxsg=%f/txsg=%f/rxhg=%f/txhg=%f)(0x%x/0x%x/0x%x)\n",
+               (tmp->vpb_model==vpb_model_v4pci)?"V4PCI": (tmp->vpb_model==vpb_model_v12pci)?"V12PCI":"[Unknown model]",
                tmp->dev, tmp->rxswgain, tmp->txswgain, tmp->rxgain, tmp->txgain, bal1, bal2, bal3 );
 
        return tmp;
 }
 
-static int vpb_indicate(struct ast_channel *ast, int condition)
+static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt;
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
        int res = 0;
        int tmp = 0;
 
+       if (use_ast_ind == 1) {
+               if (option_verbose > 3)
+                       ast_verbose(VERBOSE_PREFIX_4 "%s: vpb_indicate called when using Ast Indications !?!\n", p->dev);
+               return 0;
+       }
+
        if (option_verbose > 3)
                ast_verbose(VERBOSE_PREFIX_4 "%s: vpb_indicate [%d] state[%d]\n", p->dev, condition,ast->_state);
 /*
@@ -1417,7 +1791,7 @@ static int vpb_indicate(struct ast_channel *ast, int condition)
 
 static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)newchan->pvt->pvt;
+       struct vpb_pvt *p = (struct vpb_pvt *)newchan->tech_pvt;
        int res = 0;
 
 /*
@@ -1432,10 +1806,16 @@ static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
        }
 
        if (newchan->_state == AST_STATE_RINGING){
-               if (use_ast_ind == 1)
+               if (use_ast_ind == 1) {
+                       if (option_verbose > 3)
+                               ast_verbose(VERBOSE_PREFIX_4 "%s: vpb_fixup Calling ast_indicate\n", p->dev);
                        ast_indicate(newchan, AST_CONTROL_RINGING);
-               else
-                       vpb_indicate(newchan, AST_CONTROL_RINGING);
+               }
+               else {
+                       if (option_verbose > 3)
+                               ast_verbose(VERBOSE_PREFIX_4 "%s: vpb_fixup Calling vpb_indicate\n", p->dev);
+                       vpb_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
+               }
        }
 
        res= ast_mutex_unlock(&p->lock);
@@ -1447,10 +1827,16 @@ static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 
 static int vpb_digit(struct ast_channel *ast, char digit)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt;
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
        char s[2];
        int res = 0;
 
+       if (use_ast_dtmf){
+               if (option_verbose > 3)
+                       ast_verbose(VERBOSE_PREFIX_4 "%s: vpb_digit: asked to play digit[%c] but we are using asterisk dtmf play back?!\n", p->dev, digit);
+               return 0;
+       }
+
 /*
        if (option_verbose > 3) ast_verbose("%s: LOCKING in digit \n", p->dev);
        if (option_verbose > 3) ast_verbose("%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
@@ -1462,7 +1848,7 @@ static int vpb_digit(struct ast_channel *ast, char digit)
        s[1] = '\0';
 
        if (option_verbose > 3)
-               ast_verbose(VERBOSE_PREFIX_4 "%s: play digit[%s]\n", p->dev, s);
+               ast_verbose(VERBOSE_PREFIX_4 "%s: vpb_digit: asked to play digit[%s]\n", p->dev, s);
 
        ast_mutex_lock(&p->play_dtmf_lock);
        strncat(p->play_dtmf,s,sizeof(*p->play_dtmf));
@@ -1478,7 +1864,7 @@ static int vpb_digit(struct ast_channel *ast, char digit)
 /* Places a call out of a VPB channel */
 static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt;
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
        int res = 0,i;
        char *s = strrchr(dest, '/');
        char dialstring[254] = "";
@@ -1489,6 +1875,8 @@ static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
        if (option_verbose > 3) ast_verbose("%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
 */
        ast_mutex_lock(&p->lock);
+       if (option_verbose > 3)
+               ast_verbose(VERBOSE_PREFIX_4 "%s: starting call to [%s]\n", p->dev,dest);
 
        if (s)
                s = s + 1;
@@ -1501,8 +1889,6 @@ static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
                else if ((dialstring[i] == 'f') || (dialstring[i] == 'F'))
                        dialstring[i] = '&';
        }       
-       if (option_verbose > 3)
-               ast_verbose(VERBOSE_PREFIX_4 "%s: starting call\n", p->dev);
 
        if (ast->_state != AST_STATE_DOWN && ast->_state != AST_STATE_RESERVED) {
                ast_log(LOG_WARNING, "vpb_call on %s neither down nor reserved!\n", ast->name);
@@ -1546,7 +1932,7 @@ static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
                                        ast->name, call.tone_map[j].tone_id, call.tone_map[j].call_id); 
                }
 
-               if (option_verbose > 4)
+               if (option_verbose > 3)
                                ast_verbose("%s: Disabling Loop Drop detection\n",p->dev);
                vpb_disable_event(p->handle, VPB_MDROP);
                vpb_sethook_sync(p->handle,VPB_OFFHOOK);
@@ -1554,13 +1940,13 @@ static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
 
                #ifndef DIAL_WITH_CALL_PROGRESS
                vpb_sleep(300);
-               if (option_verbose > 4)
-                               ast_verbose("%s: Disabling Loop Drop detection\n",p->dev);
+               if (option_verbose > 3)
+                               ast_verbose("%s: Enabling Loop Drop detection\n",p->dev);
                vpb_enable_event(p->handle, VPB_MDROP);
                res = vpb_dial_async(p->handle, dialstring);
                #else
-               if (option_verbose > 4)
-                               ast_verbose("%s: Disabling Loop Drop detection\n",p->dev);
+               if (option_verbose > 3)
+                               ast_verbose("%s: Enabling Loop Drop detection\n",p->dev);
                vpb_enable_event(p->handle, VPB_MDROP);
                res = vpb_call_async(p->handle, dialstring);
                #endif
@@ -1592,7 +1978,7 @@ static int vpb_call(struct ast_channel *ast, char *dest, int timeout)
 
 static int vpb_hangup(struct ast_channel *ast)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt;
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
        VPB_EVENT je;
        char str[VPB_MAX_STR];
        int res =0 ;
@@ -1606,12 +1992,17 @@ static int vpb_hangup(struct ast_channel *ast)
        if (option_verbose > 1) 
                ast_verbose(VERBOSE_PREFIX_2 "%s: Hangup requested\n", ast->name);
 
-       if (!ast->pvt || !ast->pvt->pvt) {
+       if (!ast->tech || !ast->tech_pvt) {
                ast_log(LOG_WARNING, "%s: channel not connected?\n", ast->name);
                res = ast_mutex_unlock(&p->lock);
 /*
                if (option_verbose > 3) ast_verbose("%s: unLOCKING in hangup [%d]\n", p->dev,res);
 */
+               /* Free up ast dsp if we have one */
+               if ((use_ast_dtmfdet)&&(p->vad)) {
+                       ast_dsp_free(p->vad);
+                       p->vad = NULL;
+               }
                return 0;
        }
 
@@ -1622,13 +2013,13 @@ static int vpb_hangup(struct ast_channel *ast)
        if( p->readthread ){
                pthread_join(p->readthread, NULL); 
                if(option_verbose>3) 
-                       ast_verbose( VERBOSE_PREFIX_4 "%s: stopped record thread on %s\n",ast->name,p->dev);
+                       ast_verbose( VERBOSE_PREFIX_4 "%s: stopped record thread \n",ast->name);
        }
 
        /* Stop play */
        if (p->lastoutput != -1) {
                if(option_verbose>1) 
-                       ast_verbose( VERBOSE_PREFIX_2 "%s: Ending play mode on %s\n",ast->name,p->dev);
+                       ast_verbose( VERBOSE_PREFIX_2 "%s: Ending play mode \n",ast->name);
                vpb_play_terminate(p->handle);
                ast_mutex_lock(&p->play_lock); {
                        vpb_play_buf_finish(p->handle);
@@ -1647,7 +2038,7 @@ static int vpb_hangup(struct ast_channel *ast)
 */
        ast_mutex_lock(&p->lock);
 
-       if (p->mode != MODE_FXO) { 
+       if (p->mode != MODE_FXO) {
                /* station port. */
                vpb_ring_station_async(p->handle, VPB_RING_STATION_OFF,0);      
                if(p->state!=VPB_STATE_ONHOOK){
@@ -1662,6 +2053,11 @@ static int vpb_hangup(struct ast_channel *ast)
                else {
                        stoptone(p->handle);
                }
+               #ifdef VPB_PRI
+               vpb_setloop_async(p->handle, VPB_OFFHOOK);
+               vpb_sleep(100);
+               vpb_setloop_async(p->handle, VPB_ONHOOK);
+               #endif
        } else {
                stoptone(p->handle); /* Terminates any dialing */
                vpb_sethook_sync(p->handle, VPB_ONHOOK);
@@ -1682,7 +2078,13 @@ static int vpb_hangup(struct ast_channel *ast)
        p->dialtone = 0;
 
        p->owner = NULL;
-       ast->pvt->pvt=NULL;
+       ast->tech_pvt=NULL;
+
+       /* Free up ast dsp if we have one */
+       if ((use_ast_dtmfdet)&&(p->vad)) {
+               ast_dsp_free(p->vad);
+               p->vad = NULL;
+       }
 
        ast_mutex_lock(&usecnt_lock); {
                usecnt--;
@@ -1706,11 +2108,11 @@ static int vpb_hangup(struct ast_channel *ast)
 
 static int vpb_answer(struct ast_channel *ast)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt;
-       VPB_EVENT je;
-       int ret;
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
        int res = 0;
 /*
+       VPB_EVENT je;
+       int ret;
        if (option_verbose > 3) ast_verbose("%s: LOCKING in answer \n", p->dev);
        if (option_verbose > 3) ast_verbose("%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);
 */
@@ -1780,10 +2182,10 @@ static int vpb_answer(struct ast_channel *ast)
 
 static struct ast_frame  *vpb_read(struct ast_channel *ast)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt; 
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; 
        static struct ast_frame f = {AST_FRAME_NULL}; 
 
-       f.src = type;
+       f.src = "vpb";
        ast_log(LOG_NOTICE, "%s: vpb_read: should never be called!\n", p->dev);
        ast_verbose("%s: vpb_read: should never be called!\n", p->dev);
 
@@ -1855,9 +2257,11 @@ int a_gain_vector(float g, short *v, int n)
 /* Writes a frame of voice data to a VPB channel */
 static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 {
-       struct vpb_pvt *p = (struct vpb_pvt *)ast->pvt->pvt; 
+       struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; 
        int res = 0, fmt = 0;
-       struct timeval play_buf_time_start,play_buf_time_finish;
+       struct timeval play_buf_time_start;
+       int tdiff;
+
 /*     ast_mutex_lock(&p->lock); */
        if(option_verbose>5) 
                ast_verbose("%s: vpb_write: Writing to channel\n", p->dev);
@@ -1869,23 +2273,36 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
                return 0;
        } else if (ast->_state != AST_STATE_UP) {
                if(option_verbose>3) 
-                       ast_verbose("%s: vpb_write: Attempt to Write frame type[%d]subclass[%d] on not up chan\n",ast->name, frame->frametype, frame->subclass);
+                       ast_verbose("%s: vpb_write: Attempt to Write frame type[%d]subclass[%d] on not up chan(state[%d])\n",ast->name, frame->frametype, frame->subclass,ast->_state);
                p->lastoutput = -1;
 /*             ast_mutex_unlock(&p->lock); */
                return 0;
        }
 /*     ast_log(LOG_DEBUG, "%s: vpb_write: Checked frame type..\n", p->dev); */
 
+
        fmt = ast2vpbformat(frame->subclass);
        if (fmt < 0) {
                ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %d format!\n",ast->name, frame->subclass);
                return -1;
        }
-/*     ast_log(LOG_DEBUG, "%s: vpb_write: Checked frame format..\n", p->dev); */
+
+       tdiff = ast_tvdiff_ms(ast_tvnow(), p->lastplay);
+       ast_log(LOG_DEBUG, "%s: vpb_write: time since last play(%d) \n", p->dev, tdiff); 
+       if (tdiff < (VPB_SAMPLES/8 - 1)){
+               ast_log(LOG_DEBUG, "%s: vpb_write: Asked to play too often (%d) (%d)\n", p->dev, tdiff,frame->datalen); 
+//             return 0;
+       }
+       p->lastplay = ast_tvnow();
+/*
+       ast_log(LOG_DEBUG, "%s: vpb_write: Checked frame format..\n", p->dev); 
+*/
 
        ast_mutex_lock(&p->play_lock);
 
-/*     ast_log(LOG_DEBUG, "%s: vpb_write: Got play lock..\n", p->dev); */
+/*
+       ast_log(LOG_DEBUG, "%s: vpb_write: Got play lock..\n", p->dev); 
+*/
 
        /* Check if we have set up the play_buf */
        if (p->lastoutput == -1) {
@@ -1893,11 +2310,16 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
                if(option_verbose>1) {
                        ast_verbose("%s: vpb_write: Starting play mode (codec=%d)[%s]\n",p->dev,fmt,ast2vpbformatname(frame->subclass));
                }
+               p->lastoutput = fmt;
+               ast_mutex_unlock(&p->play_lock);
+               return 0;
        } else if (p->lastoutput != fmt) {
                vpb_play_buf_finish(p->handle);
                vpb_play_buf_start(p->handle, fmt);
                if(option_verbose>1) 
                        ast_verbose("%s: vpb_write: Changed play format (%d=>%d)\n",p->dev,p->lastoutput,fmt);
+               ast_mutex_unlock(&p->play_lock);
+               return 0;
        }
        p->lastoutput = fmt;
 
@@ -1908,26 +2330,17 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
                a_gain_vector(p->txswgain - MAX_VPB_GAIN , (short*)frame->data, frame->datalen/sizeof(short));
 
 /*     ast_log(LOG_DEBUG, "%s: vpb_write: Applied gain..\n", p->dev); */
-
-/*     gettimeofday(&tv, NULL); */
-/*     return ((double)tv.tv_sec*1000)+((double)tv.tv_usec/1000); */
+/*     ast_log(LOG_DEBUG, "%s: vpb_write: play_buf_time %d\n", p->dev, p->play_buf_time); */
 
        if ((p->read_state == 1)&&(p->play_buf_time<5)){
-       gettimeofday(&play_buf_time_start,NULL);
-       res = vpb_play_buf_sync(p->handle, (char*)frame->data, frame->datalen);
-       if( (res == VPB_OK) && (option_verbose > 5) ) {
-               short * data = (short*)frame->data;
-               ast_verbose("%s: vpb_write: Wrote chan (codec=%d) %d %d\n", p->dev, fmt, data[0],data[1]);
-       }
-       gettimeofday(&play_buf_time_finish,NULL);
-       if (play_buf_time_finish.tv_sec == play_buf_time_start.tv_sec){
-               p->play_buf_time=(int)((play_buf_time_finish.tv_usec-play_buf_time_start.tv_usec)/1000);
-/*             ast_log(LOG_DEBUG, "%s: vpb_write: Timing start(%d) finish(%d)\n", p->dev,play_buf_time_start.tv_usec,play_buf_time_finish.tv_usec); */
-       }
-       else {
-               p->play_buf_time=(int)((play_buf_time_finish.tv_sec - play_buf_time_start.tv_sec)*100)+(int)((play_buf_time_finish.tv_usec-play_buf_time_start.tv_usec)/1000);
-       }
-/*     ast_log(LOG_DEBUG, "%s: vpb_write: Wrote data [%d](%d=>%s) to play_buf in [%d]ms..\n", p->dev,frame->datalen,fmt,ast2vpbformatname(frame->subclass),p->play_buf_time); */
+               play_buf_time_start = ast_tvnow();
+/*             res = vpb_play_buf_sync(p->handle, (char*)frame->data, tdiff*8*2); */
+               res = vpb_play_buf_sync(p->handle, (char*)frame->data, frame->datalen);
+               if( res == VPB_OK && option_verbose > 5 ) {
+                       short * data = (short*)frame->data;
+                       ast_verbose("%s: vpb_write: Wrote chan (codec=%d) %d %d\n", p->dev, fmt, data[0],data[1]);
+               }
+               p->play_buf_time = ast_tvdiff_ms(ast_tvnow(), play_buf_time_start);
        }
        else {
                p->chuck_count++;
@@ -1951,10 +2364,10 @@ static void *do_chanreads(void *pvt)
        int bridgerec = 0;
        int afmt, readlen, res, fmt, trycnt=0;
        int ignore_dtmf;
-       char * getdtmf_var = NULL;
+       const char * getdtmf_var = NULL;
 
        fr->frametype = AST_FRAME_VOICE;
-       fr->src = type;
+       fr->src = "vpb";
        fr->mallocd = 0;
        fr->delivery.tv_sec = 0;
        fr->delivery.tv_usec = 0;
@@ -1996,8 +2409,9 @@ static void *do_chanreads(void *pvt)
                        }
                }
 
-/*             if ( (p->owner->_state != AST_STATE_UP) || !bridgerec) { */
-               if ( (p->owner->_state != AST_STATE_UP) ) {
+/*             if ( (p->owner->_state != AST_STATE_UP) || !bridgerec) */
+               if ( (p->owner->_state != AST_STATE_UP) ) 
+               {
                        if (option_verbose > 4) {
                                if (p->owner->_state != AST_STATE_UP)
                                        ast_verbose("%s: chanreads: Im not up[%d]\n", p->dev,p->owner->_state);
@@ -2018,7 +2432,7 @@ static void *do_chanreads(void *pvt)
                if( getdtmf_var && ( strcasecmp( getdtmf_var, "yes" ) == 0 ) )
                        ignore_dtmf = 0;
 
-               if( ignore_dtmf != p->last_ignore_dtmf ) {
+               if(( ignore_dtmf != p->last_ignore_dtmf ) &&(!use_ast_dtmfdet)){
                        if(option_verbose>1) 
                                ast_verbose( VERBOSE_PREFIX_2 "%s:Now %s DTMF \n",
                                        p->dev, ignore_dtmf ? "ignoring" : "listening for");
@@ -2038,7 +2452,6 @@ static void *do_chanreads(void *pvt)
                        /* This DTMF is played by asterisk and leads to an annoying trailing beep on CISCO phones */
                        if( !ignore_dtmf) 
                                vpb_set_event_mask(p->handle, VPB_EVENTS_NODTMF );
-/*                     if (strcmp(p->owner->type,"vpb")==0){ */
                        if (p->bridge == NULL){
                                vpb_dial_sync(p->handle,p->play_dtmf);
                                if(option_verbose>1) 
@@ -2057,9 +2470,9 @@ static void *do_chanreads(void *pvt)
                }
                ast_mutex_unlock(&p->play_dtmf_lock);
 
-/*             afmt = (p->owner) ? p->owner->pvt->rawreadformat : AST_FORMAT_SLINEAR; */
+/*             afmt = (p->owner) ? p->owner->rawreadformat : AST_FORMAT_SLINEAR; */
                if (p->owner){
-                       afmt = p->owner->pvt->rawreadformat;
+                       afmt = p->owner->rawreadformat;
 /*                     ast_log(LOG_DEBUG,"%s: Record using owner format [%s]\n", p->dev, ast2vpbformatname(afmt)); */
                }
                else {
@@ -2076,15 +2489,18 @@ static void *do_chanreads(void *pvt)
                if (p->lastinput == -1) {
                        vpb_record_buf_start(p->handle, fmt);
                        vpb_reset_record_fifo_alarm(p->handle);
+                       p->lastinput = fmt;
                        if(option_verbose>1) 
                                ast_verbose( VERBOSE_PREFIX_2 "%s: Starting record mode (codec=%d)[%s]\n",p->dev,fmt,ast2vpbformatname(afmt));
+                       continue;
                } else if (p->lastinput != fmt) {
                        vpb_record_buf_finish(p->handle);
                        vpb_record_buf_start(p->handle, fmt);
+                       p->lastinput = fmt;
                        if(option_verbose>1) 
                                ast_verbose( VERBOSE_PREFIX_2 "%s: Changed record format (%d=>%d)\n",p->dev,p->lastinput,fmt);
+                       continue;
                }
-               p->lastinput = fmt;
 
                /* Read only if up and not bridged, or a bridge for which we can read. */
                if (option_verbose > 5) {
@@ -2104,7 +2520,25 @@ static void *do_chanreads(void *pvt)
                        fr->subclass = afmt;
                        fr->data = readbuf;
                        fr->datalen = readlen;
-
+                       fr->frametype = AST_FRAME_VOICE;
+
+                       if ((use_ast_dtmfdet)&&(p->vad)){
+                               fr = ast_dsp_process(p->owner,p->vad,fr);
+                               if (fr && (fr->frametype == AST_FRAME_DTMF))
+                                       ast_log(LOG_DEBUG, "%s: chanreads: Detected DTMF '%c'\n",p->dev, fr->subclass);
+                               if (fr->subclass == 'm'){
+                                       /* conf mute request */
+                                       fr->frametype = AST_FRAME_NULL;
+                                       fr->subclass = 0;
+                               }
+                               else if (fr->subclass == 'u'){
+                                       /* Unmute */
+                                       fr->frametype = AST_FRAME_NULL;
+                                       fr->subclass = 0;
+                               }
+                               else if (fr->subclass == 'f'){
+                               }
+                       }
                        /* Using trylock here to prevent deadlock when channel is hungup
                         * (ast_hangup() immediately gets lock)
                         */
@@ -2161,10 +2595,6 @@ static void *do_chanreads(void *pvt)
                                        ast_verbose("%s: p->stopreads[%d] p->owner[%p]\n", p->dev, p->stopreads,(void *)p->owner);
                                }  
                        }
-               } else {
-                       ast_log(LOG_WARNING,"%s: Record failure (%s)\n", p->dev, vpb_strerror(res));
-                       vpb_record_buf_finish(p->handle);
-                       vpb_record_buf_start(p->handle, fmt);
                }
                if (option_verbose > 4)
                        ast_verbose("%s: chanreads: Finished cycle...\n", p->dev);
@@ -2185,6 +2615,8 @@ static void *do_chanreads(void *pvt)
 static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
 {
        struct ast_channel *tmp; 
+       char cid_num[256];
+       char cid_name[256];
 
        if (me->owner) {
            ast_log(LOG_WARNING, "Called vpb_new on owned channel (%s) ?!\n", me->dev);
@@ -2195,31 +2627,34 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
            
        tmp = ast_channel_alloc(1);
        if (tmp) {
-               strncpy(tmp->name, me->dev, sizeof(tmp->name) - 1);
-               tmp->type = type;
+               if (use_ast_ind == 1){
+                       tmp->tech = &vpb_tech_indicate;
+               }
+               else {
+                       tmp->tech = &vpb_tech;
+               }
+
+               ast_string_field_set(tmp, name, me->dev);
+               
+               tmp->callgroup = me->callgroup;
+               tmp->pickupgroup = me->pickupgroup;
               
                /* Linear is the preferred format. Although Voicetronix supports other formats
                 * they are all converted to/from linear in the vpb code. Best for us to use
                 * linear since we can then adjust volume in this modules.
                 */
                tmp->nativeformats = prefformat;
-               tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
-               tmp->pvt->rawwriteformat =  AST_FORMAT_SLINEAR;
+               tmp->rawreadformat = AST_FORMAT_SLINEAR;
+               tmp->rawwriteformat =  AST_FORMAT_SLINEAR;
                ast_setstate(tmp, state);
-               if (state == AST_STATE_RING)
+               if (state == AST_STATE_RING) {
                        tmp->rings = 1;
-               tmp->pvt->pvt = me;
-               /* set call backs */
-               tmp->pvt->send_digit = vpb_digit;
-               tmp->pvt->call = vpb_call;
-               tmp->pvt->hangup = vpb_hangup;
-               tmp->pvt->answer = vpb_answer;
-               tmp->pvt->read = vpb_read;
-               tmp->pvt->write = vpb_write;
-               tmp->pvt->bridge = vpb_bridge;
-               if (use_ast_ind == 0)
-                       tmp->pvt->indicate = vpb_indicate;
-               tmp->pvt->fixup = vpb_fixup;
+                       cid_name[0] = '\0';
+                       cid_num[0] = '\0';
+                       ast_callerid_split(me->callerid, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
+                       ast_set_callerid(tmp, cid_num, cid_name, cid_num);
+               }
+               tmp->tech_pvt = me;
                
                strncpy(tmp->context, context, sizeof(tmp->context)-1);
                if (strlen(me->ext))
@@ -2227,7 +2662,7 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
                else
                        strncpy(tmp->exten, "s",  sizeof(tmp->exten) - 1);
                if (strlen(me->language))
-                       strncpy(tmp->language, me->language, sizeof(tmp->language)-1);
+                       ast_string_field_set(tmp, language, me->language);
 
                me->owner = tmp;
      
@@ -2237,14 +2672,19 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
                me->last_ignore_dtmf = 1;
                me->readthread = 0;
                me->play_dtmf[0] = '\0';
+               me->faxhandled =0;
                
-               me->lastgrunt  = get_time_in_ms(); /* Assume at least one grunt tone seen now. */
+               me->lastgrunt  = ast_tvnow(); /* Assume at least one grunt tone seen now. */
+               me->lastplay  = ast_tvnow(); /* Assume at least one grunt tone seen now. */
 
                ast_mutex_lock(&usecnt_lock);
                usecnt++;
                ast_mutex_unlock(&usecnt_lock);
                ast_update_use_count();
                if (state != AST_STATE_DOWN) {
+                       if ((me->mode != MODE_FXO)&&(state != AST_STATE_UP)){
+                               vpb_answer(tmp);
+                       }
                        if (ast_pbx_start(tmp)) {
                                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
                                ast_hangup(tmp);
@@ -2332,15 +2772,84 @@ static float parse_gain_value(char *gain_type, char *value)
        return gain;
 }
 
+
+int unload_module()
+{
+       struct vpb_pvt *p;
+       /* First, take us out of the channel loop */
+       if (use_ast_ind == 1){
+               ast_channel_unregister(&vpb_tech_indicate);
+       }
+       else {
+               ast_channel_unregister(&vpb_tech);
+       }
+
+       ast_mutex_lock(&iflock); {
+               /* Hangup all interfaces if they have an owner */
+               p = iflist;
+               while(p) {
+                       if (p->owner)
+                               ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+                       p = p->next;
+               }
+               iflist = NULL;
+       } ast_mutex_unlock(&iflock);
+
+       ast_mutex_lock(&monlock); {
+               if (mthreadactive > -1) {
+                       pthread_cancel(monitor_thread);
+                       pthread_join(monitor_thread, NULL);
+               }
+               mthreadactive = -2;
+       } ast_mutex_unlock(&monlock);
+
+       ast_mutex_lock(&iflock); {
+               /* Destroy all the interfaces and free their memory */
+
+               while(iflist) {
+                       p = iflist;                 
+                       ast_mutex_destroy(&p->lock);
+                       pthread_cancel(p->readthread);
+                       ast_mutex_destroy(&p->owner_lock);
+                       ast_mutex_destroy(&p->record_lock);
+                       ast_mutex_destroy(&p->play_lock);
+                       ast_mutex_destroy(&p->play_dtmf_lock);
+                       p->readthread = 0;
+
+                       vpb_close(p->handle);
+
+                       iflist = iflist->next;
+
+                       free(p);
+               }
+               iflist = NULL;
+       } ast_mutex_unlock(&iflock);
+
+       ast_mutex_lock(&bridge_lock); {
+               memset(bridges, 0, sizeof bridges);          
+       } ast_mutex_unlock(&bridge_lock);
+       ast_mutex_destroy(&bridge_lock);
+       for(int i = 0; i < max_bridges; i++ ) {
+               ast_mutex_destroy(&bridges[i].lock);
+               ast_cond_destroy(&bridges[i].cond);
+       }
+       free(bridges);
+
+       return 0;
+}
+
 int load_module()
 {
        struct ast_config *cfg;
        struct ast_variable *v;
        struct vpb_pvt *tmp;
        int board = 0, group = 0;
+       ast_group_t     callgroup = 0;
+       ast_group_t     pickupgroup = 0;
        int mode = MODE_IMMEDIATE;
        float txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; 
        float txswgain = 0, rxswgain = 0; 
+       int got_gain=0;
        int first_channel = 1;
        int echo_cancel = DEFAULT_ECHO_CANCEL;
        int error = 0; /* Error flag */
@@ -2349,7 +2858,7 @@ int load_module()
        int bal3 = -1;
        char * callerid = NULL;
 
-       cfg = ast_load(config);
+       cfg = ast_config_load(config);
 
        /* We *must* have a config file otherwise stop immediately */
        if (!cfg) {
@@ -2369,6 +2878,37 @@ int load_module()
                                use_ast_ind = 1;
                                ast_log(LOG_NOTICE,"VPB driver using Asterisk Indication functions!\n");
                        }
+                       else if (strcasecmp(v->name, "break-for-dtmf") == 0) {
+                               if (ast_true(v->value)){
+                                       break_for_dtmf = 1;
+                               }
+                               else {
+                                       break_for_dtmf = 0;
+                                       ast_log(LOG_NOTICE,"VPB driver not stopping for DTMF's in native bridge\n");
+                               }
+                       }
+                       else if (strcasecmp(v->name, "ast-dtmf") == 0) {
+                               use_ast_dtmf = 1;
+                               ast_log(LOG_NOTICE,"VPB driver using Asterisk DTMF play functions!\n");
+                       }
+                       else if (strcasecmp(v->name, "ast-dtmf-det") == 0) {
+                               use_ast_dtmfdet = 1;
+                               ast_log(LOG_NOTICE,"VPB driver using Asterisk DTMF detection functions!\n");
+                       }
+                       else if (strcasecmp(v->name, "relaxdtmf") == 0) {
+                               relaxdtmf = 1;
+                               ast_log(LOG_NOTICE,"VPB driver using Relaxed DTMF with Asterisk DTMF detections functions!\n");
+                       }
+                       else if (strcasecmp(v->name, "timer_period_ring") ==0) {
+                               timer_period_ring = atoi(v->value);
+                       }
+                       else if (strcasecmp(v->name, "ecsuppthres") ==0) {
+                               ec_supp_threshold = atoi(v->value);
+                       }
+                       else if (strcasecmp(v->name, "dtmfidd") ==0) {
+                               dtmf_idd = atoi(v->value);
+                               ast_log(LOG_NOTICE,"VPB Driver setting DTMF IDD to [%d]ms\n",dtmf_idd);
+                       }
                        v = v->next;
                }
        
@@ -2379,13 +2919,19 @@ int load_module()
                                board = atoi(v->value);
                        } else  if (strcasecmp(v->name, "group") == 0){
                                group = atoi(v->value);
+                       } else  if (strcasecmp(v->name, "callgroup") == 0){
+                               callgroup = ast_get_group(v->value);
+                       } else  if (strcasecmp(v->name, "pickupgroup") == 0){
+                               pickupgroup = ast_get_group(v->value);
+                       } else  if (strcasecmp(v->name, "usepolaritycid") == 0){
+                               UsePolarityCID = atoi(v->value);
                        } else  if (strcasecmp(v->name, "useloopdrop") == 0){
                                UseLoopDrop = atoi(v->value);
                        } else  if (strcasecmp(v->name, "usenativebridge") == 0){
                                UseNativeBridge = atoi(v->value);
                        } else if (strcasecmp(v->name, "channel") == 0) {
                                int channel = atoi(v->value);
-                               tmp = mkif(board, channel, mode, txgain, rxgain, txswgain, rxswgain, bal1, bal2, bal3, callerid, echo_cancel,group);
+                               tmp = mkif(board, channel, mode, got_gain, txgain, rxgain, txswgain, rxswgain, bal1, bal2, bal3, callerid, echo_cancel,group,callgroup,pickupgroup);
                                if (tmp) {
                                        if(first_channel) {
                                                mkbrd( tmp->vpb_model, echo_cancel );
@@ -2418,12 +2964,16 @@ int load_module()
                                        echo_cancel = 0;
                        } else if (strcasecmp(v->name, "txgain") == 0) {
                                txswgain = parse_gain_value(v->name, v->value);
+                               got_gain |=VPB_GOT_TXSWG;
                        } else if (strcasecmp(v->name, "rxgain") == 0) {
                                rxswgain = parse_gain_value(v->name, v->value);
+                               got_gain |=VPB_GOT_RXSWG;
                        } else if (strcasecmp(v->name, "txhwgain") == 0) {
                                txgain = parse_gain_value(v->name, v->value);
+                               got_gain |=VPB_GOT_TXHWG;
                        } else if (strcasecmp(v->name, "rxhwgain") == 0) {
                                rxgain = parse_gain_value(v->name, v->value);
+                               got_gain |=VPB_GOT_RXHWG;
                        } else if (strcasecmp(v->name, "bal1") == 0) {
                                bal1 = strtol(v->value, NULL, 16);
                                if(bal1<0 || bal1>255) {
@@ -2454,11 +3004,25 @@ int load_module()
                done: (void)0;
        } ast_mutex_unlock(&iflock);
 
-       ast_destroy(cfg);
+       ast_config_destroy(cfg);
 
-       if (!error && ast_channel_register(type, tdesc, prefformat, vpb_request) != 0) {
-               ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
-               error = -1;
+       if (use_ast_ind == 1){
+               if (!error && ast_channel_register(&vpb_tech_indicate) != 0) {
+                       ast_log(LOG_ERROR, "Unable to register channel class 'vpb'\n");
+                       error = -1;
+               }
+               else {
+                       ast_log(LOG_NOTICE,"VPB driver Registered (w/AstIndication)\n");
+               }
+       }
+       else {
+               if (!error && ast_channel_register(&vpb_tech) != 0) {
+                       ast_log(LOG_ERROR, "Unable to register channel class 'vpb'\n");
+                       error = -1;
+               }
+               else {
+                       ast_log(LOG_NOTICE,"VPB driver Registered )\n");
+               }
        }
 
 
@@ -2470,82 +3034,17 @@ int load_module()
        return error;
 }
 
-
-int unload_module()
-{
-       struct vpb_pvt *p;
-       /* First, take us out of the channel loop */
-       ast_channel_unregister(type);
-
-       ast_mutex_lock(&iflock); {
-               /* Hangup all interfaces if they have an owner */
-               p = iflist;
-               while(p) {
-                       if (p->owner)
-                               ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
-                       p = p->next;
-               }
-               iflist = NULL;
-       } ast_mutex_unlock(&iflock);
-
-       ast_mutex_lock(&monlock); {
-               if (mthreadactive > -1) {
-                       pthread_cancel(monitor_thread);
-                       pthread_join(monitor_thread, NULL);
-               }
-               mthreadactive = -2;
-       } ast_mutex_unlock(&monlock);
-
-       ast_mutex_lock(&iflock); {
-               /* Destroy all the interfaces and free their memory */
-
-               while(iflist) {
-                       p = iflist;                 
-                       ast_mutex_destroy(&p->lock);
-                       pthread_cancel(p->readthread);
-                       ast_mutex_destroy(&p->owner_lock);
-                       ast_mutex_destroy(&p->record_lock);
-                       ast_mutex_destroy(&p->play_lock);
-                       ast_mutex_destroy(&p->play_dtmf_lock);
-                       p->readthread = 0;
-
-                       vpb_close(p->handle);
-
-                       iflist = iflist->next;
-
-                       free(p);
-               }
-               iflist = NULL;
-       } ast_mutex_unlock(&iflock);
-
-       ast_mutex_lock(&bridge_lock); {
-               memset(bridges, 0, sizeof bridges);          
-       } ast_mutex_unlock(&bridge_lock);
-       ast_mutex_destroy(&bridge_lock);
-       for(int i = 0; i < max_bridges; i++ ) {
-               ast_mutex_destroy(&bridges[i].lock);
-               pthread_cond_destroy(&bridges[i].cond);
-       }
-       free(bridges);
-
-       return 0;
-}
-
 int usecount()
 {
-       int res;
-       ast_mutex_lock(&usecnt_lock);
-       res = usecnt;
-       ast_mutex_unlock(&usecnt_lock);
-       return res;
+       return usecnt;
 }
 
-char *description()
+const char *description()
 {
-       return desc;
+       return (char *) desc;
 }
 
-char *key()
+const char *key()
 {
        return ASTERISK_GPL_KEY;
 }
@@ -2555,3 +3054,5 @@ char *key()
  }
 #endif
 /**/
+
+