diff --git a/CREDITS b/CREDITS
index 8473ec89e97715d8ef15c395d557958ce312621f..13c4d5ad71037dfd908a97bc660b788658b5fb74 100755
--- a/CREDITS
+++ b/CREDITS
@@ -11,6 +11,7 @@ Telesthetic - for supporting SIP development
 
 Christos Ricudis - for substantial code contributions
 
+Paul Bagyenda, Digital Solutions - for initial Voicetronix driver development
 === WISHLIST CONTRIBUTERS ===
 Jeremy McNamara - SpeeX support
 Nick Seraphin - RDNIS support
diff --git a/channels/Makefile b/channels/Makefile
index bf20133ea3947ff4f94f734f224ce3e10a051ac7..179a90072fd0a7437c16e0f944008bb40cd2ac2d 100755
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -94,10 +94,10 @@ chan_nbs.so: chan_nbs.o
 	$(CC) -shared -Xlinker -x -o $@ $< -lnbs
 
 chan_vpb.o: chan_vpb.c
-	$(CC) -c $(CFLAGS) -o $@ chan_vpb.c
+	$(CXX) -c $(CFLAGS) -o $@ chan_vpb.c
 
 chan_vpb.so: chan_vpb.o
-	 $(CCC) -shared -Xlinker -x -o $@ $< -lvpb -lpthread -lm -ldl
+	 $(CXX) -shared -Xlinker -x -o $@ $< -lvpb -lpthread -lm -ldl
 
 #chan_modem.so : chan_modem.o
 #	$(CC) -rdynamic -shared -Xlinker -x -o $@ $<
diff --git a/channels/chan_vpb.c b/channels/chan_vpb.c
index e034c00ebb6829042836fbb7d0f13fb1d447d255..9ff96402c188e007bd02c4b52852f1e27d5a4378 100755
--- a/channels/chan_vpb.c
+++ b/channels/chan_vpb.c
@@ -35,8 +35,8 @@
 
 
 #define DEFAULT_GAIN 1.0
-#define VPB_SAMPLES 160 /* 20ms for recording and playback.*/
-#define VPB_MAX_BUF VPB_SAMPLES*4
+#define VPB_SAMPLES 240 
+#define VPB_MAX_BUF VPB_SAMPLES*4 + AST_FRIENDLY_OFFSET
 
 #define VPB_NULL_EVENT 200
 
@@ -102,6 +102,19 @@ static VPB_TONE Busytone     = {425,   0,   0, -10,  -100, -100,   500,  500};
 static VPB_TONE Ringbacktone = {425,   0,   0, -10,  -100, -100,  1000, 3000};
 #endif
 
+#define VPB_MAX_BRIDGES 128 
+static struct vpb_bridge_t {
+     int inuse;
+     struct ast_channel *c0, *c1, **rc;
+     struct ast_frame **fo;
+     int flags;
+     
+     pthread_mutex_t lock;
+     pthread_cond_t cond;
+} bridges[VPB_MAX_BRIDGES]; /* Bridges...*/
+
+static pthread_mutex_t bridge_lock = AST_MUTEX_INITIALIZER;
+
 static struct vpb_pvt {
 
      struct ast_channel *owner;		/* Channel we belong to, possibly NULL */
@@ -110,6 +123,7 @@ static struct vpb_pvt {
 
      char dev[256];
 
+     struct ast_frame f, fr;
      char buf[VPB_MAX_BUF];			/* Static buffer for reading frames */
 
      int dialtone;
@@ -126,10 +140,11 @@ static struct vpb_pvt {
      int lastinput;
      int lastoutput;
 
-    
+     struct vpb_bridge_t *bridge;
+     
      pthread_mutex_t lock;
 
-     int hangup;
+    int stopreads; /* Stop reading...*/
      pthread_t readthread;    /* For monitoring read channel. One per owned channel. */
 
      struct vpb_pvt *next;			/* Next channel in list */
@@ -137,10 +152,90 @@ static struct vpb_pvt {
 
 static char callerid[AST_MAX_EXTENSION];
 
+static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
+{
+     struct vpb_pvt *p0 = (struct vpb_pvt *)c0->pvt->pvt;
+     struct vpb_pvt *p1 = (struct vpb_pvt *)c1->pvt->pvt;
+     int i, len = sizeof bridges/sizeof bridges[0], res;
+     
+     /* Bridge channels, check if we can.  I believe we always can, so find a slot.*/
+     
+     ast_pthread_mutex_lock(&bridge_lock); {
+	  for (i = 0; i < len; i++) 
+	       if (!bridges[i].inuse)
+		    break;
+	  if (i < len) {
+	       bridges[i].inuse = 1;
+	       bridges[i].flags = flags;
+	       bridges[i].rc = rc;
+	       bridges[i].fo = fo;
+	       bridges[i].c0 = c0;
+	       bridges[i].c1 = c1;
+	       pthread_mutex_init(&bridges[i].lock, NULL);
+	       pthread_cond_init(&bridges[i].cond, NULL);
+	  } 	       
+     } ast_pthread_mutex_unlock(&bridge_lock); 
+
+     if (i == len) {
+	  ast_log(LOG_WARNING, "Failed to bridge %s and %s!\n", c0->name, c1->name);
+	  return -2;
+     } else {
+
+	  /* Set bridge pointers. You don't want to take these locks while holding bridge lock.*/
+	  ast_pthread_mutex_lock(&p0->lock); {
+	       p0->bridge = &bridges[i];
+	  } ast_pthread_mutex_unlock(&p0->lock);
+
+	  ast_pthread_mutex_lock(&p1->lock); {
+	       p1->bridge = &bridges[i];
+	  } ast_pthread_mutex_unlock(&p1->lock);
+
+	  if (option_verbose > 1) 
+	       ast_verbose(VERBOSE_PREFIX_3 
+			   " Bridging call entered with [%s, %s]\n", c0->name, c1->name);
+     }
+     res = vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_ON, 0);
+
+     if (res != VPB_OK) 
+	  goto done;
+
+     res = pthread_cond_wait(&bridges[i].cond, &bridges[i].lock); /* Wait for condition signal. */
+     
+     
+ done: /* Out of wait. */
+
+     vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_OFF, 0); 
+
+     
+     ast_pthread_mutex_lock(&bridge_lock); {
+	  bridges[i].inuse = 0;
+	  pthread_mutex_destroy(&bridges[i].lock);
+	  pthread_cond_destroy(&bridges[i].cond);	
+     } ast_pthread_mutex_unlock(&bridge_lock); 
+     
+     ast_pthread_mutex_lock(&p0->lock); {
+	  p0->bridge = NULL;
+     } ast_pthread_mutex_unlock(&p0->lock);
+     
+     ast_pthread_mutex_lock(&p1->lock); {
+	  p1->bridge = NULL;
+     } ast_pthread_mutex_unlock(&p1->lock);
+
+     
+     if (option_verbose > 2) 
+	  ast_verbose(VERBOSE_PREFIX_3 
+		      " Bridging call done with [%s, %s] => %d\n", c0->name, c1->name, res);
+    
+     if (res != 0 && res != VPB_OK) /* Don't assume VPB_OK is zero! */
+	  return -1;
+     else 
+	  return 0;
+}
 
 static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
 {
      struct ast_frame f = {AST_FRAME_CONTROL}; /* default is control, Clear rest. */
+     int endbridge = 0;
 
      if (option_verbose > 4) 
 	  ast_verbose(VERBOSE_PREFIX_3 " %s handle_owned got event: [%d=>%d]\n",
@@ -201,8 +296,49 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
      }
 
      if (option_verbose > 2) 
-	  ast_verbose(VERBOSE_PREFIX_3 " handle_owned: putting frame: [%d=>%d]\n",
-		      f.frametype, f.subclass);
+	  ast_verbose(VERBOSE_PREFIX_3 " handle_owned: putting frame: [%d=>%d], bridge=%p\n",
+		      f.frametype, f.subclass, (void *)p->bridge);
+
+     ast_pthread_mutex_lock(&p->lock); {
+	  if (p->bridge) { /* Check what happened, see if we need to report it. */
+	       switch (f.frametype) { 
+	       case AST_FRAME_DTMF:
+		    if (!(p->bridge->c0 == p->owner && 
+			  (p->bridge->flags & AST_BRIDGE_DTMF_CHANNEL_0) ) &&
+			!(p->bridge->c1 == p->owner && 
+			  (p->bridge->flags & AST_BRIDGE_DTMF_CHANNEL_1) )) 
+			 /* Kill bridge, this is interesting. */
+			 endbridge = 1;
+		    break;
+		    
+	       case AST_FRAME_CONTROL:
+		    if (!(p->bridge->flags & AST_BRIDGE_IGNORE_SIGS)) 
+#if 0
+			 if (f.subclass == AST_CONTROL_BUSY ||
+			     f.subclass == AST_CONTROL_CONGESTION ||
+			     f.subclass == AST_CONTROL_HANGUP ||
+			     f.subclass == AST_CONTROL_FLASH)
+#endif
+			      endbridge = 1;
+		    break;
+	       default:
+		    
+		    break;
+	       }
+	       if (endbridge) {
+		    if (p->bridge->fo)
+			 *p->bridge->fo = ast_frisolate(&f);
+		    if (p->bridge->rc)
+			 *p->bridge->rc = p->owner;
+		    
+		    ast_pthread_mutex_lock(&p->bridge->lock); {
+			 pthread_cond_signal(&p->bridge->cond);
+		    } ast_pthread_mutex_unlock(&p->bridge->lock); 	       		   
+	       }	  
+	  }
+     } ast_pthread_mutex_unlock(&p->lock);
+     
+     if (endbridge) return 0;
      
      if (f.frametype >= 0 && f.frametype != AST_FRAME_NULL) 
 	  ast_queue_frame(p->owner, &f, 0);
@@ -425,8 +561,12 @@ struct vpb_pvt *mkif(int board, int channel, int mode, float txgain, float rxgai
      tmp->lastinput = -1;
      tmp->lastoutput = -1;
 
+     tmp->bridge = NULL;
+
      tmp->readthread = 0;
 
+     pthread_mutex_init(&tmp->lock, NULL);
+
      if (setrxgain)      
 	  vpb_record_set_gain(tmp->handle, rxgain);
      if (settxgain)  
@@ -522,19 +662,21 @@ static int vpb_hangup(struct ast_channel *ast)
 
     ast_setstate(ast,AST_STATE_DOWN);
     
-    p->lastinput = p->lastoutput  = -1;
-    p->ext[0]  = 0;
-    p->owner = NULL;
-    p->dialtone = 0;
-    ast->pvt->pvt = NULL; 
-       
+    ast_pthread_mutex_lock(&p->lock); {    
+	 p->lastinput = p->lastoutput  = -1;
+	 p->ext[0]  = 0;
+	 p->owner = NULL;
+	 p->dialtone = 0;
+	 ast->pvt->pvt = NULL; 
+    } ast_pthread_mutex_unlock(&p->lock);
+	 
     ast_pthread_mutex_lock(&usecnt_lock); {
 	usecnt--;
     } ast_pthread_mutex_unlock(&usecnt_lock);
     ast_update_use_count();
 
     /* Stop thread doing reads. */
-    p->hangup = 1;
+    p->stopreads = 1;
     pthread_join(p->readthread, NULL); 
 
     if (option_verbose > 2)
@@ -625,13 +767,10 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
     fmt = ast2vpbformat(frame->subclass);
 
     if (option_verbose > 4)
-	 ast_verbose(VERBOSE_PREFIX_3 
-		     " Write chan %s: got frame type = %d, "
-		     "samples=%d, len=%d, oldfmt=%d,new=%d,rawwrite=%d\n",
-		     p->dev, frame->subclass, 
-		     frame->samples, frame->datalen, p->lastoutput, fmt, 
-		     ast->pvt->rawwriteformat);
-    
+	ast_verbose(VERBOSE_PREFIX_3 
+		    " Write chan %s: got frame type = %d\n",
+		    p->dev, frame->subclass);
+       
     if (fmt < 0) {
 	ast_log(LOG_WARNING, "vpb_write Cannot handle frames of %d format!\n", 
 		frame->subclass);
@@ -656,55 +795,89 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 static void *do_chanreads(void *pvt)
 {
      struct vpb_pvt *p = (struct vpb_pvt *)pvt;
-     char buf[VPB_MAX_BUF];
-     struct ast_frame fr = {AST_FRAME_VOICE};
+     struct ast_frame *fr = &p->fr;
+     char *readbuf = ((char *)p->buf) + AST_FRIENDLY_OFFSET;
+     int bridgerec = 0;
+ 
+     fr->frametype = AST_FRAME_VOICE;
+     fr->src = type;
+     fr->mallocd = 0;
      
-     fr.src = type;
+     memset(p->buf, 0, sizeof p->buf);
 
-     while (!p->hangup && p->owner) {	 
+     while (!p->stopreads && p->owner) {	 
 	 int res = -1, fmt;
 	 struct ast_channel *owner = p->owner;
 	 int afmt = (owner) ? owner->pvt->rawreadformat : AST_FORMAT_SLINEAR;
 	 int state = (owner) ? owner->_state : AST_STATE_DOWN;
-	 int readlen;
+	 int readlen;	
 	 
 	 fmt = ast2vpbformat(afmt);
+	 
+	 if (fmt < 0) {
+	     p->stopreads = 1;
+	     goto done;
+	 }
+
 	 readlen = VPB_SAMPLES * astformatbits(afmt) / 8;
 
 	 if (p->lastinput != fmt) {
 	     if (option_verbose > 2) 
-		 ast_verbose(" Read_channel ##  %s: Setting record mode\n", 
-			     p->dev);     	     
+		 ast_verbose(" Read_channel ##  %s: Setting record mode, bridge = %d\n", 
+			     p->dev, p->bridge ? 1 : 0);     	     
 	     vpb_record_buf_start(p->handle, fmt);
 	     p->lastinput = fmt;
 	 } 
 
-
-	 if (state == AST_STATE_UP)  /* Read only if up. */
-	      res = vpb_record_buf_sync(p->handle, buf, readlen);
-	
+	 ast_pthread_mutex_lock(&p->lock); {
+	      if (p->bridge) 
+		   if (p->bridge->c0 == p->owner && 
+		       (p->bridge->flags & AST_BRIDGE_REC_CHANNEL_0))
+			bridgerec = 1;
+		   else if (p->bridge->c1 == p->owner && 
+		       (p->bridge->flags & AST_BRIDGE_REC_CHANNEL_1))
+			bridgerec = 1;
+		   else 
+			bridgerec = 0;
+	      else
+		   bridgerec = 1;
+	 } ast_pthread_mutex_unlock(&p->lock);
+	 
+	 if (state == AST_STATE_UP && bridgerec)  /* Read only if up and not bridged, or a bridge for which we can read. */
+	      res = vpb_record_buf_sync(p->handle, readbuf, readlen);
+	 else {
+	      res = 0;
+	      vpb_sleep(10);
+	 }
 	 if (res == VPB_OK) {
-	     fr.subclass = afmt;
-	     fr.samples = VPB_SAMPLES;
-	     fr.datalen = readlen;
-	     fr.data = buf;
-	     
-	     ast_queue_frame(p->owner, &fr, 0);
+	      fr->subclass = afmt;
+	      fr->samples = VPB_SAMPLES;
+	      fr->data = readbuf;
+	      fr->datalen = readlen;
+	      fr->offset = AST_FRIENDLY_OFFSET;
+
+	      ast_pthread_mutex_lock(&p->lock); {    
+		   if (p->owner) ast_queue_frame(p->owner, fr, 0);
+	      } ast_pthread_mutex_unlock(&p->lock);
 	 } else 
-	     vpb_sleep(10);
+	      p->stopreads = 1;
+	 	 
+     done: (void)0;
 	 if (option_verbose > 4)
-	     if (state == AST_STATE_UP)
-		 ast_verbose(" Read_channel  %s (state=%d): got frame: res=%d, rawread=%d, rlen=%d\n", 
-			     p->dev, state, res, owner ? owner->pvt->rawreadformat : -1, readlen);     
+	     ast_verbose(" Read_channel  %s (state=%d), res=%d, bridge=%d\n", 
+			 p->dev, state, res, bridgerec);     
      }
      
-     /* When hangup seen, go away! */
+     /* When stopreads seen, go away! */
      vpb_record_buf_finish(p->handle);
 
+     if (option_verbose > 4)
+	 ast_verbose(" Read_channel  %s terminating, stopreads=%d, owner=%s\n", 
+			     p->dev, p->stopreads, p->owner? "yes" : "no");     
+
      return NULL;
 }
 
-
 static struct ast_channel *vpb_new(struct vpb_pvt *i, int state, char *context)
 {
 	struct ast_channel *tmp; 
@@ -732,6 +905,7 @@ static struct ast_channel *vpb_new(struct vpb_pvt *i, int state, char *context)
 		tmp->pvt->answer = vpb_answer;
 		tmp->pvt->read = vpb_read;
 		tmp->pvt->write = vpb_write;
+		tmp->pvt->bridge = vpb_bridge;
 
 		strncpy(tmp->context, context, sizeof(tmp->context)-1);
 		if (strlen(i->ext))
@@ -756,8 +930,8 @@ static struct ast_channel *vpb_new(struct vpb_pvt *i, int state, char *context)
 			  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
 			  ast_hangup(tmp);
 		     }
-		pthread_mutex_init(&i->lock, NULL);
-		i->hangup = 0; /* So read thread runs. */	
+
+		i->stopreads = 0; /* So read thread runs. */	
 		/* Finally start read monitoring thread. */
 		pthread_create(&i->readthread, NULL, do_chanreads, (void *)i);
 	} else
@@ -961,7 +1135,10 @@ int unload_module()
 
 		while(iflist) {
 		     p = iflist;		    
-
+		     pthread_mutex_destroy(&p->lock);
+		     pthread_cancel(p->readthread);
+		     p->readthread = 0;
+		     
 		     iflist = iflist->next;
 		     
 		     free(p);
@@ -969,6 +1146,11 @@ int unload_module()
 		iflist = NULL;
 	} ast_pthread_mutex_unlock(&iflock);
 	
+	ast_pthread_mutex_lock(&bridge_lock); {
+	     memset(bridges, 0, sizeof bridges);	     
+	} ast_pthread_mutex_unlock(&bridge_lock);
+	pthread_mutex_destroy(&bridge_lock);
+
 	return 0;
 }