1 diff -Nru asterisk-addons-1.4.8.org/build_tools/menuselect-deps.in asterisk-addons-1.4.8/build_tools/menuselect-deps.in
2 --- asterisk-addons-1.4.8.org/build_tools/menuselect-deps.in 2007-05-14 18:22:44.000000000 +0200
3 +++ asterisk-addons-1.4.8/build_tools/menuselect-deps.in 2009-06-04 22:20:03.000000000 +0200
5 +BLUETOOTH=@PBX_BLUETOOTH@
6 MYSQLCLIENT=@PBX_MYSQLCLIENT@
7 ASTERISK=@PBX_ASTERISK@
8 diff -Nru asterisk-addons-1.4.8.org/channels/chan_mobile.c asterisk-addons-1.4.8/channels/chan_mobile.c
9 --- asterisk-addons-1.4.8.org/channels/chan_mobile.c 1970-01-01 01:00:00.000000000 +0100
10 +++ asterisk-addons-1.4.8/channels/chan_mobile.c 2009-06-04 22:20:03.000000000 +0200
13 + * Asterisk -- An open source telephony toolkit.
15 + * Copyright (C) 1999 - 2006, Digium, Inc.
17 + * Mark Spencer <markster@digium.com>
19 + * See http://www.asterisk.org for more information about
20 + * the Asterisk project. Please do not directly contact
21 + * any of the maintainers of this project for assistance;
22 + * the project provides a web site, mailing lists and IRC
23 + * channels for your use.
25 + * This program is free software, distributed under the terms of
26 + * the GNU General Public License Version 2. See the LICENSE file
27 + * at the top of the source tree.
32 + * \brief Bluetooth Mobile Device channel driver
34 + * \author Dave Bowerman <david.bowerman@gmail.com>
36 + * \ingroup channel_drivers
40 + <depend>bluetooth</depend>
43 +#include <asterisk.h>
45 +ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
49 +#include <sys/socket.h>
50 +#include <sys/time.h>
54 +#include <arpa/inet.h>
56 +#include <sys/ioctl.h>
59 +#include <bluetooth/bluetooth.h>
60 +#include <bluetooth/hci.h>
61 +#include <bluetooth/hci_lib.h>
62 +#include <bluetooth/sdp.h>
63 +#include <bluetooth/sdp_lib.h>
64 +#include <bluetooth/rfcomm.h>
65 +#include <bluetooth/sco.h>
66 +#include <bluetooth/l2cap.h>
68 +#include <asterisk/lock.h>
69 +#include <asterisk/channel.h>
70 +#include <asterisk/config.h>
71 +#include <asterisk/logger.h>
72 +#include <asterisk/module.h>
73 +#include <asterisk/pbx.h>
74 +#include <asterisk/options.h>
75 +#include <asterisk/utils.h>
76 +#include <asterisk/linkedlists.h>
77 +#include <asterisk/cli.h>
78 +#include <asterisk/devicestate.h>
79 +#include <asterisk/causes.h>
80 +#include <asterisk/dsp.h>
81 +#include <asterisk/app.h>
82 +#include <asterisk/manager.h>
84 +#define MBL_CONFIG "mobile.conf"
86 +#define DEVICE_FRAME_SIZE 48
87 +#define DEVICE_FRAME_FORMAT AST_FORMAT_SLINEAR
88 +#define CHANNEL_FRAME_SIZE 320
90 +static int prefformat = DEVICE_FRAME_FORMAT;
92 +static int discovery_interval = 60; /* The device discovery interval, default 60 seconds. */
93 +static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */
94 +static sdp_session_t *sdp_session;
102 + MBL_STATE_INIT = 0,
114 + MBL_STATE_OUTGOING,
118 + MBL_STATE_INCOMING,
126 +struct adapter_pvt {
127 + int dev_id; /* device id */
128 + int hci_socket; /* device descriptor */
129 + char id[31]; /* the 'name' from mobile.conf */
130 + bdaddr_t addr; /* adddress of adapter */
131 + unsigned int inuse:1; /* are we in use ? */
132 + unsigned int alignment_detection:1; /* do alignment detection on this adpater? */
134 + AST_LIST_ENTRY(adapter_pvt) entry;
137 +static AST_RWLIST_HEAD_STATIC(adapters, adapter_pvt);
140 + struct ast_channel *owner; /* Channel we belong to, possibly NULL */
141 + struct ast_frame fr; /* "null" frame */
142 + enum mbl_type type; /* Phone or Headset */
143 + char id[31]; /* The id from mobile.conf */
144 + int group; /* group number for group dialling */
145 + bdaddr_t addr; /* address of device */
146 + struct adapter_pvt *adapter; /* the adapter we use */
147 + char context[AST_MAX_CONTEXT]; /* the context for incoming calls */
148 + char connected; /* is it connected? */
149 + int rfcomm_port; /* rfcomm port number */
150 + int rfcomm_socket; /* rfcomm socket descriptor */
151 + char rfcomm_buf[256];
152 + char io_buf[CHANNEL_FRAME_SIZE + AST_FRIENDLY_OFFSET];
153 + char io_save_buf[DEVICE_FRAME_SIZE];
156 + int sco_socket; /* sco socket descriptor */
157 + pthread_t sco_listener_thread; /* inbound sco listener for this device */
158 + enum mbl_state state; /* monitor thread current state */
159 + pthread_t monitor_thread; /* monitor thread handle */
160 + char dial_number[AST_MAX_EXTENSION]; /* number for the monitor thread to dial */
162 + char ciev_call_0[5]; /* dynamically built reponse strings */
163 + char ciev_call_1[5];
164 + char ciev_callsetup_0[5];
165 + char ciev_callsetup_1[5];
166 + char ciev_callsetup_2[5];
167 + char ciev_callsetup_3[5];
168 + unsigned int no_callsetup:1;
169 + unsigned int has_sms:1;
170 + unsigned int sent_answer:1;
171 + unsigned int do_alignment_detection:1;
172 + unsigned int alignment_detection_triggered:1;
173 + unsigned int do_hangup:1;
174 + unsigned int blackberry:1;
175 + short alignment_samples[4];
176 + int alignment_count;
178 + struct ast_dsp *dsp;
179 + struct ast_frame *dsp_fr;
183 + AST_LIST_ENTRY(mbl_pvt) entry;
186 +static AST_RWLIST_HEAD_STATIC(devices, mbl_pvt);
189 +static const char show_usage[] =
190 +"Usage: mobile show devices\n"
191 +" Shows the state of Bluetooth Cell / Mobile devices.\n";
193 +static const char search_usage[] =
194 +"Usage: mobile search\n"
195 +" Searches for Bluetooth Cell / Mobile devices in range.\n";
197 +static const char rfcomm_usage[] =
198 +"Usage: mobile rfcomm command\n"
199 +" Send command to the rfcomm port.\n";
201 +static int handle_cli_mobile_show_devices(int fd, int argc, char **argv);
202 +static int handle_cli_mobile_search(int fd, int argc, char **argv);
203 +static int handle_cli_mobile_rfcomm(int fd, int argc, char **argv);
205 +static struct ast_cli_entry mbl_cli[] = {
206 + {{"mobile", "show", "devices", NULL}, handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices", show_usage},
207 + {{"mobile", "search", NULL}, handle_cli_mobile_search, "Search for Bluetooth Cell / Mobile devices", search_usage},
208 + {{"mobile", "rfcomm", NULL}, handle_cli_mobile_rfcomm, "Send commands to the rfcomm port for debugging", rfcomm_usage},
212 +static char *app_mblstatus = "MobileStatus";
213 +static char *mblstatus_synopsis = "MobileStatus(Device,Variable)";
214 +static char *mblstatus_desc =
215 +"MobileStatus(Device,Variable)\n"
216 +" Device - Id of mobile device from mobile.conf\n"
217 +" Variable - Variable to store status in will be 1-3.\n"
218 +" In order, Disconnected, Connected & Free, Connected & Busy.\n";
220 +static char *app_mblsendsms = "MobileSendSMS";
221 +static char *mblsendsms_synopsis = "MobileSendSMS(Device,Dest,Message)";
222 +static char *mblsendsms_desc =
223 +"MobileSendSms(Device,Dest,Message)\n"
224 +" Device - Id of device from mobile.conf\n"
225 +" Dest - destination\n"
226 +" Message - text of the message\n";
228 +static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num);
229 +static struct ast_channel *mbl_request(const char *type, int format, void *data, int *cause);
230 +static int mbl_call(struct ast_channel *ast, char *dest, int timeout);
231 +static int mbl_hangup(struct ast_channel *ast);
232 +static int mbl_answer(struct ast_channel *ast);
233 +static int mbl_digit_begin(struct ast_channel *ast, char digit);
234 +static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
235 +static struct ast_frame *mbl_read(struct ast_channel *ast);
236 +static int mbl_write(struct ast_channel *ast, struct ast_frame *frame);
237 +static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
238 +static int mbl_devicestate(void *data);
240 +static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen);
242 +static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel);
243 +static int rfcomm_write(struct mbl_pvt *pvt, char *buf);
244 +static int rfcomm_read(struct mbl_pvt *pvt, char *buf, char flush, int timeout);
246 +static int sco_connect(bdaddr_t src, bdaddr_t dst);
247 +static int sco_write(int s, char *buf, int len);
248 +static int sco_read(int s, char *buf, int len);
250 +static void *do_sco_listen(void *data);
251 +static int sdp_search(char *addr, int profile);
253 +static const struct ast_channel_tech mbl_tech = {
255 + .description = "Bluetooth Mobile Device Channel Driver",
256 + .capabilities = AST_FORMAT_SLINEAR,
257 + .requester = mbl_request,
259 + .hangup = mbl_hangup,
260 + .answer = mbl_answer,
261 + .send_digit_begin = mbl_digit_begin,
262 + .send_digit_end = mbl_digit_end,
264 + .write = mbl_write,
265 + .fixup = mbl_fixup,
266 + .devicestate = mbl_devicestate
269 +/* CLI Commands implementation */
271 +static int handle_cli_mobile_show_devices(int fd, int argc, char **argv)
273 + struct mbl_pvt *pvt;
277 +#define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-5.5s %-3.3s\n"
280 + return RESULT_SHOWUSAGE;
282 + ast_cli(fd, FORMAT1, "ID", "Address", "Group", "Adapter", "Connected", "State", "SMS");
283 + AST_RWLIST_RDLOCK(&devices);
284 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
285 + ba2str(&pvt->addr, bdaddr);
286 + snprintf(group, 5, "%d", pvt->group);
287 + ast_cli(fd, FORMAT1, pvt->id, bdaddr, group, pvt->adapter->id, pvt->connected ? "Yes" : "No",
288 + (pvt->state == MBL_STATE_IDLE) ? "Free" : (pvt->state < MBL_STATE_IDLE) ? "Init" : "Busy",
289 + (pvt->has_sms) ? "Yes" : "No");
291 + AST_RWLIST_UNLOCK(&devices);
295 + return RESULT_SUCCESS;
298 +static int handle_cli_mobile_search(int fd, int argc, char **argv)
300 + struct adapter_pvt *adapter;
301 + inquiry_info *ii = NULL;
302 + int max_rsp, num_rsp;
304 + int i, phport, hsport;
305 + char addr[19] = {0};
306 + char name[31] = {0};
308 +#define FORMAT1 "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"
309 +#define FORMAT2 "%-17.17s %-30.30s %-6.6s %-7.7s %d\n"
312 + return RESULT_SHOWUSAGE;
314 + /* find a free adapter */
315 + AST_RWLIST_RDLOCK(&adapters);
316 + AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
317 + if (!adapter->inuse)
320 + AST_RWLIST_UNLOCK(&adapters);
323 + ast_cli(fd, "All Bluetooth adapters are in use at this time.\n");
324 + return RESULT_SUCCESS;
329 + flags = IREQ_CACHE_FLUSH;
331 + ii = alloca(max_rsp * sizeof(inquiry_info));
332 + num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
334 + ast_cli(fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
335 + for (i = 0; i < num_rsp; i++) {
336 + ba2str(&(ii + i)->bdaddr, addr);
338 + if (hci_read_remote_name(adapter->hci_socket, &(ii + i)->bdaddr, sizeof(name) - 1, name, 0) < 0)
339 + strcpy(name, "[unknown]");
340 + phport = sdp_search(addr, HANDSFREE_AGW_PROFILE_ID);
342 + hsport = sdp_search(addr, HEADSET_PROFILE_ID);
345 + ast_cli(fd, FORMAT2, addr, name, (phport > 0 || hsport > 0) ? "Yes" : "No",
346 + (phport > 0) ? "Phone" : "Headset", (phport > 0) ? phport : hsport);
349 + ast_cli(fd, "No Bluetooth Cell / Mobile devices found.\n");
354 + return RESULT_SUCCESS;
357 +static int handle_cli_mobile_rfcomm(int fd, int argc, char **argv)
360 + struct mbl_pvt *pvt = NULL;
363 + return RESULT_SHOWUSAGE;
365 + AST_RWLIST_RDLOCK(&devices);
366 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
367 + if (!strcmp(pvt->id, argv[2]))
370 + AST_RWLIST_UNLOCK(&devices);
372 + if (!pvt || !pvt->connected) {
373 + ast_cli(fd, "Device %s not found.\n", argv[2]);
374 + return RESULT_SUCCESS;
377 + snprintf(buf, sizeof(buf), "%s\r", argv[3]);
378 + rfcomm_write(pvt, buf);
380 + return RESULT_SUCCESS;
385 + Dialplan applications implementation
389 +static int mbl_status_exec(struct ast_channel *ast, void *data)
392 + struct mbl_pvt *pvt;
397 + AST_DECLARE_APP_ARGS(args,
398 + AST_APP_ARG(device);
399 + AST_APP_ARG(variable);
402 + if (ast_strlen_zero(data))
405 + parse = ast_strdupa(data);
407 + AST_STANDARD_APP_ARGS(args, parse);
409 + if (ast_strlen_zero(args.device) || ast_strlen_zero(args.variable))
414 + AST_RWLIST_RDLOCK(&devices);
415 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
416 + if (!strcmp(pvt->id, args.device))
419 + AST_RWLIST_UNLOCK(&devices);
422 + if (pvt->connected)
428 + snprintf(status, sizeof(status), "%d", stat);
429 + pbx_builtin_setvar_helper(ast, args.variable, status);
435 +static int mbl_sendsms_exec(struct ast_channel *ast, void *data)
438 + struct mbl_pvt *pvt;
441 + AST_DECLARE_APP_ARGS(args,
442 + AST_APP_ARG(device);
444 + AST_APP_ARG(message);
447 + if (ast_strlen_zero(data))
450 + parse = ast_strdupa(data);
452 + AST_STANDARD_APP_ARGS(args, parse);
454 + if (ast_strlen_zero(args.device)) {
455 + ast_log(LOG_ERROR,"NULL device for message -- SMS will not be sent.\n");
459 + if (ast_strlen_zero(args.dest)) {
460 + ast_log(LOG_ERROR,"NULL destination for message -- SMS will not be sent.\n");
464 + if (ast_strlen_zero(args.message)) {
465 + ast_log(LOG_ERROR,"NULL Message to be sent -- SMS will not be sent.\n");
469 + AST_RWLIST_RDLOCK(&devices);
470 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
471 + if (!strcmp(pvt->id, args.device))
474 + AST_RWLIST_UNLOCK(&devices);
477 + ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n", args.device);
481 + if (!pvt->connected) {
482 + ast_log(LOG_ERROR,"Bluetooth device %s wasn't connected -- SMS will not be sent.\n", args.device);
486 + if (!pvt->has_sms) {
487 + ast_log(LOG_ERROR,"Bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n", args.device);
491 + if (pvt->state != MBL_STATE_IDLE) {
492 + ast_log(LOG_ERROR,"Bluetooth device %s isn't IDLE -- SMS will not be sent.\n", args.device);
496 + ast_copy_string(pvt->dial_number, args.dest, sizeof(pvt->dial_number));
497 + ast_copy_string(pvt->sms_txt, args.message, sizeof(pvt->sms_txt));
498 + pvt->state = MBL_STATE_OUTSMS;
506 + Channel Driver callbacks
510 +static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num)
513 + struct ast_channel *chn;
515 + if (pipe(pvt->io_pipe) == -1) {
516 + ast_log(LOG_ERROR, "Failed to create io_pipe.\n");
520 + if (pvt->sco_socket != -1)
521 + close(pvt->sco_socket);
522 + pvt->sco_socket = -1;
523 + pvt->io_save_len = 0;
524 + pvt->sent_answer = 0;
525 + pvt->skip_frames = 0;
526 + pvt->alignment_count = 0;
527 + pvt->alignment_detection_triggered = 0;
528 + if (pvt->adapter->alignment_detection)
529 + pvt->do_alignment_detection = 1;
531 + pvt->do_alignment_detection = 0;
532 + pvt->do_hangup = 1;
533 + chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context, 0, "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
535 + chn->tech = &mbl_tech;
536 + chn->nativeformats = prefformat;
537 + chn->rawreadformat = prefformat;
538 + chn->rawwriteformat = prefformat;
539 + chn->writeformat = prefformat;
540 + chn->readformat = prefformat;
541 + chn->tech_pvt = pvt;
542 + chn->fds[0] = pvt->io_pipe[0];
543 + if (state == AST_STATE_RING)
545 + ast_string_field_set(chn, language, "en");
554 +static struct ast_channel *mbl_request(const char *type, int format, void *data, int *cause)
557 + struct ast_channel *chn = NULL;
558 + struct mbl_pvt *pvt;
559 + char *dest_dev = NULL;
560 + char *dest_num = NULL;
561 + int oldformat, group = -1;
564 + ast_log(LOG_WARNING, "Channel requested with no data\n");
565 + *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
569 + oldformat = format;
570 + format &= (AST_FORMAT_SLINEAR);
572 + ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%d'\n", oldformat);
573 + *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
577 + dest_dev = ast_strdupa((char *)data);
579 + dest_num = strchr(dest_dev, '/');
581 + *dest_num++ = 0x00;
583 + if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) {
584 + group = atoi(&dest_dev[1]);
587 + /* Find requested device and make sure it's connected. */
588 + AST_RWLIST_RDLOCK(&devices);
589 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
590 + if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) {
592 + } else if (!strcmp(pvt->id, dest_dev)) {
596 + AST_RWLIST_UNLOCK(&devices);
597 + if (!pvt || !pvt->connected || pvt->owner) {
598 + ast_log(LOG_WARNING, "Request to call on device %s which is not connected / already in use.\n", dest_dev);
599 + *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
603 + if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) {
604 + ast_log(LOG_WARNING, "Can't determine destination number.\n");
605 + *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
609 + chn = mbl_new(AST_STATE_DOWN, pvt, NULL);
611 + ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
612 + *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
620 +static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
623 + struct mbl_pvt *pvt;
624 + char *dest_dev = NULL;
625 + char *dest_num = NULL;
627 + dest_dev = ast_strdupa((char *)dest);
629 + pvt = ast->tech_pvt;
631 + if (pvt->type == MBL_TYPE_PHONE) {
632 + dest_num = strchr(dest_dev, '/');
634 + ast_log(LOG_WARNING, "Cant determine destination number.\n");
637 + *dest_num++ = 0x00;
640 + if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
641 + ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast->name);
645 + ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
647 + if (pvt->type == MBL_TYPE_PHONE) {
648 + ast_copy_string(pvt->dial_number, dest_num, sizeof(pvt->dial_number));
649 + pvt->state = MBL_STATE_DIAL;
650 + pvt->dial_timeout = (timeout == 0) ? 30 : timeout;
652 + pvt->state = MBL_STATE_RING;
659 +static int mbl_hangup(struct ast_channel *ast)
662 + struct mbl_pvt *pvt;
664 + if (!ast->tech_pvt) {
665 + ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
668 + pvt = ast->tech_pvt;
670 + ast_log(LOG_DEBUG, "Hanging up device %s.\n", pvt->id);
674 + close(pvt->io_pipe[0]);
675 + close(pvt->io_pipe[1]);
677 + if (pvt->type == MBL_TYPE_HEADSET && pvt->sco_socket != -1) {
678 + close(pvt->sco_socket);
679 + pvt->sco_socket = -1;
682 + if ((pvt->state == MBL_STATE_INCOMING || pvt->state == MBL_STATE_OUTGOING || pvt->state == MBL_STATE_DIAL1 || pvt->state == MBL_STATE_RING3) && pvt->type == MBL_TYPE_PHONE) {
683 + if (pvt->do_hangup) {
684 + rfcomm_write(pvt, "AT+CHUP\r");
686 + pvt->state = MBL_STATE_HANGUP;
687 + pvt->hangup_count = 0;
689 + pvt->state = MBL_STATE_IDLE;
692 + ast->tech_pvt = NULL;
693 + ast_setstate(ast, AST_STATE_DOWN);
699 +static int mbl_answer(struct ast_channel *ast)
702 + struct mbl_pvt *pvt;
704 + pvt = ast->tech_pvt;
706 + rfcomm_write(pvt, "ATA\r");
708 + ast_setstate(ast, AST_STATE_UP);
710 + pvt->sent_answer = 1;
716 +static int mbl_digit_begin(struct ast_channel *chan, char digit)
723 +static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
726 + struct mbl_pvt *pvt;
729 + pvt = ast->tech_pvt;
731 + if (pvt->type == MBL_TYPE_HEADSET)
734 + ast_log(LOG_DEBUG, "Dialed %c\n", digit);
749 + snprintf(buf, sizeof(buf), "AT+VTS=%c\r", digit);
750 + rfcomm_write(pvt, buf);
753 + ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
761 +static struct ast_frame *mbl_read(struct ast_channel *ast)
764 + struct mbl_pvt *pvt = ast->tech_pvt;
765 + struct ast_frame *f;
768 + //ast_log(LOG_DEBUG, "*** mbl_read()\n");
771 + return &ast_null_frame;
773 + memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
774 + pvt->fr.frametype = AST_FRAME_VOICE;
775 + pvt->fr.subclass = DEVICE_FRAME_FORMAT;
776 + pvt->fr.datalen = CHANNEL_FRAME_SIZE;
777 + pvt->fr.samples = CHANNEL_FRAME_SIZE / 2;
778 + pvt->fr.src = "Mobile";
779 + pvt->fr.offset = AST_FRIENDLY_OFFSET;
780 + pvt->fr.mallocd = 0;
781 + pvt->fr.delivery.tv_sec = 0;
782 + pvt->fr.delivery.tv_usec = 0;
783 + pvt->fr.data = pvt->io_buf + AST_FRIENDLY_OFFSET;
785 + if ((r = read(pvt->io_pipe[0], pvt->fr.data, CHANNEL_FRAME_SIZE)) != CHANNEL_FRAME_SIZE) {
787 + ast_log(LOG_ERROR, "read error %d\n", errno);
788 + return &ast_null_frame;
790 + pvt->fr.datalen = r;
791 + pvt->fr.samples = r / 2;
795 + f = ast_dsp_process(0, pvt->dsp, &pvt->fr);
796 + if (f && (f->frametype == AST_FRAME_DTMF_END)) {
797 + pvt->fr.frametype = AST_FRAME_DTMF_END;
798 + pvt->fr.subclass = f->subclass;
805 +static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
808 + struct mbl_pvt *pvt = ast->tech_pvt;
809 + int i, r, io_need, num_frames;
810 + char *pfr, buf[DEVICE_FRAME_SIZE];
812 + //ast_log(LOG_DEBUG, "*** mbl_write\n");
814 + if (frame->frametype != AST_FRAME_VOICE) {
819 + if (pvt->io_save_len > 0) {
820 + io_need = DEVICE_FRAME_SIZE - pvt->io_save_len;
821 + memcpy(pvt->io_save_buf + pvt->io_save_len, frame->data, io_need);
822 + sco_write(pvt->sco_socket, pvt->io_save_buf, DEVICE_FRAME_SIZE);
823 + if ((r = sco_read(pvt->sco_socket, buf, DEVICE_FRAME_SIZE))) {
824 + if (pvt->do_alignment_detection)
825 + do_alignment_detection(pvt, buf, r);
826 + if (ast->_state == AST_STATE_UP) /* Dont queue the audio in the pipe if the call is not up yet. just toss it. */
827 + sco_write(pvt->io_pipe[1], buf, r);
831 + num_frames = (frame->datalen - io_need) / DEVICE_FRAME_SIZE;
832 + pfr = frame->data + io_need;
834 + for (i=0; i<num_frames; i++) {
835 + sco_write(pvt->sco_socket, pfr, DEVICE_FRAME_SIZE);
836 + if ((r = sco_read(pvt->sco_socket, buf, DEVICE_FRAME_SIZE))) {
837 + if (pvt->do_alignment_detection)
838 + do_alignment_detection(pvt, buf, r);
839 + if (ast->_state == AST_STATE_UP)
840 + sco_write(pvt->io_pipe[1], buf, r);
842 + pfr += DEVICE_FRAME_SIZE;
845 + pvt->io_save_len = (frame->datalen - io_need) - (num_frames * DEVICE_FRAME_SIZE);
846 + if (pvt->io_save_len > 0) {
847 + memcpy(pvt->io_save_buf, pfr, pvt->io_save_len);
854 +static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
857 + struct mbl_pvt *pvt = oldchan->tech_pvt;
859 + if (pvt && pvt->owner == oldchan)
860 + pvt->owner = newchan;
866 +static int mbl_devicestate(void *data)
870 + int res = AST_DEVICE_INVALID;
871 + struct mbl_pvt *pvt;
873 + device = ast_strdupa(S_OR(data, ""));
875 + ast_log(LOG_DEBUG, "Checking device state for device %s\n", device);
877 + AST_RWLIST_RDLOCK(&devices);
878 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
879 + if (!strcmp(pvt->id, device))
882 + AST_RWLIST_UNLOCK(&devices);
885 + if (pvt->connected) {
887 + res = AST_DEVICE_INUSE;
889 + res = AST_DEVICE_NOT_INUSE;
905 + do_alignment_detection()
907 + This routine attempts to detect where we get misaligned sco audio data from the bluetooth adaptor.
909 + Its enabled by alignmentdetect=yes under the adapter entry in mobile.conf
911 + Some adapters suffer a problem where occasionally they will byte shift the audio stream one byte to the right.
912 + The result is static or white noise on the inbound (from the adapter) leg of the call.
913 + This is characterised by a sudden jump in magnitude of the value of the 16 bit samples.
915 + Here we look at the first 4 48 byte frames. We average the absolute values of each sample in the frame,
916 + then average the sum of the averages of frames 1, 2, and 3.
917 + Frame zero is usually zero.
918 + If the end result > 100, and it usually is if we have the problem, set a flag and compensate by shifting the bytes
919 + for each subsequent frame during the call.
921 + If the result is <= 100 then clear the flag so we dont come back in here...
923 + This seems to work OK....
927 +static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen)
934 + if (pvt->alignment_detection_triggered) {
935 + for (i=buflen, p=buf+buflen-1; i>0; i--, p--)
941 + if (pvt->alignment_count < 4) {
943 + for (i=0, a=0; i<buflen/2; i++) {
947 + pvt->alignment_samples[pvt->alignment_count++] = a;
951 + ast_log(LOG_DEBUG, "Alignment Detection result is [%-d %-d %-d %-d]\n", pvt->alignment_samples[0], pvt->alignment_samples[1], pvt->alignment_samples[2], pvt->alignment_samples[3]);
953 + a = abs(pvt->alignment_samples[1]) + abs(pvt->alignment_samples[2]) + abs(pvt->alignment_samples[3]);
956 + pvt->alignment_detection_triggered = 1;
957 + ast_log(LOG_DEBUG, "Alignment Detection Triggered.\n");
959 + pvt->do_alignment_detection = 0;
969 +static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel) {
971 + struct sockaddr_rc addr;
974 + if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
975 + ast_log(LOG_DEBUG, "socket() failed (%d).\n", errno);
979 + memset(&addr, 0, sizeof(addr));
980 + addr.rc_family = AF_BLUETOOTH;
981 + bacpy(&addr.rc_bdaddr, &src);
982 + addr.rc_channel = (uint8_t) 1;
983 + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
984 + ast_log(LOG_DEBUG, "bind() failed (%d).\n", errno);
989 + memset(&addr, 0, sizeof(addr));
990 + addr.rc_family = AF_BLUETOOTH;
991 + bacpy(&addr.rc_bdaddr, &dst);
992 + addr.rc_channel = remote_channel;
993 + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
994 + ast_log(LOG_DEBUG, "connect() failed (%d).\n", errno);
1003 +static int rfcomm_write(struct mbl_pvt *pvt, char *buf)
1007 + ssize_t num_write;
1010 + ast_log(LOG_DEBUG, "rfcomm_write() (%s) [%s]\n", pvt->id, buf);
1011 + len = strlen(buf);
1014 + if ((num_write = write(pvt->rfcomm_socket, p, len)) == -1) {
1015 + ast_log(LOG_DEBUG, "rfcomm_write() error [%d]\n", errno);
1028 + Here we need to return complete '\r' terminated single responses to the devices monitor thread, or
1029 + a timeout if nothing is available.
1030 + The rfcomm connection to the device is asynchronous, so there is no guarantee that responses will
1031 + be returned in a single read() call. We handle this by buffering the input and returning one response
1032 + per call, or a timeout if nothing is available.
1036 +static int rfcomm_read(struct mbl_pvt *pvt, char *buf, char flush, int timeout)
1039 + int sel, rlen, slen;
1041 + struct timeval tv;
1045 + if ((p = strchr(pvt->rfcomm_buf, '\r'))) {
1049 + memmove(buf, pvt->rfcomm_buf, strlen(pvt->rfcomm_buf));
1050 + *(buf + strlen(pvt->rfcomm_buf)) = 0x00;
1051 + memmove(pvt->rfcomm_buf, p, strlen(p));
1052 + *(pvt->rfcomm_buf+strlen(p)) = 0x00;
1056 + pvt->rfcomm_buf[0] = 0x00;
1060 + FD_SET(pvt->rfcomm_socket, &rfds);
1062 + tv.tv_sec = timeout;
1065 + if ((sel = select(pvt->rfcomm_socket + 1, &rfds, NULL, NULL, &tv)) > 0) {
1066 + if (FD_ISSET(pvt->rfcomm_socket, &rfds)) {
1067 + slen = strlen(pvt->rfcomm_buf);
1068 + rlen = read(pvt->rfcomm_socket, pvt->rfcomm_buf + slen, sizeof(pvt->rfcomm_buf) - slen - 1);
1070 + pvt->rfcomm_buf[slen+rlen] = 0x00;
1071 + if ((p = strchr(pvt->rfcomm_buf, '\r'))) {
1075 + memmove(buf, pvt->rfcomm_buf, strlen(pvt->rfcomm_buf));
1076 + *(buf + strlen(pvt->rfcomm_buf)) = 0x00;
1077 + memmove(pvt->rfcomm_buf, p, strlen(p));
1078 + *(pvt->rfcomm_buf+strlen(p)) = 0x00;
1084 + } else if (sel == 0) { /* timeout */
1098 +static int sco_connect(bdaddr_t src, bdaddr_t dst)
1101 + struct sockaddr_sco addr;
1104 + if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1105 + ast_log(LOG_DEBUG, "socket() failed (%d).\n", errno);
1109 + memset(&addr, 0, sizeof(addr));
1110 + addr.sco_family = AF_BLUETOOTH;
1111 + bacpy(&addr.sco_bdaddr, &src);
1112 + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1113 + ast_log(LOG_DEBUG, "bind() failed (%d).\n", errno);
1118 + memset(&addr, 0, sizeof(addr));
1119 + addr.sco_family = AF_BLUETOOTH;
1120 + bacpy(&addr.sco_bdaddr, &dst);
1122 + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1123 + ast_log(LOG_DEBUG, "sco connect() failed (%d).\n", errno);
1132 +static int sco_write(int s, char *buf, int len)
1138 + ast_log(LOG_DEBUG, "sco_write() not ready\n");
1142 + ast_log(LOG_DEBUG, "sco_write()\n");
1144 + r = write(s, buf, len);
1146 + ast_log(LOG_DEBUG, "sco write error %d\n", errno);
1154 +static int sco_read(int s, char *buf, int len)
1160 + ast_log(LOG_DEBUG, "sco_read() not ready\n");
1164 + ast_log(LOG_DEBUG, "sco_read()\n");
1166 + r = read(s, buf, len);
1168 + ast_log(LOG_DEBUG, "sco_read() error %d\n", errno);
1182 +static int sdp_search(char *addr, int profile)
1185 + sdp_session_t *session = 0;
1188 + uint32_t range = 0x0000ffff;
1189 + sdp_list_t *response_list, *search_list, *attrid_list;
1191 + sdp_list_t *proto_list;
1192 + sdp_record_t *sdprec;
1194 + str2ba(addr, &bdaddr);
1196 + session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
1198 + ast_log(LOG_DEBUG, "sdp_connect() failed on device %s.\n", addr);
1202 + sdp_uuid32_create(&svc_uuid, profile);
1203 + search_list = sdp_list_append(0, &svc_uuid);
1204 + attrid_list = sdp_list_append(0, &range);
1205 + response_list = 0x00;
1206 + status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
1207 + if (status == 0) {
1208 + if (response_list) {
1209 + sdprec = (sdp_record_t *) response_list->data;
1210 + proto_list = 0x00;
1211 + if (sdp_get_access_protos(sdprec, &proto_list) == 0) {
1212 + port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
1213 + sdp_list_free(proto_list, 0);
1215 + sdp_record_free(sdprec);
1216 + sdp_list_free(response_list, 0);
1218 + ast_log(LOG_DEBUG, "No responses returned for device %s.\n", addr);
1220 + ast_log(LOG_DEBUG, "sdp_service_search_attr_req() failed on device %s.\n", addr);
1222 + sdp_list_free(search_list, 0);
1223 + sdp_list_free(attrid_list, 0);
1224 + sdp_close(session);
1230 +static sdp_session_t *sdp_register(void)
1233 + uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
1234 + uint8_t rfcomm_channel = 1;
1235 + const char *service_name = "Asterisk PABX";
1236 + const char *service_dsc = "Asterisk PABX";
1237 + const char *service_prov = "Asterisk";
1239 + uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class1_uuid, svc_class2_uuid;
1240 + sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
1241 + sdp_data_t *channel = 0;
1244 + sdp_session_t *session = 0;
1246 + sdp_record_t *record = sdp_record_alloc();
1248 + sdp_uuid128_create(&svc_uuid, &service_uuid_int);
1249 + sdp_set_service_id(record, svc_uuid);
1251 + sdp_uuid32_create(&svc_class1_uuid, GENERIC_AUDIO_SVCLASS_ID);
1252 + sdp_uuid32_create(&svc_class2_uuid, HEADSET_PROFILE_ID);
1254 + svc_uuid_list = sdp_list_append(0, &svc_class1_uuid);
1255 + svc_uuid_list = sdp_list_append(svc_uuid_list, &svc_class2_uuid);
1256 + sdp_set_service_classes(record, svc_uuid_list);
1258 + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1259 + root_list = sdp_list_append(0, &root_uuid);
1260 + sdp_set_browse_groups( record, root_list );
1262 + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1263 + l2cap_list = sdp_list_append(0, &l2cap_uuid);
1264 + proto_list = sdp_list_append(0, l2cap_list);
1266 + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1267 + channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
1268 + rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
1269 + sdp_list_append(rfcomm_list, channel);
1270 + sdp_list_append(proto_list, rfcomm_list);
1272 + access_proto_list = sdp_list_append(0, proto_list);
1273 + sdp_set_access_protos(record, access_proto_list);
1275 + sdp_set_info_attr(record, service_name, service_prov, service_dsc);
1277 + if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
1278 + ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
1280 + err = sdp_record_register(session, record, 0);
1282 + sdp_data_free(channel);
1283 + sdp_list_free(rfcomm_list, 0);
1284 + sdp_list_free(root_list, 0);
1285 + sdp_list_free(access_proto_list, 0);
1286 + sdp_list_free(svc_uuid_list, 0);
1298 +static void *do_monitor_phone(void *data)
1301 + struct mbl_pvt *pvt = (struct mbl_pvt *)data;
1302 + struct ast_channel *chn;
1305 + char cid_num[AST_MAX_EXTENSION], *pcids, *pcide;
1306 + int s, t, i, smsi;
1307 + int group, group2;
1308 + int callp = 0, callsetupp;
1309 + char brsf, nsmode, *p, *p1;
1311 + char sms_txt[160];
1313 + brsf = nsmode = 0;
1315 + if (!rfcomm_write(pvt, "AT+BRSF=4\r"))
1320 + if (pvt->state == MBL_STATE_DIAL1)
1321 + t = pvt->dial_timeout;
1322 + else if (pvt->state == MBL_STATE_HANGUP)
1324 + else if (pvt->state == MBL_STATE_OUTSMS1)
1326 + else if (pvt->state == MBL_STATE_OUTSMS2)
1331 + s = rfcomm_read(pvt, buf, 0, t);
1333 + if ((s > 0) && (buf[0] != 0x0) && (buf[0] != '\r')) {
1334 + ast_log(LOG_DEBUG, "rfcomm_read() (%s) [%s]\n", pvt->id, buf);
1335 + switch (pvt->state) {
1336 + case MBL_STATE_INIT:
1337 + if (strstr(buf, "+BRSF:")) {
1339 + } else if (strstr(buf, "ERROR") && !nsmode) { /* Hmmm, Non-Standard Phone, just continue */
1340 + rfcomm_write(pvt, "AT+CIND=?\r");
1343 + } else if (strstr(buf, "OK") && brsf) {
1344 + if (pvt->blackberry) {
1345 + rfcomm_write(pvt, "AT+CMER=3,0,0,1\r");
1346 + pvt->state = MBL_STATE_INIT3;
1348 + rfcomm_write(pvt, "AT+CIND=?\r");
1353 + case MBL_STATE_INIT1:
1354 + if (strstr(buf, "+CIND:")) {
1355 + group = callp = callsetupp = 0;
1357 + for (i=0; i<strlen(buf); i++) {
1358 + if (buf[i] == '(')
1360 + if (buf[i] == ')') {
1365 + if (strstr(buf+i, "\"call\""))
1367 + if (strstr(buf+i, "\"call_setup\""))
1368 + callsetupp = group2;
1369 + if (strstr(buf+i, "\"callsetup\""))
1370 + callsetupp = group2;
1372 + snprintf(pvt->ciev_call_0, sizeof(pvt->ciev_call_0), "%d,0", callp);
1373 + snprintf(pvt->ciev_call_1, sizeof(pvt->ciev_call_1), "%d,1", callp);
1374 + snprintf(pvt->ciev_callsetup_0, sizeof(pvt->ciev_callsetup_0), "%d,0", callsetupp);
1375 + snprintf(pvt->ciev_callsetup_1, sizeof(pvt->ciev_callsetup_1), "%d,1", callsetupp);
1376 + snprintf(pvt->ciev_callsetup_2, sizeof(pvt->ciev_callsetup_2), "%d,2", callsetupp);
1377 + snprintf(pvt->ciev_callsetup_3, sizeof(pvt->ciev_callsetup_3), "%d,3", callsetupp);
1378 + if (callsetupp == 0) /* This phone has no call setup indication!! ... */
1379 + pvt->no_callsetup = 1;
1380 + ast_log(LOG_DEBUG, "CIEV_CALL=%d CIEV_CALLSETUP=%d\n", callp, callsetupp);
1382 + if (strstr(buf, "OK")) {
1383 + rfcomm_write(pvt, "AT+CIND?\r");
1387 + case MBL_STATE_INIT2:
1388 + if ((p = strstr(buf, "+CIND:"))) {
1390 + if (*(p+(callp*2)) == '1') {
1391 + ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
1394 + } else if (strstr(buf, "OK")) {
1395 + if (pvt->blackberry) {
1396 + rfcomm_write(pvt, "AT+CLIP=1\r");
1397 + pvt->state = MBL_STATE_INIT4;
1399 + rfcomm_write(pvt, "AT+CMER=3,0,0,1\r");
1404 + case MBL_STATE_INIT3:
1405 + if (strstr(buf, "OK")) {
1406 + if (pvt->blackberry) {
1407 + rfcomm_write(pvt, "AT+CIND=?\r");
1408 + pvt->state = MBL_STATE_INIT1;
1410 + rfcomm_write(pvt, "AT+CLIP=1\r");
1415 + case MBL_STATE_INIT4:
1416 + if (strstr(buf, "OK")) {
1417 + rfcomm_write(pvt, "AT+VGS=15\r");
1421 + case MBL_STATE_INIT5:
1422 + if (strstr(buf, "OK")) {
1423 + rfcomm_write(pvt, "AT+CMGF=1\r");
1427 + case MBL_STATE_INIT6:
1428 + if (strstr(buf, "ERROR")) { /* No SMS Support ! */
1429 + pvt->state = MBL_STATE_PREIDLE;
1430 + } else if (strstr(buf, "OK")) {
1431 + rfcomm_write(pvt, "AT+CNMI=2,1,0,1,0\r");
1435 + case MBL_STATE_INIT7:
1436 + if (strstr(buf, "OK")) { /* We have SMS Support */
1438 + pvt->state = MBL_STATE_PREIDLE;
1439 + } else if (strstr(buf, "ERROR")) {
1441 + pvt->state = MBL_STATE_PREIDLE;
1444 + case MBL_STATE_PREIDLE: /* Nothing handled here, wait for timeout, then off we go... */
1446 + case MBL_STATE_IDLE:
1447 + ast_log(LOG_DEBUG, "Device %s [%s]\n", pvt->id, buf);
1448 + if (strstr(buf, "RING")) {
1449 + pvt->state = MBL_STATE_RING;
1450 + } else if (strstr(buf, "+CIEV:")) {
1451 + if (strstr(buf, pvt->ciev_callsetup_3)) { /* User has dialed out on handset */
1452 + monitor = 0; /* We disconnect now, as he is */
1453 + } /* probably leaving BT range... */
1456 + case MBL_STATE_DIAL: /* Nothing handled here, we need to wait for a timeout */
1458 + case MBL_STATE_DIAL1:
1459 + if (strstr(buf, "OK")) {
1460 + if (pvt->no_callsetup) {
1461 + ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
1463 + ast_setstate(pvt->owner, AST_STATE_RINGING);
1465 + pvt->state = MBL_STATE_OUTGOING;
1468 + case MBL_STATE_OUTGOING:
1469 + if (strstr(buf, "+CIEV")) {
1470 + if (strstr(buf, pvt->ciev_call_0)) { /* call was hung up */
1471 + pvt->do_hangup = 0;
1472 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1473 + } else if (strstr(buf, pvt->ciev_callsetup_3)) { /* b-party ringing */
1474 + ast_queue_control(pvt->owner, AST_CONTROL_RINGING);
1475 + } else if (strstr(buf, pvt->ciev_call_1) && !pvt->no_callsetup) { /* b-party answer */
1476 + ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
1480 + case MBL_STATE_RING:
1481 + cid_num[0] = 0x00;
1482 + if ((pcids = strstr(buf, "+CLIP:"))) {
1483 + if ((pcids = strchr(pcids, '"'))) {
1484 + if ((pcide = strchr(pcids+1, '"'))) {
1485 + strncpy(cid_num, pcids+1, pcide - pcids - 1);
1486 + cid_num[pcide - pcids - 1] = 0x00;
1489 + chn = mbl_new(AST_STATE_RING, pvt, cid_num);
1491 + if (ast_pbx_start(chn)) {
1492 + ast_log(LOG_ERROR, "Unable to start pbx on incoming call.\n");
1495 + pvt->state = MBL_STATE_RING3;
1497 + ast_log(LOG_ERROR, "Unable to allocate channel for incoming call.\n");
1498 + rfcomm_write(pvt, "AT+CHUP\r");
1499 + pvt->state = MBL_STATE_IDLE;
1503 + case MBL_STATE_RING2:
1504 + chn = mbl_new(AST_STATE_RING, pvt, cid_num);
1506 + if (ast_pbx_start(chn)) {
1507 + ast_log(LOG_ERROR, "Unable to start pbx on incoming call.\n");
1510 + pvt->state = MBL_STATE_RING3;
1512 + ast_log(LOG_ERROR, "Unable to allocate channel for incoming call.\n");
1513 + rfcomm_write(pvt, "AT+CHUP\r");
1514 + pvt->state = MBL_STATE_IDLE;
1517 + case MBL_STATE_RING3:
1518 + if (strstr(buf, "+CIEV")) {
1519 + if (strstr(buf, pvt->ciev_call_1)) {
1520 + if (pvt->sent_answer) { /* We answered */
1521 + pvt->state = MBL_STATE_INCOMING;
1522 + } else { /* User answered on handset!, disconnect */
1523 + pvt->state = MBL_STATE_IDLE;
1524 + if (pvt->sco_socket > -1)
1525 + close(pvt->sco_socket);
1526 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1529 + if ((strstr(buf, pvt->ciev_callsetup_0) || strstr(buf, pvt->ciev_call_0))) { /* Caller disconnected */
1530 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1534 + case MBL_STATE_INCOMING:
1535 + if (strstr(buf, "+CIEV")) {
1536 + if (strstr(buf, pvt->ciev_call_0)) {
1537 + pvt->do_hangup = 0;
1538 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1542 + case MBL_STATE_HANGUP:
1543 + if (strstr(buf, "OK") || strstr(buf, pvt->ciev_call_0)) {
1544 + close(pvt->sco_socket);
1545 + pvt->sco_socket = -1;
1546 + pvt->state = MBL_STATE_IDLE;
1549 + case MBL_STATE_INSMS:
1550 + if (strstr(buf, "+CMGR:")) {
1551 + memset(sms_src, 0x00, sizeof(sms_src));
1552 + if ((p = strchr(buf, ','))) {
1553 + if (*(++p) == '"')
1555 + if ((p1 = strchr(p, ','))) {
1556 + if (*(--p1) == '"')
1558 + memset(sms_src, 0x00, sizeof(sms_src));
1559 + strncpy(sms_src, p, p1 - p + 1);
1562 + } else if (strstr(buf, "OK")) {
1563 + chn = mbl_new(AST_STATE_DOWN, pvt, NULL);
1564 + strcpy(chn->exten, "sms");
1565 + pbx_builtin_setvar_helper(chn, "SMSSRC", sms_src);
1566 + pbx_builtin_setvar_helper(chn, "SMSTXT", sms_txt);
1567 + if (ast_pbx_start(chn))
1568 + ast_log(LOG_ERROR, "Unable to start pbx on incoming sms.\n");
1569 + pvt->state = MBL_STATE_IDLE;
1571 + ast_copy_string(sms_txt, buf, sizeof(sms_txt));
1574 + case MBL_STATE_OUTSMS:
1576 + case MBL_STATE_OUTSMS1:
1578 + case MBL_STATE_OUTSMS2:
1579 + if (strstr(buf, "OK")) {
1580 + pvt->state = MBL_STATE_IDLE;
1584 + /* Unsolicited responses */
1586 + if (strstr(buf, "+CMTI:")) { /* SMS Incoming... */
1587 + if ((p = strchr(buf, ','))) {
1591 + snprintf(buf, sizeof(buf), "AT+CMGR=%d\r", smsi);
1592 + rfcomm_write(pvt, buf);
1593 + pvt->state = MBL_STATE_INSMS;
1598 + } else if (s == 0) { /* Timeouts */
1599 + if (pvt->state == MBL_STATE_INIT2) { /* Some devices dont respond to AT+CIND? properly. RIM Blackberry 4 example */
1601 + rfcomm_write(pvt, "AT+CMER=3,0,0,1\r");
1602 + } else if (pvt->state == MBL_STATE_INIT3) { /* Some devices dont respond to AT+CMER=3,0,0,1 properly. VK 2020 for example */
1604 + rfcomm_write(pvt, "AT+CLIP=1\r");
1605 + } else if (pvt->state == MBL_STATE_PREIDLE) {
1606 + pvt->connected = 1;
1607 + ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s initialised and ready.\n", pvt->id);
1608 + pvt->state = MBL_STATE_IDLE;
1609 + } else if (pvt->state == MBL_STATE_DIAL) {
1610 + snprintf(buf, sizeof(buf), "ATD%s;\r", pvt->dial_number);
1611 + if (!rfcomm_write(pvt, buf)) {
1612 + ast_log(LOG_ERROR, "Dial failed on %s state %d\n", pvt->owner->name, pvt->state);
1613 + ast_queue_control(pvt->owner, AST_CONTROL_CONGESTION);
1614 + pvt->state = MBL_STATE_IDLE;
1616 + pvt->state = MBL_STATE_DIAL1;
1618 + } else if (pvt->state == MBL_STATE_DIAL1) {
1619 + ast_log(LOG_ERROR, "Dial failed on %s state %d\n", pvt->owner->name, pvt->state);
1620 + ast_queue_control(pvt->owner, AST_CONTROL_CONGESTION);
1621 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1622 + pvt->state = MBL_STATE_IDLE;
1623 + } else if (pvt->state == MBL_STATE_RING) { /* No CLIP?, bump it */
1624 + pvt->state = MBL_STATE_RING2;
1625 + } else if (pvt->state == MBL_STATE_HANGUP) {
1626 + if (pvt->do_hangup) {
1627 + if (pvt->hangup_count == 6) {
1628 + ast_log(LOG_DEBUG, "Device %s failed to hangup after 6 tries, disconnecting.\n", pvt->id);
1631 + rfcomm_write(pvt, "AT+CHUP\r");
1632 + pvt->hangup_count++;
1634 + pvt->state = MBL_STATE_IDLE;
1635 + } else if (pvt->state == MBL_STATE_OUTSMS) {
1636 + snprintf(buf, sizeof(buf), "AT+CMGS=\"%s\"\r", pvt->dial_number);
1637 + rfcomm_write(pvt, buf);
1638 + pvt->state = MBL_STATE_OUTSMS1;
1639 + } else if (pvt->state == MBL_STATE_OUTSMS1) {
1640 + if (pvt->rfcomm_buf[0] == '>') {
1641 + snprintf(buf, sizeof(buf), "%s%c", pvt->sms_txt, 0x1a);
1642 + rfcomm_write(pvt, buf);
1643 + pvt->state = MBL_STATE_OUTSMS2;
1645 + ast_log(LOG_ERROR, "Failed to send SMS to %s on device %s\n", pvt->dial_number, pvt->id);
1646 + pvt->state = MBL_STATE_IDLE;
1648 + } else if (pvt->state == MBL_STATE_OUTSMS2) {
1649 + ast_log(LOG_ERROR, "Failed to send SMS to %s on device %s\n", pvt->dial_number, pvt->id);
1650 + pvt->state = MBL_STATE_IDLE;
1652 + } else if (s == -1) {
1653 + if (option_verbose > 2)
1654 + ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has disconnected, reason (%d).\n", pvt->id, errno);
1660 + if (pvt->rfcomm_socket > -1)
1661 + close(pvt->rfcomm_socket);
1662 + if (pvt->sco_socket > -1)
1663 + close(pvt->sco_socket);
1664 + pvt->sco_socket = -1;
1665 + pvt->connected = 0;
1666 + pvt->monitor_thread = AST_PTHREADT_NULL;
1668 + pthread_cancel(pvt->sco_listener_thread);
1669 + pthread_join(pvt->sco_listener_thread, NULL);
1670 + pvt->sco_listener_thread = AST_PTHREADT_NULL;
1672 + close(pvt->adapter->sco_socket);
1674 + manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
1676 + pvt->adapter->inuse = 0;
1682 +static void *do_monitor_headset(void *data)
1685 + struct mbl_pvt *pvt = (struct mbl_pvt *)data;
1690 + pvt->state = MBL_STATE_PREIDLE;
1694 + if (pvt->state == MBL_STATE_RING2)
1698 + s = rfcomm_read(pvt, buf, 0, t);
1700 + if ((s > 0) && (buf[0] != 0x0) && (buf[0] != '\r')) {
1701 + ast_log(LOG_DEBUG, "rfcomm_read() (%s) [%s]\n", pvt->id, buf);
1702 + switch (pvt->state) {
1703 + case MBL_STATE_RING2:
1704 + if (strstr(buf, "AT+CKPD=")) {
1705 + ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
1706 + pvt->state = MBL_STATE_INCOMING;
1707 + rfcomm_write(pvt, "\r\n+VGS=13\r\n");
1708 + rfcomm_write(pvt, "\r\n+VGM=13\r\n");
1711 + case MBL_STATE_INCOMING:
1712 + if (strstr(buf, "AT+CKPD=")) {
1713 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1719 + if (strstr(buf, "AT+VGS=")) {
1720 + rfcomm_write(pvt, "\r\nOK\r\n");
1721 + } else if (strstr(buf, "AT+VGM=")) {
1722 + rfcomm_write(pvt, "\r\nOK\r\n");
1724 + } else if (s == 0) { /* Timeouts */
1725 + if (pvt->state == MBL_STATE_PREIDLE) {
1726 + pvt->connected = 1;
1727 + ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s initialised and ready.\n", pvt->id);
1728 + pvt->state = MBL_STATE_IDLE;
1729 + } else if (pvt->state == MBL_STATE_RING) {
1730 + pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr);
1731 + if (pvt->sco_socket > -1) {
1732 + ast_setstate(pvt->owner, AST_STATE_RINGING);
1733 + ast_queue_control(pvt->owner, AST_CONTROL_RINGING);
1734 + pvt->state = MBL_STATE_RING2;
1736 + ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1738 + } else if (pvt->state == MBL_STATE_RING2) {
1739 + rfcomm_write(pvt, "\r\nRING\r\n");
1741 + } else if (s == -1) {
1742 + if (option_verbose > 2)
1743 + ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has disconnected, reason (%d).\n", pvt->id, errno);
1749 + if (pvt->rfcomm_socket > -1)
1750 + close(pvt->rfcomm_socket);
1751 + if (pvt->sco_socket > -1)
1752 + close(pvt->sco_socket);
1753 + pvt->sco_socket = -1;
1754 + pvt->connected = 0;
1755 + pvt->monitor_thread = AST_PTHREADT_NULL;
1757 + manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
1759 + pvt->adapter->inuse = 0;
1765 +static int start_monitor(struct mbl_pvt *pvt)
1768 + if (pvt->type == MBL_TYPE_PHONE) {
1769 + if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_phone, pvt) < 0) {
1770 + pvt->monitor_thread = AST_PTHREADT_NULL;
1773 + /* we are a phone, so spin the sco listener on the adapter as well */
1774 + if (ast_pthread_create_background(&pvt->sco_listener_thread, NULL, do_sco_listen, pvt->adapter) < 0) {
1775 + ast_log(LOG_ERROR, "Unable to create sco listener thread for device %s.\n", pvt->id);
1779 + if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_headset, pvt) < 0) {
1780 + pvt->monitor_thread = AST_PTHREADT_NULL;
1789 +static void *do_discovery(void *data)
1792 + struct adapter_pvt *adapter;
1793 + struct mbl_pvt *pvt;
1796 + AST_RWLIST_RDLOCK(&adapters);
1797 + AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
1798 + if (!adapter->inuse) {
1799 + AST_RWLIST_RDLOCK(&devices);
1800 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
1801 + if (!adapter->inuse && !pvt->connected && !strcmp(adapter->id, pvt->adapter->id)) {
1802 + if ((pvt->rfcomm_socket = rfcomm_connect(adapter->addr, pvt->addr, pvt->rfcomm_port)) > -1) {
1804 + if (start_monitor(pvt)) {
1805 + pvt->connected = 1;
1806 + adapter->inuse = 1;
1807 + manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id);
1808 + if (option_verbose > 2)
1809 + ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has connected.\n", pvt->id);
1814 + AST_RWLIST_UNLOCK(&devices);
1817 + AST_RWLIST_UNLOCK(&adapters);
1819 + sleep(discovery_interval);
1825 +static void *do_sco_listen(void *data)
1829 + struct sockaddr_sco addr;
1831 + struct sco_options so;
1834 + socklen_t addrlen;
1835 + struct mbl_pvt *pvt;
1836 + struct adapter_pvt *adapter = (struct adapter_pvt *) data;
1838 + if ((adapter->sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1839 + ast_log(LOG_ERROR, "Unable to create sco listener socket.\n");
1842 + memset(&addr, 0, sizeof(addr));
1843 + addr.sco_family = AF_BLUETOOTH;
1844 + bacpy(&addr.sco_bdaddr, &adapter->addr);
1845 + if (bind(adapter->sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1846 + ast_log(LOG_ERROR, "Unable to bind sco listener socket. (%d)\n", errno);
1847 + close(adapter->sco_socket);
1850 + if (setsockopt(adapter->sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
1851 + ast_log(LOG_ERROR, "Unable to setsockopt sco listener socket.\n");
1852 + close(adapter->sco_socket);
1855 + if (listen(adapter->sco_socket, 5) < 0) {
1856 + ast_log(LOG_ERROR, "Unable to listen sco listener socket.\n");
1857 + close(adapter->sco_socket);
1861 + ast_log(LOG_DEBUG, "About to accept() socket.\n");
1862 + addrlen = sizeof(struct sockaddr_sco);
1863 + if ((ns = accept(adapter->sco_socket, (struct sockaddr *)&addr, &addrlen)) > -1) {
1864 + ast_log(LOG_DEBUG, "accept()ed socket.\n");
1866 + getsockopt(ns, SOL_SCO, SCO_OPTIONS, &so, &len);
1868 + ba2str(&addr.sco_bdaddr, saddr);
1869 + ast_log(LOG_DEBUG, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu);
1872 + AST_RWLIST_RDLOCK(&devices);
1873 + AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
1874 + if (!bacmp(&pvt->addr, &addr.sco_bdaddr))
1877 + AST_RWLIST_UNLOCK(&devices);
1879 + if (pvt->sco_socket != -1)
1880 + close(pvt->sco_socket);
1881 + pvt->sco_socket = ns;
1883 + ast_log(LOG_DEBUG, "Could not find device for incoming Audio Connection.\n");
1885 + ast_log(LOG_ERROR, "accept() failed %d\n", errno);
1899 +static int mbl_load_config(void)
1902 + struct ast_config *cfg = NULL;
1904 + struct ast_variable *var;
1905 + const char *id, *address, *useadapter, *port, *context, *type, *skip, *group, *master, *nocallsetup, *aligndetect, *blackberry;
1906 + struct mbl_pvt *pvt;
1907 + struct adapter_pvt *adapter;
1909 + struct hci_dev_req dr;
1910 + char nadapters = 0;
1911 + // struct ast_flags config_flags = { 0 };
1913 + cfg = ast_config_load(MBL_CONFIG);
1917 + for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
1918 + if (!strcasecmp(var->name, "interval"))
1919 + discovery_interval = atoi(var->value);
1922 + /* load adapters first */
1923 + cat = ast_category_browse(cfg, NULL);
1925 + if (!strcasecmp(cat, "adapter")) {
1926 + id = ast_variable_retrieve(cfg, cat, "id");
1927 + address = ast_variable_retrieve(cfg, cat, "address");
1928 + master = ast_variable_retrieve(cfg, cat, "forcemaster");
1929 + aligndetect = ast_variable_retrieve(cfg, cat, "alignmentdetection");
1930 + ast_log(LOG_DEBUG, "Loading adapter %s %s.\n", id, address);
1931 + if (!ast_strlen_zero(id) && !ast_strlen_zero(address)) {
1932 + if ((adapter = ast_calloc(1, sizeof(*adapter)))) {
1933 + ast_copy_string(adapter->id, id, sizeof(adapter->id));
1934 + str2ba(address, &adapter->addr);
1935 + if (!ast_strlen_zero(aligndetect)) {
1936 + if (*aligndetect == 'Y' || *aligndetect == 'y')
1937 + adapter->alignment_detection = 1;
1939 + adapter->dev_id = hci_devid(address);
1940 + adapter->hci_socket = hci_open_dev(adapter->dev_id);
1941 + if (adapter->dev_id < 0 || adapter->hci_socket < 0) {
1942 + ast_log(LOG_ERROR, "Unable to open adapter %s. It won't be enabled.\n", adapter->id);
1943 + ast_free(adapter);
1945 + if ((master) && (*master)) {
1946 + dr.dev_id = adapter->dev_id;
1947 + if (hci_strtolm("master", &dr.dev_opt)) {
1948 + if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) {
1949 + ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER.\n", adapter->id);
1953 + hci_read_voice_setting(adapter->hci_socket, &vs, 1000);
1955 + if (vs != 0x0060) {
1956 + ast_log(LOG_ERROR, "Incorrect voice setting for adapter %s, it must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id);
1957 + hci_close_dev(adapter->hci_socket);
1958 + ast_free(adapter);
1960 + AST_RWLIST_WRLOCK(&adapters);
1961 + AST_RWLIST_INSERT_HEAD(&adapters, adapter, entry);
1962 + AST_RWLIST_UNLOCK(&adapters);
1968 + ast_log(LOG_ERROR, "id/address missing for adapter %s. It won't be enabled.\n", cat);
1970 + cat = ast_category_browse(cfg, cat);
1974 + ast_log(LOG_WARNING, "***********************************************************************\n");
1975 + ast_log(LOG_WARNING, "No Adapters defined. Please review mobile.conf. See sample for details.\n");
1976 + ast_log(LOG_WARNING, "***********************************************************************\n");
1979 + /* now load devices */
1980 + cat = ast_category_browse(cfg, NULL);
1982 + if (strcasecmp(cat, "general") && strcasecmp(cat, "adapter")) {
1983 + ast_log(LOG_DEBUG, "Loading device %s.\n", cat);
1984 + address = ast_variable_retrieve(cfg, cat, "address");
1985 + useadapter = ast_variable_retrieve(cfg, cat, "adapter");
1986 + port = ast_variable_retrieve(cfg, cat, "port");
1987 + context = ast_variable_retrieve(cfg, cat, "context");
1988 + type = ast_variable_retrieve(cfg, cat, "type");
1989 + skip = ast_variable_retrieve(cfg, cat, "dtmfskip");
1990 + group = ast_variable_retrieve(cfg, cat, "group");
1991 + nocallsetup = ast_variable_retrieve(cfg, cat, "nocallsetup");
1992 + blackberry = ast_variable_retrieve(cfg, cat, "blackberry");
1993 + if (!ast_strlen_zero(address) && !ast_strlen_zero(port) && !ast_strlen_zero(useadapter)) {
1994 + /* find the adapter */
1995 + AST_RWLIST_RDLOCK(&adapters);
1996 + AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
1997 + if (!strcmp(adapter->id, useadapter))
2000 + AST_RWLIST_UNLOCK(&adapters);
2002 + ast_log(LOG_ERROR, "Device %s configured to use unknown adapter %s. It won't be enabled.\n", cat, useadapter);
2005 + if ((pvt = ast_calloc(1, sizeof(*pvt)))) {
2006 + if (type && !strcmp(type, "headset"))
2007 + pvt->type = MBL_TYPE_HEADSET;
2009 + pvt->type = MBL_TYPE_PHONE;
2012 + pvt->blackberry = ast_true(blackberry);
2014 + ast_copy_string(pvt->id, cat, sizeof(pvt->id));
2015 + str2ba(address, &pvt->addr);
2016 + ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
2018 + pvt->group = atoi(group); /* group 0 if invalid */
2019 + pvt->state = MBL_STATE_INIT;
2020 + pvt->rfcomm_socket = -1;
2021 + pvt->rfcomm_port = atoi(port);
2022 + pvt->sco_socket = -1;
2023 + pvt->monitor_thread = AST_PTHREADT_NULL;
2024 + pvt->sco_listener_thread = AST_PTHREADT_NULL;
2025 + if (!ast_strlen_zero(nocallsetup)) {
2026 + if ((*nocallsetup == 'y') || (*nocallsetup == 'Y')) {
2027 + pvt->no_callsetup = 1;
2028 + ast_log(LOG_DEBUG, "Setting nocallsetup mode for device %s.\n", pvt->id);
2031 + pvt->dsp = ast_dsp_new();
2033 + if ((pvt->dtmf_skip = atoi(skip)) == 0)
2034 + pvt->dtmf_skip = 200;
2036 + pvt->dtmf_skip = 200;
2037 + ast_dsp_set_features(pvt->dsp, DSP_FEATURE_DTMF_DETECT);
2038 + ast_dsp_digitmode(pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
2039 + pvt->adapter = adapter;
2040 + AST_RWLIST_WRLOCK(&devices);
2041 + AST_RWLIST_INSERT_HEAD(&devices, pvt, entry);
2042 + AST_RWLIST_UNLOCK(&devices);
2045 + ast_log(LOG_ERROR, "Device %s has no address/port/adapter configured. It won't be enabled.\n", cat);
2048 + cat = ast_category_browse(cfg, cat);
2051 + ast_config_destroy(cfg);
2057 +static int unload_module(void)
2060 + struct mbl_pvt *pvt;
2061 + struct adapter_pvt *adapter;
2063 + /* First, take us out of the channel loop */
2064 + ast_channel_unregister(&mbl_tech);
2066 + /* Kill the discovery thread */
2067 + if (discovery_thread != AST_PTHREADT_NULL) {
2068 + pthread_cancel(discovery_thread);
2069 + pthread_join(discovery_thread, NULL);
2072 + /* Destroy the device list */
2073 + AST_RWLIST_WRLOCK(&devices);
2074 + while ((pvt = AST_RWLIST_REMOVE_HEAD(&devices, entry))) {
2075 + if (pvt->monitor_thread != AST_PTHREADT_NULL) {
2076 + pthread_cancel(pvt->monitor_thread);
2077 + pthread_join(pvt->monitor_thread, NULL);
2079 + if (pvt->sco_listener_thread != AST_PTHREADT_NULL) {
2080 + pthread_cancel(pvt->sco_listener_thread);
2081 + pthread_join(pvt->sco_listener_thread, NULL);
2083 + if (pvt->sco_socket > -1) {
2084 + close(pvt->sco_socket);
2086 + if (pvt->adapter->sco_socket > -1) {
2087 + close(pvt->adapter->sco_socket);
2089 + if (pvt->rfcomm_socket > -1) {
2090 + close(pvt->rfcomm_socket);
2092 + ast_dsp_free(pvt->dsp);
2095 + AST_RWLIST_UNLOCK(&devices);
2097 + /* Destroy the adapter list */
2098 + AST_RWLIST_WRLOCK(&adapters);
2099 + while ((adapter = AST_RWLIST_REMOVE_HEAD(&adapters, entry))) {
2100 + hci_close_dev(adapter->hci_socket);
2101 + ast_free(adapter);
2103 + AST_RWLIST_UNLOCK(&adapters);
2106 + sdp_close(sdp_session);
2108 + /* Unregister the CLI & APP */
2109 + ast_cli_unregister_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
2110 + ast_unregister_application(app_mblstatus);
2111 + ast_unregister_application(app_mblsendsms);
2117 +static int load_module(void)
2122 + /* Check if we have Bluetooth, no point loading otherwise... */
2123 + dev_id = hci_get_route(NULL);
2124 + s = hci_open_dev(dev_id);
2125 + if (dev_id < 0 || s < 0) {
2126 + ast_log(LOG_ERROR, "No Bluetooth device found. Not loading module.\n");
2127 + return AST_MODULE_LOAD_DECLINE;
2132 + if (!mbl_load_config()) {
2133 + ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", MBL_CONFIG);
2134 + return AST_MODULE_LOAD_DECLINE;
2137 + sdp_session = sdp_register();
2139 + /* Spin the discovery thread */
2140 + if (ast_pthread_create_background(&discovery_thread, NULL, do_discovery, NULL) < 0) {
2141 + ast_log(LOG_ERROR, "Unable to create discovery thread.\n");
2142 + return AST_MODULE_LOAD_DECLINE;
2145 + ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
2146 + ast_register_application(app_mblstatus, mbl_status_exec, mblstatus_synopsis, mblstatus_desc);
2147 + ast_register_application(app_mblsendsms, mbl_sendsms_exec, mblsendsms_synopsis, mblsendsms_desc);
2149 + /* Make sure we can register our channel type */
2150 + if (ast_channel_register(&mbl_tech)) {
2151 + ast_log(LOG_ERROR, "Unable to register channel class %s\n", "Mobile");
2152 + return AST_MODULE_LOAD_FAILURE;
2158 +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bluetooth Mobile Device Channel Driver",
2159 + .load = load_module,
2160 + .unload = unload_module,
2162 diff -Nru asterisk-addons-1.4.8.org/configs/mobile.conf.sample asterisk-addons-1.4.8/configs/mobile.conf.sample
2163 --- asterisk-addons-1.4.8.org/configs/mobile.conf.sample 1970-01-01 01:00:00.000000000 +0100
2164 +++ asterisk-addons-1.4.8/configs/mobile.conf.sample 2009-06-04 22:20:03.000000000 +0200
2168 +; configuration file for chan_mobile
2172 +interval=30 ; Number of seconds between trying to connect to devices.
2174 +; The following is a list of adapters we use.
2175 +; id must be unique and address is the bdaddr of the adapter from hciconfig.
2176 +; Each adapter may only have one device (headset or phone) connected at a time.
2177 +; Add an [adapter] entry for each adapter you have.
2181 +address=00:09:DD:60:01:A3
2182 +;forcemaster=yes ; attempt to force adapter into master mode. default is no.
2183 +;alignmentdetection=yes ; enable this if you sometimes get 'white noise' on asterisk side of the call
2184 + ; its a bug in the bluetooth adapter firmware, enabling this will compensate for it.
2189 +address=00:80:C8:35:52:78
2191 +; The following is a list of the devices we deal with.
2192 +; Every device listed below will be available for calls in and out of Asterisk.
2193 +; Each device needs an adapter=xxxx entry which determines which bluetooth adapter is used.
2194 +; Use the CLI command 'mobile search' to discover devices.
2195 +; Use the CLI command 'mobile show devices' to see device status.
2197 +; To place a call out through a mobile phone use Dial(Mobile/[device]/NNN.....) or Dial(Mobile/gn/NNN......) in your dialplan.
2198 +; To call a headset use Dial(Mobile/[device]).
2201 +address=00:E0:91:7F:46:44 ; the address of the phone
2202 +port=4 ; the rfcomm port number (from mobile search)
2203 +context=incoming-mobile ; dialplan context for incoming calls
2204 +adapter=dlink ; adapter to use
2205 +group=1 ; this phone is in channel group 1
2206 +;nocallsetup=yes ; set this only if your phone reports that it supports call progress notification, but does not do it. Motorola L6 for example.
2209 +address=00:60:57:32:7E:B2
2211 +context=incoming-mobile
2214 +;blackberry=yes ; set this if you are using a blackberry device
2217 +address=00:60:57:32:7E:B1
2219 +context=incoming-mobile
2221 +group=1 ; this phone is in channel group 1 also.
2224 +address=00:0B:9E:11:AE:C6
2226 +type=headset ; This is a headset, not a Phone !
2230 +address=00:0B:9E:11:74:A5
2234 diff -Nru asterisk-addons-1.4.8.org/configure.ac asterisk-addons-1.4.8/configure.ac
2235 --- asterisk-addons-1.4.8.org/configure.ac 2008-02-13 23:58:11.000000000 +0100
2236 +++ asterisk-addons-1.4.8/configure.ac 2009-06-04 22:20:03.000000000 +0200
2237 @@ -161,11 +161,13 @@
2238 # from here on down, library checking should be done in alphabetical order
2239 # by the --with option name, to make things easier for the users :-)
2241 +AST_EXT_LIB_SETUP([BLUETOOTH], [Bluetooth Support], [bluetooth])
2242 AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
2243 AST_EXT_LIB_SETUP([NCURSES], [ncurses], [ncurses])
2244 AST_EXT_LIB_SETUP([MYSQLCLIENT], [mysqlclient], [mysqlclient])
2245 AST_EXT_LIB_SETUP([ASTERISK], [asterisk], [asterisk])
2247 +AST_EXT_LIB_CHECK([BLUETOOTH], [bluetooth], [ba2str], [bluetooth/bluetooth.h])
2248 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
2250 AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [curses.h])
2251 diff -Nru asterisk-addons-1.4.8.org/makeopts.in asterisk-addons-1.4.8/makeopts.in
2252 --- asterisk-addons-1.4.8.org/makeopts.in 2008-02-13 23:58:11.000000000 +0100
2253 +++ asterisk-addons-1.4.8/makeopts.in 2009-06-04 22:20:03.000000000 +0200
2255 sharedstatedir = @sharedstatedir@
2256 sysconfdir = @sysconfdir@
2258 +BLUETOOTH_LIB=@BLUETOOTH_LIB@
2259 +BLUETOOTH_INCLUDE=@BLUETOOTH_INCLUDE@
2261 CURSES_LIB=@CURSES_LIB@
2262 CURSES_INCLUDE=@CURSES_INCLUDE@