1 diff -urN asterisk-1.4.0-beta3-o-o/build_tools/menuselect-deps.in asterisk-1.4.0-beta3/build_tools/menuselect-deps.in
2 --- asterisk-1.4.0-beta3-o-o/build_tools/menuselect-deps.in 2006-09-19 11:07:22.000000000 -0600
3 +++ asterisk-1.4.0-beta3/build_tools/menuselect-deps.in 2006-11-06 12:45:04.000000000 -0700
6 +BLUETOOTH=@PBX_BLUETOOTH@
10 diff -urN asterisk-1.4.0-beta3-o-o/channels/chan_bluetooth.c asterisk-1.4.0-beta3/channels/chan_bluetooth.c
11 --- asterisk-1.4.0-beta3-o-o/channels/chan_bluetooth.c 1969-12-31 17:00:00.000000000 -0700
12 +++ asterisk-1.4.0-beta3/channels/chan_bluetooth.c 2006-11-06 12:44:39.000000000 -0700
15 + * Asterisk -- A telephony toolkit for Linux.
17 + * Asterisk Bluetooth Channel
19 + * Author: Theo Zourzouvillys <theo@adaptive-it.co.uk>
21 + * Adaptive Linux Solutions <http://www.adaptive-it.co.uk>
23 + * Copyright (C) 2004 Adaptive Linux Solutions
25 + * This program is free software, distributed under the terms of
26 + * the GNU General Public License
28 + * ******************* NOTE NOTE NOTE NOTE NOTE *********************
30 + * This code is not at all tested, and only been developed with a
31 + * HBH-200 headset and a Nokia 6310i right now.
33 + * Expect it to crash, dial random numbers, and steal all your money.
35 + * PLEASE try any headsets and phones, and let me know the results,
36 + * working or not, along with all debug output!
38 + * ------------------------------------------------------------------
40 + * Asterisk Bluetooth Support
42 + * Well, here we go - Attempt to provide Handsfree profile support in
43 + * both AG and HF modes, AG (AudioGateway) mode support for using
44 + * headsets, and HF (Handsfree) mode for utilising mobile/cell phones
46 + * It would be nice to also provide Headset support at some time in
47 + * the future, however, a working Handsfree profile is nice for now,
48 + * and as far as I can see, almost all new HS devices also support HF
50 + * ------------------------------------------------------------------
53 + * You need to have bluez's bluetooth stack, along with user space
54 + * tools (>=v2.10), and running hcid and sdsp.
56 + * See bluetooth.conf for configuration details.
58 + * - Ensure bluetooth subsystem is up and running. 'hciconfig'
59 + * should show interface as UP.
61 + * - If you're trying to use a headset/HS, start up asterisk, and try
62 + * to pair it as you normally would.
64 + * - If you're trying to use a Phone/AG, just make sure bluetooth is
65 + * enabled on your phone, and start up asterisk.
67 + * - 'bluetooth show peers' will show all bluetooth devices states.
69 + * - Send a call out by using Dial(BLT/DevName/0123456). Call a HS
70 + * with Dial(BLT/DevName)
72 + * ------------------------------------------------------------------
75 + * - What should happen when an AG is paired with asterisk and
76 + * someone uses the AG dalling a number manually? My test phone
77 + * seems to try to open an SCO link. Perhaps an extension to
78 + * route the call to, or maybe drop the RFCOM link all together?
80 + * ------------------------------------------------------------------
83 + * PLEASE email <theo@adaptive-it.co.uk> with the results of ANY
84 + * device not listed in here (working or not), or if the device is
85 + * listed and it doesn't work! Please also email full debug output
86 + * for any device not working correctly or generating errors in log.
88 + * HandsFree Profile:
91 + * - Ericsson HBH-200
93 + * AG (AudioGateway):
96 + * ------------------------------------------------------------------
98 + * Questions, bugs, or (preferably) patches to:
100 + * <theo@adaptive-it.co.uk>
102 + * ------------------------------------------------------------------
107 + * \brief Channel driver for Bluetooth phones and headsets
109 + * \author Theo Zourzouvillys <theo@adaptive-it.co.uk>
112 + * \arg \ref Config_bluetooth
114 + * \ingroup channel_drivers
119 + <depend>bluetooth</depend>
123 +/* ---------------------------------- */
127 +#include <asterisk/lock.h>
128 +#include <asterisk/utils.h>
129 +#include <asterisk/channel.h>
130 +#include <asterisk/channel_pvt.h>
131 +#include <asterisk/config.h>
132 +#include <asterisk/logger.h>
133 +#include <asterisk/module.h>
134 +#include <asterisk/pbx.h>
135 +#include <asterisk/sched.h>
136 +#include <asterisk/options.h>
137 +#include <asterisk/cli.h>
138 +#include <asterisk/callerid.h>
139 +#include <sys/socket.h>
140 +#include <sys/signal.h>
141 +#include <sys/time.h>
145 +#include <arpa/inet.h>
147 +#include <sys/ioctl.h>
150 +#include <bluetooth/bluetooth.h>
151 +#include <bluetooth/hci.h>
152 +#include <bluetooth/hci_lib.h>
153 +#include <bluetooth/sco.h>
154 +#include <bluetooth/rfcomm.h>
155 +#include <bluetooth/sdp.h>
156 +#include <bluetooth/sdp_lib.h>
158 +/* --- Data types and definitions --- */
160 +#ifndef HANDSFREE_AUDIO_GW_SVCLASS_ID
161 +# define HANDSFREE_AUDIO_GW_SVCLASS_ID 0x111f
164 +#define BLUETOOTH_FORMAT AST_FORMAT_SLINEAR
165 +#define BLT_CHAN_NAME "BLT"
166 +#define BLT_CONFIG_FILE "bluetooth.conf"
167 +#define BLT_RDBUFF_MAX 1024
168 +#define BLT_DEFAULT_HCI_DEV 0
169 +#define BLT_SVN_REVISION "$Rev: 38 $"
171 +/* ---------------------------------- */
174 + BLT_ROLE_NONE = 0, // Unknown Device
175 + BLT_ROLE_HS = 1, // Device is a Headset
176 + BLT_ROLE_AG = 2 // Device is an Audio Gateway
179 +/* State when we're in HS mode */
182 + BLT_STATE_WANT_R = 0,
183 + BLT_STATE_WANT_N = 1,
184 + BLT_STATE_WANT_CMD = 2,
185 + BLT_STATE_WANT_N2 = 3,
190 + BLT_STATUS_CONNECTING,
191 + BLT_STATUS_NEGOTIATING,
193 + BLT_STATUS_RINGING,
194 + BLT_STATUS_IN_CALL,
197 +/* ---------------------------------- */
199 +/* Default config settings */
201 +#define BLT_DEFAULT_CHANNEL_AG 5
202 +#define BLT_DEFAULT_CHANNEL_HS 6
203 +#define BLT_DEFAULT_ROLE BLT_ROLE_HS
204 +#define BLT_OBUF_LEN (48 * 25)
208 +/* ---------------------------------- */
210 +typedef struct blt_dev blt_dev_t;
212 +// XXX:T: Tidy this lot up.
215 + blt_status_t status; /* Device Status */
217 + struct ast_channel * owner; /* Channel we belong to, possibly NULL */
218 + blt_dev_t * dev; /* The bluetooth device channel is for */
219 + struct ast_frame fr; /* Recieved frame */
222 + int sco_pipe[2]; /* SCO alert pipe */
223 + int sco; /* SCO fd */
224 + int sco_handle; /* SCO Handle */
225 + int sco_mtu; /* SCO MTU */
226 + int sco_running; /* 1 when sCO thread should be running */
227 + pthread_t sco_thread; /* SCO thread */
228 + ast_mutex_t sco_lock; /* SCO lock */
229 + int sco_pos_in; /* Reader in position */
230 + int sco_pos_out; /* Reader out position */
231 + int sco_sending; /* Sending SCO packets */
232 + char buf[1024]; /* Incoming data buffer */
233 + char sco_buf_out[BUFLEN+1]; /* 24 chunks of 48 */
234 + char sco_buf_in[BUFLEN+1]; /* 24 chunks of 48 */
236 + char dnid[1024]; /* Outgoi gncall dialed number */
237 + unsigned char * obuf[BLT_OBUF_LEN]; /* Outgoing data buffer */
238 + int obuf_len; /* Output Buffer Position */
239 + int obuf_wpos; /* Buffer Reader */
242 + int autoconnect; /* 1 for autoconnect */
243 + int outgoing_id; /* Outgoing connection scheduler id */
244 + char * name; /* Devices friendly name */
245 + blt_role_t role; /* Device role (HS or AG) */
246 + bdaddr_t bdaddr; /* remote address */
247 + int channel; /* remote channel */
248 + int rd; /* RFCOMM fd */
249 + int tmp_rd; /* RFCOMM fd */
250 + int call_cnt; /* Number of attempted calls */
251 + ast_mutex_t lock; /* RFCOMM socket lock */
252 + char rd_buff[BLT_RDBUFF_MAX]; /* RFCOMM input buffer */
253 + int rd_buff_pos; /* RFCOMM input buffer position */
254 + int ready; /* 1 When ready */
257 + char last_ok_cmd[BLT_RDBUFF_MAX]; /* Runtime[AG]: Last AT command that was OK */
258 + int cind; /* Runtime[AG]: Recieved +CIND */
259 + int call_pos, service_pos, callsetup_pos; /* Runtime[AG]: Positions in CIND/CMER */
260 + int call, service, callsetup; /* Runtime[AG]: Values */
263 + blt_state_t state; /* Runtime: Device state (AG mode only) */
264 + int ring_timer; /* Runtime:Ring Timer */
265 + char last_err_cmd[BLT_RDBUFF_MAX]; /* Runtime: Last AT command that was OK */
266 + void (*cb)(blt_dev_t * dev, char * str); /* Runtime: Callback when in HS mode */
268 + int brsf; /* Runtime: Bluetooth Retrieve Supported Features */
269 + int bvra; /* Runtime: Bluetooth Voice Recognised Activation */
270 + int gain_speaker; /* Runtime: Gain Of Speaker */
271 + int clip; /* Runtime: Supports CLID */
272 + int colp; /* Runtime: Connected Line ID */
273 + int elip; /* Runtime: (Ericsson) Supports CLID */
274 + int eolp; /* Runtime: (Ericsson) Connected Line ID */
275 + int ringing; /* Runtime: Device is ringing */
277 + blt_dev_t * next; /* Next in linked list */
281 +typedef struct blt_atcb {
286 + /* DTE callbacks: */
287 + int (*set)(blt_dev_t * dev, const char * arg, int len);
288 + int (*read)(blt_dev_t * dev);
289 + int (*execute)(blt_dev_t * dev, const char * data);
290 + int (*test)(blt_dev_t * dev);
292 + /* DCE callbacks: */
293 + int (*unsolicited)(blt_dev_t * dev, const char * value);
297 +/* ---------------------------------- */
299 +static void rd_close(blt_dev_t * dev, int reconnect, int err);
300 +static int send_atcmd(blt_dev_t * device, const char * fmt, ...);
301 +static int sco_connect(blt_dev_t * dev);
303 +/* ---------------------------------- */
305 +/* RFCOMM channel we listen on*/
306 +static int rfcomm_channel_ag = BLT_DEFAULT_CHANNEL_AG;
307 +static int rfcomm_channel_hs = BLT_DEFAULT_CHANNEL_HS;
309 +/* Address of local bluetooth interface */
310 +static int hcidev_id;
311 +static bdaddr_t local_bdaddr;
313 +/* All the current sockets */
314 +AST_MUTEX_DEFINE_STATIC(iface_lock);
315 +static blt_dev_t * iface_head;
316 +static int ifcount = 0;
318 +static int sdp_record_hs = -1;
319 +static int sdp_record_ag = -1;
321 +/* RFCOMM listen socket */
322 +static int rfcomm_sock_ag = -1;
323 +static int rfcomm_sock_hs = -1;
324 +static int sco_socket = -1;
326 +static int monitor_pid = -1;
328 +/* The socket monitoring thread */
329 +static pthread_t monitor_thread = AST_PTHREADT_NULL;
330 +AST_MUTEX_DEFINE_STATIC(monitor_lock);
332 +/* Cound how many times this module is currently in use */
333 +static int usecnt = 0;
334 +AST_MUTEX_DEFINE_STATIC(usecnt_lock);
336 +static struct sched_context * sched = NULL;
338 +/* ---------------------------------- */
341 +role2str(blt_role_t role)
348 + case BLT_ROLE_NONE:
354 +status2str(blt_status_t status)
357 + case BLT_STATUS_DOWN:
359 + case BLT_STATUS_CONNECTING:
360 + return "Connecting";
361 + case BLT_STATUS_NEGOTIATING:
362 + return "Negotiating";
363 + case BLT_STATUS_READY:
365 + case BLT_STATUS_RINGING:
367 + case BLT_STATUS_IN_CALL:
373 +int sock_err(int fd)
376 + int len = sizeof(ret);
377 + getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
381 +/* ---------------------------------- */
384 +parse_cind(const char * str, char * name, int name_len)
388 + memset(name, 0, name_len);
392 + if (++c == 1 && *(str+1) == '"') {
393 + const char * start = str + 2;
396 + while (*str && *str != '"') {
402 + strncpy(name, start, (len > name_len) ? name_len : len);
404 + } else if (*str == ')')
406 + else if (c == 0 && *str == ',')
414 +set_cind(blt_dev_t * dev, int indicator, int val)
417 + ast_log(LOG_DEBUG, "CIND %d set to %d\n", indicator, val);
419 + if (indicator == dev->callsetup_pos) {
423 + dev->callsetup = val;
427 + // Outgoign ringing
428 + if (dev->owner && dev->role == BLT_ROLE_AG)
429 + ast_queue_control(dev->owner, AST_CONTROL_RINGING);
436 + if (dev->owner && dev->role == BLT_ROLE_AG && dev->call == 0)
437 + ast_queue_control(dev->owner, AST_CONTROL_CONGESTION);
441 + } else if (indicator == dev->service_pos) {
446 + ast_log(LOG_NOTICE, "Audio Gateway %s lost signal\n", dev->name);
447 + else if (dev->service == 0 && val > 0)
448 + ast_log(LOG_NOTICE, "Audio Gateway %s got signal\n", dev->name);
450 + dev->service = val;
452 + } else if (indicator == dev->call_pos) {
460 + ast_queue_control(dev->owner, AST_CONTROL_ANSWER);
461 + } else if (val == 0)
462 + ast_queue_control(dev->owner, AST_CONTROL_HANGUP);
470 +/* ---------------------------------- */
473 +set_buffer(char * ring, char * data, int circular_len, int * pos, int data_len)
475 + int start_pos = *(pos);
480 + // Set can_do to the most we can do in this copy.
482 + copy = MIN(circular_len - start_pos, data_len);
483 + memcpy(ring + start_pos, data + done, copy);
489 + if (start_pos == circular_len)
492 + *(pos) = start_pos;
497 +get_buffer(char * dst, char * ring, int ring_size, int * head, int to_copy)
501 + // |1|2|3|4|5|6|7|8|9|
506 + // Set can_do to the most we can do in this copy.
507 + copy = MIN(ring_size - *head, to_copy);
509 + // ast_log(LOG_DEBUG, "Getting: %d bytes, From pos %d\n", copy, *head);
510 + memcpy(dst, ring + *head, copy);
516 + if (*head == ring_size )
524 +/* Handle SCO audio sync.
526 + * If we are the MASTER, then we control the timing,
527 + * in 48 byte chunks. If we're the SLAVE, we send
528 + * as and when we recieve a packet.
530 + * Because of packet/timing nessecity, we
531 + * start up a thread when we're passing audio, so
532 + * that things are timed exactly right.
534 + * sco_thread() is the function that handles it.
539 +sco_thread(void * data)
541 + blt_dev_t * dev = (blt_dev_t*)data;
543 + struct pollfd pfd[2];
551 + // Avoid deadlock in odd circumstances
553 + ast_log(LOG_DEBUG, "SCO thread started on fd %d, pid %d\n", dev->sco, getpid());
555 + // dev->status = BLT_STATUS_IN_CALL;
556 + // ast_queue_control(dev->owner, AST_CONTROL_ANSWER);
557 + // Set buffer to silence, just incase.
559 + ast_mutex_lock(&(dev->sco_lock));
561 + memset(dev->sco_buf_in, 0x7f, BUFLEN);
562 + memset(dev->sco_buf_out, 0x7f, BUFLEN);
564 + dev->sco_pos_in = 0;
565 + dev->sco_pos_out = 0;
567 + ast_mutex_unlock(&(dev->sco_lock));
571 + ast_mutex_lock(&(dev->sco_lock));
573 + if (dev->sco_running != 1) {
574 + ast_log(LOG_DEBUG, "SCO stopped.\n");
578 + pfd[0].fd = dev->sco;
579 + pfd[0].events = POLLIN;
581 + pfd[1].fd = dev->sco_pipe[1];
582 + pfd[1].events = POLLIN;
584 + ast_mutex_unlock(&(dev->sco_lock));
586 + res = poll(pfd, 2, 50);
588 + if (res == -1 && errno != EINTR) {
589 + ast_log(LOG_DEBUG, "SCO poll() error\n");
596 + ast_mutex_lock(&(dev->sco_lock));
598 + if (pfd[0].revents & POLLIN) {
600 + len = read(dev->sco, buf, 48);
603 + ast_mutex_lock(&(dev->lock));
604 + set_buffer(dev->sco_buf_in, buf, BUFLEN, &in_pos, len);
605 + get_buffer(buf, dev->sco_buf_out, BUFLEN, &out_pos, len);
606 + write(dev->sco, buf, len);
607 + if (dev->owner && dev->owner->_state == AST_STATE_UP)
608 + write(dev->sco_pipe[1], &c, 1);
609 + ast_mutex_unlock(&(dev->lock));
612 + ast_mutex_unlock(&(dev->sco_lock));
614 + } else if (pfd[0].revents) {
616 + int e = sock_err(pfd[0].fd);
617 + ast_log(LOG_ERROR, "SCO connection error: %s (errno %d)\n", strerror(e), e);
620 + } else if (pfd[1].revents & POLLIN) {
624 + len = read(pfd[1].fd, &c, 1);
625 + sending = (sending) ? 0 : 1;
627 + ast_mutex_unlock(&(dev->sco_lock));
629 + } else if (pfd[1].revents) {
631 + int e = sock_err(pfd[1].fd);
632 + ast_log(LOG_ERROR, "SCO pipe connection event %d on pipe[1]=%d: %s (errno %d)\n", pfd[1].revents, pfd[1].fd, strerror(e), e);
636 + ast_log(LOG_NOTICE, "Unhandled poll output\n");
637 + ast_mutex_unlock(&(dev->sco_lock));
642 + ast_mutex_lock(&(dev->lock));
645 + dev->sco_running = -1;
646 + ast_mutex_unlock(&(dev->sco_lock));
648 + ast_queue_control(dev->owner, AST_CONTROL_HANGUP);
649 + ast_mutex_unlock(&(dev->lock));
650 + ast_log(LOG_DEBUG, "SCO thread stopped\n");
654 +/* Start SCO thread. Must be called with dev->lock */
657 +sco_start(blt_dev_t * dev, int fd)
660 + if (dev->sco_pipe[1] <= 0) {
661 + ast_log(LOG_ERROR, "SCO pipe[1] == %d\n", dev->sco_pipe[1]);
665 + ast_mutex_lock(&(dev->sco_lock));
667 + if (dev->sco_running != -1) {
668 + ast_log(LOG_ERROR, "Tried to start SCO thread while already running\n");
669 + ast_mutex_unlock(&(dev->sco_lock));
673 + if (dev->sco == -1) {
676 + } else if (sco_connect(dev) != 0) {
677 + ast_log(LOG_ERROR, "SCO fd invalid\n");
678 + ast_mutex_unlock(&(dev->sco_lock));
683 + dev->sco_running = 1;
685 + if (ast_pthread_create(&(dev->sco_thread), NULL, sco_thread, dev) < 0) {
686 + ast_log(LOG_ERROR, "Unable to start SCO thread.\n");
687 + dev->sco_running = -1;
688 + ast_mutex_unlock(&(dev->sco_lock));
692 + ast_mutex_unlock(&(dev->sco_lock));
697 +/* Stop SCO thread. Must be called with dev->lock */
700 +sco_stop(blt_dev_t * dev)
702 + ast_mutex_lock(&(dev->sco_lock));
703 + if (dev->sco_running == 1)
704 + dev->sco_running = 0;
706 + dev->sco_running = -1;
707 + dev->sco_sending = 0;
708 + ast_mutex_unlock(&(dev->sco_lock));
712 +/* ---------------------------------- */
714 +/* Answer the call. Call with lock held on device */
717 +answer(blt_dev_t * dev)
720 + if ( (!dev->owner) || (dev->ready != 1) || (dev->status != BLT_STATUS_READY && dev->status != BLT_STATUS_RINGING)) {
721 + ast_log(LOG_ERROR, "Attempt to answer() in invalid state (owner=%p, ready=%d, status=%s)\n",
722 + dev->owner, dev->ready, status2str(dev->status));
726 + // dev->sd = sco_connect(&local_bdaddr, &(dev->bdaddr), NULL, NULL, 0);
727 + // dev->status = BLT_STATUS_IN_CALL;
728 + // dev->owner->fds[0] = dev->sd;
729 + // if we are answering (hitting button):
730 + ast_queue_control(dev->owner, AST_CONTROL_ANSWER);
731 + // if asterisk signals us to answer:
732 + // ast_setstate(ast, AST_STATE_UP);
734 + /* Start SCO link */
735 + sco_start(dev, -1);
739 +/* ---------------------------------- */
742 +blt_write(struct ast_channel * ast, struct ast_frame * frame)
744 + blt_dev_t * dev = ast->pvt->pvt;
746 + /* Write a frame of (presumably voice) data */
748 + if (frame->frametype != AST_FRAME_VOICE) {
749 + ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
753 + if (!(frame->subclass & BLUETOOTH_FORMAT)) {
754 + ast_log(LOG_WARNING, "Cannot handle frames in format %d\n", frame->subclass);
758 + if (ast->_state != AST_STATE_UP) {
762 + ast_mutex_lock(&(dev->sco_lock));
763 + set_buffer(dev->sco_buf_out, frame->data, BUFLEN, &(dev->sco_pos_out), MIN(frame->datalen, BUFLEN));
764 + ast_mutex_unlock(&(dev->sco_lock));
770 +static struct ast_frame *
771 +blt_read(struct ast_channel * ast)
773 + blt_dev_t * dev = ast->pvt->pvt;
777 + /* Some nice norms */
779 + dev->fr.datalen = 0;
780 + dev->fr.samples = 0;
781 + dev->fr.data = NULL;
782 + dev->fr.src = BLT_CHAN_NAME;
783 + dev->fr.offset = 0;
784 + dev->fr.mallocd = 0;
785 + dev->fr.delivery.tv_sec = 0;
786 + dev->fr.delivery.tv_usec = 0;
788 + ast_mutex_lock(&(dev->sco_lock));
789 + dev->sco_sending = 1;
790 + read(dev->sco_pipe[0], &c, 1);
791 + len = get_buffer(dev->buf, dev->sco_buf_in, BUFLEN, &(dev->sco_pos_in), 48);
792 + ast_mutex_unlock(&(dev->sco_lock));
794 + dev->fr.data = dev->buf;
795 + dev->fr.samples = len / 2;
796 + dev->fr.datalen = len;
797 + dev->fr.frametype = AST_FRAME_VOICE;
798 + dev->fr.subclass = BLUETOOTH_FORMAT;
799 + dev->fr.offset = 0;
804 +/* Escape Any '"' in str. Return malloc()ed string */
806 +escape_str(char * str)
820 + ret = malloc(len + 1);
821 + pret = memset(ret, 0, len + 1);
835 +ring_hs(blt_dev_t * dev)
837 +#if (ASTERISK_VERSION_NUM < 010100)
838 + char tmp[AST_MAX_EXTENSION];
842 + ast_mutex_lock(&(dev->lock));
844 + if (dev->owner == NULL) {
845 + ast_mutex_unlock(&(dev->lock));
850 + dev->status = BLT_STATUS_RINGING;
852 + send_atcmd(dev, "RING");
854 + dev->owner->rings++;
856 + // XXX:T: '"' needs to be escaped in ELIP.
858 +#if (ASTERISK_VERSION_NUM < 010100)
860 + if (dev->owner->callerid) {
862 + memset(tmp, 0, sizeof(tmp));
863 + strncpy(tmp, dev->owner->callerid, sizeof(tmp)-1);
865 + if (!ast_callerid_parse(tmp, &name, &num)) {
867 + if (dev->clip && num)
868 + send_atcmd(dev, "+CLIP: \"%s\",129", num);
870 + if (dev->elip && name) {
871 + char * esc = escape_str(name);
872 + send_atcmd(dev, "*ELIP: \"%s\"", esc);
881 + if (dev->clip && dev->owner->cid.cid_num)
882 + send_atcmd(dev, "+CLIP: \"%s\",129", dev->owner->cid.cid_num);
884 + if (dev->elip && dev->owner->cid.cid_name) {
885 + char * esc = escape_str(dev->owner->cid.cid_name);
886 + send_atcmd(dev, "*ELIP: \"%s\"", esc);
892 + ast_mutex_unlock(&(dev->lock));
898 + * If the HS is already connected, then just send RING, otherwise, things get a
899 + * little more sticky. We first have to find the channel for HS using SDP,
900 + * then intiate the connection. Once we've done that, we can start the call.
904 +blt_call(struct ast_channel * ast, char * dest, int timeout)
906 + blt_dev_t * dev = ast->pvt->pvt;
908 + if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
909 + ast_log(LOG_WARNING, "blt_call called on %s, neither down nor reserved\n", ast->name);
913 + ast_log(LOG_DEBUG, "Calling %s on %s [t: %d]\n", dest, ast->name, timeout);
915 + if (ast_mutex_lock(&iface_lock)) {
916 + ast_log(LOG_ERROR, "Failed to get iface_lock.\n");
920 +// ast_mutex_lock(&(dev->lock));
922 + if (dev->ready == 0) {
923 + ast_log(LOG_WARNING, "Tried to call a device not ready/connected.\n");
924 + ast_setstate(ast, AST_CONTROL_CONGESTION);
925 +// ast_mutex_unlock(&(dev->lock));
926 + ast_mutex_unlock(&iface_lock);
930 + if (dev->role == BLT_ROLE_HS) {
932 + send_atcmd(dev, "+CIEV: 3,1");
934 + dev->ring_timer = ast_sched_add(sched, 5000, AST_SCHED_CB(ring_hs), dev);
938 + ast_setstate(ast, AST_STATE_RINGING);
939 + ast_queue_control(ast, AST_CONTROL_RINGING);
941 + } else if (dev->role == BLT_ROLE_AG) {
943 + send_atcmd(dev, "ATD%s;", dev->dnid);
947 + ast_setstate(ast, AST_CONTROL_CONGESTION);
948 + ast_log(LOG_ERROR, "Unknown device role\n");
952 +// ast_mutex_unlock(&(dev->lock));
953 + ast_mutex_unlock(&iface_lock);
959 +blt_hangup(struct ast_channel * ast)
961 + blt_dev_t * dev = ast->pvt->pvt;
963 + ast_log(LOG_DEBUG, "blt_hangup(%s)\n", ast->name);
965 + if (!ast->pvt->pvt) {
966 + ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
970 + if (ast_mutex_lock(&iface_lock)) {
971 + ast_log(LOG_ERROR, "Failed to get iface_lock\n");
975 + ast_mutex_lock(&(dev->lock));
978 + dev->sco_sending = 0;
980 + if (dev->role == BLT_ROLE_HS) {
982 + if (dev->ringing == 0) {
983 + // Actual call in progress
984 + send_atcmd(dev, "+CIEV: 2,0");
987 + // Just ringing still
989 + if (dev->role == BLT_ROLE_HS)
990 + send_atcmd(dev, "+CIEV: 3,0");
992 + if (dev->ring_timer >= 0)
993 + ast_sched_del(sched, dev->ring_timer);
995 + dev->ring_timer = -1;
1000 + } else if (dev->role == BLT_ROLE_AG) {
1003 + send_atcmd(dev, "AT+CHUP");
1007 + if (dev->status == BLT_STATUS_IN_CALL || dev->status == BLT_STATUS_RINGING)
1008 + dev->status = BLT_STATUS_READY;
1010 + ast->pvt->pvt = NULL;
1011 + dev->owner = NULL;
1012 + ast_mutex_unlock(&(dev->lock));
1013 + ast_setstate(ast, AST_STATE_DOWN);
1014 + ast_mutex_unlock(&(iface_lock));
1020 +blt_indicate(struct ast_channel * c, int condition)
1022 + ast_log(LOG_DEBUG, "blt_indicate (%d)\n", condition);
1024 + switch(condition) {
1025 + case AST_CONTROL_RINGING:
1028 + ast_log(LOG_WARNING, "Don't know how to condition %d\n", condition);
1035 +blt_answer(struct ast_channel * ast)
1037 + blt_dev_t * dev = ast->pvt->pvt;
1039 + ast_mutex_lock(&dev->lock);
1041 + // if (dev->ring_timer >= 0)
1042 + // ast_sched_del(sched, dev->ring_timer);
1043 + // dev->ring_timer = -1;
1045 + ast_log(LOG_DEBUG, "Answering interface\n");
1047 + if (ast->_state != AST_STATE_UP) {
1048 + send_atcmd(dev, "+CIEV: 2,1");
1049 + send_atcmd(dev, "+CIEV: 3,0");
1050 + sco_start(dev, -1);
1051 + ast_setstate(ast, AST_STATE_UP);
1054 + ast_mutex_unlock(&dev->lock);
1059 +static struct ast_channel *
1060 +blt_new(blt_dev_t * dev, int state, const char * context, const char * number)
1062 + struct ast_channel * ast;
1065 + if ((ast = ast_channel_alloc(1)) == NULL) {
1066 + ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
1070 + snprintf(ast->name, sizeof(ast->name), "BLT/%s", dev->name);
1072 + // ast->fds[0] = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
1074 + ast->nativeformats = BLUETOOTH_FORMAT;
1075 + ast->pvt->rawreadformat = BLUETOOTH_FORMAT;
1076 + ast->pvt->rawwriteformat = BLUETOOTH_FORMAT;
1077 + ast->writeformat = BLUETOOTH_FORMAT;
1078 + ast->readformat = BLUETOOTH_FORMAT;
1080 + ast_setstate(ast, state);
1082 + ast->type = BLT_CHAN_NAME;
1084 + ast->pvt->pvt = dev;
1086 + ast->pvt->call = blt_call;
1087 + ast->pvt->indicate = blt_indicate;
1088 + ast->pvt->hangup = blt_hangup;
1089 + ast->pvt->read = blt_read;
1090 + ast->pvt->write = blt_write;
1091 + ast->pvt->answer = blt_answer;
1093 + strncpy(ast->context, context, sizeof(ast->context)-1);
1094 + strncpy(ast->exten, number, sizeof(ast->exten) - 1);
1096 + ast->language[0] = '\0';
1098 + ast->fds[0] = dev->sco_pipe[0];
1099 + write(dev->sco_pipe[1], &c, 1);
1103 + ast_mutex_lock(&usecnt_lock);
1105 + ast_mutex_unlock(&usecnt_lock);
1107 + ast_update_use_count();
1109 + if (state != AST_STATE_DOWN) {
1110 + if (ast_pbx_start(ast)) {
1111 + ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast->name);
1119 +static struct ast_channel *
1120 +#if (ASTERISK_VERSION_NUM < 010100)
1121 +blt_request(char * type, int format, void * local_data)
1123 +blt_request(const char * type, int format, void * local_data)
1126 + char * data = (char*)local_data;
1128 + blt_dev_t * dev = NULL;
1129 + struct ast_channel * ast = NULL;
1130 + char * number = data, * dname;
1132 + dname = strsep(&number, "/");
1134 + oldformat = format;
1136 + format &= BLUETOOTH_FORMAT;
1139 + ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
1143 + ast_log(LOG_DEBUG, "Dialing '%s' via '%s'\n", number, dname);
1145 + if (ast_mutex_lock(&iface_lock)) {
1146 + ast_log(LOG_ERROR, "Unable to lock iface_list\n");
1153 + if (strcmp(dev->name, dname) == 0) {
1154 + ast_mutex_lock(&(dev->lock));
1155 + if (!dev->ready) {
1156 + ast_log(LOG_ERROR, "Device %s is not connected\n", dev->name);
1157 + ast_mutex_unlock(&(dev->lock));
1158 + ast_mutex_unlock(&iface_lock);
1166 + ast_mutex_unlock(&iface_lock);
1169 + ast_log(LOG_WARNING, "Failed to find device named '%s'\n", dname);
1173 + if (number && dev->role != BLT_ROLE_AG) {
1174 + ast_log(LOG_WARNING, "Tried to send a call out on non AG\n");
1175 + ast_mutex_unlock(&(dev->lock));
1179 + if (dev->role == BLT_ROLE_AG)
1180 + strncpy(dev->dnid, number, sizeof(dev->dnid) - 1);
1182 + ast = blt_new(dev, AST_STATE_DOWN, "bluetooth", "s");
1184 + ast_mutex_unlock(&(dev->lock));
1189 +/* ---------------------------------- */
1192 +/* ---- AT COMMAND SOCKET STUFF ---- */
1195 +send_atcmd(blt_dev_t * dev, const char * fmt, ...)
1201 + va_start(ap, fmt);
1202 + len = vsnprintf(buf, 1023, fmt, ap);
1205 + if (option_verbose)
1206 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < %s\n", role2str(dev->role), 10, dev->name, buf);
1208 + write(dev->rd, "\r\n", 2);
1209 + len = write(dev->rd, buf, len);
1210 + write(dev->rd, "\r\n", 2);
1211 + return (len) ? 0 : -1;
1216 +send_atcmd_ok(blt_dev_t * dev, const char * cmd)
1219 + strncpy(dev->last_ok_cmd, cmd, BLT_RDBUFF_MAX - 1);
1220 + if (option_verbose)
1221 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < OK\n", role2str(dev->role), 10, dev->name);
1222 + len = write(dev->rd, "\r\nOK\r\n", 6);
1223 + return (len) ? 0 : -1;
1227 +send_atcmd_error(blt_dev_t * dev)
1231 + if (option_verbose)
1232 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s < ERROR\n", role2str(dev->role), 10, dev->name);
1234 +// write(dev->rd, "\r\n", 2);
1235 +// len = write(dev->rd, dev->last_ok_cmd, 5);
1236 + write(dev->rd, "\r\n", 2);
1237 + len = write(dev->rd, "ERROR", 5);
1238 + write(dev->rd, "\r\n", 2);
1240 + return (len) ? 0 : -1;
1244 +/* ---------------------------------- */
1246 +/* -- Handle negotiation when we're an AG -- */
1248 +/* Bluetooth Support */
1251 +atcmd_brsf_set(blt_dev_t * dev, const char * arg, int len)
1253 + ast_log(LOG_DEBUG, "Device Supports: %s\n", arg);
1254 + dev->brsf = atoi(arg);
1255 + send_atcmd(dev, "+BRSF: %d", 23);
1259 +/* Bluetooth Voice Recognition */
1262 +atcmd_bvra_set(blt_dev_t * dev, const char * arg, int len)
1264 + ast_log(LOG_WARNING, "+BVRA Not Yet Supported\n");
1267 + // XXX:T: Fix voice recognition somehow!
1268 + int action = atoi(arg);
1269 + ast_log(LOG_DEBUG, "Voice Recognition: %s\n", (a) ? "ACTIVATED" : "DEACTIVATED");
1270 + if ((action == 0) & (dev->bvra == 1)) {
1273 + // XXX:T: Shutdown any active bvra channel
1274 + ast_log(LOG_DEBUG, "Voice Recognition: DISABLED\n");
1275 + } else if ((action == 1) && (dev->bvra == 0)) {
1278 + // XXX:T: Schedule connection to voice recognition extension/application
1279 + ast_log(LOG_DEBUG, "Voice Recognition: ENABLED\n");
1281 + ast_log(LOG_ERROR, "+BVRA out of sync (we think %d, but HS wants %d)\n", dev->bvra, action);
1291 +atcmd_cclk_read(blt_dev_t * dev)
1294 + const time_t ti = time(0);
1295 + tp = localtime_r(&ti, &t);
1296 + send_atcmd(dev, "+CCLK: \"%02d/%02d/%02d,%02d:%02d:%02d+%02d\"",
1297 + (tp->tm_year % 100), (tp->tm_mon + 1), (tp->tm_mday),
1298 + tp->tm_hour, tp->tm_min, tp->tm_sec, ((tp->tm_gmtoff / 60) / 15));
1302 +/* CHUP - Hangup Call */
1305 +atcmd_chup_execute(blt_dev_t * dev, const char * data)
1307 + if (!dev->owner) {
1308 + ast_log(LOG_ERROR, "Request to hangup call when none in progress\n");
1311 + ast_log(LOG_DEBUG, "Hangup Call\n");
1312 + ast_queue_control(dev->owner, AST_CONTROL_HANGUP);
1316 +/* CIND - Call Indicator */
1319 +atcmd_cind_read(blt_dev_t * dev)
1321 + send_atcmd(dev, "+CIND: 1,0,0");
1326 +atcmd_cind_test(blt_dev_t * dev)
1328 + send_atcmd(dev, "+CIND: (\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0-4))");
1335 +atcmd_clan_read(blt_dev_t * dev)
1337 + send_atcmd(dev, "+CLAN: \"en\"");
1341 +/* Caller Id Presentation */
1344 +atcmd_clip_set(blt_dev_t * dev, const char * arg, int len)
1346 + dev->clip = atoi(arg);
1350 +/* Conneced Line Identification Presentation */
1353 +atcmd_colp_set(blt_dev_t * dev, const char * arg, int len)
1355 + dev->colp = atoi(arg);
1359 +/* CMER - Mobile Equipment Event Reporting */
1362 +atcmd_cmer_set(blt_dev_t * dev, const char * arg, int len)
1365 + dev->status = BLT_STATUS_READY;
1369 +/* PhoneBook Types:
1371 + * - FD - SIM Fixed Dialing Phone Book
1372 + * - ME - ME Phone book
1373 + * - SM - SIM Phone Book
1374 + * - DC - ME dialled-calls list
1375 + * - RC - ME recieved-calls lisr
1376 + * - MC - ME missed-calls list
1377 + * - MV - ME Voice Activated Dialing List
1378 + * - HP - Hierachial Phone Book
1379 + * - BC - Own Business Card (PIN2 required)
1383 +/* Read Phone Book Entry */
1386 +atcmd_cpbr_set(blt_dev_t * dev, const char * arg, int len)
1388 + // XXX:T: Fix the phone book!
1389 + // * Maybe add res_phonebook or something? */
1390 + send_atcmd(dev, "+CPBR: %d,\"%s\",128,\"%s\"", atoi(arg), arg, arg);
1394 +/* Select Phone Book */
1397 +atcmd_cpbs_set(blt_dev_t * dev, const char * arg, int len)
1399 + // XXX:T: I guess we'll just accept any?
1404 +atcmd_cscs_set(blt_dev_t * dev, const char * arg, int len)
1406 + // XXX:T: Language
1411 +atcmd_eips_set(blt_dev_t * dev, const char * arg, int len)
1413 + ast_log(LOG_DEBUG, "Identify Presentation Set: %s=%s\n",
1414 + (*(arg) == 49) ? "ELIP" : "EOLP",
1415 + (*(arg+2) == 49) ? "ON" : "OFF");
1418 + dev->eolp = (*(arg+2) == 49) ? 1 : 0;
1420 + dev->elip = (*(arg+2) == 49) ? 1 : 0;
1425 +/* VGS - Speaker Volume Gain */
1428 +atcmd_vgs_set(blt_dev_t * dev, const char * arg, int len)
1430 + dev->gain_speaker = atoi(arg);
1436 +atcmd_dial_execute(blt_dev_t * dev, const char * data)
1438 + char * number = NULL;
1440 + /* Make sure there is a ';' at the end of the line */
1441 + if (*(data + (strlen(data) - 1)) != ';') {
1442 + ast_log(LOG_WARNING, "Can't dial non-voice right now: %s\n", data);
1446 + number = strndup(data, strlen(data) - 1);
1447 + ast_log(LOG_NOTICE, "Dial: [%s]\n", number);
1449 + send_atcmd(dev, "+CIEV: 2,1");
1450 + send_atcmd(dev, "+CIEV: 3,0");
1452 + sco_start(dev, -1);
1454 + if (blt_new(dev, AST_STATE_UP, "bluetooth", number) == NULL) {
1466 +atcmd_answer_execute(blt_dev_t * dev, const char * data)
1469 + if (!dev->ringing || !dev->owner) {
1470 + ast_log(LOG_WARNING, "Can't answer non existant call\n");
1476 + if (dev->ring_timer >= 0)
1477 + ast_sched_del(sched, dev->ring_timer);
1479 + dev->ring_timer = -1;
1481 + send_atcmd(dev, "+CIEV: 2,1");
1482 + send_atcmd(dev, "+CIEV: 3,0");
1484 + return answer(dev);
1488 +ag_unsol_ciev(blt_dev_t * dev, const char * data)
1490 + const char * orig = data;
1494 + while (*(data) && *(data) == ' ')
1497 + if (*(data) == 0) {
1498 + ast_log(LOG_WARNING, "Invalid value[1] for '+CIEV:%s'\n", orig);
1502 + indicator = *(data++) - 48;
1504 + if (*(data++) != ',') {
1505 + ast_log(LOG_WARNING, "Invalid value[2] for '+CIEV:%s'\n", orig);
1509 + if (*(data) == 0) {
1510 + ast_log(LOG_WARNING, "Invalid value[3] for '+CIEV:%s'\n", orig);
1514 + status = *(data) - 48;
1516 + set_cind(dev, indicator, status);
1522 +ag_unsol_cind(blt_dev_t * dev, const char * data)
1525 + while (*(data) && *(data) == ' ')
1529 + if (dev->cind == 0)
1534 + while ((data = parse_cind(data, name, 1023)) != NULL) {
1535 + ast_log(LOG_DEBUG, "CIND: %d=%s\n", pos, name);
1536 + if (strcmp(name, "call") == 0)
1537 + dev->call_pos = pos;
1538 + else if (strcmp(name, "service") == 0)
1539 + dev->service_pos = pos;
1540 + else if (strcmp(name, "call_setup") == 0 || strcmp(name, "callsetup") == 0)
1541 + dev->callsetup_pos = pos;
1545 + ast_log(LOG_DEBUG, "CIND: %d=%s\n", pos, name);
1549 + int pos = 1, len = 0;
1551 + const char * start = data;
1554 + if (*data == ',') {
1555 + memset(val, 0, 128);
1556 + strncpy(val, start, len);
1557 + set_cind(dev, pos, atoi(val));
1568 + memset(val, 0, 128);
1569 + strncpy(val, start, len);
1570 + ast_log(LOG_DEBUG, "CIND IND %d set to %d [%s]\n", pos, atoi(val), val);
1581 + { "A", NULL, NULL, atcmd_answer_execute, NULL, NULL },
1582 + { "D", NULL, NULL, atcmd_dial_execute, NULL, NULL },
1583 + { "+BRSF", atcmd_brsf_set, NULL, NULL, NULL, NULL },
1584 + { "+BVRA", atcmd_bvra_set, NULL, NULL, NULL, NULL },
1585 + { "+CCLK", NULL, atcmd_cclk_read, NULL, NULL, NULL },
1586 + { "+CHUP", NULL, NULL, atcmd_chup_execute, NULL, NULL },
1587 + { "+CIEV", NULL, NULL, NULL, NULL, ag_unsol_ciev },
1588 + { "+CIND", NULL, atcmd_cind_read, NULL, atcmd_cind_test, ag_unsol_cind },
1589 + { "+CLAN", NULL, atcmd_clan_read, NULL, NULL, NULL },
1590 + { "+CLIP", atcmd_clip_set, NULL, NULL, NULL, NULL },
1591 + { "+COLP", atcmd_colp_set, NULL, NULL, NULL, NULL },
1592 + { "+CMER", atcmd_cmer_set, NULL, NULL, NULL, NULL },
1593 + { "+CPBR", atcmd_cpbr_set, NULL, NULL, NULL, NULL },
1594 + { "+CPBS", atcmd_cpbs_set, NULL, NULL, NULL, NULL },
1595 + { "+CSCS", atcmd_cscs_set, NULL, NULL, NULL, NULL },
1596 + { "*EIPS", atcmd_eips_set, NULL, NULL, NULL, NULL },
1597 + { "+VGS", atcmd_vgs_set, NULL, NULL, NULL, NULL },
1600 +#define ATCMD_LIST_LEN (sizeof(atcmd_list) / sizeof(blt_atcb_t))
1602 +/* ---------------------------------- */
1604 +/* -- Handle negotiation when we're a HS -- */
1607 +ag_unknown_response(blt_dev_t * dev, char * cmd)
1609 + ast_log(LOG_DEBUG, "Got UNKN response: %s\n", cmd);
1617 +ag_cgmi_response(blt_dev_t * dev, char * cmd)
1619 + // CGMM - Phone Model
1620 + // CGMR - Phone Revision
1623 + // VTS - send tone
1627 + // CSMS - SMS STUFFS
1631 + // CSCA - sms CENTER NUMBER
1632 + // CNMI - SMS INDICATION
1633 + // ast_log(LOG_DEBUG, "Manufacturer: %s\n", cmd);
1634 + dev->cb = ag_unknown_response;
1638 +ag_cgmi_valid_response(blt_dev_t * dev, char * cmd)
1640 + // send_atcmd(dev, "AT+WS46?");
1641 + // send_atcmd(dev, "AT+CRC=1");
1642 + // send_atcmd(dev, "AT+CNUM");
1644 + if (strcmp(cmd, "OK") == 0) {
1645 + send_atcmd(dev, "AT+CGMI");
1646 + dev->cb = ag_cgmi_response;
1648 + dev->cb = ag_unknown_response;
1653 +ag_clip_response(blt_dev_t * dev, char * cmd)
1655 + send_atcmd(dev, "AT+CGMI=?");
1656 + dev->cb = ag_cgmi_valid_response;
1660 +ag_cmer_response(blt_dev_t * dev, char * cmd)
1662 + dev->cb = ag_clip_response;
1664 + dev->status = BLT_STATUS_READY;
1665 + send_atcmd(dev, "AT+CLIP=1");
1669 +ag_cind_status_response(blt_dev_t * dev, char * cmd)
1671 + // XXX:T: Handle response.
1672 + dev->cb = ag_cmer_response;
1673 + send_atcmd(dev, "AT+CMER=3,0,0,1");
1674 + // Initiase SCO link!
1678 +ag_cind_response(blt_dev_t * dev, char * cmd)
1680 + dev->cb = ag_cind_status_response;
1682 + send_atcmd(dev, "AT+CIND?");
1686 +ag_brsf_response(blt_dev_t * dev, char * cmd)
1688 + dev->cb = ag_cind_response;
1689 + ast_log(LOG_DEBUG, "Bluetooth features: %s\n", cmd);
1691 + send_atcmd(dev, "AT+CIND=?");
1694 +/* ---------------------------------- */
1697 +sdp_register(sdp_session_t * session)
1699 + // XXX:T: Fix this horrible function so it makes some sense and is extensible!
1700 + sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1701 + uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1702 + sdp_profile_desc_t profile;
1703 + sdp_list_t *aproto, *proto[2];
1704 + sdp_record_t record;
1705 + uint8_t u8 = rfcomm_channel_ag;
1706 + uint8_t u8_hs = rfcomm_channel_hs;
1707 + sdp_data_t *channel;
1710 + memset((void *)&record, 0, sizeof(sdp_record_t));
1711 + record.handle = 0xffffffff;
1712 + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1713 + root = sdp_list_append(0, &root_uuid);
1714 + sdp_set_browse_groups(&record, root);
1716 + // Register as an AG
1718 + sdp_uuid16_create(&svclass_uuid, HANDSFREE_AUDIO_GW_SVCLASS_ID);
1719 + svclass_id = sdp_list_append(0, &svclass_uuid);
1720 + sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1721 + svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1722 + sdp_set_service_classes(&record, svclass_id);
1723 + sdp_uuid16_create(&profile.uuid, 0x111f);
1724 + profile.version = 0x0100;
1725 + pfseq = sdp_list_append(0, &profile);
1727 + sdp_set_profile_descs(&record, pfseq);
1729 + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1730 + proto[0] = sdp_list_append(0, &l2cap_uuid);
1731 + apseq = sdp_list_append(0, proto[0]);
1733 + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1734 + proto[1] = sdp_list_append(0, &rfcomm_uuid);
1735 + channel = sdp_data_alloc(SDP_UINT8, &u8);
1736 + proto[1] = sdp_list_append(proto[1], channel);
1737 + apseq = sdp_list_append(apseq, proto[1]);
1739 + aproto = sdp_list_append(0, apseq);
1740 + sdp_set_access_protos(&record, aproto);
1742 + sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1744 + if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1745 + ast_log(LOG_ERROR, "Service Record registration failed\n");
1750 + sdp_record_ag = record.handle;
1752 + ast_log(LOG_NOTICE, "HeadsetAudioGateway service registered\n");
1754 + sdp_data_free(channel);
1755 + sdp_list_free(proto[0], 0);
1756 + sdp_list_free(proto[1], 0);
1757 + sdp_list_free(apseq, 0);
1758 + sdp_list_free(aproto, 0);
1762 + memset((void *)&record, 0, sizeof(sdp_record_t));
1763 + record.handle = 0xffffffff;
1764 + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1765 + root = sdp_list_append(0, &root_uuid);
1766 + sdp_set_browse_groups(&record, root);
1768 + // Register as an HS
1770 + sdp_uuid16_create(&svclass_uuid, HANDSFREE_AUDIO_GW_SVCLASS_ID);
1771 + svclass_id = sdp_list_append(0, &svclass_uuid);
1772 + sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1773 + svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1774 + sdp_set_service_classes(&record, svclass_id);
1775 + sdp_uuid16_create(&profile.uuid, 0x111e);
1776 + profile.version = 0x0100;
1777 + pfseq = sdp_list_append(0, &profile);
1778 + sdp_set_profile_descs(&record, pfseq);
1780 + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1781 + proto[0] = sdp_list_append(0, &l2cap_uuid);
1782 + apseq = sdp_list_append(0, proto[0]);
1784 + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1785 + proto[1] = sdp_list_append(0, &rfcomm_uuid);
1786 + channel = sdp_data_alloc(SDP_UINT8, &u8_hs);
1787 + proto[1] = sdp_list_append(proto[1], channel);
1788 + apseq = sdp_list_append(apseq, proto[1]);
1790 + aproto = sdp_list_append(0, apseq);
1791 + sdp_set_access_protos(&record, aproto);
1792 + sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1794 + if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1795 + ast_log(LOG_ERROR, "Service Record registration failed\n");
1800 + sdp_record_hs = record.handle;
1802 + ast_log(LOG_NOTICE, "HeadsetAudioGateway service registered\n");
1805 + sdp_data_free(channel);
1806 + sdp_list_free(proto[0], 0);
1807 + sdp_list_free(proto[1], 0);
1808 + sdp_list_free(apseq, 0);
1809 + sdp_list_free(aproto, 0);
1815 +rfcomm_listen(bdaddr_t * bdaddr, int channel)
1819 + struct sockaddr_rc loc_addr;
1822 + if ((sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
1823 + ast_log(LOG_ERROR, "Can't create socket: %s (errno: %d)\n", strerror(errno), errno);
1827 + loc_addr.rc_family = AF_BLUETOOTH;
1829 + /* Local Interface Address */
1830 + bacpy(&loc_addr.rc_bdaddr, bdaddr);
1833 + loc_addr.rc_channel = channel;
1835 + if (bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) {
1836 + ast_log(LOG_ERROR, "Can't bind socket: %s (errno: %d)\n", strerror(errno), errno);
1841 + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
1842 + ast_log(LOG_ERROR, "Set socket SO_REUSEADDR option on failed: errno %d, %s", errno, strerror(errno));
1847 + if (fcntl(sock, F_SETFL, O_RDWR|O_NONBLOCK) != 0)
1848 + ast_log(LOG_ERROR, "Can't set RFCOMM socket to NBIO\n");
1850 + if (listen(sock, 10) < 0) {
1851 + ast_log(LOG_ERROR,"Can not listen on the socket. %s(%d)\n", strerror(errno), errno);
1856 + ast_log(LOG_NOTICE, "Listening for RFCOMM channel %d connections on FD %d\n", channel, sock);
1863 +sco_listen(bdaddr_t * bdaddr)
1867 + struct sockaddr_sco loc_addr;
1869 + memset(&loc_addr, 0, sizeof(loc_addr));
1871 + if ((sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1872 + ast_log(LOG_ERROR, "Can't create SCO socket: %s (errno: %d)\n", strerror(errno), errno);
1876 + loc_addr.sco_family = AF_BLUETOOTH;
1877 + bacpy(&loc_addr.sco_bdaddr, BDADDR_ANY);
1879 + if (bind(sock, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) {
1880 + ast_log(LOG_ERROR, "Can't bind SCO socket: %s (errno: %d)\n", strerror(errno), errno);
1885 + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
1886 + ast_log(LOG_ERROR, "Set SCO socket SO_REUSEADDR option on failed: errno %d, %s", errno, strerror(errno));
1891 + if (fcntl(sock, F_SETFL, O_RDWR|O_NONBLOCK) != 0)
1892 + ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n");
1894 + if (listen(sock, 10) < 0) {
1895 + ast_log(LOG_ERROR,"Can not listen on SCO socket: %s(%d)\n", strerror(errno), errno);
1900 + ast_log(LOG_NOTICE, "Listening for SCO connections on FD %d\n", sock);
1906 +rfcomm_connect(bdaddr_t * src, bdaddr_t * dst, int channel, int nbio)
1908 + struct sockaddr_rc addr;
1911 + if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
1915 + memset(&addr, 0, sizeof(addr));
1916 + addr.rc_family = AF_BLUETOOTH;
1917 + bacpy(&addr.rc_bdaddr, src);
1918 + addr.rc_channel = 0;
1920 + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1925 + memset(&addr, 0, sizeof(addr));
1926 + addr.rc_family = AF_BLUETOOTH;
1927 + bacpy(&addr.rc_bdaddr, dst);
1928 + addr.rc_channel = channel;
1931 + if (fcntl(s, F_SETFL, O_RDWR|O_NONBLOCK) != 0)
1932 + ast_log(LOG_ERROR, "Can't set RFCOMM socket to NBIO\n");
1935 + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 && (nbio != 1 || (errno != EAGAIN))) {
1943 +/* Must be called with dev->lock held */
1946 +sco_connect(blt_dev_t * dev)
1948 + struct sockaddr_sco addr;
1949 + // struct sco_conninfo conn;
1950 + // struct sco_options opts;
1952 + // bdaddr_t * src = &local_bdaddr;
1955 + bdaddr_t * dst = &(dev->bdaddr);
1957 + if (dev->sco != -1) {
1958 + ast_log(LOG_ERROR, "SCO fd already open.\n");
1962 + if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1963 + ast_log(LOG_ERROR, "Can't create SCO socket(): %s\n", strerror(errno));
1967 + memset(&addr, 0, sizeof(addr));
1969 + addr.sco_family = AF_BLUETOOTH;
1970 + bacpy(&addr.sco_bdaddr, BDADDR_ANY);
1972 + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1973 + ast_log(LOG_ERROR, "Can't bind() SCO socket: %s\n", strerror(errno));
1978 + memset(&addr, 0, sizeof(addr));
1979 + addr.sco_family = AF_BLUETOOTH;
1980 + bacpy(&addr.sco_bdaddr, dst);
1982 + if (fcntl(s, F_SETFL, O_RDWR|O_NONBLOCK) != 0)
1983 + ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n");
1985 + if ((connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) && (errno != EAGAIN)) {
1986 + ast_log(LOG_ERROR, "Can't connect() SCO socket: %s (errno %d)\n", strerror(errno), errno);
1991 + //size = sizeof(conn);
1994 +/* XXX:T: HERE, fix getting SCO conninfo.
1996 + if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) {
1997 + ast_log(LOG_ERROR, "Can't getsockopt SCO_CONNINFO on SCO socket: %s\n", strerror(errno));
2002 + size = sizeof(opts);
2004 + if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) {
2005 + ast_log(LOG_ERROR, "Can't getsockopt SCO_OPTIONS on SCO socket: %s\n", strerror(errno));
2010 + dev->sco_handle = conn.hci_handle;
2011 + dev->sco_mtu = opts.mtu;
2015 + ast_log(LOG_DEBUG, "SCO: %d\n", s);
2023 +/* ---------------------------------- */
2025 +/* Non blocking (async) outgoing bluetooth connection */
2028 +try_connect(blt_dev_t * dev)
2031 + ast_mutex_lock(&(dev->lock));
2033 + if (dev->status != BLT_STATUS_CONNECTING && dev->status != BLT_STATUS_DOWN) {
2034 + ast_mutex_unlock(&(dev->lock));
2038 + if (dev->rd != -1) {
2041 + struct pollfd pfd;
2043 + if (dev->status != BLT_STATUS_CONNECTING) {
2044 + ast_mutex_unlock(&(dev->lock));
2045 + dev->outgoing_id = -1;
2049 + // ret = connect(dev->rd, (struct sockaddr *)&(dev->addr), sizeof(struct sockaddr_rc)); //
2052 + pfd.events = POLLIN | POLLOUT;
2054 + ret = poll(&pfd, 1, 0);
2059 + dev->status = BLT_STATUS_DOWN;
2060 + dev->outgoing_id = ast_sched_add(sched, 10000, AST_SCHED_CB(try_connect), dev);
2061 + ast_mutex_unlock(&(dev->lock));
2067 + int len = sizeof(ret);
2068 + getsockopt(dev->rd, SOL_SOCKET, SO_ERROR, &ret, &len);
2072 + ast_log(LOG_NOTICE, "Initialised bluetooth link to device %s\n", dev->name);
2076 + struct hci_conn_info_req * cr;
2080 + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
2081 + dd = hci_open_dev(hcidev_id);
2082 + cr->type = ACL_LINK;
2083 + bacpy(&cr->bdaddr, &(dev->bdaddr));
2085 + if (ioctl(dd, HCIGETCONNINFO, (unsigned long)cr) < 0) {
2086 + ast_log(LOG_ERROR, "Failed to get connection info: %s\n", strerror(errno));
2088 + ast_log(LOG_DEBUG, "HCI Handle: %d\n", cr->conn_info->handle);
2091 + if (hci_read_remote_name(dd, &(dev->bdaddr), sizeof(name), name, 25000) == 0)
2092 + ast_log(LOG_DEBUG, "Remote Name: %s\n", name);
2097 + dev->status = BLT_STATUS_NEGOTIATING;
2099 + /* If this device is a AG, we initiate the negotiation. */
2101 + if (dev->role == BLT_ROLE_AG) {
2102 + dev->cb = ag_brsf_response;
2103 + send_atcmd(dev, "AT+BRSF=23");
2106 + dev->outgoing_id = -1;
2107 + ast_mutex_unlock(&(dev->lock));
2112 + if (ret != EHOSTDOWN)
2113 + ast_log(LOG_NOTICE, "Connect to device %s failed: %s (errno %d)\n", dev->name, strerror(ret), ret);
2117 + dev->status = BLT_STATUS_DOWN;
2118 + dev->outgoing_id = ast_sched_add(sched, (ret == EHOSTDOWN) ? 10000 : 2500, AST_SCHED_CB(try_connect), dev);
2119 + ast_mutex_unlock(&(dev->lock));
2126 + dev->outgoing_id = ast_sched_add(sched, 100, AST_SCHED_CB(try_connect), dev);
2127 + ast_mutex_unlock(&(dev->lock));
2131 + fd = rfcomm_connect(&local_bdaddr, &(dev->bdaddr), dev->channel, 1);
2134 + ast_log(LOG_WARNING, "NBIO connect() to %s returned %d: %s\n", dev->name, errno, strerror(errno));
2135 + dev->outgoing_id = ast_sched_add(sched, 5000, AST_SCHED_CB(try_connect), dev);
2136 + ast_mutex_unlock(&(dev->lock));
2141 + dev->status = BLT_STATUS_CONNECTING;
2142 + dev->outgoing_id = ast_sched_add(sched, 100, AST_SCHED_CB(try_connect), dev);
2143 + ast_mutex_unlock(&(dev->lock));
2148 +/* Called whenever a new command is recieved while we're the AG */
2152 +process_rfcomm_cmd(blt_dev_t * dev, char * cmd)
2155 + char * fullcmd = cmd;
2157 + if (option_verbose)
2158 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, cmd);
2160 + /* Read the 'AT' from the start of the string */
2161 + if (strncmp(cmd, "AT", 2)) {
2162 + ast_log(LOG_WARNING, "Unknown command without 'AT': %s\n", cmd);
2163 + send_atcmd_error(dev);
2169 + // Don't forget 'AT' on it's own is OK.
2171 + if (strlen(cmd) == 0) {
2172 + send_atcmd_ok(dev, fullcmd);
2176 + for (i = 0 ; i < ATCMD_LIST_LEN ; i++) {
2177 + if (strncmp(atcmd_list[i].str, cmd, strlen(atcmd_list[i].str)) == 0) {
2178 + char * pos = (cmd + strlen(atcmd_list[i].str));
2179 + if ((strncmp(pos, "=?", 2) == 0) && (strlen(pos) == 2)) {
2180 + /* TEST command */
2181 + if (atcmd_list[i].test) {
2182 + if (atcmd_list[i].test(dev) == 0)
2183 + send_atcmd_ok(dev, fullcmd);
2185 + send_atcmd_error(dev);
2187 + send_atcmd_ok(dev, fullcmd);
2189 + } else if ((strncmp(pos, "?", 1) == 0) && (strlen(pos) == 1)) {
2190 + /* READ command */
2191 + if (atcmd_list[i].read) {
2192 + if (atcmd_list[i].read(dev) == 0)
2193 + send_atcmd_ok(dev, fullcmd);
2195 + send_atcmd_error(dev);
2197 + ast_log(LOG_WARNING, "AT Command: '%s' missing READ function\n", fullcmd);
2198 + send_atcmd_error(dev);
2200 + } else if (strncmp(pos, "=", 1) == 0) {
2202 + if (atcmd_list[i].set) {
2203 + if (atcmd_list[i].set(dev, (pos + 1), (*(pos + 1)) ? strlen(pos + 1) : 0) == 0)
2204 + send_atcmd_ok(dev, fullcmd);
2206 + send_atcmd_error(dev);
2208 + ast_log(LOG_WARNING, "AT Command: '%s' missing SET function\n", fullcmd);
2209 + send_atcmd_error(dev);
2212 + /* EXECUTE command */
2213 + if (atcmd_list[i].execute) {
2214 + if (atcmd_list[i].execute(dev, cmd + strlen(atcmd_list[i].str)) == 0)
2215 + send_atcmd_ok(dev, fullcmd);
2217 + send_atcmd_error(dev);
2219 + ast_log(LOG_WARNING, "AT Command: '%s' missing EXECUTE function\n", fullcmd);
2220 + send_atcmd_error(dev);
2227 + ast_log(LOG_WARNING, "Unknown AT Command: '%s' (%s)\n", fullcmd, cmd);
2228 + send_atcmd_error(dev);
2233 +/* Called when a socket is incoming */
2236 +handle_incoming(int fd, blt_role_t role)
2239 + struct sockaddr_rc addr;
2240 + int len = sizeof(addr);
2242 + // Got a new incoming socket.
2243 + ast_log(LOG_DEBUG, "Incoming RFCOMM socket\n");
2245 + ast_mutex_lock(&iface_lock);
2247 + fd = accept(fd, (struct sockaddr*)&addr, &len);
2251 + if (bacmp(&(dev->bdaddr), &addr.rc_bdaddr) == 0) {
2252 + ast_log(LOG_DEBUG, "Connect from %s\n", dev->name);
2253 + ast_mutex_lock(&(dev->lock));
2254 + /* Kill any outstanding connect attempt. */
2255 + if (dev->outgoing_id > -1) {
2256 + ast_sched_del(sched, dev->outgoing_id);
2257 + dev->outgoing_id = -1;
2260 + rd_close(dev, 0, 0);
2262 + dev->status = BLT_STATUS_NEGOTIATING;
2265 + if (dev->role == BLT_ROLE_AG) {
2266 + dev->cb = ag_brsf_response;
2267 + send_atcmd(dev, "AT+BRSF=23");
2270 + ast_mutex_unlock(&(dev->lock));
2276 + if (dev == NULL) {
2277 + ast_log(LOG_WARNING, "Connect from unknown device\n");
2280 + ast_mutex_unlock(&iface_lock);
2286 +handle_incoming_sco(int master)
2290 + struct sockaddr_sco addr;
2291 + struct sco_conninfo conn;
2292 + struct sco_options opts;
2293 + int len = sizeof(addr);
2296 + ast_log(LOG_DEBUG, "Incoming SCO socket\n");
2298 + fd = accept(master, (struct sockaddr*)&addr, &len);
2300 + if (fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK) != 0) {
2301 + ast_log(LOG_ERROR, "Can't set SCO socket to NBIO\n");
2306 + len = sizeof(conn);
2308 + if (getsockopt(fd, SOL_SCO, SCO_CONNINFO, &conn, &len) < 0) {
2309 + ast_log(LOG_ERROR, "Can't getsockopt SCO_CONNINFO on SCO socket: %s\n", strerror(errno));
2314 + len = sizeof(opts);
2316 + if (getsockopt(fd, SOL_SCO, SCO_OPTIONS, &opts, &len) < 0) {
2317 + ast_log(LOG_ERROR, "Can't getsockopt SCO_OPTIONS on SCO socket: %s\n", strerror(errno));
2322 + ast_mutex_lock(&iface_lock);
2325 + if (bacmp(&(dev->bdaddr), &addr.sco_bdaddr) == 0) {
2326 + ast_log(LOG_DEBUG, "SCO Connect from %s\n", dev->name);
2327 + ast_mutex_lock(&(dev->lock));
2328 + if (dev->sco_running != -1) {
2329 + ast_log(LOG_ERROR, "Incoming SCO socket, but SCO thread already running.\n");
2331 + sco_start(dev, fd);
2333 + ast_mutex_unlock(&(dev->lock));
2339 + ast_mutex_unlock(&iface_lock);
2341 + if (dev == NULL) {
2342 + ast_log(LOG_WARNING, "SCO Connect from unknown device\n");
2345 + // XXX:T: We need to handle the fact we might have an outgoing connection attempt in progress.
2346 + ast_log(LOG_DEBUG, "SCO: %d, HCIHandle=%d, MUT=%d\n", fd, conn.hci_handle, opts.mtu);
2354 +/* Called when there is data waiting on a socket */
2357 +handle_rd_data(blt_dev_t * dev)
2362 + while ((ret = read(dev->rd, &c, 1)) == 1) {
2364 + // log_buf[i++] = c;
2366 + if (dev->role == BLT_ROLE_HS) {
2369 + ret = process_rfcomm_cmd(dev, dev->rd_buff);
2370 + dev->rd_buff_pos = 0;
2371 + memset(dev->rd_buff, 0, BLT_RDBUFF_MAX);
2375 + if (dev->rd_buff_pos >= BLT_RDBUFF_MAX)
2378 + dev->rd_buff[dev->rd_buff_pos++] = c;
2380 + } else if (dev->role == BLT_ROLE_AG) {
2382 + switch (dev->state) {
2384 + case BLT_STATE_WANT_R:
2386 + dev->state = BLT_STATE_WANT_N;
2387 + } else if (c == '+') {
2388 + dev->state = BLT_STATE_WANT_CMD;
2389 + dev->rd_buff[dev->rd_buff_pos++] = '+';
2391 + ast_log(LOG_ERROR, "Device %s: Expected '\\r', got %d. state=BLT_STATE_WANT_R\n", dev->name, c);
2396 + case BLT_STATE_WANT_N:
2398 + dev->state = BLT_STATE_WANT_CMD;
2400 + ast_log(LOG_ERROR, "Device %s: Expected '\\n', got %d. state=BLT_STATE_WANT_N\n", dev->name, c);
2405 + case BLT_STATE_WANT_CMD:
2407 + dev->state = BLT_STATE_WANT_N2;
2409 + if (dev->rd_buff_pos >= BLT_RDBUFF_MAX) {
2410 + ast_log(LOG_ERROR, "Device %s: Buffer exceeded\n", dev->name);
2413 + dev->rd_buff[dev->rd_buff_pos++] = c;
2417 + case BLT_STATE_WANT_N2:
2420 + dev->state = BLT_STATE_WANT_R;
2422 + if (dev->rd_buff[0] == '+') {
2424 + // find unsolicited
2425 + for (i = 0 ; i < ATCMD_LIST_LEN ; i++) {
2426 + if (strncmp(atcmd_list[i].str, dev->rd_buff, strlen(atcmd_list[i].str)) == 0) {
2427 + if (atcmd_list[i].unsolicited)
2428 + atcmd_list[i].unsolicited(dev, dev->rd_buff + strlen(atcmd_list[i].str) + 1);
2430 + ast_log(LOG_WARNING, "Device %s: Unhandled Unsolicited: %s\n", dev->name, dev->rd_buff);
2435 + if (option_verbose)
2436 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff);
2438 + if (i == ATCMD_LIST_LEN)
2439 + ast_log(LOG_DEBUG, "Device %s: Got unsolicited message: %s\n", dev->name, dev->rd_buff);
2444 + strcmp(dev->rd_buff, "OK") != 0 &&
2445 + strcmp(dev->rd_buff, "CONNECT") != 0 &&
2446 + strcmp(dev->rd_buff, "RING") != 0 &&
2447 + strcmp(dev->rd_buff, "NO CARRIER") != 0 &&
2448 + strcmp(dev->rd_buff, "ERROR") != 0 &&
2449 + strcmp(dev->rd_buff, "NO DIALTONE") != 0 &&
2450 + strcmp(dev->rd_buff, "BUSY") != 0 &&
2451 + strcmp(dev->rd_buff, "NO ANSWER") != 0 &&
2452 + strcmp(dev->rd_buff, "DELAYED") != 0
2454 + // It must be a multiline error
2455 + strncpy(dev->last_err_cmd, dev->rd_buff, 1023);
2456 + if (option_verbose)
2457 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff);
2458 + } else if (dev->cb) {
2459 + if (option_verbose)
2460 + ast_verbose(VERBOSE_PREFIX_1 "[%s] %*s > %s\n", role2str(dev->role), 10, dev->name, dev->rd_buff);
2461 + dev->cb(dev, dev->rd_buff);
2463 + ast_log(LOG_ERROR, "Device %s: Data on socket in HS mode, but no callback\n", dev->name);
2468 + dev->rd_buff_pos = 0;
2469 + memset(dev->rd_buff, 0, BLT_RDBUFF_MAX);
2473 + ast_log(LOG_ERROR, "Device %s: Expected '\\n' got %d. state = BLT_STATE_WANT_N2:\n", dev->name, c);
2481 + ast_log(LOG_ERROR, "Device %s: Unknown device state %d\n", dev->name, dev->state);
2493 +/* Close the devices RFCOMM socket, and SCO if it exists. Must hold dev->lock */
2496 +rd_close(blt_dev_t * dev, int reconnect, int e)
2505 + dev->status = BLT_STATUS_DOWN;
2510 + ast_setstate(dev->owner, AST_STATE_DOWN);
2511 + ast_queue_control(dev->owner, AST_CONTROL_HANGUP);
2514 + /* Schedule a reconnect */
2515 + if (reconnect && dev->autoconnect) {
2516 + dev->outgoing_id = ast_sched_add(sched, 5000, AST_SCHED_CB(try_connect), dev);
2518 + if (monitor_thread == pthread_self()) {
2519 + // Because we're not the monitor thread, we needd to inturrupt poll().
2520 + pthread_kill(monitor_thread, SIGURG);
2524 + ast_log(LOG_NOTICE, "Device %s disconnected, scheduled reconnect in 5 seconds: %s (errno %d)\n", dev->name, strerror(e), e);
2526 + ast_log(LOG_NOTICE, "Device %s disconnected: %s (errno %d)\n", dev->name, strerror(e), e);
2533 + * Remember that we can only add to the scheduler from
2534 + * the do_monitor thread, as it calculates time to next one from
2539 +do_monitor(void * data)
2541 +#define SRV_SOCK_CNT 3
2545 + struct pollfd * pfds = malloc(sizeof(struct pollfd) * (ifcount + SRV_SOCK_CNT));
2547 + /* -- We start off by trying to connect all of our devices (non blocking) -- */
2549 + monitor_pid = getpid();
2551 + if (ast_mutex_lock(&iface_lock)) {
2552 + ast_log(LOG_ERROR, "Failed to get iface_lock.\n");
2559 + if (socketpair(PF_UNIX, SOCK_STREAM, 0, dev->sco_pipe) != 0) {
2560 + ast_log(LOG_ERROR, "Failed to create socket pair: %s (errno %d)\n", strerror(errno), errno);
2561 + ast_mutex_unlock(&iface_lock);
2565 + if (dev->autoconnect && dev->status == BLT_STATUS_DOWN)
2566 + dev->outgoing_id = ast_sched_add(sched, 1500, AST_SCHED_CB(try_connect), dev);
2569 + ast_mutex_unlock(&iface_lock);
2571 + /* -- Now, Scan all sockets, and service scheduler -- */
2573 + pfds[0].fd = rfcomm_sock_ag;
2574 + pfds[0].events = POLLIN;
2576 + pfds[1].fd = rfcomm_sock_hs;
2577 + pfds[1].events = POLLIN;
2579 + pfds[2].fd = sco_socket;
2580 + pfds[2].events = POLLIN;
2583 + int cnt = SRV_SOCK_CNT;
2586 + /* -- Build pfds -- */
2588 + if (ast_mutex_lock(&iface_lock)) {
2589 + ast_log(LOG_ERROR, "Failed to get iface_lock.\n");
2594 + ast_mutex_lock(&(dev->lock));
2595 + if (dev->rd > 0 && ((dev->status != BLT_STATUS_DOWN) && (dev->status != BLT_STATUS_CONNECTING))) {
2596 + pfds[cnt].fd = dev->rd;
2597 + pfds[cnt].events = POLLIN;
2600 + ast_mutex_unlock(&(dev->lock));
2603 + ast_mutex_unlock(&iface_lock);
2605 + /* -- End Build pfds -- */
2607 + res = ast_sched_wait(sched);
2608 + res = poll(pfds, cnt, MAX(100, MIN(100, res)));
2611 + ast_sched_runq(sched);
2613 + if (pfds[0].revents) {
2614 + handle_incoming(rfcomm_sock_ag, BLT_ROLE_AG);
2618 + if (pfds[1].revents) {
2619 + handle_incoming(rfcomm_sock_hs, BLT_ROLE_HS);
2623 + if (pfds[2].revents) {
2624 + handle_incoming_sco(sco_socket);
2631 + for (i = SRV_SOCK_CNT ; i < cnt ; i++) {
2633 + /* Optimise a little bit */
2636 + else if (pfds[i].revents == 0)
2639 + /* -- Find the socket that has activity -- */
2641 + if (ast_mutex_lock(&iface_lock)) {
2642 + ast_log(LOG_ERROR, "Failed to get iface_lock.\n");
2649 + if (pfds[i].fd == dev->rd) {
2650 + ast_mutex_lock(&(dev->lock));
2651 + if (pfds[i].revents & POLLIN) {
2652 + if (handle_rd_data(dev) == -1) {
2653 + rd_close(dev, 0, 0);
2656 + rd_close(dev, 1, sock_err(dev->rd));
2658 + ast_mutex_unlock(&(dev->lock));
2665 + if (dev == NULL) {
2666 + ast_log(LOG_ERROR, "Unhandled fd from poll()\n");
2667 + close(pfds[i].fd);
2670 + ast_mutex_unlock(&iface_lock);
2672 + /* -- End find socket with activity -- */
2682 +restart_monitor(void)
2685 + if (monitor_thread == AST_PTHREADT_STOP)
2688 + if (ast_mutex_lock(&monitor_lock)) {
2689 + ast_log(LOG_WARNING, "Unable to lock monitor\n");
2693 + if (monitor_thread == pthread_self()) {
2694 + ast_mutex_unlock(&monitor_lock);
2695 + ast_log(LOG_WARNING, "Cannot kill myself\n");
2699 + if (monitor_thread != AST_PTHREADT_NULL) {
2701 + /* Just signal it to be sure it wakes up */
2702 + pthread_cancel(monitor_thread);
2703 + pthread_kill(monitor_thread, SIGURG);
2704 + ast_log(LOG_DEBUG, "Waiting for monitor thread to join...\n");
2705 + pthread_join(monitor_thread, NULL);
2706 + ast_log(LOG_DEBUG, "joined\n");
2710 + /* Start a new monitor */
2711 + if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
2712 + ast_mutex_unlock(&monitor_lock);
2713 + ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
2719 + ast_mutex_unlock(&monitor_lock);
2724 +blt_parse_config(void)
2726 + struct ast_config * cfg;
2727 + struct ast_variable * v;
2730 + cfg = ast_load(BLT_CONFIG_FILE);
2733 + ast_log(LOG_NOTICE, "Unable to load Bluetooth config: %s. Bluetooth disabled\n", BLT_CONFIG_FILE);
2737 + v = ast_variable_browse(cfg, "general");
2740 + if (!strcasecmp(v->name, "rfchannel_ag")) {
2741 + rfcomm_channel_ag = atoi(v->value);
2742 + } else if (!strcasecmp(v->name, "rfchannel_hs")) {
2743 + rfcomm_channel_hs = atoi(v->value);
2744 + } else if (!strcasecmp(v->name, "interface")) {
2745 + hcidev_id = atoi(v->value);
2747 + ast_log(LOG_WARNING, "Unknown config key '%s' in section [general]\n", v->name);
2751 + cat = ast_category_browse(cfg, NULL);
2757 + if (strcasecmp(cat, "general")) {
2758 + blt_dev_t * device = malloc(sizeof(blt_dev_t));
2759 + memset(device, 0, sizeof(blt_dev_t));
2760 + device->sco_running = -1;
2763 + device->outgoing_id = -1;
2764 + device->status = BLT_STATUS_DOWN;
2765 + str2ba(cat, &(device->bdaddr));
2766 + device->name = ast_variable_retrieve(cfg, cat, "name");
2768 + str = ast_variable_retrieve(cfg, cat, "type");
2770 + if (str == NULL) {
2771 + ast_log(LOG_ERROR, "Device [%s] has no role. Specify type=<HS/AG>\n", cat);
2773 + } else if (strcasecmp(str, "HS") == 0)
2774 + device->role = BLT_ROLE_HS;
2775 + else if (strcasecmp(str, "AG") == 0) {
2776 + device->role = BLT_ROLE_AG;
2778 + ast_log(LOG_ERROR, "Device [%s] has invalid role '%s'\n", cat, str);
2782 + /* XXX:T: Find channel to use using SDP.
2783 + * However, this needs to be non blocking, and I can't see
2784 + * anything in sdp_lib.h that will allow non blocking calls.
2787 + device->channel = 1;
2789 + if ((str = ast_variable_retrieve(cfg, cat, "channel")) != NULL)
2790 + device->channel = atoi(str);
2792 + if ((str = ast_variable_retrieve(cfg, cat, "autoconnect")) != NULL)
2793 + device->autoconnect = (strcasecmp(str, "yes") == 0 || strcmp(str, "1") == 0) ? 1 : 0;
2795 + device->next = iface_head;
2796 + iface_head = device;
2800 + cat = ast_category_browse(cfg, cat);
2807 +blt_show_peers(int fd, int argc, char *argv[])
2811 + if (ast_mutex_lock(&iface_lock)) {
2812 + ast_log(LOG_ERROR, "Failed to get Iface lock\n");
2813 + ast_cli(fd, "Failed to get iface lock\n");
2814 + return RESULT_FAILURE;
2819 + ast_cli(fd, "BDAddr Name Role Status A/C SCOCon/Fd/Th Sig\n");
2820 + ast_cli(fd, "----------------- ---------- ---- ----------- --- ------------ ---\n");
2824 + ba2str(&(dev->bdaddr), b1);
2825 + ast_cli(fd, "%s %-10s %-4s %-11s %-3s %2d/%02d/%-6ld %s\n",
2826 + b1, dev->name, (dev->role == BLT_ROLE_HS) ? "HS" : "AG", status2str(dev->status),
2827 + (dev->autoconnect) ? "Yes" : "No",
2831 + (dev->role == BLT_ROLE_AG) ? (dev->service) ? "Yes" : "No" : "N/A"
2836 + ast_mutex_unlock(&iface_lock);
2837 + return RESULT_SUCCESS;
2841 +blt_show_information(int fd, int argc, char *argv[])
2844 + ba2str(&local_bdaddr, b1);
2845 + ast_cli(fd, "-------------------------------------------\n");
2846 + ast_cli(fd, " Version : %s\n", BLT_SVN_REVISION);
2847 + ast_cli(fd, " Monitor PID : %d\n", monitor_pid);
2848 + ast_cli(fd, " RFCOMM AG : Channel %d, FD %d\n", rfcomm_channel_ag, rfcomm_sock_ag);
2849 + ast_cli(fd, " RFCOMM HS : Channel %d, FD %d\n", rfcomm_channel_hs, rfcomm_sock_hs);
2850 + ast_cli(fd, " Device : hci%d, MAC Address %s\n", hcidev_id, b1);
2851 + ast_cli(fd, "-------------------------------------------\n");
2852 + return RESULT_SUCCESS;
2856 +blt_ag_sendcmd(int fd, int argc, char *argv[])
2861 + return RESULT_SHOWUSAGE;
2863 + ast_mutex_lock(&iface_lock);
2866 + if (!strcasecmp(argv[2], dev->name))
2870 + ast_mutex_unlock(&iface_lock);
2873 + ast_cli(fd, "Device '%s' does not exist\n", argv[2]);
2874 + return RESULT_FAILURE;
2877 + if (dev->role != BLT_ROLE_AG) {
2878 + ast_cli(fd, "Device '%s' is not an AudioGateway\n", argv[2]);
2879 + return RESULT_FAILURE;
2882 + if (dev->status == BLT_STATUS_DOWN || dev->status == BLT_STATUS_NEGOTIATING) {
2883 + ast_cli(fd, "Device '%s' is not connected\n", argv[2]);
2884 + return RESULT_FAILURE;
2887 + if (*(argv[3] + strlen(argv[3]) - 1) == '.')
2888 + *(argv[3] + strlen(argv[3]) - 1) = '?';
2890 + ast_cli(fd, "Sending AT command to %s: %s\n", dev->name, argv[3]);
2892 + ast_mutex_lock(&(dev->lock));
2893 + send_atcmd(dev, argv[3]);
2894 + ast_mutex_unlock(&(dev->lock));
2896 + return RESULT_SUCCESS;
2900 +complete_device(char * line, char * word, int pos, int state, int rpos, blt_role_t role)
2909 + ast_mutex_lock(&iface_lock);
2915 + if ((dev->role == role) && (!strncasecmp(word, dev->name, strlen(word)))) {
2916 + if (++which > state)
2924 + ret = strdup(dev->name);
2928 + ast_mutex_unlock(&iface_lock);
2934 +complete_device_2_ag(char * line, char * word, int pos, int state)
2936 + return complete_device(line, word, pos, state, 2, BLT_ROLE_AG);
2939 +static char show_peers_usage[] =
2940 +"Usage: bluetooth show peers\n"
2941 +" List all bluetooth peers and their status\n";
2943 +static struct ast_cli_entry
2945 + { { "bluetooth", "show", "peers", NULL }, blt_show_peers, "List Bluetooth Peers", show_peers_usage };
2948 +static char ag_sendcmd[] =
2949 +"Usage: bluetooth ag <device> sendcmd <cmd>\n"
2950 +" Sends a AT cmd over the RFCOMM link, and print result (AG only)\n";
2952 +static struct ast_cli_entry
2954 + { { "bluetooth", "sendcmd", NULL }, blt_ag_sendcmd, "Send AG an AT command", ag_sendcmd, complete_device_2_ag };
2956 +static char show_information[] =
2957 +"Usage: bluetooth show information\n"
2958 +" Lists information about the bluetooth subsystem\n";
2960 +static struct ast_cli_entry
2961 +cli_show_information =
2962 + { { "bluetooth", "show", "information", NULL }, blt_show_information, "List Bluetooth Info", show_information };
2965 +remove_sdp_records(void)
2968 + sdp_session_t * sdp;
2969 + sdp_list_t * attr;
2970 + sdp_record_t * rec;
2972 + uint32_t range = 0x0000ffff;
2974 + if (sdp_record_ag == -1 || sdp_record_hs == -1)
2977 + ast_log(LOG_DEBUG, "Removing SDP records\n");
2979 + sdp = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
2984 + attr = sdp_list_append(0, &range);
2985 + rec = sdp_service_attr_req(sdp, sdp_record_ag, SDP_ATTR_REQ_RANGE, attr);
2986 + sdp_list_free(attr, 0);
2989 + if (sdp_record_unregister(sdp, rec) == 0)
2992 + attr = sdp_list_append(0, &range);
2993 + rec = sdp_service_attr_req(sdp, sdp_record_hs, SDP_ATTR_REQ_RANGE, attr);
2994 + sdp_list_free(attr, 0);
2997 + if (sdp_record_unregister(sdp, rec) == 0)
3003 + ast_log(LOG_NOTICE, "Removed SDP records\n");
3005 + ast_log(LOG_ERROR, "Failed to remove SDP records\n");
3010 +__unload_module(void)
3013 + ast_channel_unregister(BLT_CHAN_NAME);
3015 + if (monitor_thread != AST_PTHREADT_NULL) {
3017 + if (ast_mutex_lock(&monitor_lock)) {
3019 + if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
3020 + pthread_cancel(monitor_thread);
3021 + pthread_kill(monitor_thread, SIGURG);
3022 + fprintf(stderr, "Waiting for monitor thread to join...\n");
3023 + pthread_join(monitor_thread, NULL);
3024 + fprintf(stderr, "joined\n");
3026 + monitor_thread = AST_PTHREADT_STOP;
3027 + ast_mutex_unlock(&monitor_lock);
3031 + ast_log(LOG_WARNING, "Unable to lock the monitor\n");
3038 + ast_unregister_atexit(remove_sdp_records);
3039 + remove_sdp_records();
3046 + sdp_session_t * sess;
3050 + hcidev_id = BLT_DEFAULT_HCI_DEV;
3052 + if (blt_parse_config() != 0) {
3053 + ast_log(LOG_ERROR, "Bluetooth configuration error. Bluetooth Disabled\n");
3054 + return unload_module();
3057 + dd = hci_open_dev(hcidev_id);
3059 + ast_log(LOG_ERROR, "Unable to open interface hci%d: %s.\n", hcidev_id, strerror(errno));
3063 + hci_read_voice_setting(dd, &vs, 1000);
3067 + if (vs != 0x0060) {
3068 + ast_log(LOG_ERROR, "Bluetooth voice setting must be 0x0060, not 0x%04x\n", vs);
3073 + if ((sched = sched_context_create()) == NULL) {
3074 + ast_log(LOG_WARNING, "Unable to create schedule context\n");
3078 + memset(&local_bdaddr, 0, sizeof(local_bdaddr));
3080 + hci_devba(hcidev_id, &local_bdaddr);
3082 + /* --- Add SDP record --- */
3084 + sess = sdp_connect(&local_bdaddr, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3086 + if ((rfcomm_sock_ag = rfcomm_listen(&local_bdaddr, rfcomm_channel_ag)) < 0) {
3090 + if ((rfcomm_sock_hs = rfcomm_listen(&local_bdaddr, rfcomm_channel_hs)) < 0)
3093 + if ((sco_socket = sco_listen(&local_bdaddr)) < 0)
3097 + ast_log(LOG_ERROR, "Failed to connect to SDP server: %s\n", strerror(errno));
3101 + if (sdp_register(sess) != 0) {
3102 + ast_log(LOG_ERROR, "Failed to register HeadsetAudioGateway in SDP\n");
3108 + if (restart_monitor() != 0)
3111 + if (ast_channel_register(BLT_CHAN_NAME, "Bluetooth Driver", BLUETOOTH_FORMAT, blt_request)) {
3112 + ast_log(LOG_ERROR, "Unable to register channel class BTL\n");
3113 + __unload_module();
3117 + ast_cli_register(&cli_show_information);
3118 + ast_cli_register(&cli_show_peers);
3119 + ast_cli_register(&cli_ag_sendcmd);
3121 + ast_register_atexit(remove_sdp_records);
3123 + ast_log(LOG_NOTICE, "Loaded Bluetooth support, %s\n", BLT_SVN_REVISION + 1);
3129 +unload_module(void)
3131 + ast_cli_unregister(&cli_ag_sendcmd);
3132 + ast_cli_unregister(&cli_show_peers);
3133 + ast_cli_unregister(&cli_show_information);
3134 + return __unload_module();
3141 + ast_mutex_lock(&usecnt_lock);
3143 + ast_mutex_unlock(&usecnt_lock);
3147 +char *description()
3149 + return "Bluetooth Channel Driver";
3155 + return ASTERISK_GPL_KEY;
3159 diff -urN asterisk-1.4.0-beta3-o-o/configs/bluetooth.conf.sample asterisk-1.4.0-beta3/configs/bluetooth.conf.sample
3160 --- asterisk-1.4.0-beta3-o-o/configs/bluetooth.conf.sample 1969-12-31 17:00:00.000000000 -0700
3161 +++ asterisk-1.4.0-beta3/configs/bluetooth.conf.sample 2006-11-06 12:44:39.000000000 -0700
3164 +; Channel we listen on as a HS (Headset)
3166 +; Channel we listen on as an AG (AudioGateway)
3168 +; hci interface to use (number - e.g '0')
3171 +;; A HBH-500 Handsfree Kit
3172 +[00:0A:D9:A1:AA:D2]
3173 +; Any name to use, this is what we use to send calls to (BLT/<name>).
3175 +; IS this a HS or AG?
3179 +; RFCOMM channel to connect to. For a HandsSet:
3180 +; sdptool search --bdaddr xx:xx:xx:xx:xx:xx 0x111E
3181 +; or,for an AudioGateway (Phone):
3182 +; sdptool search --bdaddr xx:xx:xx:xx:xx:xx 0x111F
3184 +; Find the 'channel' value under RFCOMM.
3187 +; Automatically conenct?
3191 +[00:60:57:1C:00:99]
3196 diff -urN asterisk-1.4.0-beta3-o-o/configure.ac asterisk-1.4.0-beta3/configure.ac
3197 --- asterisk-1.4.0-beta3-o-o/configure.ac 2006-10-13 09:41:14.000000000 -0600
3198 +++ asterisk-1.4.0-beta3/configure.ac 2006-11-06 12:44:39.000000000 -0700
3200 # by the --with option name, to make things easier for the users :-)
3202 AST_EXT_LIB_SETUP([ALSA], [Advanced Linux Sound Architecture], [asound])
3203 +AST_EXT_LIB_SETUP([BLUETOOTH], [Bluetooth], [bluetooth])
3204 AST_EXT_LIB_SETUP([CURL], [cURL], [curl])
3205 AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
3206 AST_EXT_LIB_SETUP([GNUTLS], [GNU TLS support (used for iksemel only)], [gnutls])
3209 AST_EXT_LIB_CHECK([ALSA], [asound], [snd_spcm_init], [alsa/asoundlib.h], [-lm -ldl])
3211 +AST_EXT_LIB_CHECK([BLUETOOTH], [bluetooth], [bt_malloc], [bluetooth/bluetooth.h])
3213 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
3216 diff -urN asterisk-1.4.0-beta3-o-o/makeopts.in asterisk-1.4.0-beta3/makeopts.in
3217 --- asterisk-1.4.0-beta3-o-o/makeopts.in 2006-09-19 08:04:15.000000000 -0600
3218 +++ asterisk-1.4.0-beta3/makeopts.in 2006-11-06 12:44:39.000000000 -0700
3221 SUPPSERV_INCLUDE=@SUPPSERV_INCLUDE@
3222 SUPPSERV_LIB=@SUPPSERV_LIB@
3224 +BLUETOOTH_INCLUDE=@BLUETOOTH_INCLUDE@
3225 +BLUETOOTH_LIB=@BLUETOOTH_LIB@