Blocked revisions 36725 via svnmerge
[asterisk/asterisk.git] / channels / chan_vpb.c
old mode 100755 (executable)
new mode 100644 (file)
index c93c03d..d615e60
@@ -1,8 +1,6 @@
 /*
- * 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 - 2005, Ben Kramer
  * 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/dsp.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>
@@ -76,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";
@@ -134,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;
 
@@ -154,6 +177,9 @@ 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;
 
@@ -163,6 +189,7 @@ 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 \
@@ -215,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;
 
@@ -243,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 */
@@ -261,6 +291,8 @@ static struct vpb_pvt {
        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)*/
 
@@ -282,7 +314,7 @@ static struct vpb_pvt {
 
        struct ast_dsp *vad;                    /* AST  Voice Activation Detection dsp */
 
-       double lastgrunt;                       /* time stamp (secs since epoc) of last grunt event */
+       struct timeval lastgrunt;                       /* time stamp of last grunt event */
 
        ast_mutex_t lock;                       /* This one just protects bridge ptr below */
        vpb_bridge_t *bridge;
@@ -295,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;
@@ -306,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
 */
@@ -318,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;
@@ -334,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;
        }
 
 /*
@@ -363,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); {
@@ -378,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;
 
@@ -417,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;
 
@@ -428,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;
@@ -442,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) || 
@@ -497,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
@@ -518,28 +627,33 @@ static double get_time_in_ms()
 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);
@@ -552,8 +666,8 @@ static void get_callerid(struct vpb_pvt *p)
 #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);
 
@@ -581,7 +695,13 @@ static void get_callerid(struct vpb_pvt *p)
                                owner->cid.cid_num = strdup(cli_struct->cldn);
                                owner->cid.cid_name = strdup(cli_struct->cn);
                                */
-                               ast_set_callerid(owner, cli_struct->cldn, cli_struct->cn, cli_struct->cldn);
+                               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);
@@ -609,10 +729,14 @@ 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(p->callerid_type == 1) {
        if (option_verbose>3) ast_verbose(VERBOSE_PREFIX_4 "Collected caller ID already\n");
@@ -680,18 +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);
-               if (name && !ast_strlen_zero(name)){
-                       owner->cid.cid_name = strdup(name);
-                       snprintf(p->callerid,(sizeof(p->callerid)-1),"%s %s",number,name);
-               }
-               else {
-                       snprintf(p->callerid,(sizeof(p->callerid)-1),"%s",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 (cs)
                callerid_free(cs);
 }
@@ -734,7 +854,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
        if (option_verbose > 3) 
                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) {
@@ -798,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) 
@@ -807,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:
@@ -842,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;
@@ -917,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);                      
                        }         
                }
@@ -964,6 +1113,9 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
        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];
@@ -973,15 +1125,37 @@ 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(p->callerid_type == 1) {
-                                       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 */
+                               }
+                               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;
                                }
-                               get_callerid_ast(p);    /* Caller ID using the ast functions */
+
                                vpb_timer_stop(p->ring_timer);
                                vpb_timer_start(p->ring_timer);
                        }
@@ -1042,8 +1216,13 @@ static inline int monitor_handle_notowned(struct vpb_pvt *p, VPB_EVENT *e)
                                }
                        } 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 */
+                               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);
                                }
                        } 
@@ -1096,6 +1275,15 @@ 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 ( ast_canmatch_extension(NULL, p->context, p->ext, 1, p->callerid)){
                                        if (option_verbose > 3)
@@ -1322,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);
                        }
                }
        }
@@ -1339,7 +1527,11 @@ static void mkbrd(vpb_model_t model, int echo_cancel)
                        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");
                        }
                }
@@ -1351,7 +1543,7 @@ static void mkbrd(vpb_model_t model, int echo_cancel)
 
 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];
@@ -1375,6 +1567,8 @@ static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float t
        tmp->mode = mode;
 
        tmp->group = group;
+       tmp->callgroup = callgroup;
+       tmp->pickupgroup = pickupgroup;
 
        /* Initilize dtmf caller ID position variable */
        tmp->dtmf_caller_pos=0;
@@ -1478,7 +1672,7 @@ static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float t
        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);
+       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);
@@ -1504,9 +1698,9 @@ static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float t
        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 );
+               ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF);
                if (relaxdtmf)
-                       ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+                       ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF|DSP_DIGITMODE_RELAXDTMF);
        }
        else {
                tmp->vad = NULL;
@@ -1522,12 +1716,18 @@ static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float t
        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);
 /*
@@ -1591,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;
 
 /*
@@ -1606,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);
@@ -1621,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);
@@ -1636,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));
@@ -1652,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] = "";
@@ -1663,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;
@@ -1675,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);
@@ -1766,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 ;
@@ -1780,8 +1992,7 @@ 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);
 /*
@@ -1842,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);
@@ -1862,7 +2078,7 @@ 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)) {
@@ -1892,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);
 */
@@ -1966,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);
 
@@ -2041,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);
@@ -2062,11 +2280,20 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
        }
 /*     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;
        }
+
+       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); 
 */
@@ -2083,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;
 
@@ -2098,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++;
@@ -2141,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;
@@ -2247,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 {
@@ -2266,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) {
@@ -2300,6 +2526,18 @@ static void *do_chanreads(void *pvt)
                                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)
@@ -2357,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);
@@ -2393,16 +2627,25 @@ 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) {
                        tmp->rings = 1;
@@ -2411,19 +2654,7 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
                        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->pvt->pvt = me;
-               /* set call backs */
-               if (use_ast_dtmf == 0)
-                       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;
+               tmp->tech_pvt = me;
                
                strncpy(tmp->context, context, sizeof(tmp->context)-1);
                if (strlen(me->ext))
@@ -2431,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;
      
@@ -2441,8 +2672,10 @@ 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++;
@@ -2539,12 +2772,80 @@ 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; 
@@ -2577,6 +2878,15 @@ 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");
@@ -2589,6 +2899,9 @@ int load_module()
                                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);
                        }
@@ -2606,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, got_gain, 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 );
@@ -2687,9 +3006,23 @@ int load_module()
 
        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");
+               }
        }
 
 
@@ -2701,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;
 }
@@ -2786,3 +3054,5 @@ char *key()
  }
 #endif
 /**/
+
+