Blocked revisions 36725 via svnmerge
[asterisk/asterisk.git] / channels / chan_vpb.c
old mode 100755 (executable)
new mode 100644 (file)
index 68eadb6..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/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 "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>
@@ -77,7 +96,6 @@ extern "C" {
 /**/
 
 static const char desc[] = "VoiceTronix V6PCI/V12PCI/V4PCI  API Support";
-static const char type[] = "vpb";
 static const char tdesc[] = "Standard VoiceTronix API Driver";
 static const char config[] = "vpb.conf";
 
@@ -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;
 
@@ -166,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 \
@@ -218,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;
 
@@ -267,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)*/
 
@@ -288,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;
@@ -301,6 +327,7 @@ 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];
@@ -321,18 +348,20 @@ 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 int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
-static int vpb_indicate(struct ast_channel *ast, int condition);
+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 const struct ast_channel_tech vpb_tech = {
-       type: type,
+static struct ast_channel_tech vpb_tech = {
+       type: "vpb",
        description: tdesc,
        capabilities: AST_FORMAT_SLINEAR,
-       properties: NULL,
+       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,
@@ -342,7 +371,7 @@ static const struct ast_channel_tech vpb_tech = {
        send_image: NULL,
        send_html: NULL,
        exception: NULL,
-       bridge: vpb_bridge,
+       bridge: ast_vpb_bridge,
        indicate: vpb_indicate,
        fixup: vpb_fixup,
        setoption: NULL,
@@ -352,7 +381,36 @@ static const struct ast_channel_tech vpb_tech = {
        bridged_channel: NULL
 };
 
-/* Can't get vpb_bridge() working on v4pci without either a horrible 
+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
 */
@@ -364,15 +422,14 @@ static const struct ast_channel_tech vpb_tech = {
 /* #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->tech_pvt;
        struct vpb_pvt *p1 = (struct vpb_pvt *)c1->tech_pvt;
-       int i, res;
-
+       int i;
+       int res;
        struct ast_channel *cs[3];
        struct ast_channel *who;
-       int to = -1;
        struct ast_frame *f;
 
        cs[0] = c0;
@@ -380,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;
        }
 
 /*
@@ -412,7 +469,7 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
                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); {
@@ -427,6 +484,9 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
                        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) 
@@ -474,8 +534,12 @@ 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) {
+                               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))
@@ -549,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
@@ -570,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);
@@ -604,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);
 
@@ -633,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);
@@ -661,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");
@@ -732,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);
 }
@@ -786,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 = (char *)type;
+       f.src = "vpb";
        switch (e->type) {
                case VPB_RING:
                        if (p->mode == MODE_FXO) {
@@ -854,13 +922,15 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
                        else if (e->data == VPB_FAX){
                                if (!p->faxhandled){
                                        if (strcmp(p->owner->exten, "fax")) {
-                                               if (ast_exists_extension(p->owner, ast_strlen_zero(p->owner->macrocontext) ? p->owner->context : p->owner->macrocontext, "fax", 1, p->owner->cid.cid_num)) {
+                                               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, p->owner->context, "fax", 1))
-                                                               ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, p->owner->context);
+                                                       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
@@ -870,7 +940,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
 
                        } 
                        else if (e->data == VPB_GRUNT) {
-                               if( ( get_time_in_ms() - p->lastgrunt ) > gruntdetect_timeout ) {
+                               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) 
@@ -878,7 +948,7 @@ 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;
                                }
                        } 
@@ -915,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;
@@ -990,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);                      
                        }         
                }
@@ -1037,7 +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];
@@ -1047,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);
                        }
@@ -1116,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);
                                }
                        } 
@@ -1405,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);
                        }
                }
        }
@@ -1422,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");
                        }
                }
@@ -1563,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);
@@ -1607,14 +1716,17 @@ 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->tech_pvt;
        int res = 0;
        int tmp = 0;
 
-       if (!use_ast_ind)
+       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);
@@ -1694,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);
@@ -1757,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;
@@ -1769,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);
@@ -1935,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);
@@ -1986,10 +2109,10 @@ static int vpb_hangup(struct ast_channel *ast)
 static int vpb_answer(struct ast_channel *ast)
 {
        struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt;
-       VPB_EVENT je;
-       int ret;
        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);
 */
@@ -2062,7 +2185,7 @@ static struct ast_frame  *vpb_read(struct ast_channel *ast)
        struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; 
        static struct ast_frame f = {AST_FRAME_NULL}; 
 
-       f.src = (char *)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);
 
@@ -2136,7 +2259,9 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 {
        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);
@@ -2155,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); 
 */
@@ -2176,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;
 
@@ -2191,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++;
@@ -2234,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 = (char *)type;
+       fr->src = "vpb";
        fr->mallocd = 0;
        fr->delivery.tv_sec = 0;
        fr->delivery.tv_usec = 0;
@@ -2359,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) {
@@ -2462,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);
@@ -2498,9 +2627,14 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
            
        tmp = ast_channel_alloc(1);
        if (tmp) {
-               tmp->tech = &vpb_tech;
-               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;
@@ -2528,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;
      
@@ -2540,7 +2674,8 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
                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++;
@@ -2637,6 +2772,72 @@ 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;
@@ -2698,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);
                        }
@@ -2719,6 +2923,8 @@ int load_module()
                                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){
@@ -2800,9 +3006,23 @@ int load_module()
 
        ast_config_destroy(cfg);
 
-       if (!error && ast_channel_register(&vpb_tech) != 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");
+               }
        }
 
 
@@ -2814,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(&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);
-               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 (char *) desc;
 }
 
-char *key()
+const char *key()
 {
        return ASTERISK_GPL_KEY;
 }
@@ -2899,3 +3054,5 @@ char *key()
  }
 #endif
 /**/
+
+