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
);