Asterisk 1.4 chan_bluetooth update

I became interested in chan_bluetooth about a week ago and started experimenting with asterisk 1.4 beta2. It doesn’t look like anyone (Theo) is maintaining this, and, as it was not working for me, I began making modifications. After about a week of solid effort I now have a working version with added features that I deemed necessary for meaningful functionality. I added two main features and fixed one bug that was causing occasional asterisk core dumps.

All changes I made were in the “AG” function as I was only interested in being able to use a remote cell to call my bluetooth cell connected to my Asterisk box, and then call out via Voip service (i.e. free cell to pstn calls - mobile to mobile is free in my case)

Caller ID: Although Theo appeared to implement CID functionality, he left out the final step of send the data to Asterisk. I’ve added this and now CID information is getting passed into my Asterisk system (and on to my local phones).

DTMF: It’s the responsibility of the channel driver to handle DTMF. I added this (inband DTMF detection). The remote cell I was using to test this sent about a 2 sec long DTMF so I was forced to add some rudimentary debounce code. Reliability of inband DTMF over cell network isn’t very good to begin with, so some missing keys might occur, and occasionally I still get a multiple report for a single key hit. I have my dialplan read the number back to me before it dials out, just to be sure.

Asterisk core dumps/crashes: When using the original and the modified versions of chan_bluetooth, I would occasionally get an Asterisk crash. When the remote end hang up first, the local bluetooth cell shuts down the sco when the local caller is still reading data. The read fails (and returns -1) and this was not being handled correctly.

Other changes were made which helped my particular bluetooth phone (motorola v195) be more stable, and I would assume other as well. These involved how the phone is answered, hungup and when the channel is brought up.

To compile, copy the code (chan_bluetooth.c) into the channels directory of your asterisk build tree and run “make” at the top level. This should pick up the code. The only problem I was having was with the link/load, and rather than trying to fix the Make, I just added a load script that performs the link/load and copies the resulting chan_bluetooth.so to the install modules directory. This script I put in the channels directory, so after I run the make at the top level, I cd to channels directory and run ./cbt_load. Here’s that script:

gcc -shared -Xlinker -x -o chan_bluetooth.so chan_bluetooth.o -lbluetooth
cp -f chan_bluetooth.so /usr/lib/asterisk/modules

enjoy. Oh, here’s a patch file (made with diff -n, that resulted in the shortest patch file) :

d1 1
a94 4
#include "asterisk.h"

ASTERISK_FILE_VERSION(__FILE__, "$Revision: 43212 $")

a107 1
#include <asterisk/dsp.h>
d174 1
a174 1
#define BLT_DEFAULT_ROLE         BLT_ROLE_AG
d205 1
a205 1
  int wakeread;                      /* blt_read() needs to be woken */
a230 2
  int lfr;                          /* for inband DTMF debounce */
  int hclip;                        /* supress subsequent CLIPs */
a258 3
  //ast processing
  struct ast_dsp *dtmfd                    /* dtmf detection dsp */

a282 1
static struct ast_channel *blt_new(blt_dev_t *dev,int state,const char *context,const char *number);
d489 1
a489 1
        // Outgoing ringing
a519 3
    if (!dev->owner && val==1)
      blt_new(dev, AST_STATE_UP, dev->context, "s");

d522 1
a522 2
        if (dev->sco_running != 1)
          sco_start(dev, -1);
d618 1
a618 1
  int len,wlen;
d676 1
a676 1
      if (len>0) {
a910 18

  /* process with dsp for inband DTMF */
  if (dev->dtmfd) {
    struct ast_frame *f2 = ast_dsp_process(ast, dev->dtmfd, &dev->fr);
    if (f2 && (f2->frametype == AST_FRAME_DTMF)) {
        if (dev->lfr<38) {
          f2->frametype=AST_FRAME_NULL;
          f2->subclass=BLUETOOTH_FORMAT;
          ast_verbose("******ignorig DTMF frame,within 38\n");
        } else {
          ast_verbose("Detected inband DTMF digit: %c on BLT, lfr=%d\n", f2->subclass,dev->lfr);
        }
        dev->lfr=0;
        return f2;
    }
    if (dev->lfr<500) dev->lfr++;
  }

d1114 2
a1115 5
    //send_atcmd(dev, "ATH");
    //send_atcmd(dev, "AT+CHUP");
    send_atcmd(dev, "AT+CKPD=200");
    send_atcmd(dev, "+CIEV: 2,0");
    send_atcmd(dev, "+CIEV: 3,0");
a1121 6
  if (dev->dtmfd) {
    ast_dsp_free(dev->dtmfd);
    dev->dtmfd=NULL;
  }
  dev->hclip=0;

d1159 6
a1164 6
  //if (ast->_state != AST_STATE_UP) {
  //  send_atcmd(dev, "+CIEV: 2,1");
  //  send_atcmd(dev, "+CIEV: 3,0");
  //  sco_start(dev, -1);
  //  ast_setstate(ast, AST_STATE_UP);
  //}
d1194 1
a1194 1
  //ast->type = BLT_CHAN_NAME;
d1214 1
a1214 7
  dev->dtmfd = ast_dsp_new();
  if (dev->dtmfd) {
    ast_dsp_set_features(dev->dtmfd, DSP_FEATURE_DTMF_DETECT);
    ast_dsp_digitmode(dev->dtmfd, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
  }
  dev->lfr=500;
  //ast->language[0] = '\0';
d1725 1
a1725 15
  if (!dev->hclip) {
    strcpy(dev->cid_num,number);
    strcpy(dev->cid_name,name);
    send_atcmd(dev, "AT+CKPD=200");
    //blt_new(dev, AST_STATE_RING, dev->context, "s");
    dev->hclip=1;
  } else {
    ast_log(LOG_WARNING, "Secondary +CLIP\n");
    if (strcmp(dev->cid_num,number)==0 && dev->sco_running!=-1) {
      sco_stop(dev);
      //blt_hangup(dev->owner);
    }
  }

  //blt_new(dev, AST_STATE_RING, dev->context, "s");
d1810 1
a1810 1
  send_atcmd(dev, "AT+CGMI=?");
d3326 1
a3326 4
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bluetooth",
                .load = load_module,
                .unload = unload_module
               );

wow, looks pretty nice!!!

you will probably want to head over to bugs.digium.com and file this as a feature enhancement bug - that would be the best way for this to get looked at.

most of the devs don’t really hang out here much - if you want to talk to them, you probably need to head over to the asterisk-users and/or asterisk-dev mailing lists.

This is great… :smile:
Thank you for this.

Please say you have posted it to the dev team, this is a much needed facility.

Hi Jrigg,
Where did you find the latest chan_bluetooth sources?

Sorry I’m asking that, but I’ve tried the svn and I can not get the code.

Could you send or post a file with the chan_bluetooth.c and other neede files? to make my life easy. :smiley:
I’m a newbie in Linux and I’m not understanding very well what I need to do to get your improvrd code running.

Thanks in advance.

Hi Jrigg,

Your works seems to be very interesting and I really would like to test it. Could you give us a copy of your forked sources of chan_bluetooth rather than a patch? Or perhaps I did not understand how install it?

I’d also tried chan_gsm_bt few months ago but it was not working with my Nokia 6630… Did you test it?

Thanks for your work

In fact, I had never used patch… Can someone help me ?

I already have the chan_bluetooth.c file, this is OK. Then I have to copy the patch file in a text file “chan_bluetooth.diff” (for example) and apply something like “patch chan_bluetooth.c < chan_bluetooth.diff” ? Is it correct ?

My computer returns

patch chan_bluetooth.c < chan_bluetooth.diff

patch: **** Only garbage was found in the patch input.

… ?

The patch is send in html code.
So cut and past won’t work (tabs and spaces are ‘scambled’)

But also someone else has done some work…

cvs -d :pserver:anoncvs at cvs.infradead.org:/home/cvs login

cvs -d :pserver:anoncvs at cvs.infradead.org:/home/cvs co chan_bluetooth

Replace at with @
password is anoncvs

Before I give this a try, can someone confirm if this will work on Asterisk 1.2?

Cheers, Des.

Hi,
I can confirm you chan_gsm_bt is working on version 1.2.X
I’m having the channel driver for bluetooth up and runing.
I was very successful to pair a Motorola v3, and get calls in and out.

Trying to pair other cell phones like Ericsson T39 T636 or Nokia 6230 was a imposible for me.

Communication issues, I don’t know why but every 5 to 10 calls I have problems with the audio, the audio is allways OK from any IP Phone to the cell network, but a big noise from the cell network to the IP Phone.
Audio is excellent.
I was especting for someone with good knoledge to help to fix the situation around the audio.

That’s all from my side

[quote=“amigliora”]Hi,
I can confirm you chan_gsm_bt is working on version 1.2.X
I[/quote]

We are talkinig about chan_bluetooth on this thread, not chan_gsm_bt!

Cheers, Des.

[quote=“amigliora”]Hi Jrigg,
Where did you find the latest chan_bluetooth sources?

Sorry I’m asking that, but I’ve tried the svn and I can not get the code.
[/quote]

The latest source for chan_bluetooth is here:-

crazygreek.co.uk/content/chan_bluetooth

down the bottom is the link to the latest snapshot.

Cheers, Des.

[quote=“cuppie”]The patch is send in html code.
So cut and past won’t work (tabs and spaces are ‘scambled’)[/quote]

Is there a straight forward way of changing the html to what we need?

I think that code is the original unpatched code?

Cheers, Des.

Hi,

I just want to say that the code on Theo’s site , isn’t the latest.

The code from infradead is asterisk 1.2+ ready.
So no patching is needed
The code on the cvs of infradead has changed last week.
Look into the asterisk-dev mailing list archive.

But there is also another one, ready for Asterisk 1.2+
thetechguide.com/howto/aster … tooth.html
So try it.
The only working nokia is the 6310(i)
With newer nokia’s the audio stays on the cell phone for outgoing calls.

I’ve also tried miax.
This works for other nokia’s.
But it uses a slin or gsm codec
I’ve problems when translation gsm to ulaw : poor quality.
The big plus on miax , is the fact it’s maintained.
The developer replies his mailing list.

Here is a unified version of the patch. You should be able to cut and paste to a file and run patch command as follows:

%patch chan_bluetooth.c patchfile

This patch is against the code from Theo’s site, not the latest SVN at digium where DesG checked something in mid October with some minor grammatical cleanup. I could regenerate a new patch against that SVN code if so desired, but I think that there was no functional change in what DesG submitted. DesG, you could do this work and get it into SVN if you want. Anyway here it is again (in unified format this time).

--- chan_bluetooth.c    2006-01-21 22:57:15.000000000 -0700
+++ chan_bluetooth.new  2006-10-05 17:32:38.000000000 -0600
@@ -1,4 +1,3 @@
-#define ASTERISK_VERSION_NUM   010201
 /*
  * Asterisk -- A telephony toolkit for Linux.
  *
@@ -92,6 +91,10 @@
 
 /* ---------------------------------- */
 
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 43212 $")
+
 #include <stdio.h>
 #include <string.h>
 #include <asterisk/lock.h>
@@ -105,6 +108,7 @@
 #include <asterisk/options.h>
 #include <asterisk/cli.h>
 #include <asterisk/callerid.h>
+#include <asterisk/dsp.h>
 #include <asterisk/version.h>
 
 #include <sys/socket.h>
@@ -171,7 +175,7 @@
 
 #define BLT_DEFAULT_CHANNEL_AG   5
 #define BLT_DEFAULT_CHANNEL_HS   6
-#define BLT_DEFAULT_ROLE         BLT_ROLE_HS
+#define BLT_DEFAULT_ROLE         BLT_ROLE_AG
 #define BLT_OBUF_LEN             (48 * 25)
 
 #define BUFLEN (4800)
@@ -202,7 +206,7 @@
   ast_mutex_t sco_lock;              /* SCO lock */
   int sco_pos_in;                    /* Reader in position (drain)*/
   int sco_pos_inrcv;                 /* Reader in position (fill) */
-       int wakeread; /* blt_read() needs to be woken */
+  int wakeread;                      /* blt_read() needs to be woken */
   int sco_pos_out;                   /* Reader out position */
   int sco_sending;                   /* Sending SCO packets */
   char buf[1200];                    /* Incoming data buffer */
@@ -228,6 +232,8 @@
   ast_mutex_t lock;                 /* RFCOMM socket lock */
   char rd_buff[BLT_RDBUFF_MAX];     /* RFCOMM input buffer */
   int rd_buff_pos;                  /* RFCOMM input buffer position */
+  int lfr;                          /* for inband DTMF debounce */
+  int hclip;                        /* supress subsequent CLIPs */
   int ready;                        /* 1 When ready */
   char *context;
 
@@ -256,6 +262,9 @@
 
   blt_dev_t * next;                        /* Next in linked list */
 
+  //ast processing
+  struct ast_dsp *dtmfd                    /* dtmf detection dsp */
+
 };
 
 typedef struct blt_atcb {
@@ -280,6 +289,7 @@
 static int send_atcmd(blt_dev_t * device, const char * fmt, ...);
 static int sco_connect(blt_dev_t * dev);
 static int sco_start(blt_dev_t * dev, int fd);
+static struct ast_channel *blt_new(blt_dev_t *dev,int state,const char *context,const char *number);
 
 /* ---------------------------------- */
 
@@ -486,7 +496,7 @@
 
     switch (val) {
       case 3:
-        // Outgoign ringing
+        // Outgoing ringing
         if (dev->owner && dev->role == BLT_ROLE_AG)
           ast_queue_control(dev->owner, AST_CONTROL_RINGING);
         break;
@@ -517,9 +527,13 @@
 
     dev->call = val;
 
+    if (!dev->owner && val==1)
+      blt_new(dev, AST_STATE_UP, dev->context, "s");
+
     if (dev->owner) {
       if (val == 1) {
-       sco_start(dev, -1);
+        if (dev->sco_running != 1)
+         sco_start(dev, -1);
         ast_queue_control(dev->owner, AST_CONTROL_ANSWER);
       } else if (val == 0)
         ast_queue_control(dev->owner, AST_CONTROL_HANGUP);
@@ -615,7 +629,7 @@
   char c = 1;
   int sending;
   char buf[1024];
-  int len;
+  int len,wlen;
 
   // Avoid deadlock in odd circumstances
 
@@ -673,7 +687,7 @@
 
       len = read(dev->sco, buf, 48);
 
-      if (len) {
+      if (len>0) {
         ast_mutex_lock(&(dev->lock));
 
         if (dev->owner && dev->owner->_state == AST_STATE_UP) {
@@ -908,6 +922,24 @@
   dev->fr.frametype = AST_FRAME_VOICE;
   dev->fr.subclass = BLUETOOTH_FORMAT;
   dev->fr.offset = AST_FRIENDLY_OFFSET;
+
+  /* process with dsp for inband DTMF */
+  if (dev->dtmfd) {
+    struct ast_frame *f2 = ast_dsp_process(ast, dev->dtmfd, &dev->fr);
+    if (f2 && (f2->frametype == AST_FRAME_DTMF)) {
+        if (dev->lfr<38) {
+          f2->frametype=AST_FRAME_NULL;
+          f2->subclass=BLUETOOTH_FORMAT;
+          ast_verbose("******ignorig DTMF frame,within 38\n");
+        } else {
+          ast_verbose("Detected inband DTMF digit: %c on BLT, lfr=%d\n", f2->subclass,dev->lfr);
+        }
+        dev->lfr=0;
+        return f2;
+    }
+    if (dev->lfr<500) dev->lfr++;
+  }
+
   return &dev->fr;
 }
 
@@ -1111,14 +1143,23 @@
   } else if (dev->role == BLT_ROLE_AG) {
 
     // Cancel call.
-    send_atcmd(dev, "ATH");
-    send_atcmd(dev, "AT+CHUP");
+    //send_atcmd(dev, "ATH");
+    //send_atcmd(dev, "AT+CHUP");
+    send_atcmd(dev, "AT+CKPD=200");
+    send_atcmd(dev, "+CIEV: 2,0");
+    send_atcmd(dev, "+CIEV: 3,0");
 
   }
 
   if (dev->status == BLT_STATUS_IN_CALL || dev->status == BLT_STATUS_RINGING)
     dev->status = BLT_STATUS_READY;
 
+  if (dev->dtmfd) {
+    ast_dsp_free(dev->dtmfd);
+    dev->dtmfd=NULL;
+  }
+  dev->hclip=0;
+
   ast->tech_pvt = NULL;
   dev->owner = NULL;
   ast_mutex_unlock(&(dev->lock));
@@ -1156,12 +1197,12 @@
 
   ast_log(LOG_DEBUG, "Answering interface\n");
 
-  if (ast->_state != AST_STATE_UP) {
-    send_atcmd(dev, "+CIEV: 2,1");
-    send_atcmd(dev, "+CIEV: 3,0");
-    sco_start(dev, -1);
-    ast_setstate(ast, AST_STATE_UP);
-  }
+  //if (ast->_state != AST_STATE_UP) {
+  //  send_atcmd(dev, "+CIEV: 2,1");
+  //  send_atcmd(dev, "+CIEV: 3,0");
+  //  sco_start(dev, -1);
+  //  ast_setstate(ast, AST_STATE_UP);
+  //}
 
   ast_mutex_unlock(&dev->lock);
 
@@ -1191,7 +1232,7 @@
 
   ast_setstate(ast, state);
 
-  ast->type = BLT_CHAN_NAME;
+  //ast->type = BLT_CHAN_NAME;
 
   ast->tech_pvt = dev;
 #if ASTERISK_VERSION_NUM > 010107
@@ -1211,7 +1252,13 @@
     ast_set_callerid(ast, dev->cid_num, dev->cid_name, dev->cid_num);
   }
 
-  ast->language[0] = '\0';
+  dev->dtmfd = ast_dsp_new();
+  if (dev->dtmfd) {
+    ast_dsp_set_features(dev->dtmfd, DSP_FEATURE_DTMF_DETECT);
+    ast_dsp_digitmode(dev->dtmfd, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
+  }
+  dev->lfr=500;
+  //ast->language[0] = '\0';
 
   ast->fds[0] = dev->sco_pipe[0];
   write(dev->sco_pipe[1], &c, 1);
@@ -1722,7 +1769,21 @@
   parse_clip(data, number, sizeof(number)-1, name, sizeof(name)-1, &type);
   ast_log(LOG_NOTICE, "Parsed '+CLIP: %s' number='%s' type='%d' name='%s'\n", data, number, type, name);
 
-  blt_new(dev, AST_STATE_RING, dev->context, "s");
+  if (!dev->hclip) {
+    strcpy(dev->cid_num,number);
+    strcpy(dev->cid_name,name);
+    send_atcmd(dev, "AT+CKPD=200");
+    //blt_new(dev, AST_STATE_RING, dev->context, "s");
+    dev->hclip=1;
+  } else {
+    ast_log(LOG_WARNING, "Secondary +CLIP\n");
+    if (strcmp(dev->cid_num,number)==0 && dev->sco_running!=-1) {
+      sco_stop(dev);
+      //blt_hangup(dev->owner);
+    }
+  }
+
+  //blt_new(dev, AST_STATE_RING, dev->context, "s");
 
   return 0;
 }
@@ -1807,7 +1868,7 @@
 void
 ag_clip_response(blt_dev_t * dev, char * cmd)
 {
-  send_atcmd(dev, "AT+CGMI");
+  send_atcmd(dev, "AT+CGMI=?");
   dev->cb = ag_cgmi_valid_response;
 }
 
@@ -3323,4 +3384,7 @@
   return ASTERISK_GPL_KEY;
 }
 
-
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bluetooth",
+                .load = load_module,
+                .unload = unload_module
+               );

[quote=“cuppie”]Hi,

I just want to say that the code on Theo’s site , isn’t the latest.

The code from infradead is asterisk 1.2+ ready.
So no patching is needed
The code on the cvs of infradead has changed last week.
Look into the asterisk-dev mailing list archive.
[/quote]

This cvs version of the code, I believe, is what DesG checked in a few weeks ago. It does not have this patch included, just some minor grammatical cleanup. The patch I provided needs to be run against Theo’s last, not this cvn latest. I can create a patch that could be applied to this cvn version if so desired.

The code you reference here is the same as Theo’s latest, except they’ve added one additional line at the top to make it compile:

#define ASTERISK_VERSION_NUM  010201

The patch provided here can be run against that code if you remove that line first.

[quote=“jrigg”]

This patch is against the code from Theo’s site, not the latest SVN at digium where DesG checked something in mid October with some minor grammatical cleanup. [/quote]

It wasn’t me who checked it in.

You were quite clear which version of code your patch applied to :smile:

Not wishing to bother you with my troubles, but here is what I get applying your patch to Theo’s latest code.:-

[root@CentOS1 chan_bluetooth]# patch chan_bluetooth.c bt.diff
patching file chan_bluetooth.c
Reversed (or previously applied) patch detected!  Assume -R? [n]
Apply anyway? [n]
Skipping patch.
patch: **** malformed patch at line 69: *context,const char *number);

Any pointers welcome :smile:

Cheers, Des.

Ok DesG, I’ve now looked further into this. This patch was not for the code at Theo’s site (I just downloaded that and compared it to my original source and they don’t match). The source I started with matches, I believe, what was in ifradead cvs early October. Ifradead posted a grammatical update sometime late October, so this patch won’t work with that anymore. The other site referenced above (thetechguide) can still be used as follows:

wget http://www.thetechguide.com/howto/asterisk/bluetoothfiles.tar.gz
tar xzf bluetoothfiles.tar.gz

find the chan_bluetooth.c code in the usr/src/asterisk-test/bluetooth/chan_bluetooth directory

then run the patch on that code. I’ve walked through this process and verified the results.

I apologize for thinking the source came from Theo’s site.

Maybe I spoke too soon, when I Cut-n-Paste the patch above it differs from my original patch (as someone stated above) in 5 places where tabs and spaces don’t align. It would be nice if this site allowed uploads so unalterd files could be posted. When I run the cut-n-paste version of the patch on the file it fails as follows:

patching file chan_bluetooth.c
Hunk #1 FAILED at 1.
Hunk #5 FAILED at 206.
Hunk #10 FAILED at 527.
3 out of 20 hunks FAILED – saving rejects to file chan_bluetooth.c.rej

If you (or someone) want to host this somewhere, then pm me your email and I’ll email the patch, the original code and the patched code.

[quote=“cuppie”]

I’ve also tried miax.
This works for other nokia’s.
But it uses a slin or gsm codec
I’ve problems when translation gsm to ulaw : poor quality.
The big plus on miax , is the fact it’s maintained.
The developer replies his mailing list.[/quote]

Can you explain how to use miax ?

ok, I have received the current chan_bluetooth.c file and the patch file from jrigg.

Thanks for that!

Here is a link for anyone that needs a copy:-

Asterisk Bluetooth Files

Please note this is not the full package needed to compile chan_bluetooth. This includes 2 files, the current chan_bluetooth.c from jrigg, and the patch file that you can use to patch the code contained in thetechguide link.

Cheers, Des.