Asterisk - The Open Source Telephony Project GIT-master-2de1a68
chan_mobile.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief Bluetooth Mobile Device channel driver
22 *
23 * \author Dave Bowerman <david.bowerman@gmail.com>
24 *
25 * \ingroup channel_drivers
26 */
27
28/*! \li \ref chan_mobile.c uses the configuration file \ref chan_mobile.conf
29 * \addtogroup configuration_file Configuration Files
30 */
31
32/*!
33 * \page chan_mobile.conf chan_mobile.conf
34 * \verbinclude chan_mobile.conf.sample
35 */
36
37/*** MODULEINFO
38 <depend>bluetooth</depend>
39 <defaultenabled>no</defaultenabled>
40 <support_level>extended</support_level>
41 ***/
42
43#include "asterisk.h"
44
45#include <pthread.h>
46#include <signal.h>
47
48#include <bluetooth/bluetooth.h>
49#include <bluetooth/hci.h>
50#include <bluetooth/hci_lib.h>
51#include <bluetooth/sdp.h>
52#include <bluetooth/sdp_lib.h>
53#include <bluetooth/rfcomm.h>
54#include <bluetooth/sco.h>
55#include <bluetooth/l2cap.h>
56
57#include "asterisk/compat.h"
58#include "asterisk/lock.h"
59#include "asterisk/callerid.h"
60#include "asterisk/channel.h"
61#include "asterisk/config.h"
62#include "asterisk/logger.h"
63#include "asterisk/module.h"
64#include "asterisk/pbx.h"
65#include "asterisk/options.h"
66#include "asterisk/utils.h"
68#include "asterisk/cli.h"
70#include "asterisk/causes.h"
71#include "asterisk/dsp.h"
72#include "asterisk/app.h"
73#include "asterisk/manager.h"
74#include "asterisk/io.h"
75#include "asterisk/smoother.h"
77
78#define MBL_CONFIG "chan_mobile.conf"
79#define MBL_CONFIG_OLD "mobile.conf"
80
81#define DEVICE_FRAME_SIZE 48
82#define DEVICE_FRAME_FORMAT ast_format_slin
83#define CHANNEL_FRAME_SIZE 320
84
85static int discovery_interval = 60; /* The device discovery interval, default 60 seconds. */
86static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */
87static sdp_session_t *sdp_session;
88
90static int unloading_flag = 0;
91static inline int check_unloading(void);
92static inline void set_unloading(void);
93
97};
98
100 int dev_id; /* device id */
101 int hci_socket; /* device descriptor */
102 char id[31]; /* the 'name' from mobile.conf */
103 bdaddr_t addr; /* adddress of adapter */
104 unsigned int inuse:1; /* are we in use ? */
105 unsigned int alignment_detection:1; /* do alignment detection on this adapter? */
106 struct io_context *io; /*!< io context for audio connections */
107 struct io_context *accept_io; /*!< io context for sco listener */
108 int *sco_id; /*!< the io context id of the sco listener socket */
109 int sco_socket; /*!< sco listener socket */
110 pthread_t sco_listener_thread; /*!< sco listener thread */
112};
113
115
116struct msg_queue_entry;
117struct hfp_pvt;
118struct mbl_pvt {
119 struct ast_channel *owner; /* Channel we belong to, possibly NULL */
120 struct ast_frame fr; /* "null" frame */
121 ast_mutex_t lock; /*!< pvt lock */
122 /*! queue for messages we are expecting */
124 enum mbl_type type; /* Phone or Headset */
125 char id[31]; /* The id from mobile.conf */
126 int group; /* group number for group dialling */
127 bdaddr_t addr; /* address of device */
128 struct adapter_pvt *adapter; /* the adapter we use */
129 char context[AST_MAX_CONTEXT]; /* the context for incoming calls */
130 struct hfp_pvt *hfp; /*!< hfp pvt */
131 int rfcomm_port; /* rfcomm port number */
132 int rfcomm_socket; /* rfcomm socket descriptor */
133 char rfcomm_buf[256];
135 struct ast_smoother *bt_out_smoother; /* our bt_out_smoother, for making 48 byte frames */
136 struct ast_smoother *bt_in_smoother; /* our smoother, for making "normal" CHANNEL_FRAME_SIZEed byte frames */
137 int sco_socket; /* sco socket descriptor */
138 pthread_t monitor_thread; /* monitor thread handle */
139 int timeout; /*!< used to set the timeout for rfcomm data (may be used in the future) */
140 unsigned int no_callsetup:1;
141 unsigned int has_sms:1;
144 unsigned int blackberry:1;
148 struct ast_dsp *dsp;
151
152 /* flags */
153 unsigned int outgoing:1; /*!< outgoing call */
154 unsigned int incoming:1; /*!< incoming call */
155 unsigned int outgoing_sms:1; /*!< outgoing sms */
156 unsigned int incoming_sms:1; /*!< outgoing sms */
157 unsigned int needcallerid:1; /*!< we need callerid */
158 unsigned int needchup:1; /*!< we need to send a chup */
159 unsigned int needring:1; /*!< we need to send a RING */
160 unsigned int answered:1; /*!< we sent/received an answer */
161 unsigned int connected:1; /*!< do we have an rfcomm connection to a device */
162
164};
165
166/*! Structure used by hfp_parse_clip to return two items */
167struct cidinfo {
168 char *cnum;
169 char *cnam;
170};
171
173
174static int handle_response_ok(struct mbl_pvt *pvt, char *buf);
175static int handle_response_error(struct mbl_pvt *pvt, char *buf);
176static int handle_response_ciev(struct mbl_pvt *pvt, char *buf);
177static int handle_response_clip(struct mbl_pvt *pvt, char *buf);
178static int handle_response_ring(struct mbl_pvt *pvt, char *buf);
179static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
180static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
181static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
182static int handle_response_busy(struct mbl_pvt *pvt);
183static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf);
184static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf);
185static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);
186
187/* CLI stuff */
188static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
189static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
190static char *handle_cli_mobile_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
191static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
192
193static struct ast_cli_entry mbl_cli[] = {
194 AST_CLI_DEFINE(handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices"),
195 AST_CLI_DEFINE(handle_cli_mobile_search, "Search for Bluetooth Cell / Mobile devices"),
196 AST_CLI_DEFINE(handle_cli_mobile_rfcomm, "Send commands to the rfcomm port for debugging"),
197 AST_CLI_DEFINE(handle_cli_mobile_cusd, "Send CUSD commands to the mobile"),
198};
199
200/* App stuff */
201static char *app_mblstatus = "MobileStatus";
202static char *mblstatus_synopsis = "MobileStatus(Device,Variable)";
203static char *mblstatus_desc =
204"MobileStatus(Device,Variable)\n"
205" Device - Id of mobile device from mobile.conf\n"
206" Variable - Variable to store status in will be 1-3.\n"
207" In order, Disconnected, Connected & Free, Connected & Busy.\n";
208
209static char *app_mblsendsms = "MobileSendSMS";
210static char *mblsendsms_synopsis = "MobileSendSMS(Device,Dest,Message)";
211static char *mblsendsms_desc =
212"MobileSendSms(Device,Dest,Message)\n"
213" Device - Id of device from mobile.conf\n"
214" Dest - destination\n"
215" Message - text of the message\n";
216
217static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo,
218 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
219static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
220 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
221static int mbl_call(struct ast_channel *ast, const char *dest, int timeout);
222static int mbl_hangup(struct ast_channel *ast);
223static int mbl_answer(struct ast_channel *ast);
224static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
225static struct ast_frame *mbl_read(struct ast_channel *ast);
226static int mbl_write(struct ast_channel *ast, struct ast_frame *frame);
227static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
228static int mbl_devicestate(const char *data);
229
230static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen);
231
232static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control);
233static int mbl_queue_hangup(struct mbl_pvt *pvt);
234static int mbl_ast_hangup(struct mbl_pvt *pvt);
235static int mbl_has_service(struct mbl_pvt *pvt);
236
237static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel);
238static int rfcomm_write(int rsock, char *buf);
239static int rfcomm_write_full(int rsock, char *buf, size_t count);
240static int rfcomm_wait(int rsock, int *ms);
241static ssize_t rfcomm_read(int rsock, char *buf, size_t count);
242
243static int sco_connect(bdaddr_t src, bdaddr_t dst);
244static int sco_write(int s, char *buf, int len);
245static int sco_accept(int *id, int fd, short events, void *data);
246static int sco_bind(struct adapter_pvt *adapter);
247
248static void *do_sco_listen(void *data);
249static int sdp_search(char *addr, int profile);
250
251static int headset_send_ring(const void *data);
252
253/*
254 * bluetooth handsfree profile helpers
255 */
256
257#define HFP_HF_ECNR (1 << 0)
258#define HFP_HF_CW (1 << 1)
259#define HFP_HF_CID (1 << 2)
260#define HFP_HF_VOICE (1 << 3)
261#define HFP_HF_VOLUME (1 << 4)
262#define HFP_HF_STATUS (1 << 5)
263#define HFP_HF_CONTROL (1 << 6)
264
265#define HFP_AG_CW (1 << 0)
266#define HFP_AG_ECNR (1 << 1)
267#define HFP_AG_VOICE (1 << 2)
268#define HFP_AG_RING (1 << 3)
269#define HFP_AG_TAG (1 << 4)
270#define HFP_AG_REJECT (1 << 5)
271#define HFP_AG_STATUS (1 << 6)
272#define HFP_AG_CONTROL (1 << 7)
273#define HFP_AG_ERRORS (1 << 8)
274
275#define HFP_CIND_UNKNOWN -1
276#define HFP_CIND_NONE 0
277#define HFP_CIND_SERVICE 1
278#define HFP_CIND_CALL 2
279#define HFP_CIND_CALLSETUP 3
280#define HFP_CIND_CALLHELD 4
281#define HFP_CIND_SIGNAL 5
282#define HFP_CIND_ROAM 6
283#define HFP_CIND_BATTCHG 7
284
285/* call indicator values */
286#define HFP_CIND_CALL_NONE 0
287#define HFP_CIND_CALL_ACTIVE 1
288
289/* callsetup indicator values */
290#define HFP_CIND_CALLSETUP_NONE 0
291#define HFP_CIND_CALLSETUP_INCOMING 1
292#define HFP_CIND_CALLSETUP_OUTGOING 2
293#define HFP_CIND_CALLSETUP_ALERTING 3
294
295/* service indicator values */
296#define HFP_CIND_SERVICE_NONE 0
297#define HFP_CIND_SERVICE_AVAILABLE 1
298
299/*!
300 * \brief This struct holds HFP features that we support.
301 */
302struct hfp_hf {
303 int ecnr:1; /*!< echo-cancel/noise reduction */
304 int cw:1; /*!< call waiting and three way calling */
305 int cid:1; /*!< cli presentation (callier id) */
306 int voice:1; /*!< voice recognition activation */
307 int volume:1; /*!< remote volume control */
308 int status:1; /*!< enhanced call status */
309 int control:1; /*!< enhanced call control*/
310};
311
312/*!
313 * \brief This struct holds HFP features the AG supports.
314 */
315struct hfp_ag {
316 int cw:1; /*!< three way calling */
317 int ecnr:1; /*!< echo-cancel/noise reduction */
318 int voice:1; /*!< voice recognition */
319 int ring:1; /*!< in band ring tone capability */
320 int tag:1; /*!< attach a number to a voice tag */
321 int reject:1; /*!< ability to reject a call */
322 int status:1; /*!< enhanced call status */
323 int control:1; /*!< enhanced call control*/
324 int errors:1; /*!< extended error result codes*/
325};
326
327/*!
328 * \brief This struct holds mappings for indications.
329 */
330struct hfp_cind {
331 int service; /*!< whether we have service or not */
332 int call; /*!< call state */
333 int callsetup; /*!< bluetooth call setup indications */
334 int callheld; /*!< bluetooth call hold indications */
335 int signal; /*!< signal strength */
336 int roam; /*!< roaming indicator */
337 int battchg; /*!< battery charge indicator */
338};
339
340
341/*!
342 * \brief This struct holds state information about the current hfp connection.
343 */
344struct hfp_pvt {
345 struct mbl_pvt *owner; /*!< the mbl_pvt struct that owns this struct */
346 int initialized:1; /*!< whether a service level connection exists or not */
347 int nocallsetup:1; /*!< whether we detected a callsetup indicator */
348 struct hfp_ag brsf; /*!< the supported feature set of the AG */
349 int cind_index[16]; /*!< the cind/ciev index to name mapping for this AG */
350 int cind_state[16]; /*!< the cind/ciev state for this AG */
351 struct hfp_cind cind_map; /*!< the cind name to index mapping for this AG */
352 int rsock; /*!< our rfcomm socket */
353 int rport; /*!< our rfcomm port */
354 int sent_alerting; /*!< have we sent alerting? */
355};
356
357
358/* Our supported features.
359 * we only support caller id
360 */
361static struct hfp_hf hfp_our_brsf = {
362 .ecnr = 0,
363 .cw = 0,
364 .cid = 1,
365 .voice = 0,
366 .volume = 0,
367 .status = 0,
368 .control = 0,
369};
370
371
372static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value);
373static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf);
374static int parse_next_token(char string[], const int start, const char delim);
375static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf);
376static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text);
377static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf);
378static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf);
379static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf);
380static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf);
381
382static int hfp_brsf2int(struct hfp_hf *hf);
383static struct hfp_ag *hfp_int2brsf(int brsf, struct hfp_ag *ag);
384
385static int hfp_send_brsf(struct hfp_pvt *hfp, struct hfp_hf *brsf);
386static int hfp_send_cind(struct hfp_pvt *hfp);
387static int hfp_send_cind_test(struct hfp_pvt *hfp);
388static int hfp_send_cmer(struct hfp_pvt *hfp, int status);
389static int hfp_send_clip(struct hfp_pvt *hfp, int status);
390static int hfp_send_vgs(struct hfp_pvt *hfp, int value);
391
392#if 0
393static int hfp_send_vgm(struct hfp_pvt *hfp, int value);
394#endif
395static int hfp_send_dtmf(struct hfp_pvt *hfp, char digit);
396static int hfp_send_cmgf(struct hfp_pvt *hfp, int mode);
397static int hfp_send_cnmi(struct hfp_pvt *hfp);
398static int hfp_send_cmgr(struct hfp_pvt *hfp, int index);
399static int hfp_send_cmgs(struct hfp_pvt *hfp, const char *number);
400static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message);
401static int hfp_send_chup(struct hfp_pvt *hfp);
402static int hfp_send_atd(struct hfp_pvt *hfp, const char *number);
403static int hfp_send_ata(struct hfp_pvt *hfp);
404static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code);
405
406/*
407 * bluetooth headset profile helpers
408 */
409static int hsp_send_ok(int rsock);
410static int hsp_send_error(int rsock);
411static int hsp_send_vgs(int rsock, int gain);
412static int hsp_send_vgm(int rsock, int gain);
413static int hsp_send_ring(int rsock);
414
415
416/*
417 * Hayes AT command helpers
418 */
419typedef enum {
420 /* errors */
424 /* at responses */
436 /* at commands */
455
456static int at_match_prefix(char *buf, char *prefix);
457static at_message_t at_read_full(int rsock, char *buf, size_t count);
458static inline const char *at_msg2str(at_message_t msg);
459
463 void *data;
464
466};
467
468static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to);
469static int msg_queue_push_data(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to, void *data);
470static struct msg_queue_entry *msg_queue_pop(struct mbl_pvt *pvt);
471static void msg_queue_free_and_pop(struct mbl_pvt *pvt);
472static void msg_queue_flush(struct mbl_pvt *pvt);
473static struct msg_queue_entry *msg_queue_head(struct mbl_pvt *pvt);
474
475/*
476 * channel stuff
477 */
478
479static struct ast_channel_tech mbl_tech = {
480 .type = "Mobile",
481 .description = "Bluetooth Mobile Device Channel Driver",
482 .requester = mbl_request,
483 .call = mbl_call,
484 .hangup = mbl_hangup,
485 .answer = mbl_answer,
486 .send_digit_end = mbl_digit_end,
487 .read = mbl_read,
488 .write = mbl_write,
489 .fixup = mbl_fixup,
490 .devicestate = mbl_devicestate
491};
492
493/* CLI Commands implementation */
494
495static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
496{
497 struct mbl_pvt *pvt;
498 char bdaddr[18];
499 char group[6];
500
501#define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-10.10s %-3.3s\n"
502
503 switch (cmd) {
504 case CLI_INIT:
505 e->command = "mobile show devices";
506 e->usage =
507 "Usage: mobile show devices\n"
508 " Shows the state of Bluetooth Cell / Mobile devices.\n";
509 return NULL;
510 case CLI_GENERATE:
511 return NULL;
512 }
513
514 if (a->argc != 3)
515 return CLI_SHOWUSAGE;
516
517 ast_cli(a->fd, FORMAT1, "ID", "Address", "Group", "Adapter", "Connected", "State", "SMS");
520 ast_mutex_lock(&pvt->lock);
521 ba2str(&pvt->addr, bdaddr);
522 snprintf(group, sizeof(group), "%d", pvt->group);
523 ast_cli(a->fd, FORMAT1,
524 pvt->id,
525 bdaddr,
526 group,
527 pvt->adapter->id,
528 pvt->connected ? "Yes" : "No",
529 (!pvt->connected) ? "None" : (pvt->owner) ? "Busy" : (pvt->outgoing_sms || pvt->incoming_sms) ? "SMS" : (mbl_has_service(pvt)) ? "Free" : "No Service",
530 (pvt->has_sms) ? "Yes" : "No"
531 );
532 ast_mutex_unlock(&pvt->lock);
533 }
535
536#undef FORMAT1
537
538 return CLI_SUCCESS;
539}
540
541static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
542{
543 struct adapter_pvt *adapter;
544 inquiry_info *ii = NULL;
545 int max_rsp, num_rsp;
546 int len, flags;
547 int i, phport, hsport;
548 char addr[19] = {0};
549 char name[31] = {0};
550
551#define FORMAT1 "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n"
552#define FORMAT2 "%-17.17s %-30.30s %-6.6s %-7.7s %d\n"
553
554 switch (cmd) {
555 case CLI_INIT:
556 e->command = "mobile search";
557 e->usage =
558 "Usage: mobile search\n"
559 " Searches for Bluetooth Cell / Mobile devices in range.\n";
560 return NULL;
561 case CLI_GENERATE:
562 return NULL;
563 }
564
565 if (a->argc != 2)
566 return CLI_SHOWUSAGE;
567
568 /* find a free adapter */
571 if (!adapter->inuse)
572 break;
573 }
575
576 if (!adapter) {
577 ast_cli(a->fd, "All Bluetooth adapters are in use at this time.\n");
578 return CLI_SUCCESS;
579 }
580
581 len = 8;
582 max_rsp = 255;
583 flags = IREQ_CACHE_FLUSH;
584
585 ii = ast_alloca(max_rsp * sizeof(inquiry_info));
586 num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
587 if (num_rsp > 0) {
588 ast_cli(a->fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
589 for (i = 0; i < num_rsp; i++) {
590 ba2str(&(ii + i)->bdaddr, addr);
591 name[0] = 0x00;
592 if (hci_read_remote_name(adapter->hci_socket, &(ii + i)->bdaddr, sizeof(name) - 1, name, 0) < 0)
593 strcpy(name, "[unknown]");
594 phport = sdp_search(addr, HANDSFREE_AGW_PROFILE_ID);
595 if (!phport)
596 hsport = sdp_search(addr, HEADSET_PROFILE_ID);
597 else
598 hsport = 0;
599 ast_cli(a->fd, FORMAT2, addr, name, (phport > 0 || hsport > 0) ? "Yes" : "No",
600 (phport > 0) ? "Phone" : "Headset", (phport > 0) ? phport : hsport);
601 }
602 } else
603 ast_cli(a->fd, "No Bluetooth Cell / Mobile devices found.\n");
604
605#undef FORMAT1
606#undef FORMAT2
607
608 return CLI_SUCCESS;
609}
610
611static char *handle_cli_mobile_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
612{
613 char buf[128];
614 struct mbl_pvt *pvt = NULL;
615
616 switch (cmd) {
617 case CLI_INIT:
618 e->command = "mobile rfcomm";
619 e->usage =
620 "Usage: mobile rfcomm <device ID> <command>\n"
621 " Send <command> to the rfcomm port on the device\n"
622 " with the specified <device ID>.\n";
623 return NULL;
624 case CLI_GENERATE:
625 return NULL;
626 }
627
628 if (a->argc != 4)
629 return CLI_SHOWUSAGE;
630
633 if (!strcmp(pvt->id, a->argv[2]))
634 break;
635 }
637
638 if (!pvt) {
639 ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
640 goto e_return;
641 }
642
643 ast_mutex_lock(&pvt->lock);
644 if (!pvt->connected) {
645 ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
646 goto e_unlock_pvt;
647 }
648
649 snprintf(buf, sizeof(buf), "%s\r", a->argv[3]);
652
653e_unlock_pvt:
654 ast_mutex_unlock(&pvt->lock);
655e_return:
656 return CLI_SUCCESS;
657}
658
659static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
660{
661 char buf[128];
662 struct mbl_pvt *pvt = NULL;
663
664 switch (cmd) {
665 case CLI_INIT:
666 e->command = "mobile cusd";
667 e->usage =
668 "Usage: mobile cusd <device ID> <command>\n"
669 " Send cusd <command> to the rfcomm port on the device\n"
670 " with the specified <device ID>.\n";
671 return NULL;
672 case CLI_GENERATE:
673 return NULL;
674 }
675
676 if (a->argc != 4)
677 return CLI_SHOWUSAGE;
678
681 if (!strcmp(pvt->id, a->argv[2]))
682 break;
683 }
685
686 if (!pvt) {
687 ast_cli(a->fd, "Device %s not found.\n", a->argv[2]);
688 goto e_return;
689 }
690
691 ast_mutex_lock(&pvt->lock);
692 if (!pvt->connected) {
693 ast_cli(a->fd, "Device %s not connected.\n", a->argv[2]);
694 goto e_unlock_pvt;
695 }
696
697 snprintf(buf, sizeof(buf), "%s", a->argv[3]);
698 if (hfp_send_cusd(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CUSD)) {
699 ast_cli(a->fd, "[%s] error sending CUSD\n", pvt->id);
700 goto e_unlock_pvt;
701 }
702
703e_unlock_pvt:
704 ast_mutex_unlock(&pvt->lock);
705e_return:
706 return CLI_SUCCESS;
707}
708
709/*
710
711 Dialplan applications implementation
712
713*/
714
715static int mbl_status_exec(struct ast_channel *ast, const char *data)
716{
717
718 struct mbl_pvt *pvt;
719 char *parse;
720 int stat;
721 char status[2];
722
724 AST_APP_ARG(device);
725 AST_APP_ARG(variable);
726 );
727
728 if (ast_strlen_zero(data))
729 return -1;
730
731 parse = ast_strdupa(data);
732
734
735 if (ast_strlen_zero(args.device) || ast_strlen_zero(args.variable))
736 return -1;
737
738 stat = 1;
739
742 if (!strcmp(pvt->id, args.device))
743 break;
744 }
746
747 if (pvt) {
748 ast_mutex_lock(&pvt->lock);
749 if (pvt->connected)
750 stat = 2;
751 if (pvt->owner)
752 stat = 3;
753 ast_mutex_unlock(&pvt->lock);
754 }
755
756 snprintf(status, sizeof(status), "%d", stat);
757 pbx_builtin_setvar_helper(ast, args.variable, status);
758
759 return 0;
760
761}
762
763static int mbl_sendsms_exec(struct ast_channel *ast, const char *data)
764{
765
766 struct mbl_pvt *pvt;
767 char *parse, *message;
768
770 AST_APP_ARG(device);
771 AST_APP_ARG(dest);
773 );
774
775 if (ast_strlen_zero(data))
776 return -1;
777
778 parse = ast_strdupa(data);
779
781
782 if (ast_strlen_zero(args.device)) {
783 ast_log(LOG_ERROR,"NULL device for message -- SMS will not be sent.\n");
784 return -1;
785 }
786
787 if (ast_strlen_zero(args.dest)) {
788 ast_log(LOG_ERROR,"NULL destination for message -- SMS will not be sent.\n");
789 return -1;
790 }
791
792 if (ast_strlen_zero(args.message)) {
793 ast_log(LOG_ERROR,"NULL Message to be sent -- SMS will not be sent.\n");
794 return -1;
795 }
796
799 if (!strcmp(pvt->id, args.device))
800 break;
801 }
803
804 if (!pvt) {
805 ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n", args.device);
806 goto e_return;
807 }
808
809 ast_mutex_lock(&pvt->lock);
810 if (!pvt->connected) {
811 ast_log(LOG_ERROR,"Bluetooth device %s wasn't connected -- SMS will not be sent.\n", args.device);
812 goto e_unlock_pvt;
813 }
814
815 if (!pvt->has_sms) {
816 ast_log(LOG_ERROR,"Bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n", args.device);
817 goto e_unlock_pvt;
818 }
819
820 message = ast_strdup(args.message);
821
822 if (hfp_send_cmgs(pvt->hfp, args.dest)
824
825 ast_log(LOG_ERROR, "[%s] problem sending SMS message\n", pvt->id);
826 goto e_free_message;
827 }
828
829 ast_mutex_unlock(&pvt->lock);
830
831 return 0;
832
833e_free_message:
835e_unlock_pvt:
836 ast_mutex_unlock(&pvt->lock);
837e_return:
838 return -1;
839}
840
841/*
842
843 Channel Driver callbacks
844
845*/
846
847static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo,
848 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
849{
850 struct ast_channel *chn;
851
852 pvt->answered = 0;
853 pvt->alignment_count = 0;
856 pvt->do_alignment_detection = 1;
857 else
858 pvt->do_alignment_detection = 0;
859
863
864 chn = ast_channel_alloc(1, state,
867 0, 0, pvt->context, assignedids, requestor, 0,
868 "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
869 if (!chn) {
870 goto e_return;
871 }
872
879 ast_channel_tech_pvt_set(chn, pvt);
880
881 if (state == AST_STATE_RING)
882 ast_channel_rings_set(chn, 1);
883
884 ast_channel_language_set(chn, "en");
885 pvt->owner = chn;
886
887 if (pvt->sco_socket != -1) {
888 ast_channel_set_fd(chn, 0, pvt->sco_socket);
889 }
891
892 return chn;
893
894e_return:
895 return NULL;
896}
897
898static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
899 const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
900{
901
902 struct ast_channel *chn = NULL;
903 struct mbl_pvt *pvt;
904 char *dest_dev = NULL;
905 char *dest_num = NULL;
906 int group = -1;
907
908 if (!data) {
909 ast_log(LOG_WARNING, "Channel requested with no data\n");
911 return NULL;
912 }
913
916 ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
918 return NULL;
919 }
920
921 dest_dev = ast_strdupa(data);
922
923 dest_num = strchr(dest_dev, '/');
924 if (dest_num)
925 *dest_num++ = 0x00;
926
927 if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) {
928 group = atoi(&dest_dev[1]);
929 }
930
931 /* Find requested device and make sure it's connected. */
934 if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) {
935 if (!mbl_has_service(pvt)) {
936 continue;
937 }
938
939 break;
940 } else if (!strcmp(pvt->id, dest_dev)) {
941 break;
942 }
943 }
945 if (!pvt || !pvt->connected || pvt->owner) {
946 ast_log(LOG_WARNING, "Request to call on device %s which is not connected / already in use.\n", dest_dev);
948 return NULL;
949 }
950
951 if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) {
952 ast_log(LOG_WARNING, "Can't determine destination number.\n");
954 return NULL;
955 }
956
957 ast_mutex_lock(&pvt->lock);
958 chn = mbl_new(AST_STATE_DOWN, pvt, NULL, assignedids, requestor);
959 ast_mutex_unlock(&pvt->lock);
960 if (!chn) {
961 ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
963 return NULL;
964 }
965
966 return chn;
967
968}
969
970static int mbl_call(struct ast_channel *ast, const char *dest, int timeout)
971{
972 struct mbl_pvt *pvt;
973 char *dest_dev;
974 char *dest_num = NULL;
975
976 dest_dev = ast_strdupa(dest);
977
978 pvt = ast_channel_tech_pvt(ast);
979
980 if (pvt->type == MBL_TYPE_PHONE) {
981 dest_num = strchr(dest_dev, '/');
982 if (!dest_num) {
983 ast_log(LOG_WARNING, "Cant determine destination number.\n");
984 return -1;
985 }
986 *dest_num++ = 0x00;
987 }
988
990 ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
991 return -1;
992 }
993
994 ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
995
996 ast_mutex_lock(&pvt->lock);
997 if (pvt->type == MBL_TYPE_PHONE) {
998 if (hfp_send_atd(pvt->hfp, dest_num)) {
999 ast_mutex_unlock(&pvt->lock);
1000 ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
1001 return -1;
1002 }
1003 pvt->hangupcause = 0;
1004 pvt->needchup = 1;
1005 msg_queue_push(pvt, AT_OK, AT_D);
1006 } else {
1007 if (hsp_send_ring(pvt->rfcomm_socket)) {
1008 ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
1009 ast_mutex_unlock(&pvt->lock);
1010 return -1;
1011 }
1012
1013 if ((pvt->ring_sched_id = ast_sched_add(pvt->sched, 6000, headset_send_ring, pvt)) == -1) {
1014 ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
1015 ast_mutex_unlock(&pvt->lock);
1016 return -1;
1017 }
1018
1019 pvt->outgoing = 1;
1020 pvt->needring = 1;
1021 }
1022 ast_mutex_unlock(&pvt->lock);
1023
1024 return 0;
1025
1026}
1027
1028static int mbl_hangup(struct ast_channel *ast)
1029{
1030
1031 struct mbl_pvt *pvt;
1032
1033 if (!ast_channel_tech_pvt(ast)) {
1034 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
1035 return 0;
1036 }
1037 pvt = ast_channel_tech_pvt(ast);
1038
1039 ast_debug(1, "[%s] hanging up device\n", pvt->id);
1040
1041 ast_mutex_lock(&pvt->lock);
1042 ast_channel_set_fd(ast, 0, -1);
1043 close(pvt->sco_socket);
1044 pvt->sco_socket = -1;
1045
1046 if (pvt->needchup) {
1047 hfp_send_chup(pvt->hfp);
1049 pvt->needchup = 0;
1050 }
1051
1052 pvt->outgoing = 0;
1053 pvt->incoming = 0;
1054 pvt->needring = 0;
1055 pvt->owner = NULL;
1057
1058 ast_mutex_unlock(&pvt->lock);
1059
1061
1062 return 0;
1063
1064}
1065
1066static int mbl_answer(struct ast_channel *ast)
1067{
1068
1069 struct mbl_pvt *pvt;
1070
1071 pvt = ast_channel_tech_pvt(ast);
1072
1073 if (pvt->type == MBL_TYPE_HEADSET)
1074 return 0;
1075
1076 ast_mutex_lock(&pvt->lock);
1077 if (pvt->incoming) {
1078 hfp_send_ata(pvt->hfp);
1079 msg_queue_push(pvt, AT_OK, AT_A);
1080 pvt->answered = 1;
1081 }
1082 ast_mutex_unlock(&pvt->lock);
1083
1084 return 0;
1085
1086}
1087
1088static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1089{
1090 struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1091
1092 if (pvt->type == MBL_TYPE_HEADSET)
1093 return 0;
1094
1095 ast_mutex_lock(&pvt->lock);
1096 if (hfp_send_dtmf(pvt->hfp, digit)) {
1097 ast_mutex_unlock(&pvt->lock);
1098 ast_debug(1, "[%s] error sending digit %c\n", pvt->id, digit);
1099 return -1;
1100 }
1102 ast_mutex_unlock(&pvt->lock);
1103
1104 ast_debug(1, "[%s] dialed %c\n", pvt->id, digit);
1105
1106 return 0;
1107}
1108
1109static struct ast_frame *mbl_read(struct ast_channel *ast)
1110{
1111
1112 struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1113 struct ast_frame *fr = &ast_null_frame;
1114 int r;
1115
1116 ast_debug(3, "*** mbl_read()\n");
1117
1118 while (ast_mutex_trylock(&pvt->lock)) {
1120 }
1121
1122 if (!pvt->owner || pvt->sco_socket == -1) {
1123 goto e_return;
1124 }
1125
1126 memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
1129 pvt->fr.src = "Mobile";
1131 pvt->fr.mallocd = 0;
1132 pvt->fr.delivery.tv_sec = 0;
1133 pvt->fr.delivery.tv_usec = 0;
1134 pvt->fr.data.ptr = pvt->io_buf + AST_FRIENDLY_OFFSET;
1135
1136 do {
1137 if ((r = read(pvt->sco_socket, pvt->fr.data.ptr, DEVICE_FRAME_SIZE)) == -1) {
1138 if (errno != EAGAIN && errno != EINTR) {
1139 ast_debug(1, "[%s] read error %d, going to wait for new connection\n", pvt->id, errno);
1140 close(pvt->sco_socket);
1141 pvt->sco_socket = -1;
1142 ast_channel_set_fd(ast, 0, -1);
1143 }
1144 goto e_return;
1145 }
1146
1147 pvt->fr.datalen = r;
1148 pvt->fr.samples = r / 2;
1149
1150 if (pvt->do_alignment_detection)
1151 do_alignment_detection(pvt, pvt->fr.data.ptr, r);
1152
1153 ast_smoother_feed(pvt->bt_in_smoother, &pvt->fr);
1155 } while (fr == NULL);
1156 fr = ast_dsp_process(ast, pvt->dsp, fr);
1157
1158 ast_mutex_unlock(&pvt->lock);
1159
1160 return fr;
1161
1162e_return:
1163 ast_mutex_unlock(&pvt->lock);
1164 return fr;
1165}
1166
1167static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
1168{
1169
1170 struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
1171 struct ast_frame *f;
1172
1173 ast_debug(3, "*** mbl_write\n");
1174
1175 if (frame->frametype != AST_FRAME_VOICE) {
1176 return 0;
1177 }
1178
1179 while (ast_mutex_trylock(&pvt->lock)) {
1181 }
1182
1184
1185 while ((f = ast_smoother_read(pvt->bt_out_smoother))) {
1186 sco_write(pvt->sco_socket, f->data.ptr, f->datalen);
1187 }
1188
1189 ast_mutex_unlock(&pvt->lock);
1190
1191 return 0;
1192
1193}
1194
1195static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1196{
1197
1198 struct mbl_pvt *pvt = ast_channel_tech_pvt(newchan);
1199
1200 if (!pvt) {
1201 ast_debug(1, "fixup failed, no pvt on newchan\n");
1202 return -1;
1203 }
1204
1205 ast_mutex_lock(&pvt->lock);
1206 if (pvt->owner == oldchan)
1207 pvt->owner = newchan;
1208 ast_mutex_unlock(&pvt->lock);
1209
1210 return 0;
1211
1212}
1213
1214static int mbl_devicestate(const char *data)
1215{
1216
1217 char *device;
1218 int res = AST_DEVICE_INVALID;
1219 struct mbl_pvt *pvt;
1220
1221 device = ast_strdupa(S_OR(data, ""));
1222
1223 ast_debug(1, "Checking device state for device %s\n", device);
1224
1227 if (!strcmp(pvt->id, device))
1228 break;
1229 }
1231
1232 if (!pvt)
1233 return res;
1234
1235 ast_mutex_lock(&pvt->lock);
1236 if (pvt->connected) {
1237 if (pvt->owner)
1238 res = AST_DEVICE_INUSE;
1239 else
1241
1242 if (!mbl_has_service(pvt))
1244 }
1245 ast_mutex_unlock(&pvt->lock);
1246
1247 return res;
1248
1249}
1250
1251/*
1252
1253 Callback helpers
1254
1255*/
1256
1257/*
1258
1259 do_alignment_detection()
1260
1261 This routine attempts to detect where we get misaligned sco audio data from the bluetooth adaptor.
1262
1263 Its enabled by alignmentdetect=yes under the adapter entry in mobile.conf
1264
1265 Some adapters suffer a problem where occasionally they will byte shift the audio stream one byte to the right.
1266 The result is static or white noise on the inbound (from the adapter) leg of the call.
1267 This is characterised by a sudden jump in magnitude of the value of the 16 bit samples.
1268
1269 Here we look at the first 4 48 byte frames. We average the absolute values of each sample in the frame,
1270 then average the sum of the averages of frames 1, 2, and 3.
1271 Frame zero is usually zero.
1272 If the end result > 100, and it usually is if we have the problem, set a flag and compensate by shifting the bytes
1273 for each subsequent frame during the call.
1274
1275 If the result is <= 100 then clear the flag so we don't come back in here...
1276
1277 This seems to work OK....
1278
1279*/
1280
1281static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen)
1282{
1283
1284 int i;
1285 short a, *s;
1286 char *p;
1287
1289 for (i=buflen, p=buf+buflen-1; i>0; i--, p--)
1290 *p = *(p-1);
1291 *(p+1) = 0;
1292 return;
1293 }
1294
1295 if (pvt->alignment_count < 4) {
1296 s = (short *)buf;
1297 for (i=0, a=0; i<buflen/2; i++) {
1298 a += *s++;
1299 a /= i+1;
1300 }
1301 pvt->alignment_samples[pvt->alignment_count++] = a;
1302 return;
1303 }
1304
1305 ast_debug(1, "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]);
1306
1307 a = abs(pvt->alignment_samples[1]) + abs(pvt->alignment_samples[2]) + abs(pvt->alignment_samples[3]);
1308 a /= 3;
1309 if (a > 100) {
1311 ast_debug(1, "Alignment Detection Triggered.\n");
1312 } else
1313 pvt->do_alignment_detection = 0;
1314
1315}
1316
1317static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
1318{
1319 for (;;) {
1320 if (pvt->owner) {
1321 if (ast_channel_trylock(pvt->owner)) {
1322 DEADLOCK_AVOIDANCE(&pvt->lock);
1323 } else {
1324 ast_queue_control(pvt->owner, control);
1326 break;
1327 }
1328 } else
1329 break;
1330 }
1331 return 0;
1332}
1333
1334static int mbl_queue_hangup(struct mbl_pvt *pvt)
1335{
1336 for (;;) {
1337 if (pvt->owner) {
1338 if (ast_channel_trylock(pvt->owner)) {
1339 DEADLOCK_AVOIDANCE(&pvt->lock);
1340 } else {
1341 if (pvt->hangupcause != 0) {
1343 }
1344 ast_queue_hangup(pvt->owner);
1346 break;
1347 }
1348 } else
1349 break;
1350 }
1351 return 0;
1352}
1353
1354static int mbl_ast_hangup(struct mbl_pvt *pvt)
1355{
1356 ast_hangup(pvt->owner);
1357 return 0;
1358}
1359
1360/*!
1361 * \brief Check if a mobile device has service.
1362 * \param pvt a mbl_pvt struct
1363 * \retval 1 this device has service
1364 * \retval 0 no service
1365 *
1366 * \note This function will always indicate that service is available if the
1367 * given device does not support service indication.
1368 */
1369static int mbl_has_service(struct mbl_pvt *pvt)
1370{
1371
1372 if (pvt->type != MBL_TYPE_PHONE)
1373 return 1;
1374
1375 if (!pvt->hfp->cind_map.service)
1376 return 1;
1377
1379 return 1;
1380
1381 return 0;
1382}
1383
1384/*
1385
1386 rfcomm helpers
1387
1388*/
1389
1390static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel)
1391{
1392
1393 struct sockaddr_rc addr;
1394 int s;
1395
1396 if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
1397 ast_debug(1, "socket() failed (%d).\n", errno);
1398 return -1;
1399 }
1400
1401 memset(&addr, 0, sizeof(addr));
1402 addr.rc_family = AF_BLUETOOTH;
1403 bacpy(&addr.rc_bdaddr, &src);
1404 addr.rc_channel = (uint8_t) 0;
1405 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1406 ast_debug(1, "bind() failed (%d).\n", errno);
1407 close(s);
1408 return -1;
1409 }
1410
1411 memset(&addr, 0, sizeof(addr));
1412 addr.rc_family = AF_BLUETOOTH;
1413 bacpy(&addr.rc_bdaddr, &dst);
1414 addr.rc_channel = remote_channel;
1415 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1416 ast_debug(1, "connect() failed (%d).\n", errno);
1417 close(s);
1418 return -1;
1419 }
1420
1421 return s;
1422
1423}
1424
1425/*!
1426 * \brief Write to an rfcomm socket.
1427 * \param rsock the socket to write to
1428 * \param buf the null terminated buffer to write
1429 *
1430 * This function will write characters from buf. The buffer must be null
1431 * terminated.
1432 *
1433 * \retval -1 error
1434 * \retval 0 success
1435 */
1436static int rfcomm_write(int rsock, char *buf)
1437{
1438 return rfcomm_write_full(rsock, buf, strlen(buf));
1439}
1440
1441
1442/*!
1443 * \brief Write to an rfcomm socket.
1444 * \param rsock the socket to write to
1445 * \param buf the buffer to write
1446 * \param count the number of characters from the buffer to write
1447 *
1448 * This function will write count characters from buf. It will always write
1449 * count chars unless it encounters an error.
1450 *
1451 * \retval -1 error
1452 * \retval 0 success
1453 */
1454static int rfcomm_write_full(int rsock, char *buf, size_t count)
1455{
1456 char *p = buf;
1457 ssize_t out_count;
1458
1459 ast_debug(1, "rfcomm_write() (%d) [%.*s]\n", rsock, (int) count, buf);
1460 while (count > 0) {
1461 if ((out_count = write(rsock, p, count)) == -1) {
1462 ast_debug(1, "rfcomm_write() error [%d]\n", errno);
1463 return -1;
1464 }
1465 count -= out_count;
1466 p += out_count;
1467 }
1468
1469 return 0;
1470}
1471
1472/*!
1473 * \brief Wait for activity on an rfcomm socket.
1474 * \param rsock the socket to watch
1475 * \param ms a pointer to an int containing a timeout in ms
1476 * \return zero on timeout and the socket fd (non-zero) otherwise
1477 * \retval 0 timeout
1478 */
1479static int rfcomm_wait(int rsock, int *ms)
1480{
1481 int exception, outfd;
1482 outfd = ast_waitfor_n_fd(&rsock, 1, ms, &exception);
1483 if (outfd < 0)
1484 outfd = 0;
1485
1486 return outfd;
1487}
1488
1489#ifdef RFCOMM_READ_DEBUG
1490#define rfcomm_read_debug(c) __rfcomm_read_debug(c)
1491static void __rfcomm_read_debug(char c)
1492{
1493 if (c == '\r')
1494 ast_debug(2, "rfcomm_read: \\r\n");
1495 else if (c == '\n')
1496 ast_debug(2, "rfcomm_read: \\n\n");
1497 else
1498 ast_debug(2, "rfcomm_read: %c\n", c);
1499}
1500#else
1501#define rfcomm_read_debug(c)
1502#endif
1503
1504/*!
1505 * \brief Append the given character to the given buffer and increase the
1506 * in_count.
1507 */
1508static void inline rfcomm_append_buf(char **buf, size_t count, size_t *in_count, char c)
1509{
1510 if (*in_count < count) {
1511 (*in_count)++;
1512 *(*buf)++ = c;
1513 }
1514}
1515
1516/*!
1517 * \brief Read a character from the given stream and check if it matches what
1518 * we expected.
1519 */
1520static int rfcomm_read_and_expect_char(int rsock, char *result, char expected)
1521{
1522 int res;
1523 char c;
1524
1525 if (!result)
1526 result = &c;
1527
1528 if ((res = read(rsock, result, 1)) < 1) {
1529 return res;
1530 }
1532
1533 if (*result != expected) {
1534 return -2;
1535 }
1536
1537 return 1;
1538}
1539
1540/*!
1541 * \brief Read a character from the given stream and append it to the given
1542 * buffer if it matches the expected character.
1543 */
1544static int rfcomm_read_and_append_char(int rsock, char **buf, size_t count, size_t *in_count, char *result, char expected)
1545{
1546 int res;
1547 char c;
1548
1549 if (!result)
1550 result = &c;
1551
1552 if ((res = rfcomm_read_and_expect_char(rsock, result, expected)) < 1) {
1553 return res;
1554 }
1555
1556 rfcomm_append_buf(buf, count, in_count, *result);
1557 return 1;
1558}
1559
1560/*!
1561 * \brief Read until \verbatim '\r\n'. \endverbatim
1562 * This function consumes the \verbatim'\r\n'\endverbatim but does not add it to buf.
1563 */
1564static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
1565{
1566 int res;
1567 char c;
1568
1569 while ((res = read(rsock, &c, 1)) == 1) {
1571 if (c == '\r') {
1572 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) == 1) {
1573 break;
1574 } else if (res == -2) {
1575 rfcomm_append_buf(buf, count, in_count, '\r');
1576 } else {
1577 rfcomm_append_buf(buf, count, in_count, '\r');
1578 break;
1579 }
1580 }
1581
1582 rfcomm_append_buf(buf, count, in_count, c);
1583 }
1584 return res;
1585}
1586
1587/*!
1588 * \brief Read the remainder of an AT SMS prompt.
1589 * \note the entire parsed string is \verbatim '\r\n> ' \endverbatim
1590 *
1591 * By the time this function is executed, only a ' ' is left to read.
1592 */
1593static int rfcomm_read_sms_prompt(int rsock, char **buf, size_t count, size_t *in_count)
1594{
1595 int res;
1596 if ((res = rfcomm_read_and_append_char(rsock, buf, count, in_count, NULL, ' ')) < 1)
1597 goto e_return;
1598
1599 return 1;
1600
1601e_return:
1602 ast_log(LOG_ERROR, "error parsing SMS prompt on rfcomm socket\n");
1603 return res;
1604}
1605
1606/*!
1607 * \brief Read until a \verbatim \r\nOK\r\n \endverbatim message.
1608 */
1609static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
1610{
1611 int res;
1612 char c;
1613
1614 /* here, we read until finding a \r\n, then we read one character at a
1615 * time looking for the string '\r\nOK\r\n'. If we only find a partial
1616 * match, we place that in the buffer and try again. */
1617
1618 for (;;) {
1619 if ((res = rfcomm_read_until_crlf(rsock, buf, count, in_count)) != 1) {
1620 break;
1621 }
1622
1623 rfcomm_append_buf(buf, count, in_count, '\r');
1624 rfcomm_append_buf(buf, count, in_count, '\n');
1625
1626 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
1627 if (res != -2) {
1628 break;
1629 }
1630
1631 rfcomm_append_buf(buf, count, in_count, c);
1632 continue;
1633 }
1634
1635 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
1636 if (res != -2) {
1637 break;
1638 }
1639
1640 rfcomm_append_buf(buf, count, in_count, '\r');
1641 rfcomm_append_buf(buf, count, in_count, c);
1642 continue;
1643 }
1644 if ((res = rfcomm_read_and_expect_char(rsock, &c, 'O')) != 1) {
1645 if (res != -2) {
1646 break;
1647 }
1648
1649 rfcomm_append_buf(buf, count, in_count, '\r');
1650 rfcomm_append_buf(buf, count, in_count, '\n');
1651 rfcomm_append_buf(buf, count, in_count, c);
1652 continue;
1653 }
1654
1655 if ((res = rfcomm_read_and_expect_char(rsock, &c, 'K')) != 1) {
1656 if (res != -2) {
1657 break;
1658 }
1659
1660 rfcomm_append_buf(buf, count, in_count, '\r');
1661 rfcomm_append_buf(buf, count, in_count, '\n');
1662 rfcomm_append_buf(buf, count, in_count, 'O');
1663 rfcomm_append_buf(buf, count, in_count, c);
1664 continue;
1665 }
1666
1667 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) != 1) {
1668 if (res != -2) {
1669 break;
1670 }
1671
1672 rfcomm_append_buf(buf, count, in_count, '\r');
1673 rfcomm_append_buf(buf, count, in_count, '\n');
1674 rfcomm_append_buf(buf, count, in_count, 'O');
1675 rfcomm_append_buf(buf, count, in_count, 'K');
1676 rfcomm_append_buf(buf, count, in_count, c);
1677 continue;
1678 }
1679
1680 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) != 1) {
1681 if (res != -2) {
1682 break;
1683 }
1684
1685 rfcomm_append_buf(buf, count, in_count, '\r');
1686 rfcomm_append_buf(buf, count, in_count, '\n');
1687 rfcomm_append_buf(buf, count, in_count, 'O');
1688 rfcomm_append_buf(buf, count, in_count, 'K');
1689 rfcomm_append_buf(buf, count, in_count, '\r');
1690 rfcomm_append_buf(buf, count, in_count, c);
1691 continue;
1692 }
1693
1694 /* we have successfully parsed a '\r\nOK\r\n' string */
1695 return 1;
1696 }
1697
1698 return res;
1699}
1700
1701
1702/*!
1703 * \brief Read the remainder of a +CMGR message.
1704 * \note the entire parsed string is \verbatim '+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n' \endverbatim
1705 */
1706static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
1707{
1708 int res;
1709
1710 /* append the \r\n that was stripped by the calling function */
1711 rfcomm_append_buf(buf, count, in_count, '\r');
1712 rfcomm_append_buf(buf, count, in_count, '\n');
1713
1714 if ((res = rfcomm_read_until_ok(rsock, buf, count, in_count)) != 1) {
1715 ast_log(LOG_ERROR, "error reading +CMGR message on rfcomm socket\n");
1716 }
1717
1718 return res;
1719}
1720
1721/*!
1722 * \brief Read and AT result code.
1723 * \note the entire parsed string is \verbatim '\r\n<result code>\r\n' \endverbatim
1724 */
1725static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
1726{
1727 int res;
1728 char c;
1729
1730 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\n')) < 1) {
1731 goto e_return;
1732 }
1733
1734 if ((res = rfcomm_read_and_append_char(rsock, buf, count, in_count, &c, '>')) == 1) {
1735 return rfcomm_read_sms_prompt(rsock, buf, count, in_count);
1736 } else if (res != -2) {
1737 goto e_return;
1738 }
1739
1740 rfcomm_append_buf(buf, count, in_count, c);
1741 res = rfcomm_read_until_crlf(rsock, buf, count, in_count);
1742
1743 if (res != 1)
1744 return res;
1745
1746 /* check for CMGR, which contains an embedded \r\n pairs terminated by
1747 * an \r\nOK\r\n message */
1748 if (*in_count >= 5 && !strncmp(*buf - *in_count, "+CMGR", 5)) {
1749 return rfcomm_read_cmgr(rsock, buf, count, in_count);
1750 }
1751
1752 return 1;
1753
1754e_return:
1755 ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket\n");
1756 return res;
1757}
1758
1759/*!
1760 * \brief Read the remainder of an AT command.
1761 * \note the entire parsed string is \verbatim '<at command>\r' \endverbatim
1762 */
1763static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
1764{
1765 int res;
1766 char c;
1767
1768 while ((res = read(rsock, &c, 1)) == 1) {
1770 /* stop when we get to '\r' */
1771 if (c == '\r')
1772 break;
1773
1774 rfcomm_append_buf(buf, count, in_count, c);
1775 }
1776 return res;
1777}
1778
1779/*!
1780 * \brief Read one Hayes AT message from an rfcomm socket.
1781 * \param rsock the rfcomm socket to read from
1782 * \param buf the buffer to store the result in
1783 * \param count the size of the buffer or the maximum number of characters to read
1784 *
1785 * Here we need to read complete Hayes AT messages. The AT message formats we
1786 * support are listed below.
1787 *
1788 * \verbatim
1789 * \r\n<result code>\r\n
1790 * <at command>\r
1791 * \r\n>
1792 * \endverbatim
1793 *
1794 * These formats correspond to AT result codes, AT commands, and the AT SMS
1795 * prompt respectively. When messages are read the leading and trailing \verbatim '\r' \endverbatim
1796 * and \verbatim '\n' \endverbatim characters are discarded. If the given buffer is not large enough
1797 * to hold the response, what does not fit in the buffer will be dropped.
1798 *
1799 * \note The rfcomm connection to the device is asynchronous, so there is no
1800 * guarantee that responses will be returned in a single read() call. We handle
1801 * this by blocking until we can read an entire response.
1802 *
1803 * \retval 0 end of file
1804 * \retval -1 read error
1805 * \retval -2 parse error
1806 * \retval other the number of characters added to buf
1807 */
1808static ssize_t rfcomm_read(int rsock, char *buf, size_t count)
1809{
1810 ssize_t res;
1811 size_t in_count = 0;
1812 char c;
1813
1814 if ((res = rfcomm_read_and_expect_char(rsock, &c, '\r')) == 1) {
1815 res = rfcomm_read_result(rsock, &buf, count, &in_count);
1816 } else if (res == -2) {
1817 rfcomm_append_buf(&buf, count, &in_count, c);
1818 res = rfcomm_read_command(rsock, &buf, count, &in_count);
1819 }
1820
1821 if (res < 1)
1822 return res;
1823 else
1824 return in_count;
1825}
1826
1827/*
1828
1829 sco helpers and callbacks
1830
1831*/
1832
1833static int sco_connect(bdaddr_t src, bdaddr_t dst)
1834{
1835
1836 struct sockaddr_sco addr;
1837 int s;
1838
1839 if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1840 ast_debug(1, "socket() failed (%d).\n", errno);
1841 return -1;
1842 }
1843
1844/* XXX this does not work with the do_sco_listen() thread (which also bind()s
1845 * to this address). Also I am not sure if it is necessary. */
1846#if 0
1847 memset(&addr, 0, sizeof(addr));
1848 addr.sco_family = AF_BLUETOOTH;
1849 bacpy(&addr.sco_bdaddr, &src);
1850 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1851 ast_debug(1, "bind() failed (%d).\n", errno);
1852 close(s);
1853 return -1;
1854 }
1855#endif
1856
1857 memset(&addr, 0, sizeof(addr));
1858 addr.sco_family = AF_BLUETOOTH;
1859 bacpy(&addr.sco_bdaddr, &dst);
1860
1861 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1862 ast_debug(1, "sco connect() failed (%d).\n", errno);
1863 close(s);
1864 return -1;
1865 }
1866
1867 return s;
1868
1869}
1870
1871static int sco_write(int s, char *buf, int len)
1872{
1873
1874 int r;
1875
1876 if (s == -1) {
1877 ast_debug(3, "sco_write() not ready\n");
1878 return 0;
1879 }
1880
1881 ast_debug(3, "sco_write()\n");
1882
1883 r = write(s, buf, len);
1884 if (r == -1) {
1885 ast_debug(3, "sco write error %d\n", errno);
1886 return 0;
1887 }
1888
1889 return 1;
1890
1891}
1892
1893/*!
1894 * \brief Accept SCO connections.
1895 * This function is an ast_io callback function used to accept incoming sco
1896 * audio connections.
1897 */
1898static int sco_accept(int *id, int fd, short events, void *data)
1899{
1900 struct adapter_pvt *adapter = (struct adapter_pvt *) data;
1901 struct sockaddr_sco addr;
1902 socklen_t addrlen;
1903 struct mbl_pvt *pvt;
1904 socklen_t len;
1905 char saddr[18];
1906 struct sco_options so;
1907 int sock;
1908
1909 addrlen = sizeof(struct sockaddr_sco);
1910 if ((sock = accept(fd, (struct sockaddr *)&addr, &addrlen)) == -1) {
1911 ast_log(LOG_ERROR, "error accepting audio connection on adapter %s\n", adapter->id);
1912 return 0;
1913 }
1914
1915 len = sizeof(so);
1916 getsockopt(sock, SOL_SCO, SCO_OPTIONS, &so, &len);
1917
1918 ba2str(&addr.sco_bdaddr, saddr);
1919 ast_debug(1, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu);
1920
1921 /* figure out which device this sco connection belongs to */
1922 pvt = NULL;
1925 if (!bacmp(&pvt->addr, &addr.sco_bdaddr))
1926 break;
1927 }
1929 if (!pvt) {
1930 ast_log(LOG_WARNING, "could not find device for incoming audio connection\n");
1931 close(sock);
1932 return 1;
1933 }
1934
1935 ast_mutex_lock(&pvt->lock);
1936 if (pvt->sco_socket != -1) {
1937 close(pvt->sco_socket);
1938 pvt->sco_socket = -1;
1939 }
1940
1941 pvt->sco_socket = sock;
1942 if (pvt->owner) {
1943 ast_channel_set_fd(pvt->owner, 0, sock);
1944 } else {
1945 ast_debug(1, "incoming audio connection for pvt without owner\n");
1946 }
1947
1948 ast_mutex_unlock(&pvt->lock);
1949
1950 return 1;
1951}
1952
1953/*!
1954 * \brief Bind an SCO listener socket for the given adapter.
1955 * \param adapter an adapter_pvt
1956 * \return -1 on error, non zero on success
1957 */
1958static int sco_bind(struct adapter_pvt *adapter)
1959{
1960 struct sockaddr_sco addr;
1961 int opt = 1;
1962
1963 if ((adapter->sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1964 ast_log(LOG_ERROR, "Unable to create sco listener socket for adapter %s.\n", adapter->id);
1965 goto e_return;
1966 }
1967
1968 memset(&addr, 0, sizeof(addr));
1969 addr.sco_family = AF_BLUETOOTH;
1970 bacpy(&addr.sco_bdaddr, &adapter->addr);
1971 if (bind(adapter->sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1972 ast_log(LOG_ERROR, "Unable to bind sco listener socket. (%d)\n", errno);
1973 goto e_close_socket;
1974 }
1975 if (setsockopt(adapter->sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
1976 ast_log(LOG_ERROR, "Unable to setsockopt sco listener socket.\n");
1977 goto e_close_socket;
1978 }
1979 if (listen(adapter->sco_socket, 5) < 0) {
1980 ast_log(LOG_ERROR, "Unable to listen sco listener socket.\n");
1981 goto e_close_socket;
1982 }
1983
1984 return adapter->sco_socket;
1985
1986e_close_socket:
1987 close(adapter->sco_socket);
1988 adapter->sco_socket = -1;
1989e_return:
1990 return -1;
1991}
1992
1993
1994/*
1995 * Hayes AT command helpers.
1996 */
1997
1998/*!
1999 * \brief Match the given buffer with the given prefix.
2000 * \param buf the buffer to match
2001 * \param prefix the prefix to match
2002 */
2003static int at_match_prefix(char *buf, char *prefix)
2004{
2005 return !strncmp(buf, prefix, strlen(prefix));
2006}
2007
2008/*!
2009 * \brief Read an AT message and classify it.
2010 * \param rsock an rfcomm socket
2011 * \param buf the buffer to store the result in
2012 * \param count the size of the buffer or the maximum number of characters to read
2013 * \return the type of message received, in addition buf will contain the
2014 * message received and will be null terminated
2015 * \see at_read()
2016 */
2017static at_message_t at_read_full(int rsock, char *buf, size_t count)
2018{
2019 ssize_t s;
2020 if ((s = rfcomm_read(rsock, buf, count - 1)) < 1)
2021 return s;
2022 buf[s] = '\0';
2023
2024 if (!strcmp("OK", buf)) {
2025 return AT_OK;
2026 } else if (!strcmp("ERROR", buf)) {
2027 return AT_ERROR;
2028 } else if (!strcmp("RING", buf)) {
2029 return AT_RING;
2030 } else if (!strcmp("AT+CKPD=200", buf)) {
2031 return AT_CKPD;
2032 } else if (!strcmp("> ", buf)) {
2033 return AT_SMS_PROMPT;
2034 } else if (at_match_prefix(buf, "+CMTI:")) {
2035 return AT_CMTI;
2036 } else if (at_match_prefix(buf, "+CIEV:")) {
2037 return AT_CIEV;
2038 } else if (at_match_prefix(buf, "+BRSF:")) {
2039 return AT_BRSF;
2040 } else if (at_match_prefix(buf, "+CIND:")) {
2041 return AT_CIND;
2042 } else if (at_match_prefix(buf, "+CLIP:")) {
2043 return AT_CLIP;
2044 } else if (at_match_prefix(buf, "+CMGR:")) {
2045 return AT_CMGR;
2046 } else if (at_match_prefix(buf, "+VGM:")) {
2047 return AT_VGM;
2048 } else if (at_match_prefix(buf, "+VGS:")) {
2049 return AT_VGS;
2050 } else if (at_match_prefix(buf, "+CMS ERROR:")) {
2051 return AT_CMS_ERROR;
2052 } else if (at_match_prefix(buf, "AT+VGM=")) {
2053 return AT_VGM;
2054 } else if (at_match_prefix(buf, "AT+VGS=")) {
2055 return AT_VGS;
2056 } else if (at_match_prefix(buf, "+CUSD:")) {
2057 return AT_CUSD;
2058 } else if (at_match_prefix(buf, "BUSY")) {
2059 return AT_BUSY;
2060 } else if (at_match_prefix(buf, "NO DIALTONE")) {
2061 return AT_NO_DIALTONE;
2062 } else if (at_match_prefix(buf, "NO CARRIER")) {
2063 return AT_NO_CARRIER;
2064 } else if (at_match_prefix(buf, "*ECAV:")) {
2065 return AT_ECAM;
2066 } else {
2067 return AT_UNKNOWN;
2068 }
2069}
2070
2071/*!
2072 * \brief Get the string representation of the given AT message.
2073 * \param msg the message to process
2074 * \return a string describing the given message
2075 */
2076static inline const char *at_msg2str(at_message_t msg)
2077{
2078 switch (msg) {
2079 /* errors */
2080 case AT_PARSE_ERROR:
2081 return "PARSE ERROR";
2082 case AT_READ_ERROR:
2083 return "READ ERROR";
2084 default:
2085 case AT_UNKNOWN:
2086 return "UNKNOWN";
2087 /* at responses */
2088 case AT_OK:
2089 return "OK";
2090 case AT_ERROR:
2091 return "ERROR";
2092 case AT_RING:
2093 return "RING";
2094 case AT_BRSF:
2095 return "AT+BRSF";
2096 case AT_CIND:
2097 return "AT+CIND";
2098 case AT_CIEV:
2099 return "AT+CIEV";
2100 case AT_CLIP:
2101 return "AT+CLIP";
2102 case AT_CMTI:
2103 return "AT+CMTI";
2104 case AT_CMGR:
2105 return "AT+CMGR";
2106 case AT_SMS_PROMPT:
2107 return "SMS PROMPT";
2108 case AT_CMS_ERROR:
2109 return "+CMS ERROR";
2110 case AT_BUSY:
2111 return "BUSY";
2112 case AT_NO_DIALTONE:
2113 return "NO DIALTONE";
2114 case AT_NO_CARRIER:
2115 return "NO CARRIER";
2116 /* at commands */
2117 case AT_A:
2118 return "ATA";
2119 case AT_D:
2120 return "ATD";
2121 case AT_CHUP:
2122 return "AT+CHUP";
2123 case AT_CKPD:
2124 return "AT+CKPD";
2125 case AT_CMGS:
2126 return "AT+CMGS";
2127 case AT_VGM:
2128 return "AT+VGM";
2129 case AT_VGS:
2130 return "AT+VGS";
2131 case AT_VTS:
2132 return "AT+VTS";
2133 case AT_CMGF:
2134 return "AT+CMGF";
2135 case AT_CNMI:
2136 return "AT+CNMI";
2137 case AT_CMER:
2138 return "AT+CMER";
2139 case AT_CIND_TEST:
2140 return "AT+CIND=?";
2141 case AT_CUSD:
2142 return "AT+CUSD";
2143 case AT_ECAM:
2144 return "AT*ECAM";
2145 }
2146}
2147
2148
2149/*
2150 * bluetooth handsfree profile helpers
2151 */
2152
2153 /*!
2154 * \brief Parse a ECAV event.
2155 * \param hfp an hfp_pvt struct
2156 * \param buf the buffer to parse (null terminated)
2157 * \return -1 on error (parse error) or a ECAM value on success
2158 *
2159 * Example:
2160 * \verbatim *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>]
2161 [,exitcause][,<number>,<type>] \endverbatim
2162 *
2163 * Example indicating busy:
2164 * \verbatim *ECAV: 1,7,1 \endverbatim
2165 */
2166static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
2167{
2168 int ccid = 0;
2169 int ccstatus = 0;
2170 int calltype = 0;
2171
2172 if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
2173 ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
2174 return -1;
2175 }
2176
2177 return ccstatus;
2178}
2179
2180/*!
2181 * \brief Enable Sony Ericsson extensions / indications.
2182 * \param hfp an hfp_pvt struct
2183 */
2184static int hfp_send_ecam(struct hfp_pvt *hfp)
2185{
2186 return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
2187}
2188
2189/*!
2190 * \brief Parse a CIEV event.
2191 * \param hfp an hfp_pvt struct
2192 * \param buf the buffer to parse (null terminated)
2193 * \param value a pointer to an int to store the event value in (can be NULL)
2194 * \return 0 on error (parse error, or unknown event) or a HFP_CIND_* value on
2195 * success
2196 */
2197static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
2198{
2199 int i, v;
2200 if (!value)
2201 value = &v;
2202
2203 if (!sscanf(buf, "+CIEV: %d,%d", &i, value)) {
2204 ast_debug(2, "[%s] error parsing CIEV event '%s'\n", hfp->owner->id, buf);
2205 return HFP_CIND_NONE;
2206 }
2207
2208 if (i >= ARRAY_LEN(hfp->cind_state)) {
2209 ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
2210 return HFP_CIND_NONE;
2211 }
2212
2213 hfp->cind_state[i] = *value;
2214 return hfp->cind_index[i];
2215}
2216
2217/*!
2218 * \brief Parse a CLIP event.
2219 * \param hfp an hfp_pvt struct
2220 * \param buf the buffer to parse (null terminated)
2221 * \note buf will be modified when the CID string is parsed
2222 * \return a cidinfo structure pointing to the cnam and cnum
2223 * data in buf. On parse errors, either or both pointers
2224 * will point to null strings
2225 */
2226static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
2227{
2228 int i;
2229 int tokens[6];
2230 char *cnamtmp;
2231 char delim = ' '; /* First token terminates with space */
2232 int invalid = 0; /* Number of invalid chars in cnam */
2233 struct cidinfo cidinfo = { NULL, NULL };
2234
2235 /* parse clip info in the following format:
2236 * +CLIP: "123456789",128,...
2237 */
2238 ast_debug(3, "[%s] hfp_parse_clip is processing \"%s\"\n", hfp->owner->id, buf);
2239 tokens[0] = 0; /* First token starts in position 0 */
2240 for (i = 1; i < ARRAY_LEN(tokens); i++) {
2241 tokens[i] = parse_next_token(buf, tokens[i - 1], delim);
2242 delim = ','; /* Subsequent tokens terminate with comma */
2243 }
2244 ast_debug(3, "[%s] hfp_parse_clip found tokens: 0=%s, 1=%s, 2=%s, 3=%s, 4=%s, 5=%s\n",
2245 hfp->owner->id, &buf[tokens[0]], &buf[tokens[1]], &buf[tokens[2]],
2246 &buf[tokens[3]], &buf[tokens[4]], &buf[tokens[5]]);
2247
2248 /* Clean up cnum, and make sure it is legitimate since it is untrusted. */
2249 cidinfo.cnum = ast_strip_quoted(&buf[tokens[1]], "\"", "\"");
2251 ast_debug(1, "[%s] hfp_parse_clip invalid cidinfo.cnum data \"%s\" - deleting\n",
2252 hfp->owner->id, cidinfo.cnum);
2253 cidinfo.cnum = "";
2254 }
2255
2256 /*
2257 * Some docs say tokens 2 and 3 including the commas are optional.
2258 * If absent, that would move CNAM back to token 3.
2259 */
2260 cidinfo.cnam = &buf[tokens[5]]; /* Assume it's in token 5 */
2261 if (buf[tokens[5]] == '\0' && buf[tokens[4]] == '\0') {
2262 /* Tokens 4 and 5 are empty. See if token 3 looks like CNAM (starts with ") */
2263 i = tokens[3];
2264 while (buf[i] == ' ') { /* Find the first non-blank */
2265 i++;
2266 }
2267 if (buf[i] == '"') {
2268 /* Starts with quote. Use this for CNAM. */
2269 cidinfo.cnam = &buf[i];
2270 }
2271 }
2272
2273 /* Clean up CNAM. */
2274 cidinfo.cnam = ast_strip_quoted(cidinfo.cnam, "\"", "\"");
2275 for (cnamtmp = cidinfo.cnam; *cnamtmp != '\0'; cnamtmp++) {
2276 if (!strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-,abcdefghijklmnopqrstuvwxyz_", *cnamtmp)) {
2277 *cnamtmp = '_'; /* Invalid. Replace with underscore. */
2278 invalid++;
2279 }
2280 }
2281 if (invalid) {
2282 ast_debug(2, "[%s] hfp_parse_clip replaced %d invalid byte(s) in cnam data\n",
2283 hfp->owner->id, invalid);
2284 }
2285 ast_debug(2, "[%s] hfp_parse_clip returns cnum=%s and cnam=%s\n",
2286 hfp->owner->id, cidinfo.cnum, cidinfo.cnam);
2287
2288 return cidinfo;
2289}
2290
2291/*!
2292 * \brief Terminate current token and return an index to start of the next token.
2293 * \param string the null-terminated string being parsed (will be altered!)
2294 * \param start where the current token starts
2295 * \param delim the token termination delimiter. \0 is also considered a terminator.
2296 * \return index of the next token. May be the same as this token if the string is
2297 * exhausted.
2298 */
2299static int parse_next_token(char string[], const int start, const char delim)
2300{
2301 int index;
2302 int quoting = 0;
2303
2304 for (index = start; string[index] != 0; index++) {
2305 if ((string[index] == delim) && !quoting ) {
2306 /* Found the delimiter, outside of quotes. This is the end of the token. */
2307 string[index] = '\0'; /* Terminate this token. */
2308 index++; /* Point the index to the start of the next token. */
2309 break; /* We're done. */
2310 } else if (string[index] == '"' && !quoting) {
2311 /* Found a beginning quote mark. Remember it. */
2312 quoting = 1;
2313 } else if (string[index] == '"' ) {
2314 /* Found the end quote mark. */
2315 quoting = 0;
2316 }
2317 }
2318 return index;
2319}
2320
2321/*!
2322 * \brief Parse a CMTI notification.
2323 * \param hfp an hfp_pvt struct
2324 * \param buf the buffer to parse (null terminated)
2325 * \note buf will be modified when the CMTI message is parsed
2326 * \return -1 on error (parse error) or the index of the new sms message
2327 */
2328static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
2329{
2330 int index = -1;
2331
2332 /* parse cmti info in the following format:
2333 * +CMTI: <mem>,<index>
2334 */
2335 if (!sscanf(buf, "+CMTI: %*[^,],%d", &index)) {
2336 ast_debug(2, "[%s] error parsing CMTI event '%s'\n", hfp->owner->id, buf);
2337 return -1;
2338 }
2339
2340 return index;
2341}
2342
2343/*!
2344 * \brief Parse a CMGR message.
2345 * \param hfp an hfp_pvt struct
2346 * \param buf the buffer to parse (null terminated)
2347 * \param from_number a pointer to a char pointer which will store the from
2348 * number
2349 * \param text a pointer to a char pointer which will store the message text
2350 * \note buf will be modified when the CMGR message is parsed
2351 * \retval -1 parse error
2352 * \retval 0 success
2353 */
2354static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
2355{
2356 int i, state;
2357 size_t s;
2358
2359 /* parse cmgr info in the following format:
2360 * +CMGR: <msg status>,"+123456789",...\r\n
2361 * <message text>
2362 */
2363 state = 0;
2364 s = strlen(buf);
2365 for (i = 0; i < s && state != 6; i++) {
2366 switch (state) {
2367 case 0: /* search for start of the number section (,) */
2368 if (buf[i] == ',') {
2369 state++;
2370 }
2371 break;
2372 case 1: /* find the opening quote (") */
2373 if (buf[i] == '"') {
2374 state++;
2375 }
2376 break;
2377 case 2: /* mark the start of the number */
2378 if (from_number) {
2379 *from_number = &buf[i];
2380 state++;
2381 }
2382 /* fall through */
2383 case 3: /* search for the end of the number (") */
2384 if (buf[i] == '"') {
2385 buf[i] = '\0';
2386 state++;
2387 }
2388 break;
2389 case 4: /* search for the start of the message text (\n) */
2390 if (buf[i] == '\n') {
2391 state++;
2392 }
2393 break;
2394 case 5: /* mark the start of the message text */
2395 if (text) {
2396 *text = &buf[i];
2397 state++;
2398 }
2399 break;
2400 }
2401 }
2402
2403 if (state != 6) {
2404 return -1;
2405 }
2406
2407 return 0;
2408}
2409
2410/*!
2411 * \brief Parse a CUSD answer.
2412 * \param hfp an hfp_pvt struct
2413 * \param buf the buffer to parse (null terminated)
2414 * \note buf will be modified when the CUSD string is parsed
2415 * \return NULL on error (parse error) or a pointer to the cusd message
2416 * information in buf
2417 */
2418static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
2419{
2420 int i, message_start, message_end;
2421 char *cusd;
2422 size_t s;
2423
2424 /* parse cusd message in the following format:
2425 * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#."
2426 */
2427 message_start = 0;
2428 message_end = 0;
2429 s = strlen(buf);
2430
2431 /* Find the start of the message (") */
2432 for (i = 0; i < s; i++) {
2433 if (buf[i] == '"') {
2434 message_start = i + 1;
2435 break;
2436 }
2437 }
2438
2439 if (message_start == 0 || message_start >= s) {
2440 return NULL;
2441 }
2442
2443 /* Find the end of the message (") */
2444 for (i = s; i > 0; i--) {
2445 if (buf[i] == '"') {
2446 message_end = i;
2447 break;
2448 }
2449 }
2450
2451 if (message_end == 0) {
2452 return NULL;
2453 }
2454
2455 if (message_start >= message_end) {
2456 return NULL;
2457 }
2458
2459 cusd = &buf[message_start];
2460 buf[message_end] = '\0';
2461
2462 return cusd;
2463}
2464
2465/*!
2466 * \brief Convert a hfp_hf struct to a BRSF int.
2467 * \param hf an hfp_hf brsf object
2468 * \return an integer representing the given brsf struct
2469 */
2470static int hfp_brsf2int(struct hfp_hf *hf)
2471{
2472 int brsf = 0;
2473
2474 brsf |= hf->ecnr ? HFP_HF_ECNR : 0;
2475 brsf |= hf->cw ? HFP_HF_CW : 0;
2476 brsf |= hf->cid ? HFP_HF_CID : 0;
2477 brsf |= hf->voice ? HFP_HF_VOICE : 0;
2478 brsf |= hf->volume ? HFP_HF_VOLUME : 0;
2479 brsf |= hf->status ? HFP_HF_STATUS : 0;
2480 brsf |= hf->control ? HFP_HF_CONTROL : 0;
2481
2482 return brsf;
2483}
2484
2485/*!
2486 * \brief Convert a BRSF int to an hfp_ag struct.
2487 * \param brsf a brsf integer
2488 * \param ag a AG (hfp_ag) brsf object
2489 * \return a pointer to the given hfp_ag object populated with the values from
2490 * the given brsf integer
2491 */
2492static struct hfp_ag *hfp_int2brsf(int brsf, struct hfp_ag *ag)
2493{
2494 ag->cw = brsf & HFP_AG_CW ? 1 : 0;
2495 ag->ecnr = brsf & HFP_AG_ECNR ? 1 : 0;
2496 ag->voice = brsf & HFP_AG_VOICE ? 1 : 0;
2497 ag->ring = brsf & HFP_AG_RING ? 1 : 0;
2498 ag->tag = brsf & HFP_AG_TAG ? 1 : 0;
2499 ag->reject = brsf & HFP_AG_REJECT ? 1 : 0;
2500 ag->status = brsf & HFP_AG_STATUS ? 1 : 0;
2501 ag->control = brsf & HFP_AG_CONTROL ? 1 : 0;
2502 ag->errors = brsf & HFP_AG_ERRORS ? 1 : 0;
2503
2504 return ag;
2505}
2506
2507
2508/*!
2509 * \brief Send a BRSF request.
2510 * \param hfp an hfp_pvt struct
2511 * \param brsf an hfp_hf brsf struct
2512 *
2513 * \retval 0 on success
2514 * \retval -1 on error
2515 */
2516static int hfp_send_brsf(struct hfp_pvt *hfp, struct hfp_hf *brsf)
2517{
2518 char cmd[32];
2519 snprintf(cmd, sizeof(cmd), "AT+BRSF=%d\r", hfp_brsf2int(brsf));
2520 return rfcomm_write(hfp->rsock, cmd);
2521}
2522
2523/*!
2524 * \brief Send the CIND read command.
2525 * \param hfp an hfp_pvt struct
2526 */
2527static int hfp_send_cind(struct hfp_pvt *hfp)
2528{
2529 return rfcomm_write(hfp->rsock, "AT+CIND?\r");
2530}
2531
2532/*!
2533 * \brief Send the CIND test command.
2534 * \param hfp an hfp_pvt struct
2535 */
2536static int hfp_send_cind_test(struct hfp_pvt *hfp)
2537{
2538 return rfcomm_write(hfp->rsock, "AT+CIND=?\r");
2539}
2540
2541/*!
2542 * \brief Enable or disable indicator events reporting.
2543 * \param hfp an hfp_pvt struct
2544 * \param status enable or disable events reporting (should be 1 or 0)
2545 */
2546static int hfp_send_cmer(struct hfp_pvt *hfp, int status)
2547{
2548 char cmd[32];
2549 snprintf(cmd, sizeof(cmd), "AT+CMER=3,0,0,%d\r", status ? 1 : 0);
2550 return rfcomm_write(hfp->rsock, cmd);
2551}
2552
2553/*!
2554 * \brief Send the current speaker gain level.
2555 * \param hfp an hfp_pvt struct
2556 * \param value the value to send (must be between 0 and 15)
2557 */
2558static int hfp_send_vgs(struct hfp_pvt *hfp, int value)
2559{
2560 char cmd[32];
2561 snprintf(cmd, sizeof(cmd), "AT+VGS=%d\r", value);
2562 return rfcomm_write(hfp->rsock, cmd);
2563}
2564
2565#if 0
2566/*!
2567 * \brief Send the current microphone gain level.
2568 * \param hfp an hfp_pvt struct
2569 * \param value the value to send (must be between 0 and 15)
2570 */
2571static int hfp_send_vgm(struct hfp_pvt *hfp, int value)
2572{
2573 char cmd[32];
2574 snprintf(cmd, sizeof(cmd), "AT+VGM=%d\r", value);
2575 return rfcomm_write(hfp->rsock, cmd);
2576}
2577#endif
2578
2579/*!
2580 * \brief Enable or disable calling line identification.
2581 * \param hfp an hfp_pvt struct
2582 * \param status enable or disable calling line identification (should be 1 or
2583 * 0)
2584 */
2585static int hfp_send_clip(struct hfp_pvt *hfp, int status)
2586{
2587 char cmd[32];
2588 snprintf(cmd, sizeof(cmd), "AT+CLIP=%d\r", status ? 1 : 0);
2589 return rfcomm_write(hfp->rsock, cmd);
2590}
2591
2592/*!
2593 * \brief Send a DTMF command.
2594 * \param hfp an hfp_pvt struct
2595 * \param digit the dtmf digit to send
2596 * \return the result of rfcomm_write() or -1 on an invalid digit being sent
2597 */
2598static int hfp_send_dtmf(struct hfp_pvt *hfp, char digit)
2599{
2600 char cmd[10];
2601
2602 switch(digit) {
2603 case '0':
2604 case '1':
2605 case '2':
2606 case '3':
2607 case '4':
2608 case '5':
2609 case '6':
2610 case '7':
2611 case '8':
2612 case '9':
2613 case '*':
2614 case '#':
2615 snprintf(cmd, sizeof(cmd), "AT+VTS=%c\r", digit);
2616 return rfcomm_write(hfp->rsock, cmd);
2617 default:
2618 return -1;
2619 }
2620}
2621
2622/*!
2623 * \brief Set the SMS mode.
2624 * \param hfp an hfp_pvt struct
2625 * \param mode the sms mode (0 = PDU, 1 = Text)
2626 */
2627static int hfp_send_cmgf(struct hfp_pvt *hfp, int mode)
2628{
2629 char cmd[32];
2630 snprintf(cmd, sizeof(cmd), "AT+CMGF=%d\r", mode);
2631 return rfcomm_write(hfp->rsock, cmd);
2632}
2633
2634/*!
2635 * \brief Setup SMS new message indication.
2636 * \param hfp an hfp_pvt struct
2637 */
2638static int hfp_send_cnmi(struct hfp_pvt *hfp)
2639{
2640 return rfcomm_write(hfp->rsock, "AT+CNMI=2,1,0,0,0\r");
2641}
2642
2643/*!
2644 * \brief Read an SMS message.
2645 * \param hfp an hfp_pvt struct
2646 * \param index the location of the requested message
2647 */
2648static int hfp_send_cmgr(struct hfp_pvt *hfp, int index)
2649{
2650 char cmd[32];
2651 snprintf(cmd, sizeof(cmd), "AT+CMGR=%d\r", index);
2652 return rfcomm_write(hfp->rsock, cmd);
2653}
2654
2655/*!
2656 * \brief Start sending an SMS message.
2657 * \param hfp an hfp_pvt struct
2658 * \param number the destination of the message
2659 */
2660static int hfp_send_cmgs(struct hfp_pvt *hfp, const char *number)
2661{
2662 char cmd[64];
2663 snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r", number);
2664 return rfcomm_write(hfp->rsock, cmd);
2665}
2666
2667/*!
2668 * \brief Send the text of an SMS message.
2669 * \param hfp an hfp_pvt struct
2670 * \param message the text of the message
2671 */
2672static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message)
2673{
2674 char cmd[162];
2675 snprintf(cmd, sizeof(cmd), "%.160s\x1a", message);
2676 return rfcomm_write(hfp->rsock, cmd);
2677}
2678
2679/*!
2680 * \brief Send AT+CHUP.
2681 * \param hfp an hfp_pvt struct
2682 */
2683static int hfp_send_chup(struct hfp_pvt *hfp)
2684{
2685 return rfcomm_write(hfp->rsock, "AT+CHUP\r");
2686}
2687
2688/*!
2689 * \brief Send ATD.
2690 * \param hfp an hfp_pvt struct
2691 * \param number the number to send
2692 */
2693static int hfp_send_atd(struct hfp_pvt *hfp, const char *number)
2694{
2695 char cmd[64];
2696 snprintf(cmd, sizeof(cmd), "ATD%s;\r", number);
2697 return rfcomm_write(hfp->rsock, cmd);
2698}
2699
2700/*!
2701 * \brief Send ATA.
2702 * \param hfp an hfp_pvt struct
2703 */
2704static int hfp_send_ata(struct hfp_pvt *hfp)
2705{
2706 return rfcomm_write(hfp->rsock, "ATA\r");
2707}
2708
2709/*!
2710 * \brief Send CUSD.
2711 * \param hfp an hfp_pvt struct
2712 * \param code the CUSD code to send
2713 */
2714static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code)
2715{
2716 char cmd[128];
2717 snprintf(cmd, sizeof(cmd), "AT+CUSD=1,\"%s\",15\r", code);
2718 return rfcomm_write(hfp->rsock, cmd);
2719}
2720
2721/*!
2722 * \brief Parse BRSF data.
2723 * \param hfp an hfp_pvt struct
2724 * \param buf the buffer to parse (null terminated)
2725 */
2726static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf)
2727{
2728 int brsf;
2729
2730 if (!sscanf(buf, "+BRSF:%d", &brsf))
2731 return -1;
2732
2733 hfp_int2brsf(brsf, &hfp->brsf);
2734
2735 return 0;
2736}
2737
2738/*!
2739 * \brief Parse and store the given indicator.
2740 * \param hfp an hfp_pvt struct
2741 * \param group the indicator group
2742 * \param indicator the indicator to parse
2743 */
2744static int hfp_parse_cind_indicator(struct hfp_pvt *hfp, int group, char *indicator)
2745{
2746 int value;
2747
2748 /* store the current indicator */
2749 if (group >= ARRAY_LEN(hfp->cind_state)) {
2750 ast_debug(1, "ignoring CIND state '%s' for group %d, we only support up to %d indicators\n", indicator, group, (int) sizeof(hfp->cind_state));
2751 return -1;
2752 }
2753
2754 if (!sscanf(indicator, "%d", &value)) {
2755 ast_debug(1, "error parsing CIND state '%s' for group %d\n", indicator, group);
2756 return -1;
2757 }
2758
2759 hfp->cind_state[group] = value;
2760 return 0;
2761}
2762
2763/*!
2764 * \brief Read the result of the AT+CIND? command.
2765 * \param hfp an hfp_pvt struct
2766 * \param buf the buffer to parse (null terminated)
2767 * \note hfp_send_cind_test() and hfp_parse_cind_test() should be called at
2768 * least once before this function is called.
2769 */
2770static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf)
2771{
2772 int i, state, group;
2773 size_t s;
2774 char *indicator = NULL;
2775
2776 /* parse current state of all of our indicators. The list is in the
2777 * following format:
2778 * +CIND: 1,0,2,0,0,0,0
2779 */
2780 group = 0;
2781 state = 0;
2782 s = strlen(buf);
2783 for (i = 0; i < s; i++) {
2784 switch (state) {
2785 case 0: /* search for start of the status indicators (a space) */
2786 if (buf[i] == ' ') {
2787 group++;
2788 state++;
2789 }
2790 break;
2791 case 1: /* mark this indicator */
2792 indicator = &buf[i];
2793 state++;
2794 break;
2795 case 2: /* search for the start of the next indicator (a comma) */
2796 if (buf[i] == ',') {
2797 buf[i] = '\0';
2798
2800
2801 group++;
2802 state = 1;
2803 }
2804 break;
2805 }
2806 }
2807
2808 /* store the last indicator */
2809 if (state == 2)
2811
2812 return 0;
2813}
2814
2815/*!
2816 * \brief Parse the result of the AT+CIND=? command.
2817 * \param hfp an hfp_pvt struct
2818 * \param buf the buffer to parse (null terminated)
2819 */
2820static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
2821{
2822 int i, state, group;
2823 size_t s;
2824 char *indicator = NULL;
2825
2826 hfp->nocallsetup = 1;
2827
2828 /* parse the indications list. It is in the follwing format:
2829 * +CIND: ("ind1",(0-1)),("ind2",(0-5))
2830 */
2831 group = 0;
2832 state = 0;
2833 s = strlen(buf);
2834 for (i = 0; i < s; i++) {
2835 switch (state) {
2836 case 0: /* search for start of indicator block */
2837 if (buf[i] == '(') {
2838 group++;
2839 state++;
2840 }
2841 break;
2842 case 1: /* search for '"' in indicator block */
2843 if (buf[i] == '"') {
2844 state++;
2845 }
2846 break;
2847 case 2: /* mark the start of the indicator name */
2848 indicator = &buf[i];
2849 state++;
2850 break;
2851 case 3: /* look for the end of the indicator name */
2852 if (buf[i] == '"') {
2853 buf[i] = '\0';
2854 state++;
2855 }
2856 break;
2857 case 4: /* find the start of the value range */
2858 if (buf[i] == '(') {
2859 state++;
2860 }
2861 break;
2862 case 5: /* mark the start of the value range */
2863 state++;
2864 break;
2865 case 6: /* find the end of the value range */
2866 if (buf[i] == ')') {
2867 buf[i] = '\0';
2868 state++;
2869 }
2870 break;
2871 case 7: /* process the values we found */
2872 if (group < sizeof(hfp->cind_index)) {
2873 if (!strcmp(indicator, "service")) {
2874 hfp->cind_map.service = group;
2876 } else if (!strcmp(indicator, "call")) {
2877 hfp->cind_map.call = group;
2879 } else if (!strcmp(indicator, "callsetup")) {
2880 hfp->nocallsetup = 0;
2881 hfp->cind_map.callsetup = group;
2883 } else if (!strcmp(indicator, "call_setup")) { /* non standard call setup identifier */
2884 hfp->nocallsetup = 0;
2885 hfp->cind_map.callsetup = group;
2887 } else if (!strcmp(indicator, "callheld")) {
2888 hfp->cind_map.callheld = group;
2890 } else if (!strcmp(indicator, "signal")) {
2891 hfp->cind_map.signal = group;
2893 } else if (!strcmp(indicator, "roam")) {
2894 hfp->cind_map.roam = group;
2896 } else if (!strcmp(indicator, "battchg")) {
2897 hfp->cind_map.battchg = group;
2899 } else {
2901 ast_debug(2, "ignoring unknown CIND indicator '%s'\n", indicator);
2902 }
2903 } else {
2904 ast_debug(1, "can't store indicator %d (%s), we only support up to %d indicators", group, indicator, (int) sizeof(hfp->cind_index));
2905 }
2906
2907 state = 0;
2908 break;
2909 }
2910 }
2911
2912 hfp->owner->no_callsetup = hfp->nocallsetup;
2913
2914 return 0;
2915}
2916
2917
2918/*
2919 * Bluetooth Headset Profile helpers
2920 */
2921
2922/*!
2923 * \brief Send an OK AT response.
2924 * \param rsock the rfcomm socket to use
2925 */
2926static int hsp_send_ok(int rsock)
2927{
2928 return rfcomm_write(rsock, "\r\nOK\r\n");
2929}
2930
2931/*!
2932 * \brief Send an ERROR AT response.
2933 * \param rsock the rfcomm socket to use
2934 */
2935static int hsp_send_error(int rsock)
2936{
2937 return rfcomm_write(rsock, "\r\nERROR\r\n");
2938}
2939
2940/*!
2941 * \brief Send a speaker gain unsolicited AT response
2942 * \param rsock the rfcomm socket to use
2943 * \param gain the speaker gain value
2944 */
2945static int hsp_send_vgs(int rsock, int gain)
2946{
2947 char cmd[32];
2948 snprintf(cmd, sizeof(cmd), "\r\n+VGS=%d\r\n", gain);
2949 return rfcomm_write(rsock, cmd);
2950}
2951
2952/*!
2953 * \brief Send a microphone gain unsolicited AT response
2954 * \param rsock the rfcomm socket to use
2955 * \param gain the microphone gain value
2956 */
2957static int hsp_send_vgm(int rsock, int gain)
2958{
2959 char cmd[32];
2960 snprintf(cmd, sizeof(cmd), "\r\n+VGM=%d\r\n", gain);
2961 return rfcomm_write(rsock, cmd);
2962}
2963
2964/*!
2965 * \brief Send a RING unsolicited AT response.
2966 * \param rsock the rfcomm socket to use
2967 */
2968static int hsp_send_ring(int rsock)
2969{
2970 return rfcomm_write(rsock, "\r\nRING\r\n");
2971}
2972
2973/*
2974 * message queue functions
2975 */
2976
2977/*!
2978 * \brief Add an item to the back of the queue.
2979 * \param pvt a mbl_pvt structure
2980 * \param expect the msg we expect to receive
2981 * \param response_to the message that was sent to generate the expected
2982 * response
2983 */
2984static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
2985{
2986 struct msg_queue_entry *msg;
2987 if (!(msg = ast_calloc(1, sizeof(*msg)))) {
2988 return -1;
2989 }
2990 msg->expected = expect;
2991 msg->response_to = response_to;
2992
2994 return 0;
2995}
2996
2997/*!
2998 * \brief Add an item to the back of the queue with data.
2999 * \param pvt a mbl_pvt structure
3000 * \param expect the msg we expect to receive
3001 * \param response_to the message that was sent to generate the expected
3002 * response
3003 * \param data data associated with this message, it will be freed when the
3004 * message is freed
3005 */
3007{
3008 struct msg_queue_entry *msg;
3009 if (!(msg = ast_calloc(1, sizeof(*msg)))) {
3010 return -1;
3011 }
3012 msg->expected = expect;
3013 msg->response_to = response_to;
3014 msg->data = data;
3015
3017 return 0;
3018}
3019
3020/*!
3021 * \brief Remove an item from the front of the queue.
3022 * \param pvt a mbl_pvt structure
3023 * \return a pointer to the removed item
3024 */
3025static struct msg_queue_entry *msg_queue_pop(struct mbl_pvt *pvt)
3026{
3027 return AST_LIST_REMOVE_HEAD(&pvt->msg_queue, entry);
3028}
3029
3030/*!
3031 * \brief Remove an item from the front of the queue, and free it.
3032 * \param pvt a mbl_pvt structure
3033 */
3034static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
3035{
3036 struct msg_queue_entry *msg;
3037 if ((msg = msg_queue_pop(pvt))) {
3038 if (msg->data)
3039 ast_free(msg->data);
3040 ast_free(msg);
3041 }
3042}
3043
3044/*!
3045 * \brief Remove all items from the queue and free them.
3046 * \param pvt a mbl_pvt structure
3047 */
3048static void msg_queue_flush(struct mbl_pvt *pvt)
3049{
3050 struct msg_queue_entry *msg;
3051 while ((msg = msg_queue_head(pvt)))
3053}
3054
3055/*!
3056 * \brief Get the head of a queue.
3057 * \param pvt a mbl_pvt structure
3058 * \return a pointer to the head of the given msg queue
3059 */
3060static struct msg_queue_entry *msg_queue_head(struct mbl_pvt *pvt)
3061{
3062 return AST_LIST_FIRST(&pvt->msg_queue);
3063}
3064
3065
3066
3067/*
3068
3069 sdp helpers
3070
3071*/
3072
3073static int sdp_search(char *addr, int profile)
3074{
3075
3076 sdp_session_t *session = 0;
3077 bdaddr_t bdaddr;
3078 uuid_t svc_uuid;
3079 uint32_t range = 0x0000ffff;
3080 sdp_list_t *response_list, *search_list, *attrid_list;
3081 int status, port;
3082 sdp_list_t *proto_list;
3083 sdp_record_t *sdprec;
3084
3085 str2ba(addr, &bdaddr);
3086 port = 0;
3087 session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
3088 if (!session) {
3089 ast_debug(1, "sdp_connect() failed on device %s.\n", addr);
3090 return 0;
3091 }
3092
3093 sdp_uuid32_create(&svc_uuid, profile);
3094 search_list = sdp_list_append(0, &svc_uuid);
3095 attrid_list = sdp_list_append(0, &range);
3096 response_list = 0x00;
3097 status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
3098 if (status == 0) {
3099 if (response_list) {
3100 sdprec = (sdp_record_t *) response_list->data;
3101 proto_list = 0x00;
3102 if (sdp_get_access_protos(sdprec, &proto_list) == 0) {
3103 port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
3104 sdp_list_free(proto_list, 0);
3105 }
3106 sdp_record_free(sdprec);
3107 sdp_list_free(response_list, 0);
3108 } else
3109 ast_debug(1, "No responses returned for device %s.\n", addr);
3110 } else
3111 ast_debug(1, "sdp_service_search_attr_req() failed on device %s.\n", addr);
3112
3113 sdp_list_free(search_list, 0);
3114 sdp_list_free(attrid_list, 0);
3115 sdp_close(session);
3116
3117 return port;
3118
3119}
3120
3121static sdp_session_t *sdp_register(void)
3122{
3123 uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
3124 uint8_t rfcomm_channel = 1;
3125 const char *service_name = "Asterisk PABX";
3126 const char *service_dsc = "Asterisk PABX";
3127 const char *service_prov = "Asterisk";
3128
3129 uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class1_uuid, svc_class2_uuid;
3130 sdp_list_t *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
3131 sdp_data_t *channel = 0;
3132
3133 sdp_session_t *session = 0;
3134
3135 sdp_record_t *record = sdp_record_alloc();
3136
3137 sdp_uuid128_create(&svc_uuid, &service_uuid_int);
3138 sdp_set_service_id(record, svc_uuid);
3139
3140 sdp_uuid32_create(&svc_class1_uuid, GENERIC_AUDIO_SVCLASS_ID);
3141 sdp_uuid32_create(&svc_class2_uuid, HEADSET_PROFILE_ID);
3142
3143 svc_uuid_list = sdp_list_append(0, &svc_class1_uuid);
3144 svc_uuid_list = sdp_list_append(svc_uuid_list, &svc_class2_uuid);
3145 sdp_set_service_classes(record, svc_uuid_list);
3146
3147 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3148 root_list = sdp_list_append(0, &root_uuid);
3149 sdp_set_browse_groups( record, root_list );
3150
3151 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3152 l2cap_list = sdp_list_append(0, &l2cap_uuid);
3153 proto_list = sdp_list_append(0, l2cap_list);
3154
3155 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3156 channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
3157 rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
3158 sdp_list_append(rfcomm_list, channel);
3159 sdp_list_append(proto_list, rfcomm_list);
3160
3161 access_proto_list = sdp_list_append(0, proto_list);
3162 sdp_set_access_protos(record, access_proto_list);
3163
3164 sdp_set_info_attr(record, service_name, service_prov, service_dsc);
3165
3166 if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
3167 ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
3168 else {
3169 if (sdp_record_register(session, record, 0) < 0) {
3170 ast_log(LOG_WARNING, "Failed to sdp_record_register error: %d\n", errno);
3171 return NULL;
3172 }
3173 }
3174
3175 sdp_data_free(channel);
3176 sdp_list_free(rfcomm_list, 0);
3177 sdp_list_free(root_list, 0);
3178 sdp_list_free(access_proto_list, 0);
3179 sdp_list_free(svc_uuid_list, 0);
3180
3181 return session;
3182
3183}
3184
3185/*
3186
3187 Thread routines
3188
3189*/
3190
3191/*!
3192 * \brief Handle the BRSF response.
3193 * \param pvt a mbl_pvt structure
3194 * \param buf a null terminated buffer containing an AT message
3195 * \retval 0 success
3196 * \retval -1 error
3197 */
3198static int handle_response_brsf(struct mbl_pvt *pvt, char *buf)
3199{
3200 struct msg_queue_entry *entry;
3201 if ((entry = msg_queue_head(pvt)) && entry->expected == AT_BRSF) {
3202 if (hfp_parse_brsf(pvt->hfp, buf)) {
3203 ast_debug(1, "[%s] error parsing BRSF\n", pvt->id);
3204 goto e_return;
3205 }
3206
3207 if (msg_queue_push(pvt, AT_OK, AT_BRSF)) {
3208 ast_debug(1, "[%s] error handling BRSF\n", pvt->id);
3209 goto e_return;
3210 }
3211
3213 } else if (entry) {
3214 ast_debug(1, "[%s] received unexpected AT message 'BRSF' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3215 } else {
3216 ast_debug(1, "[%s] received unexpected AT message 'BRSF'\n", pvt->id);
3217 }
3218
3219 return 0;
3220
3221e_return:
3223 return -1;
3224}
3225
3226/*!
3227 * \brief Handle the CIND response.
3228 * \param pvt a mbl_pvt structure
3229 * \param buf a null terminated buffer containing an AT message
3230 * \retval 0 success
3231 * \retval -1 error
3232 */
3233static int handle_response_cind(struct mbl_pvt *pvt, char *buf)
3234{
3235 struct msg_queue_entry *entry;
3236 if ((entry = msg_queue_head(pvt)) && entry->expected == AT_CIND) {
3237 switch (entry->response_to) {
3238 case AT_CIND_TEST:
3240 ast_debug(1, "[%s] error performing CIND test\n", pvt->id);
3241 goto e_return;
3242 }
3243 break;
3244 case AT_CIND:
3245 if (hfp_parse_cind(pvt->hfp, buf) || msg_queue_push(pvt, AT_OK, AT_CIND)) {
3246 ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3247 goto e_return;
3248 }
3249 break;
3250 default:
3251 ast_debug(1, "[%s] error getting CIND state\n", pvt->id);
3252 goto e_return;
3253 }
3255 } else if (entry) {
3256 ast_debug(1, "[%s] received unexpected AT message 'CIND' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3257 } else {
3258 ast_debug(1, "[%s] received unexpected AT message 'CIND'\n", pvt->id);
3259 }
3260
3261 return 0;
3262
3263e_return:
3265 return -1;
3266}
3267
3268/*!
3269 * \brief Handle OK AT messages.
3270 * \param pvt a mbl_pvt structure
3271 * \param buf a null terminated buffer containing an AT message
3272 * \retval 0 success
3273 * \retval -1 error
3274 */
3275static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
3276{
3277 struct msg_queue_entry *entry;
3278 if ((entry = msg_queue_head(pvt)) && entry->expected == AT_OK) {
3279 switch (entry->response_to) {
3280
3281 /* initialization stuff */
3282 case AT_BRSF:
3283 ast_debug(1, "[%s] BSRF sent successfully\n", pvt->id);
3284
3285 /* If this is a blackberry do CMER now, otherwise
3286 * continue with CIND as normal. */
3287 if (pvt->blackberry) {
3288 if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
3289 ast_debug(1, "[%s] error sending CMER\n", pvt->id);
3290 goto e_return;
3291 }
3292 } else {
3294 ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
3295 goto e_return;
3296 }
3297 }
3298 break;
3299 case AT_CIND_TEST:
3300 ast_debug(1, "[%s] CIND test sent successfully\n", pvt->id);
3301
3302 ast_debug(2, "[%s] call: %d\n", pvt->id, pvt->hfp->cind_map.call);
3303 ast_debug(2, "[%s] callsetup: %d\n", pvt->id, pvt->hfp->cind_map.callsetup);
3304 ast_debug(2, "[%s] service: %d\n", pvt->id, pvt->hfp->cind_map.service);
3305
3306 if (hfp_send_cind(pvt->hfp) || msg_queue_push(pvt, AT_CIND, AT_CIND)) {
3307 ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
3308 goto e_return;
3309 }
3310 break;
3311 case AT_CIND:
3312 ast_debug(1, "[%s] CIND sent successfully\n", pvt->id);
3313
3314 /* check if a call is active */
3315 if (pvt->hfp->cind_state[pvt->hfp->cind_map.call]) {
3316 ast_verb(3, "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
3317 goto e_return;
3318 }
3319
3320 /* If this is NOT a blackberry proceed with CMER,
3321 * otherwise send CLIP. */
3322 if (!pvt->blackberry) {
3323 if (hfp_send_cmer(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMER)) {
3324 ast_debug(1, "[%s] error sending CMER\n", pvt->id);
3325 goto e_return;
3326 }
3327 } else {
3328 if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
3329 ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
3330 goto e_return;
3331 }
3332 }
3333 break;
3334 case AT_CMER:
3335 ast_debug(1, "[%s] CMER sent successfully\n", pvt->id);
3336
3337 /* If this is a blackberry proceed with the CIND test,
3338 * otherwise send CLIP. */
3339 if (pvt->blackberry) {
3341 ast_debug(1, "[%s] error sending CIND test\n", pvt->id);
3342 goto e_return;
3343 }
3344 } else {
3345 if (hfp_send_clip(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CLIP)) {
3346 ast_debug(1, "[%s] error enabling calling line notification\n", pvt->id);
3347 goto e_return;
3348 }
3349 }
3350 break;
3351 case AT_CLIP:
3352 ast_debug(1, "[%s] calling line indication enabled\n", pvt->id);
3353 if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
3354 ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
3355 goto e_return;
3356 }
3357
3358 break;
3359 case AT_ECAM:
3360 ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
3361 if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
3362 ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
3363 goto e_return;
3364 }
3365
3366 pvt->timeout = -1;
3367 pvt->hfp->initialized = 1;
3368 ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
3369
3370 break;
3371 case AT_VGS:
3372 ast_debug(1, "[%s] volume level synchronization successful\n", pvt->id);
3373
3374 /* set the SMS operating mode to text mode */
3375 if (pvt->has_sms) {
3376 if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
3377 ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3378 goto e_return;
3379 }
3380 }
3381 break;
3382 case AT_CMGF:
3383 ast_debug(1, "[%s] sms text mode enabled\n", pvt->id);
3384 /* turn on SMS new message indication */
3385 if (hfp_send_cnmi(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_CNMI)) {
3386 ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
3387 goto e_return;
3388 }
3389 break;
3390 case AT_CNMI:
3391 ast_debug(1, "[%s] sms new message indication enabled\n", pvt->id);
3392 pvt->has_sms = 1;
3393 break;
3394 /* end initialization stuff */
3395
3396 case AT_A:
3397 ast_debug(1, "[%s] answer sent successfully\n", pvt->id);
3398 pvt->needchup = 1;
3399 break;
3400 case AT_D:
3401 ast_debug(1, "[%s] dial sent successfully\n", pvt->id);
3402 pvt->needchup = 1;
3403 pvt->outgoing = 1;
3405 break;
3406 case AT_CHUP:
3407 ast_debug(1, "[%s] successful hangup\n", pvt->id);
3408 break;
3409 case AT_CMGS:
3410 ast_debug(1, "[%s] successfully sent sms message\n", pvt->id);
3411 pvt->outgoing_sms = 0;
3412 break;
3413 case AT_VTS:
3414 ast_debug(1, "[%s] digit sent successfully\n", pvt->id);
3415 break;
3416 case AT_CUSD:
3417 ast_debug(1, "[%s] CUSD code sent successfully\n", pvt->id);
3418 break;
3419 case AT_UNKNOWN:
3420 default:
3421 ast_debug(1, "[%s] received OK for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
3422 break;
3423 }
3425 } else if (entry) {
3426 ast_debug(1, "[%s] received AT message 'OK' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3427 } else {
3428 ast_debug(1, "[%s] received unexpected AT message 'OK'\n", pvt->id);
3429 }
3430 return 0;
3431
3432e_return:
3434 return -1;
3435}
3436
3437/*!
3438 * \brief Handle ERROR AT messages.
3439 * \param pvt a mbl_pvt structure
3440 * \param buf a null terminated buffer containing an AT message
3441 * \retval 0 success
3442 * \retval -1 error
3443 */
3444static int handle_response_error(struct mbl_pvt *pvt, char *buf)
3445{
3446 struct msg_queue_entry *entry;
3447 if ((entry = msg_queue_head(pvt))
3448 && (entry->expected == AT_OK
3449 || entry->expected == AT_ERROR
3450 || entry->expected == AT_CMS_ERROR
3451 || entry->expected == AT_CMGR
3452 || entry->expected == AT_SMS_PROMPT)) {
3453 switch (entry->response_to) {
3454
3455 /* initialization stuff */
3456 case AT_BRSF:
3457 ast_debug(1, "[%s] error reading BSRF\n", pvt->id);
3458 goto e_return;
3459 case AT_CIND_TEST:
3460 ast_debug(1, "[%s] error during CIND test\n", pvt->id);
3461 goto e_return;
3462 case AT_CIND:
3463 ast_debug(1, "[%s] error requesting CIND state\n", pvt->id);
3464 goto e_return;
3465 case AT_CMER:
3466 ast_debug(1, "[%s] error during CMER request\n", pvt->id);
3467 goto e_return;
3468 case AT_CLIP:
3469 ast_debug(1, "[%s] error enabling calling line indication\n", pvt->id);
3470 goto e_return;
3471 case AT_VGS:
3472 ast_debug(1, "[%s] volume level synchronization failed\n", pvt->id);
3473
3474 /* this is not a fatal error, let's continue with initialization */
3475
3476 /* set the SMS operating mode to text mode */
3477 if (hfp_send_cmgf(pvt->hfp, 1) || msg_queue_push(pvt, AT_OK, AT_CMGF)) {
3478 ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3479 goto e_return;
3480 }
3481 break;
3482 case AT_CMGF:
3483 pvt->has_sms = 0;
3484 ast_debug(1, "[%s] error setting CMGF\n", pvt->id);
3485 ast_debug(1, "[%s] no SMS support\n", pvt->id);
3486 break;
3487 case AT_CNMI:
3488 pvt->has_sms = 0;
3489 ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
3490 ast_debug(1, "[%s] no SMS support\n", pvt->id);
3491 break;
3492 case AT_ECAM:
3493 ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
3494
3495 /* this is not a fatal error, let's continue with the initialization */
3496
3497 if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
3498 ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
3499 goto e_return;
3500 }
3501
3502 pvt->timeout = -1;
3503 pvt->hfp->initialized = 1;
3504 ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
3505
3506 break;
3507 /* end initialization stuff */
3508
3509 case AT_A:
3510 ast_debug(1, "[%s] answer failed\n", pvt->id);
3511 mbl_queue_hangup(pvt);
3512 break;
3513 case AT_D:
3514 ast_debug(1, "[%s] dial failed\n", pvt->id);
3515 pvt->needchup = 0;
3517 break;
3518 case AT_CHUP:
3519 ast_debug(1, "[%s] error sending hangup, disconnecting\n", pvt->id);
3520 goto e_return;
3521 case AT_CMGR:
3522 ast_debug(1, "[%s] error reading sms message\n", pvt->id);
3523 pvt->incoming_sms = 0;
3524 break;
3525 case AT_CMGS:
3526 ast_debug(1, "[%s] error sending sms message\n", pvt->id);
3527 pvt->outgoing_sms = 0;
3528 break;
3529 case AT_VTS:
3530 ast_debug(1, "[%s] error sending digit\n", pvt->id);
3531 break;
3532 case AT_CUSD:
3533 ast_verb(0, "[%s] error sending CUSD command\n", pvt->id);
3534 break;
3535 case AT_UNKNOWN:
3536 default:
3537 ast_debug(1, "[%s] received ERROR for unhandled request: %s\n", pvt->id, at_msg2str(entry->response_to));
3538 break;
3539 }
3541 } else if (entry) {
3542 ast_debug(1, "[%s] received AT message 'ERROR' when expecting %s, ignoring\n", pvt->id, at_msg2str(entry->expected));
3543 } else {
3544 ast_debug(1, "[%s] received unexpected AT message 'ERROR'\n", pvt->id);
3545 }
3546
3547 return 0;
3548
3549e_return:
3551 return -1;
3552}
3553
3554/*!
3555 * \brief Handle AT+CIEV messages.
3556 * \param pvt a mbl_pvt structure
3557 * \param buf a null terminated buffer containing an AT message
3558 * \retval 0 success
3559 * \retval -1 error
3560 */
3561static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
3562{
3563 int i;
3564 switch (hfp_parse_ciev(pvt->hfp, buf, &i)) {
3565 case HFP_CIND_CALL:
3566 switch (i) {
3567 case HFP_CIND_CALL_NONE:
3568 ast_debug(1, "[%s] line disconnected\n", pvt->id);
3569 if (pvt->owner) {
3570 ast_debug(1, "[%s] hanging up owner\n", pvt->id);
3571 if (mbl_queue_hangup(pvt)) {
3572 ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnecting...\n", pvt->id);
3573 return -1;
3574 }
3575 }
3576 pvt->needchup = 0;
3577 pvt->needcallerid = 0;
3578 pvt->incoming = 0;
3579 pvt->outgoing = 0;
3580 break;
3582 if (pvt->outgoing) {
3583 ast_debug(1, "[%s] remote end answered\n", pvt->id);
3585 } else if (pvt->incoming && pvt->answered) {
3587 } else if (pvt->incoming) {
3588 /* user answered from handset, disconnecting */
3589 ast_verb(3, "[%s] user answered bluetooth device from handset, disconnecting\n", pvt->id);
3590 mbl_queue_hangup(pvt);
3591 return -1;
3592 }
3593 break;
3594 }
3595 break;
3596
3597 case HFP_CIND_CALLSETUP:
3598 switch (i) {
3600 if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
3601 if (pvt->owner) {
3602 if (pvt->hfp->sent_alerting == 1) {
3604 }
3605 if (mbl_queue_hangup(pvt)) {
3606 ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnecting...\n", pvt->id);
3607 return -1;
3608 }
3609 }
3610 pvt->needchup = 0;
3611 pvt->needcallerid = 0;
3612 pvt->incoming = 0;
3613 pvt->outgoing = 0;
3614 }
3615 break;
3617 ast_debug(1, "[%s] incoming call, waiting for caller id\n", pvt->id);
3618 pvt->needcallerid = 1;
3619 pvt->incoming = 1;
3620 break;
3622 if (pvt->outgoing) {
3623 pvt->hfp->sent_alerting = 0;
3624 ast_debug(1, "[%s] outgoing call\n", pvt->id);
3625 } else {
3626 ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
3627 return -1;
3628 }
3629 break;
3631 if (pvt->outgoing) {
3632 ast_debug(1, "[%s] remote alerting\n", pvt->id);
3634 pvt->hfp->sent_alerting = 1;
3635 }
3636 break;
3637 }
3638 break;
3639 case HFP_CIND_NONE:
3640 ast_debug(1, "[%s] error parsing CIND: %s\n", pvt->id, buf);
3641 break;
3642 }
3643 return 0;
3644}
3645
3646/*!
3647 * \brief Handle AT+CLIP messages.
3648 * \param pvt a mbl_pvt structure
3649 * \param buf a null terminated buffer containing an AT message
3650 * \retval 0 success
3651 * \retval -1 error
3652 */
3653static int handle_response_clip(struct mbl_pvt *pvt, char *buf)
3654{
3655 struct msg_queue_entry *msg;
3656 struct ast_channel *chan;
3657 struct cidinfo cidinfo;
3658
3659 if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CLIP) {
3661
3662 pvt->needcallerid = 0;
3663 cidinfo = hfp_parse_clip(pvt->hfp, buf);
3664
3665 if (!(chan = mbl_new(AST_STATE_RING, pvt, &cidinfo, NULL, NULL))) {
3666 ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
3667 hfp_send_chup(pvt->hfp);
3669 return -1;
3670 }
3671
3672 /* from this point on, we need to send a chup in the event of a
3673 * hangup */
3674 pvt->needchup = 1;
3675
3676 if (ast_pbx_start(chan)) {
3677 ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
3678 mbl_ast_hangup(pvt);
3679 return -1;
3680 }
3681 }
3682
3683 return 0;
3684}
3685
3686/*!
3687 * \brief Handle RING messages.
3688 * \param pvt a mbl_pvt structure
3689 * \param buf a null terminated buffer containing an AT message
3690 * \retval 0 success
3691 * \retval -1 error
3692 */
3693static int handle_response_ring(struct mbl_pvt *pvt, char *buf)
3694{
3695 if (pvt->needcallerid) {
3696 ast_debug(1, "[%s] got ring while waiting for caller id\n", pvt->id);
3697 return msg_queue_push(pvt, AT_CLIP, AT_UNKNOWN);
3698 } else {
3699 return 0;
3700 }
3701}
3702
3703/*!
3704 * \brief Handle AT+CMTI messages.
3705 * \param pvt a mbl_pvt structure
3706 * \param buf a null terminated buffer containing an AT message
3707 * \retval 0 success
3708 * \retval -1 error
3709 */
3710static int handle_response_cmti(struct mbl_pvt *pvt, char *buf)
3711{
3712 int index = hfp_parse_cmti(pvt->hfp, buf);
3713 if (index > 0) {
3714 ast_debug(1, "[%s] incoming sms message\n", pvt->id);
3715
3716 if (hfp_send_cmgr(pvt->hfp, index)
3717 || msg_queue_push(pvt, AT_CMGR, AT_CMGR)) {
3718 ast_debug(1, "[%s] error sending CMGR to retrieve SMS message\n", pvt->id);
3719 return -1;
3720 }
3721
3722 pvt->incoming_sms = 1;
3723 return 0;
3724 } else {
3725 ast_debug(1, "[%s] error parsing incoming sms message alert, disconnecting\n", pvt->id);
3726 return -1;
3727 }
3728}
3729
3730/*!
3731 * \brief Handle AT+CMGR messages.
3732 * \param pvt a mbl_pvt structure
3733 * \param buf a null terminated buffer containing an AT message
3734 * \retval 0 success
3735 * \retval -1 error
3736 */
3737static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
3738{
3739 char *from_number = NULL, *text = NULL;
3740 struct ast_channel *chan;
3741 struct msg_queue_entry *msg;
3742
3743 if ((msg = msg_queue_head(pvt)) && msg->expected == AT_CMGR) {
3745
3746 if (hfp_parse_cmgr(pvt->hfp, buf, &from_number, &text)) {
3747 ast_debug(1, "[%s] error parsing sms message, disconnecting\n", pvt->id);
3748 return -1;
3749 }
3750
3751 ast_debug(1, "[%s] successfully read sms message\n", pvt->id);
3752 pvt->incoming_sms = 0;
3753
3754 /* XXX this channel probably does not need to be associated with this pvt */
3755 if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
3756 ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
3757 return -1;
3758 }
3759
3760 ast_channel_exten_set(chan, "sms");
3761 pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
3762 pbx_builtin_setvar_helper(chan, "SMSTXT", text);
3763
3764 if (ast_pbx_start(chan)) {
3765 ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming sms\n", pvt->id);
3766 mbl_ast_hangup(pvt);
3767 }
3768 } else {
3769 ast_debug(1, "[%s] got unexpected +CMGR message, ignoring\n", pvt->id);
3770 }
3771
3772 return 0;
3773}
3774
3775/*!
3776 * \brief Send an SMS message from the queue.
3777 * \param pvt a mbl_pvt structure
3778 * \param buf a null terminated buffer containing an AT message
3779 * \retval 0 success
3780 * \retval -1 error
3781 */
3782static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf)
3783{
3784 struct msg_queue_entry *msg;
3785 if (!(msg = msg_queue_head(pvt))) {
3786 ast_debug(1, "[%s] error, got sms prompt with no pending sms messages\n", pvt->id);
3787 return 0;
3788 }
3789
3790 if (msg->expected != AT_SMS_PROMPT) {
3791 ast_debug(1, "[%s] error, got sms prompt but no pending sms messages\n", pvt->id);
3792 return 0;
3793 }
3794
3795 if (hfp_send_sms_text(pvt->hfp, msg->data)
3796 || msg_queue_push(pvt, AT_OK, AT_CMGS)) {
3798 ast_debug(1, "[%s] error sending sms message\n", pvt->id);
3799 return 0;
3800 }
3801
3803 return 0;
3804}
3805
3806/*!
3807 * \brief Handle CUSD messages.
3808 * \param pvt a mbl_pvt structure
3809 * \param buf a null terminated buffer containing an AT message
3810 * \retval 0 success
3811 * \retval -1 error
3812 */
3813static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
3814{
3815 char *cusd;
3816
3817 if (!(cusd = hfp_parse_cusd(pvt->hfp, buf))) {
3818 ast_verb(0, "[%s] error parsing CUSD: %s\n", pvt->id, buf);
3819 return 0;
3820 }
3821
3822 ast_verb(0, "[%s] CUSD response: %s\n", pvt->id, cusd);
3823
3824 return 0;
3825}
3826
3827/*!
3828 * \brief Handle BUSY messages.
3829 * \param pvt a mbl_pvt structure
3830 * \retval 0 success
3831 * \retval -1 error
3832 */
3833static int handle_response_busy(struct mbl_pvt *pvt)
3834{
3836 pvt->needchup = 1;
3838 return 0;
3839}
3840
3841/*!
3842 * \brief Handle NO DIALTONE messages.
3843 * \param pvt a mbl_pvt structure
3844 * \param buf a null terminated buffer containing an AT message
3845 * \retval 0 success
3846 * \retval -1 error
3847 */
3848static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
3849{
3850 ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
3851 pvt->needchup = 1;
3853 return 0;
3854}
3855
3856/*!
3857 * \brief Handle NO CARRIER messages.
3858 * \param pvt a mbl_pvt structure
3859 * \param buf a null terminated buffer containing an AT message
3860 * \retval 0 success
3861 * \retval -1 error
3862 */
3863static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
3864{
3865 ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
3866 pvt->needchup = 1;
3868 return 0;
3869}
3870
3871
3872static void *do_monitor_phone(void *data)
3873{
3874 struct mbl_pvt *pvt = (struct mbl_pvt *)data;
3875 struct hfp_pvt *hfp = pvt->hfp;
3876 char buf[350];
3877 int t;
3878 at_message_t at_msg;
3879 struct msg_queue_entry *entry;
3880
3881 /* Note: At one point the initialization procedure was neatly contained
3882 * in the hfp_init() function, but that initialization method did not
3883 * work with non standard devices. As a result, the initialization
3884 * procedure is not spread throughout the event handling loop.
3885 */
3886
3887 /* start initialization with the BRSF request */
3888 ast_mutex_lock(&pvt->lock);
3889 pvt->timeout = 10000;
3891 ast_debug(1, "[%s] error sending BRSF\n", hfp->owner->id);
3892 goto e_cleanup;
3893 }
3894 ast_mutex_unlock(&pvt->lock);
3895
3896 while (!check_unloading()) {
3897 ast_mutex_lock(&pvt->lock);
3898 t = pvt->timeout;
3899 ast_mutex_unlock(&pvt->lock);
3900
3901 if (!rfcomm_wait(pvt->rfcomm_socket, &t)) {
3902 ast_debug(1, "[%s] timeout waiting for rfcomm data, disconnecting\n", pvt->id);
3903 ast_mutex_lock(&pvt->lock);
3904 if (!hfp->initialized) {
3905 if ((entry = msg_queue_head(pvt))) {
3906 switch (entry->response_to) {
3907 case AT_CIND_TEST:
3908 if (pvt->blackberry)
3909 ast_debug(1, "[%s] timeout during CIND test\n", hfp->owner->id);
3910 else
3911 ast_debug(1, "[%s] timeout during CIND test, try setting 'blackberry=yes'\n", hfp->owner->id);
3912 break;
3913 case AT_CMER:
3914 if (pvt->blackberry)
3915 ast_debug(1, "[%s] timeout after sending CMER, try setting 'blackberry=no'\n", hfp->owner->id);
3916 else
3917 ast_debug(1, "[%s] timeout after sending CMER\n", hfp->owner->id);
3918 break;
3919 default:
3920 ast_debug(1, "[%s] timeout while waiting for %s in response to %s\n", pvt->id, at_msg2str(entry->expected), at_msg2str(entry->response_to));
3921 break;
3922 }
3923 }
3924 }
3925 ast_mutex_unlock(&pvt->lock);
3926 goto e_cleanup;
3927 }
3928
3929 if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
3930 ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
3931 break;
3932 }
3933
3934 ast_debug(1, "[%s] read %s\n", pvt->id, buf);
3935
3936 switch (at_msg) {
3937 case AT_BRSF:
3938 ast_mutex_lock(&pvt->lock);
3939 if (handle_response_brsf(pvt, buf)) {
3940 ast_mutex_unlock(&pvt->lock);
3941 goto e_cleanup;
3942 }
3943 ast_mutex_unlock(&pvt->lock);
3944 break;
3945 case AT_CIND:
3946 ast_mutex_lock(&pvt->lock);
3947 if (handle_response_cind(pvt, buf)) {
3948 ast_mutex_unlock(&pvt->lock);
3949 goto e_cleanup;
3950 }
3951 ast_mutex_unlock(&pvt->lock);
3952 break;
3953 case AT_OK:
3954 ast_mutex_lock(&pvt->lock);
3955 if (handle_response_ok(pvt, buf)) {
3956 ast_mutex_unlock(&pvt->lock);
3957 goto e_cleanup;
3958 }
3959 ast_mutex_unlock(&pvt->lock);
3960 break;
3961 case AT_CMS_ERROR:
3962 case AT_ERROR:
3963 ast_mutex_lock(&pvt->lock);
3964 if (handle_response_error(pvt, buf)) {
3965 ast_mutex_unlock(&pvt->lock);
3966 goto e_cleanup;
3967 }
3968 ast_mutex_unlock(&pvt->lock);
3969 break;
3970 case AT_RING:
3971 ast_mutex_lock(&pvt->lock);
3972 if (handle_response_ring(pvt, buf)) {
3973 ast_mutex_unlock(&pvt->lock);
3974 goto e_cleanup;
3975 }
3976 ast_mutex_unlock(&pvt->lock);
3977 break;
3978 case AT_CIEV:
3979 ast_mutex_lock(&pvt->lock);
3980 if (handle_response_ciev(pvt, buf)) {
3981 ast_mutex_unlock(&pvt->lock);
3982 goto e_cleanup;
3983 }
3984 ast_mutex_unlock(&pvt->lock);
3985 break;
3986 case AT_CLIP:
3987 ast_mutex_lock(&pvt->lock);
3988 if (handle_response_clip(pvt, buf)) {
3989 ast_mutex_unlock(&pvt->lock);
3990 goto e_cleanup;
3991 }
3992 ast_mutex_unlock(&pvt->lock);
3993 break;
3994 case AT_CMTI:
3995 ast_mutex_lock(&pvt->lock);
3996 if (handle_response_cmti(pvt, buf)) {
3997 ast_mutex_unlock(&pvt->lock);
3998 goto e_cleanup;
3999 }
4000 ast_mutex_unlock(&pvt->lock);
4001 break;
4002 case AT_CMGR:
4003 ast_mutex_lock(&pvt->lock);
4004 if (handle_response_cmgr(pvt, buf)) {
4005 ast_mutex_unlock(&pvt->lock);
4006 goto e_cleanup;
4007 }
4008 ast_mutex_unlock(&pvt->lock);
4009 break;
4010 case AT_SMS_PROMPT:
4011 ast_mutex_lock(&pvt->lock);
4012 if (handle_sms_prompt(pvt, buf)) {
4013 ast_mutex_unlock(&pvt->lock);
4014 goto e_cleanup;
4015 }
4016 ast_mutex_unlock(&pvt->lock);
4017 break;
4018 case AT_CUSD:
4019 ast_mutex_lock(&pvt->lock);
4020 if (handle_response_cusd(pvt, buf)) {
4021 ast_mutex_unlock(&pvt->lock);
4022 goto e_cleanup;
4023 }
4024 ast_mutex_unlock(&pvt->lock);
4025 break;
4026 case AT_BUSY:
4027 ast_mutex_lock(&pvt->lock);
4028 if (handle_response_busy(pvt)) {
4029 ast_mutex_unlock(&pvt->lock);
4030 goto e_cleanup;
4031 }
4032 ast_mutex_unlock(&pvt->lock);
4033 break;
4034 case AT_NO_DIALTONE:
4035 ast_mutex_lock(&pvt->lock);
4036 if (handle_response_no_dialtone(pvt, buf)) {
4037 ast_mutex_unlock(&pvt->lock);
4038 goto e_cleanup;
4039 }
4040 ast_mutex_unlock(&pvt->lock);
4041 break;
4042 case AT_NO_CARRIER:
4043 ast_mutex_lock(&pvt->lock);
4044 if (handle_response_no_carrier(pvt, buf)) {
4045 ast_mutex_unlock(&pvt->lock);
4046 goto e_cleanup;
4047 }
4048 ast_mutex_unlock(&pvt->lock);
4049 break;
4050 case AT_ECAM:
4051 ast_mutex_lock(&pvt->lock);
4052 if (hfp_parse_ecav(hfp, buf) == 7) {
4053 if (handle_response_busy(pvt)) {
4054 ast_mutex_unlock(&pvt->lock);
4055 goto e_cleanup;
4056 }
4057 }
4058 ast_mutex_unlock(&pvt->lock);
4059 break;
4060 case AT_UNKNOWN:
4061 ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
4062 break;
4063 case AT_PARSE_ERROR:
4064 ast_debug(1, "[%s] error parsing message\n", pvt->id);
4065 goto e_cleanup;
4066 case AT_READ_ERROR:
4067 ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
4068 goto e_cleanup;
4069 default:
4070 break;
4071 }
4072 }
4073
4074e_cleanup:
4075
4076 if (!hfp->initialized)
4077 ast_verb(3, "Error initializing Bluetooth device %s.\n", pvt->id);
4078
4079 ast_mutex_lock(&pvt->lock);
4080 if (pvt->owner) {
4081 ast_debug(1, "[%s] device disconnected, hanging up owner\n", pvt->id);
4082 pvt->needchup = 0;
4083 mbl_queue_hangup(pvt);
4084 }
4085
4086 close(pvt->rfcomm_socket);
4087 close(pvt->sco_socket);
4088 pvt->sco_socket = -1;
4089
4090 msg_queue_flush(pvt);
4091
4092 pvt->connected = 0;
4093 hfp->initialized = 0;
4094
4095 pvt->adapter->inuse = 0;
4096 ast_mutex_unlock(&pvt->lock);
4097
4098 ast_verb(3, "Bluetooth Device %s has disconnected.\n", pvt->id);
4099 manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
4100
4101 return NULL;
4102}
4103
4104static int headset_send_ring(const void *data)
4105{
4106 struct mbl_pvt *pvt = (struct mbl_pvt *) data;
4107 ast_mutex_lock(&pvt->lock);
4108 if (!pvt->needring) {
4109 ast_mutex_unlock(&pvt->lock);
4110 return 0;
4111 }
4112 ast_mutex_unlock(&pvt->lock);
4113
4114 if (hsp_send_ring(pvt->rfcomm_socket)) {
4115 ast_debug(1, "[%s] error sending RING\n", pvt->id);
4116 return 0;
4117 }
4118 return 1;
4119}
4120
4121static void *do_monitor_headset(void *data)
4122{
4123
4124 struct mbl_pvt *pvt = (struct mbl_pvt *)data;
4125 char buf[256];
4126 int t;
4127 at_message_t at_msg;
4128 struct ast_channel *chan = NULL;
4129
4130 ast_verb(3, "Bluetooth Device %s initialised and ready.\n", pvt->id);
4131
4132 while (!check_unloading()) {
4133
4134 t = ast_sched_wait(pvt->sched);
4135 if (t == -1) {
4136 t = 6000;
4137 }
4138
4139 ast_sched_runq(pvt->sched);
4140
4141 if (rfcomm_wait(pvt->rfcomm_socket, &t) == 0)
4142 continue;
4143
4144 if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
4145 ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
4146 goto e_cleanup;
4147 }
4148 ast_debug(1, "[%s] %s\n", pvt->id, buf);
4149
4150 switch (at_msg) {
4151 case AT_VGS:
4152 case AT_VGM:
4153 /* XXX volume change requested, we will just
4154 * pretend to do something with it */
4155 if (hsp_send_ok(pvt->rfcomm_socket)) {
4156 ast_debug(1, "[%s] error sending AT message 'OK'\n", pvt->id);
4157 goto e_cleanup;
4158 }
4159 break;
4160 case AT_CKPD:
4161 ast_mutex_lock(&pvt->lock);
4162 if (pvt->outgoing) {
4163 pvt->needring = 0;
4165 if (pvt->answered) {
4166 /* we have an answered call up to the
4167 * HS, he wants to hangup */
4168 mbl_queue_hangup(pvt);
4169 } else {
4170 /* we have an outgoing call to the HS,
4171 * he wants to answer */
4172 if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
4173 ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
4174 mbl_queue_hangup(pvt);
4175 ast_mutex_unlock(&pvt->lock);
4176 goto e_cleanup;
4177 }
4178
4179 ast_channel_set_fd(pvt->owner, 0, pvt->sco_socket);
4180
4182 pvt->answered = 1;
4183
4184 if (hsp_send_vgs(pvt->rfcomm_socket, 13) || hsp_send_vgm(pvt->rfcomm_socket, 13)) {
4185 ast_debug(1, "[%s] error sending VGS/VGM\n", pvt->id);
4186 mbl_queue_hangup(pvt);
4187 ast_mutex_unlock(&pvt->lock);
4188 goto e_cleanup;
4189 }
4190 }
4191 } else if (pvt->incoming) {
4192 /* we have an incoming call from the
4193 * HS, he wants to hang up */
4194 mbl_queue_hangup(pvt);
4195 } else {
4196 /* no call is up, HS wants to dial */
4198
4199 if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
4200 ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
4201 ast_mutex_unlock(&pvt->lock);
4202 goto e_cleanup;
4203 }
4204
4205 pvt->incoming = 1;
4206
4207 if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL, NULL))) {
4208 ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
4209 ast_mutex_unlock(&pvt->lock);
4210 goto e_cleanup;
4211 }
4212
4213 ast_channel_set_fd(chan, 0, pvt->sco_socket);
4214
4215 ast_channel_exten_set(chan, "s");
4216 if (ast_pbx_start(chan)) {
4217 ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
4218 ast_hangup(chan);
4219 ast_mutex_unlock(&pvt->lock);
4220 goto e_cleanup;
4221 }
4222 }
4223 ast_mutex_unlock(&pvt->lock);
4224 break;
4225 default:
4226 ast_debug(1, "[%s] received unknown AT command: %s (%s)\n", pvt->id, buf, at_msg2str(at_msg));
4227 if (hsp_send_error(pvt->rfcomm_socket)) {
4228 ast_debug(1, "[%s] error sending AT message 'ERROR'\n", pvt->id);
4229 goto e_cleanup;
4230 }
4231 break;
4232 }
4233 }
4234
4235e_cleanup:
4236 ast_mutex_lock(&pvt->lock);
4237 if (pvt->owner) {
4238 ast_debug(1, "[%s] device disconnected, hanging up owner\n", pvt->id);
4239 mbl_queue_hangup(pvt);
4240 }
4241
4242
4243 close(pvt->rfcomm_socket);
4244 close(pvt->sco_socket);
4245 pvt->sco_socket = -1;
4246
4247 pvt->connected = 0;
4248
4249 pvt->needring = 0;
4250 pvt->outgoing = 0;
4251 pvt->incoming = 0;
4252
4253 pvt->adapter->inuse = 0;
4254 ast_mutex_unlock(&pvt->lock);
4255
4256 manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id);
4257 ast_verb(3, "Bluetooth Device %s has disconnected\n", pvt->id);
4258
4259 return NULL;
4260
4261}
4262
4263static int start_monitor(struct mbl_pvt *pvt)
4264{
4265
4266 if (pvt->type == MBL_TYPE_PHONE) {
4267 pvt->hfp->rsock = pvt->rfcomm_socket;
4268
4271 return 0;
4272 }
4273 } else {
4276 return 0;
4277 }
4278 }
4279
4280 return 1;
4281
4282}
4283
4284static void *do_discovery(void *data)
4285{
4286
4287 struct adapter_pvt *adapter;
4288 struct mbl_pvt *pvt;
4289
4290 while (!check_unloading()) {
4293 if (!adapter->inuse) {
4296 ast_mutex_lock(&pvt->lock);
4297 if (!adapter->inuse && !pvt->connected && !strcmp(adapter->id, pvt->adapter->id)) {
4298 if ((pvt->rfcomm_socket = rfcomm_connect(adapter->addr, pvt->addr, pvt->rfcomm_port)) > -1) {
4299 if (start_monitor(pvt)) {
4300 pvt->connected = 1;
4301 adapter->inuse = 1;
4302 manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id);
4303 ast_verb(3, "Bluetooth Device %s has connected, initializing...\n", pvt->id);
4304 }
4305 }
4306 }
4307 ast_mutex_unlock(&pvt->lock);
4308 }
4310 }
4311 }
4313
4314
4315 /* Go to sleep (only if we are not unloading) */
4316 if (!check_unloading())
4317 sleep(discovery_interval);
4318 }
4319
4320 return NULL;
4321}
4322
4323/*!
4324 * \brief Service new and existing SCO connections.
4325 * This thread accepts new sco connections and handles audio data. There is
4326 * one do_sco_listen thread for each adapter.
4327 */
4328static void *do_sco_listen(void *data)
4329{
4330 struct adapter_pvt *adapter = (struct adapter_pvt *) data;
4331
4332 while (!check_unloading()) {
4333 /* check for new sco connections */
4334 if (ast_io_wait(adapter->accept_io, 0) == -1) {
4335 /* handle errors */
4336 ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
4337 break;
4338 }
4339
4340 /* handle audio data */
4341 if (ast_io_wait(adapter->io, 1) == -1) {
4342 ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
4343 break;
4344 }
4345 }
4346
4347 return NULL;
4348}
4349
4350/*
4351
4352 Module
4353
4354*/
4355
4356/*!
4357 * \brief Load an adapter from the configuration file.
4358 * \param cfg the config to load the adapter from
4359 * \param cat the adapter to load
4360 *
4361 * This function loads the given adapter and starts the sco listener thread for
4362 * that adapter.
4363 *
4364 * \return NULL on error, a pointer to the adapter that was loaded on success
4365 */
4366static struct adapter_pvt *mbl_load_adapter(struct ast_config *cfg, const char *cat)
4367{
4368 const char *id, *address;
4369 struct adapter_pvt *adapter;
4370 struct ast_variable *v;
4371 struct hci_dev_req dr;
4372 uint16_t vs;
4373
4374 id = ast_variable_retrieve(cfg, cat, "id");
4375 address = ast_variable_retrieve(cfg, cat, "address");
4376
4378 ast_log(LOG_ERROR, "Skipping adapter. Missing id or address settings.\n");
4379 goto e_return;
4380 }
4381
4382 ast_debug(1, "Reading configuration for adapter %s %s.\n", id, address);
4383
4384 if (!(adapter = ast_calloc(1, sizeof(*adapter)))) {
4385 ast_log(LOG_ERROR, "Skipping adapter %s. Error allocating memory.\n", id);
4386 goto e_return;
4387 }
4388
4389 ast_copy_string(adapter->id, id, sizeof(adapter->id));
4390 str2ba(address, &adapter->addr);
4391
4392 /* attempt to connect to the adapter */
4393 adapter->dev_id = hci_devid(address);
4394 adapter->hci_socket = hci_open_dev(adapter->dev_id);
4395 if (adapter->dev_id < 0 || adapter->hci_socket < 0) {
4396 ast_log(LOG_ERROR, "Skipping adapter %s. Unable to communicate with adapter.\n", adapter->id);
4397 goto e_free_adapter;
4398 }
4399
4400 /* check voice setting */
4401 hci_read_voice_setting(adapter->hci_socket, &vs, 1000);
4402 vs = htobs(vs);
4403 if (vs != 0x0060) {
4404 ast_log(LOG_ERROR, "Skipping adapter %s. Voice setting must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id);
4405 goto e_hci_close_dev;
4406 }
4407
4408 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4409 if (!strcasecmp(v->name, "forcemaster")) {
4410 if (ast_true(v->value)) {
4411 dr.dev_id = adapter->dev_id;
4412 if (hci_strtolm("master", &dr.dev_opt)) {
4413 if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) {
4414 ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER. Ignoring 'forcemaster' option.\n", adapter->id);
4415 }
4416 }
4417 }
4418 } else if (!strcasecmp(v->name, "alignmentdetection")) {
4419 adapter->alignment_detection = ast_true(v->value);
4420 }
4421 }
4422
4423 /* create io contexts */
4424 if (!(adapter->accept_io = io_context_create())) {
4425 ast_log(LOG_ERROR, "Unable to create I/O context for audio connection listener\n");
4426 goto e_hci_close_dev;
4427 }
4428
4429 if (!(adapter->io = io_context_create())) {
4430 ast_log(LOG_ERROR, "Unable to create I/O context for audio connections\n");
4431 goto e_destroy_accept_io;
4432 }
4433
4434 /* bind the sco listener socket */
4435 if (sco_bind(adapter) < 0) {
4436 ast_log(LOG_ERROR, "Skipping adapter %s. Error binding audio connection listener socket.\n", adapter->id);
4437 goto e_destroy_io;
4438 }
4439
4440 /* add the socket to the io context */
4441 if (!(adapter->sco_id = ast_io_add(adapter->accept_io, adapter->sco_socket, sco_accept, AST_IO_IN, adapter))) {
4442 ast_log(LOG_ERROR, "Skipping adapter %s. Error adding listener socket to I/O context.\n", adapter->id);
4443 goto e_close_sco;
4444 }
4445
4446 /* start the sco listener for this adapter */
4448 ast_log(LOG_ERROR, "Skipping adapter %s. Error creating audio connection listener thread.\n", adapter->id);
4449 goto e_remove_sco;
4450 }
4451
4452 /* add the adapter to our global list */
4456 ast_debug(1, "Loaded adapter %s %s.\n", adapter->id, address);
4457
4458 return adapter;
4459
4460e_remove_sco:
4461 ast_io_remove(adapter->accept_io, adapter->sco_id);
4462e_close_sco:
4463 close(adapter->sco_socket);
4464e_destroy_io:
4465 io_context_destroy(adapter->io);
4466e_destroy_accept_io:
4467 io_context_destroy(adapter->accept_io);
4468e_hci_close_dev:
4469 hci_close_dev(adapter->hci_socket);
4470e_free_adapter:
4471 ast_free(adapter);
4472e_return:
4473 return NULL;
4474}
4475
4476/*!
4477 * \brief Load a device from the configuration file.
4478 * \param cfg the config to load the device from
4479 * \param cat the device to load
4480 * \return NULL on error, a pointer to the device that was loaded on success
4481 */
4482static struct mbl_pvt *mbl_load_device(struct ast_config *cfg, const char *cat)
4483{
4484 struct mbl_pvt *pvt;
4485 struct adapter_pvt *adapter;
4486 struct ast_variable *v;
4487 const char *address, *adapter_str, *port;
4488 ast_debug(1, "Reading configuration for device %s.\n", cat);
4489
4490 adapter_str = ast_variable_retrieve(cfg, cat, "adapter");
4491 if(ast_strlen_zero(adapter_str)) {
4492 ast_log(LOG_ERROR, "Skipping device %s. No adapter specified.\n", cat);
4493 goto e_return;
4494 }
4495
4496 /* find the adapter */
4498 AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4499 if (!strcmp(adapter->id, adapter_str))
4500 break;
4501 }
4503 if (!adapter) {
4504 ast_log(LOG_ERROR, "Skipping device %s. Unknown adapter '%s' specified.\n", cat, adapter_str);
4505 goto e_return;
4506 }
4507
4508 address = ast_variable_retrieve(cfg, cat, "address");
4509 port = ast_variable_retrieve(cfg, cat, "port");
4510 if (ast_strlen_zero(port) || ast_strlen_zero(address)) {
4511 ast_log(LOG_ERROR, "Skipping device %s. Missing required port or address setting.\n", cat);
4512 goto e_return;
4513 }
4514
4515 /* create and initialize our pvt structure */
4516 if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
4517 ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", cat);
4518 goto e_return;
4519 }
4520
4521 ast_mutex_init(&pvt->lock);
4523
4524 /* set some defaults */
4525
4526 pvt->type = MBL_TYPE_PHONE;
4527 ast_copy_string(pvt->context, "default", sizeof(pvt->context));
4528
4529 /* populate the pvt structure */
4530 pvt->adapter = adapter;
4531 ast_copy_string(pvt->id, cat, sizeof(pvt->id));
4532 str2ba(address, &pvt->addr);
4533 pvt->timeout = -1;
4534 pvt->rfcomm_socket = -1;
4535 pvt->rfcomm_port = atoi(port);
4536 pvt->sco_socket = -1;
4538 pvt->ring_sched_id = -1;
4539 pvt->has_sms = 1;
4540
4541 /* setup the bt_out_smoother */
4543 ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_out_smoother.\n", cat);
4544 goto e_free_pvt;
4545 }
4546
4547 /* setup the bt_in_smoother */
4549 ast_log(LOG_ERROR, "Skipping device %s. Error setting up frame bt_in_smoother.\n", cat);
4550 goto e_free_bt_out_smoother;
4551 }
4552
4553 /* setup the dsp */
4554 if (!(pvt->dsp = ast_dsp_new())) {
4555 ast_log(LOG_ERROR, "Skipping device %s. Error setting up dsp for dtmf detection.\n", cat);
4556 goto e_free_bt_in_smoother;
4557 }
4558
4559 /* setup the scheduler */
4560 if (!(pvt->sched = ast_sched_context_create())) {
4561 ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
4562 goto e_free_dsp;
4563 }
4564
4567
4568 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
4569 if (!strcasecmp(v->name, "type")) {
4570 if (!strcasecmp(v->value, "headset"))
4571 pvt->type = MBL_TYPE_HEADSET;
4572 else
4573 pvt->type = MBL_TYPE_PHONE;
4574 } else if (!strcasecmp(v->name, "context")) {
4575 ast_copy_string(pvt->context, v->value, sizeof(pvt->context));
4576 } else if (!strcasecmp(v->name, "group")) {
4577 /* group is set to 0 if invalid */
4578 pvt->group = atoi(v->value);
4579 } else if (!strcasecmp(v->name, "sms")) {
4580 pvt->has_sms = ast_true(v->value);
4581 } else if (!strcasecmp(v->name, "nocallsetup")) {
4582 pvt->no_callsetup = ast_true(v->value);
4583
4584 if (pvt->no_callsetup)
4585 ast_debug(1, "Setting nocallsetup mode for device %s.\n", pvt->id);
4586 } else if (!strcasecmp(v->name, "blackberry")) {
4587 pvt->blackberry = ast_true(v->value);
4588 pvt->has_sms = 0;
4589 }
4590 }
4591
4592 if (pvt->type == MBL_TYPE_PHONE) {
4593 if (!(pvt->hfp = ast_calloc(1, sizeof(*pvt->hfp)))) {
4594 ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", pvt->id);
4595 goto e_free_sched;
4596 }
4597
4598 pvt->hfp->owner = pvt;
4599 pvt->hfp->rport = pvt->rfcomm_port;
4600 pvt->hfp->nocallsetup = pvt->no_callsetup;
4601 } else {
4602 pvt->has_sms = 0;
4603 }
4604
4608 ast_debug(1, "Loaded device %s.\n", pvt->id);
4609
4610 return pvt;
4611
4612e_free_sched:
4614e_free_dsp:
4615 ast_dsp_free(pvt->dsp);
4616e_free_bt_in_smoother:
4618e_free_bt_out_smoother:
4620e_free_pvt:
4621 ast_free(pvt);
4622e_return:
4623 return NULL;
4624}
4625
4626static int mbl_load_config(void)
4627{
4628 struct ast_config *cfg;
4629 const char *cat;
4630 struct ast_variable *v;
4631 struct ast_flags config_flags = { 0 };
4632
4633 cfg = ast_config_load(MBL_CONFIG, config_flags);
4634 if (!cfg) {
4635 cfg = ast_config_load(MBL_CONFIG_OLD, config_flags);
4636 }
4637 if (!cfg)
4638 return -1;
4639
4640 /* parse [general] section */
4641 for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
4642 if (!strcasecmp(v->name, "interval")) {
4643 if (!sscanf(v->value, "%d", &discovery_interval)) {
4644 ast_log(LOG_NOTICE, "error parsing 'interval' in general section, using default value\n");
4645 }
4646 }
4647 }
4648
4649 /* load adapters */
4650 for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
4651 if (!strcasecmp(cat, "adapter")) {
4652 mbl_load_adapter(cfg, cat);
4653 }
4654 }
4655
4656 if (AST_RWLIST_EMPTY(&adapters)) {
4658 "***********************************************************************\n"
4659 "No adapters could be loaded from the configuration file.\n"
4660 "Please review mobile.conf. See sample for details.\n"
4661 "***********************************************************************\n"
4662 );
4663 ast_config_destroy(cfg);
4664 return -1;
4665 }
4666
4667 /* now load devices */
4668 for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
4669 if (strcasecmp(cat, "general") && strcasecmp(cat, "adapter")) {
4670 mbl_load_device(cfg, cat);
4671 }
4672 }
4673
4674 ast_config_destroy(cfg);
4675
4676 return 0;
4677}
4678
4679/*!
4680 * \brief Check if the module is unloading.
4681 * \retval 0 not unloading
4682 * \retval 1 unloading
4683 */
4684static inline int check_unloading()
4685{
4686 int res;
4688 res = unloading_flag;
4690
4691 return res;
4692}
4693
4694/*!
4695 * \brief Set the unloading flag.
4696 */
4697static inline void set_unloading()
4698{
4700 unloading_flag = 1;
4702}
4703
4704static int unload_module(void)
4705{
4706 struct mbl_pvt *pvt;
4707 struct adapter_pvt *adapter;
4708
4709 /* First, take us out of the channel loop */
4711
4712 /* Unregister the CLI & APP */
4713 ast_cli_unregister_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
4716
4717 /* signal everyone we are unloading */
4718 set_unloading();
4719
4720 /* Kill the discovery thread */
4722 pthread_kill(discovery_thread, SIGURG);
4723 pthread_join(discovery_thread, NULL);
4724 }
4725
4726 /* stop the sco listener threads */
4728 AST_RWLIST_TRAVERSE(&adapters, adapter, entry) {
4729 pthread_kill(adapter->sco_listener_thread, SIGURG);
4730 pthread_join(adapter->sco_listener_thread, NULL);
4731 }
4733
4734 /* Destroy the device list */
4736 while ((pvt = AST_RWLIST_REMOVE_HEAD(&devices, entry))) {
4737 if (pvt->monitor_thread != AST_PTHREADT_NULL) {
4738 pthread_kill(pvt->monitor_thread, SIGURG);
4739 pthread_join(pvt->monitor_thread, NULL);
4740 }
4741
4742 close(pvt->sco_socket);
4743 close(pvt->rfcomm_socket);
4744
4745 msg_queue_flush(pvt);
4746
4747 if (pvt->hfp) {
4748 ast_free(pvt->hfp);
4749 }
4750
4753 ast_dsp_free(pvt->dsp);
4755 ast_free(pvt);
4756 }
4758
4759 /* Destroy the adapter list */
4761 while ((adapter = AST_RWLIST_REMOVE_HEAD(&adapters, entry))) {
4762 close(adapter->sco_socket);
4763 io_context_destroy(adapter->io);
4764 io_context_destroy(adapter->accept_io);
4765 hci_close_dev(adapter->hci_socket);
4766 ast_free(adapter);
4767 }
4769
4770 if (sdp_session)
4771 sdp_close(sdp_session);
4772
4775 return 0;
4776}
4777
4778static int load_module(void)
4779{
4780
4781 int dev_id, s;
4782
4785 }
4786
4788 /* Check if we have Bluetooth, no point loading otherwise... */
4789 dev_id = hci_get_route(NULL);
4790
4791 s = hci_open_dev(dev_id);
4792 if (dev_id < 0 || s < 0) {
4793 ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
4796 hci_close_dev(s);
4798 }
4799
4800 hci_close_dev(s);
4801
4802 if (mbl_load_config()) {
4803 ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
4807 }
4808
4810
4811 /* Spin the discovery thread */
4813 ast_log(LOG_ERROR, "Unable to create discovery thread.\n");
4814 goto e_cleanup;
4815 }
4816
4817 /* register our channel type */
4819 ast_log(LOG_ERROR, "Unable to register channel class %s\n", "Mobile");
4820 goto e_cleanup;
4821 }
4822
4823 ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
4826
4828
4829e_cleanup:
4830 unload_module();
4831
4833}
4834
4835AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver",
4836 .support_level = AST_MODULE_SUPPORT_EXTENDED,
4837 .load = load_module,
4838 .unload = unload_module,
4839 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
static const struct adsi_event events[]
Definition: app_adsiprog.c:85
char digit
jack_status_t status
Definition: app_jack.c:146
char * text
Definition: app_queue.c:1639
enum queue_result id
Definition: app_queue.c:1638
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int ast_isphonenumber(const char *n)
Check if a string consists only of digits and + #.
Definition: callerid.c:1053
Internal Asterisk hangup causes.
#define AST_CAUSE_INCOMPATIBLE_DESTINATION
Definition: causes.h:135
#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL
Definition: causes.h:125
#define AST_CAUSE_FACILITY_NOT_IMPLEMENTED
Definition: causes.h:133
#define AST_CAUSE_USER_BUSY
Definition: causes.h:107
enum cc_state state
Definition: ccss.c:393
static PGresult * result
Definition: cel_pgsql.c:84
#define HFP_HF_STATUS
Definition: chan_mobile.c:262
static int rfcomm_read_and_append_char(int rsock, char **buf, size_t count, size_t *in_count, char *result, char expected)
Read a character from the given stream and append it to the given buffer if it matches the expected c...
Definition: chan_mobile.c:1544
static int mbl_hangup(struct ast_channel *ast)
Definition: chan_mobile.c:1028
static char * mblsendsms_desc
Definition: chan_mobile.c:211
static struct adapter_pvt * mbl_load_adapter(struct ast_config *cfg, const char *cat)
Load an adapter from the configuration file.
Definition: chan_mobile.c:4366
#define HFP_AG_ERRORS
Definition: chan_mobile.c:273
#define HFP_AG_CW
Definition: chan_mobile.c:265
static int handle_response_brsf(struct mbl_pvt *pvt, char *buf)
Handle the BRSF response.
Definition: chan_mobile.c:3198
static int hsp_send_ring(int rsock)
Send a RING unsolicited AT response.
Definition: chan_mobile.c:2968
static int msg_queue_push_data(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to, void *data)
Add an item to the back of the queue with data.
Definition: chan_mobile.c:3006
static void * do_monitor_headset(void *data)
Definition: chan_mobile.c:4121
static int discovery_interval
Definition: chan_mobile.c:85
static int hfp_send_brsf(struct hfp_pvt *hfp, struct hfp_hf *brsf)
Send a BRSF request.
Definition: chan_mobile.c:2516
static const char * at_msg2str(at_message_t msg)
Get the string representation of the given AT message.
Definition: chan_mobile.c:2076
static int handle_response_cmti(struct mbl_pvt *pvt, char *buf)
Handle AT+CMTI messages.
Definition: chan_mobile.c:3710
static int sco_accept(int *id, int fd, short events, void *data)
Accept SCO connections. This function is an ast_io callback function used to accept incoming sco audi...
Definition: chan_mobile.c:1898
static void * do_monitor_phone(void *data)
Definition: chan_mobile.c:3872
#define HFP_CIND_NONE
Definition: chan_mobile.c:276
static void msg_queue_free_and_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue, and free it.
Definition: chan_mobile.c:3034
static int mbl_call(struct ast_channel *ast, const char *dest, int timeout)
Definition: chan_mobile.c:970
#define HFP_AG_TAG
Definition: chan_mobile.c:269
static void rfcomm_append_buf(char **buf, size_t count, size_t *in_count, char c)
Append the given character to the given buffer and increase the in_count.
Definition: chan_mobile.c:1508
static int handle_response_clip(struct mbl_pvt *pvt, char *buf)
Handle AT+CLIP messages.
Definition: chan_mobile.c:3653
static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, char **text)
Parse a CMGR message.
Definition: chan_mobile.c:2354
static int sco_bind(struct adapter_pvt *adapter)
Bind an SCO listener socket for the given adapter.
Definition: chan_mobile.c:1958
static int hsp_send_error(int rsock)
Send an ERROR AT response.
Definition: chan_mobile.c:2935
static void * do_sco_listen(void *data)
Service new and existing SCO connections. This thread accepts new sco connections and handles audio d...
Definition: chan_mobile.c:4328
static ssize_t rfcomm_read(int rsock, char *buf, size_t count)
Read one Hayes AT message from an rfcomm socket.
Definition: chan_mobile.c:1808
static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
Handle AT+CIEV messages.
Definition: chan_mobile.c:3561
static char * handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_mobile.c:659
#define DEVICE_FRAME_FORMAT
Definition: chan_mobile.c:82
static int hfp_send_cind(struct hfp_pvt *hfp)
Send the CIND read command.
Definition: chan_mobile.c:2527
static struct hfp_ag * hfp_int2brsf(int brsf, struct hfp_ag *ag)
Convert a BRSF int to an hfp_ag struct.
Definition: chan_mobile.c:2492
static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
Read the remainder of a +CMGR message.
Definition: chan_mobile.c:1706
static int handle_response_cind(struct mbl_pvt *pvt, char *buf)
Handle the CIND response.
Definition: chan_mobile.c:3233
static int hfp_send_sms_text(struct hfp_pvt *hfp, const char *message)
Send the text of an SMS message.
Definition: chan_mobile.c:2672
#define HFP_CIND_ROAM
Definition: chan_mobile.c:282
#define HFP_CIND_CALL_ACTIVE
Definition: chan_mobile.c:287
static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
Parse a CMTI notification.
Definition: chan_mobile.c:2328
static char * app_mblsendsms
Definition: chan_mobile.c:209
static int hfp_parse_cind_indicator(struct hfp_pvt *hfp, int group, char *indicator)
Parse and store the given indicator.
Definition: chan_mobile.c:2744
#define HFP_AG_ECNR
Definition: chan_mobile.c:266
static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
Handle AT+CMGR messages.
Definition: chan_mobile.c:3737
static void msg_queue_flush(struct mbl_pvt *pvt)
Remove all items from the queue and free them.
Definition: chan_mobile.c:3048
#define rfcomm_read_debug(c)
Definition: chan_mobile.c:1501
static int hfp_send_cnmi(struct hfp_pvt *hfp)
Setup SMS new message indication.
Definition: chan_mobile.c:2638
static int rfcomm_read_sms_prompt(int rsock, char **buf, size_t count, size_t *in_count)
Read the remainder of an AT SMS prompt.
Definition: chan_mobile.c:1593
#define MBL_CONFIG
Definition: chan_mobile.c:78
#define HFP_AG_VOICE
Definition: chan_mobile.c:267
static int hfp_send_atd(struct hfp_pvt *hfp, const char *number)
Send ATD.
Definition: chan_mobile.c:2693
#define HFP_HF_CW
Definition: chan_mobile.c:258
#define HFP_CIND_CALLSETUP
Definition: chan_mobile.c:279
static int handle_response_ring(struct mbl_pvt *pvt, char *buf)
Handle RING messages.
Definition: chan_mobile.c:3693
#define HFP_CIND_SIGNAL
Definition: chan_mobile.c:281
static int mbl_status_exec(struct ast_channel *ast, const char *data)
Definition: chan_mobile.c:715
static int hfp_send_cmgf(struct hfp_pvt *hfp, int mode)
Set the SMS mode.
Definition: chan_mobile.c:2627
static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
Definition: chan_mobile.c:1167
#define DEVICE_FRAME_SIZE
Definition: chan_mobile.c:81
static void * do_discovery(void *data)
Definition: chan_mobile.c:4284
#define CHANNEL_FRAME_SIZE
Definition: chan_mobile.c:83
static int at_match_prefix(char *buf, char *prefix)
Match the given buffer with the given prefix.
Definition: chan_mobile.c:2003
#define HFP_AG_RING
Definition: chan_mobile.c:268
static int sdp_search(char *addr, int profile)
Definition: chan_mobile.c:3073
static sdp_session_t * sdp_session
Definition: chan_mobile.c:87
static int rfcomm_read_and_expect_char(int rsock, char *result, char expected)
Read a character from the given stream and check if it matches what we expected.
Definition: chan_mobile.c:1520
static char * handle_cli_mobile_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_mobile.c:611
#define HFP_CIND_CALL_NONE
Definition: chan_mobile.c:286
#define MBL_CONFIG_OLD
Definition: chan_mobile.c:79
static char * mblstatus_desc
Definition: chan_mobile.c:203
#define FORMAT1
static int mbl_load_config(void)
Definition: chan_mobile.c:4626
static int hfp_send_dtmf(struct hfp_pvt *hfp, char digit)
Send a DTMF command.
Definition: chan_mobile.c:2598
#define HFP_CIND_UNKNOWN
Definition: chan_mobile.c:275
#define HFP_HF_CID
Definition: chan_mobile.c:259
static struct mbl_pvt * mbl_load_device(struct ast_config *cfg, const char *cat)
Load a device from the configuration file.
Definition: chan_mobile.c:4482
#define HFP_CIND_CALL
Definition: chan_mobile.c:278
static int rfcomm_wait(int rsock, int *ms)
Wait for activity on an rfcomm socket.
Definition: chan_mobile.c:1479
#define HFP_CIND_SERVICE_AVAILABLE
Definition: chan_mobile.c:297
static int msg_queue_push(struct mbl_pvt *pvt, at_message_t expect, at_message_t response_to)
Add an item to the back of the queue.
Definition: chan_mobile.c:2984
static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
Read and AT result code.
Definition: chan_mobile.c:1725
static struct hfp_hf hfp_our_brsf
Definition: chan_mobile.c:361
static int handle_response_busy(struct mbl_pvt *pvt)
Handle BUSY messages.
Definition: chan_mobile.c:3833
static void set_unloading(void)
Set the unloading flag.
Definition: chan_mobile.c:4697
#define HFP_HF_CONTROL
Definition: chan_mobile.c:263
#define HFP_HF_VOLUME
Definition: chan_mobile.c:261
static int hfp_send_vgs(struct hfp_pvt *hfp, int value)
Send the current speaker gain level.
Definition: chan_mobile.c:2558
static int mbl_queue_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1334
static int mbl_sendsms_exec(struct ast_channel *ast, const char *data)
Definition: chan_mobile.c:763
static int check_unloading(void)
Check if the module is unloading.
Definition: chan_mobile.c:4684
static int hsp_send_vgm(int rsock, int gain)
Send a microphone gain unsolicited AT response.
Definition: chan_mobile.c:2957
static struct ast_cli_entry mbl_cli[]
Definition: chan_mobile.c:193
static char * app_mblstatus
Definition: chan_mobile.c:201
static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
Handle OK AT messages.
Definition: chan_mobile.c:3275
#define HFP_CIND_BATTCHG
Definition: chan_mobile.c:283
static int headset_send_ring(const void *data)
Definition: chan_mobile.c:4104
static int hsp_send_ok(int rsock)
Send an OK AT response.
Definition: chan_mobile.c:2926
static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
Read the remainder of an AT command.
Definition: chan_mobile.c:1763
static struct ast_channel * mbl_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
Definition: chan_mobile.c:898
static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
Parse a CIEV event.
Definition: chan_mobile.c:2197
static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_mobile.c:1088
static int hfp_send_ata(struct hfp_pvt *hfp)
Send ATA.
Definition: chan_mobile.c:2704
static int mbl_has_service(struct mbl_pvt *pvt)
Check if a mobile device has service.
Definition: chan_mobile.c:1369
static char * mblstatus_synopsis
Definition: chan_mobile.c:202
static int rfcomm_write_full(int rsock, char *buf, size_t count)
Write to an rfcomm socket.
Definition: chan_mobile.c:1454
#define HFP_CIND_CALLSETUP_INCOMING
Definition: chan_mobile.c:291
static char * handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_mobile.c:541
static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
Parse the result of the AT+CIND=? command.
Definition: chan_mobile.c:2820
#define HFP_CIND_SERVICE
Definition: chan_mobile.c:277
at_message_t
Definition: chan_mobile.c:419
@ AT_VGS
Definition: chan_mobile.c:443
@ AT_NO_DIALTONE
Definition: chan_mobile.c:451
@ AT_CHUP
Definition: chan_mobile.c:439
@ AT_UNKNOWN
Definition: chan_mobile.c:423
@ AT_CMGF
Definition: chan_mobile.c:445
@ AT_CIND_TEST
Definition: chan_mobile.c:448
@ AT_ERROR
Definition: chan_mobile.c:426
@ AT_ECAM
Definition: chan_mobile.c:453
@ AT_CNMI
Definition: chan_mobile.c:446
@ AT_PARSE_ERROR
Definition: chan_mobile.c:421
@ AT_OK
Definition: chan_mobile.c:425
@ AT_CIND
Definition: chan_mobile.c:429
@ AT_CIEV
Definition: chan_mobile.c:430
@ AT_CLIP
Definition: chan_mobile.c:431
@ AT_CMGS
Definition: chan_mobile.c:441
@ AT_CMER
Definition: chan_mobile.c:447
@ AT_VGM
Definition: chan_mobile.c:442
@ AT_SMS_PROMPT
Definition: chan_mobile.c:434
@ AT_RING
Definition: chan_mobile.c:427
@ AT_A
Definition: chan_mobile.c:437
@ AT_D
Definition: chan_mobile.c:438
@ AT_VTS
Definition: chan_mobile.c:444
@ AT_READ_ERROR
Definition: chan_mobile.c:422
@ AT_CKPD
Definition: chan_mobile.c:440
@ AT_BUSY
Definition: chan_mobile.c:450
@ AT_CMS_ERROR
Definition: chan_mobile.c:435
@ AT_CMGR
Definition: chan_mobile.c:433
@ AT_BRSF
Definition: chan_mobile.c:428
@ AT_CMTI
Definition: chan_mobile.c:432
@ AT_CUSD
Definition: chan_mobile.c:449
@ AT_NO_CARRIER
Definition: chan_mobile.c:452
static int hfp_send_cmgs(struct hfp_pvt *hfp, const char *number)
Start sending an SMS message.
Definition: chan_mobile.c:2660
#define HFP_HF_ECNR
Definition: chan_mobile.c:257
static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
Handle CUSD messages.
Definition: chan_mobile.c:3813
static int handle_response_error(struct mbl_pvt *pvt, char *buf)
Handle ERROR AT messages.
Definition: chan_mobile.c:3444
static int unloading_flag
Definition: chan_mobile.c:90
static int mbl_devicestate(const char *data)
Definition: chan_mobile.c:1214
#define HFP_AG_CONTROL
Definition: chan_mobile.c:272
static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
Read until.
Definition: chan_mobile.c:1564
static char * hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
Parse a CUSD answer.
Definition: chan_mobile.c:2418
#define HFP_CIND_CALLSETUP_OUTGOING
Definition: chan_mobile.c:292
static struct msg_queue_entry * msg_queue_head(struct mbl_pvt *pvt)
Get the head of a queue.
Definition: chan_mobile.c:3060
#define HFP_CIND_CALLHELD
Definition: chan_mobile.c:280
static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf)
Send an SMS message from the queue.
Definition: chan_mobile.c:3782
#define HFP_HF_VOICE
Definition: chan_mobile.c:260
static int load_module(void)
Definition: chan_mobile.c:4778
mbl_type
Definition: chan_mobile.c:94
@ MBL_TYPE_PHONE
Definition: chan_mobile.c:95
@ MBL_TYPE_HEADSET
Definition: chan_mobile.c:96
static int mbl_answer(struct ast_channel *ast)
Definition: chan_mobile.c:1066
static int hfp_send_ecam(struct hfp_pvt *hfp)
Enable Sony Ericsson extensions / indications.
Definition: chan_mobile.c:2184
static int hfp_send_chup(struct hfp_pvt *hfp)
Send AT+CHUP.
Definition: chan_mobile.c:2683
#define HFP_AG_STATUS
Definition: chan_mobile.c:271
static int hfp_send_cind_test(struct hfp_pvt *hfp)
Send the CIND test command.
Definition: chan_mobile.c:2536
static struct ast_channel * mbl_new(int state, struct mbl_pvt *pvt, struct cidinfo *cidinfo, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_mobile.c:847
static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
Parse a ECAV event.
Definition: chan_mobile.c:2166
static int hfp_send_cusd(struct hfp_pvt *hfp, const char *code)
Send CUSD.
Definition: chan_mobile.c:2714
static int mbl_queue_control(struct mbl_pvt *pvt, enum ast_control_frame_type control)
Definition: chan_mobile.c:1317
static at_message_t at_read_full(int rsock, char *buf, size_t count)
Read an AT message and classify it.
Definition: chan_mobile.c:2017
static int sco_connect(bdaddr_t src, bdaddr_t dst)
Definition: chan_mobile.c:1833
#define FORMAT2
static int mbl_ast_hangup(struct mbl_pvt *pvt)
Definition: chan_mobile.c:1354
static int unload_module(void)
Definition: chan_mobile.c:4704
static pthread_t discovery_thread
Definition: chan_mobile.c:86
static char * handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_mobile.c:495
static int hfp_send_clip(struct hfp_pvt *hfp, int status)
Enable or disable calling line identification.
Definition: chan_mobile.c:2585
static int hfp_parse_cind(struct hfp_pvt *hfp, char *buf)
Read the result of the AT+CIND? command.
Definition: chan_mobile.c:2770
static struct ast_frame * mbl_read(struct ast_channel *ast)
Definition: chan_mobile.c:1109
static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_mobile.c:1195
static int hfp_brsf2int(struct hfp_hf *hf)
Convert a hfp_hf struct to a BRSF int.
Definition: chan_mobile.c:2470
static int hsp_send_vgs(int rsock, int gain)
Send a speaker gain unsolicited AT response.
Definition: chan_mobile.c:2945
static int parse_next_token(char string[], const int start, const char delim)
Terminate current token and return an index to start of the next token.
Definition: chan_mobile.c:2299
static sdp_session_t * sdp_register(void)
Definition: chan_mobile.c:3121
static int rfcomm_write(int rsock, char *buf)
Write to an rfcomm socket.
Definition: chan_mobile.c:1436
#define HFP_CIND_CALLSETUP_NONE
Definition: chan_mobile.c:290
static int hfp_parse_brsf(struct hfp_pvt *hfp, const char *buf)
Parse BRSF data.
Definition: chan_mobile.c:2726
static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen)
Definition: chan_mobile.c:1281
static struct ast_channel_tech mbl_tech
Definition: chan_mobile.c:479
#define HFP_CIND_CALLSETUP_ALERTING
Definition: chan_mobile.c:293
static struct msg_queue_entry * msg_queue_pop(struct mbl_pvt *pvt)
Remove an item from the front of the queue.
Definition: chan_mobile.c:3025
#define HFP_AG_REJECT
Definition: chan_mobile.c:270
static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel)
Definition: chan_mobile.c:1390
static struct cidinfo hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
Parse a CLIP event.
Definition: chan_mobile.c:2226
static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
Read until a.
Definition: chan_mobile.c:1609
static char * mblsendsms_synopsis
Definition: chan_mobile.c:210
static int start_monitor(struct mbl_pvt *pvt)
Definition: chan_mobile.c:4263
static int sco_write(int s, char *buf, int len)
Definition: chan_mobile.c:1871
static ast_mutex_t unload_mutex
Definition: chan_mobile.c:89
static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
Handle NO CARRIER messages.
Definition: chan_mobile.c:3863
static int hfp_send_cmer(struct hfp_pvt *hfp, int status)
Enable or disable indicator events reporting.
Definition: chan_mobile.c:2546
static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
Handle NO DIALTONE messages.
Definition: chan_mobile.c:3848
static int hfp_send_cmgr(struct hfp_pvt *hfp, int index)
Read an SMS message.
Definition: chan_mobile.c:2648
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_rings_set(struct ast_channel *chan, int value)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1258
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
Waits for input on an fd.
Definition: channel.c:2980
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1231
#define ast_channel_trylock(chan)
Definition: channel.h:2924
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
#define AST_MAX_CONTEXT
Definition: channel.h:135
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2426
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_RING
Definition: channelstate.h:40
@ AST_STATE_DOWN
Definition: channelstate.h:36
@ AST_STATE_UP
Definition: channelstate.h:42
@ AST_STATE_RESERVED
Definition: channelstate.h:37
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7385
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Device state management.
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
Convenient Signal Processing routines.
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
void ast_dsp_digitreset(struct ast_dsp *dsp)
Reset DTMF detector.
Definition: dsp.c:1810
struct ast_frame * ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *inf)
Return AST_FRAME_NULL frames when there is silence, AST_FRAME_BUSY on busies, and call progress,...
Definition: dsp.c:1499
#define DSP_FEATURE_DIGIT_DETECT
Definition: dsp.h:28
int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
Set digit mode.
Definition: dsp.c:1857
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
Select feature set.
Definition: dsp.c:1768
#define DSP_DIGITMODE_DTMF
Definition: dsp.h:31
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
#define DSP_DIGITMODE_RELAXDTMF
Definition: dsp.h:37
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * address
Definition: f2c.h:59
#define abs(x)
Definition: f2c.h:195
@ AST_FORMAT_CMP_NOT_EQUAL
Definition: format.h:38
Media Format Cache API.
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
Find if ast_format is within the capabilities of the ast_format_cap object.
Definition: format_cap.c:581
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:734
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static char prefix[MAX_PREFIX]
Definition: http.c:144
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
General Definitions for Asterisk top level program Included by asterisk.h to handle platform-specific...
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_VOICE
ast_control_frame_type
Internal control frame subtype field values.
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_BUSY
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
I/O Management (derived from Cheops-NG)
#define AST_IO_IN
Definition: io.h:34
struct io_context * io_context_create(void)
Creates a context Create a context for I/O operations Basically mallocs an IO structure and sets up s...
Definition: io.c:81
int * ast_io_add(struct io_context *ioc, int fd, ast_io_cb callback, short events, void *data)
Adds an IO context.
Definition: io.c:162
void io_context_destroy(struct io_context *ioc)
Destroys a context.
Definition: io.c:107
int ast_io_wait(struct io_context *ioc, int howlong)
Waits for IO.
Definition: io.c:278
int ast_io_remove(struct io_context *ioc, int *id)
Removes an IO context.
Definition: io.c:245
A set of macros to manage forward-linked lists.
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:452
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
Asterisk locking-related definitions:
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
Definition: lock.h:474
#define DEADLOCK_AVOIDANCE(lock)
Definition: lock.h:479
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_trylock(a)
Definition: lock.h:191
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
#define ast_register_application(app, execute, synopsis, description)
Register an application.
Definition: module.h:610
@ AST_MODPRI_CHANNEL_DRIVER
Definition: module.h:327
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Options provided by main asterisk program.
Core PBX routines and definitions.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4708
#define NULL
Definition: resample.c:96
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:567
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:433
Asterisk internal frame definitions.
void ast_smoother_free(struct ast_smoother *s)
Definition: smoother.c:220
struct ast_frame * ast_smoother_read(struct ast_smoother *s)
Definition: smoother.c:169
#define ast_smoother_feed(s, f)
Definition: smoother.h:75
struct ast_smoother * ast_smoother_new(int bytes)
Definition: smoother.c:108
void ast_smoother_reset(struct ast_smoother *s, int bytes)
Definition: smoother.c:79
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: utils.c:1818
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
unsigned int inuse
Definition: chan_mobile.c:104
pthread_t sco_listener_thread
Definition: chan_mobile.c:110
struct io_context * accept_io
Definition: chan_mobile.c:107
bdaddr_t addr
Definition: chan_mobile.c:103
char id[31]
Definition: chan_mobile.c:102
struct adapter_pvt::@0 entry
struct io_context * io
Definition: chan_mobile.c:106
unsigned int alignment_detection
Definition: chan_mobile.c:105
int * sco_id
Definition: chan_mobile.c:108
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:604
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:628
struct ast_format_cap * capabilities
Definition: channel.h:632
const char *const type
Definition: channel.h:629
Main Channel structure associated with a channel.
const char * data
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Definition: dsp.c:407
Structure used to handle boolean flags.
Definition: utils.h:199
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
struct timeval delivery
enum ast_frame_type frametype
const char * src
Structure for mutex and tracking information.
Definition: lock.h:135
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
char * cnam
Definition: chan_mobile.c:169
char * cnum
Definition: chan_mobile.c:168
Definition: search.h:40
This struct holds HFP features the AG supports.
Definition: chan_mobile.c:315
int cw
Definition: chan_mobile.c:316
int ring
Definition: chan_mobile.c:319
int reject
Definition: chan_mobile.c:321
int control
Definition: chan_mobile.c:323
int errors
Definition: chan_mobile.c:324
int ecnr
Definition: chan_mobile.c:317
int status
Definition: chan_mobile.c:322
int tag
Definition: chan_mobile.c:320
int voice
Definition: chan_mobile.c:318
This struct holds mappings for indications.
Definition: chan_mobile.c:330
int service
Definition: chan_mobile.c:331
int callheld
Definition: chan_mobile.c:334
int battchg
Definition: chan_mobile.c:337
int signal
Definition: chan_mobile.c:335
int callsetup
Definition: chan_mobile.c:333
This struct holds HFP features that we support.
Definition: chan_mobile.c:302
int cw
Definition: chan_mobile.c:304
int control
Definition: chan_mobile.c:309
int ecnr
Definition: chan_mobile.c:303
int status
Definition: chan_mobile.c:308
int voice
Definition: chan_mobile.c:306
int cid
Definition: chan_mobile.c:305
int volume
Definition: chan_mobile.c:307
This struct holds state information about the current hfp connection.
Definition: chan_mobile.c:344
int cind_state[16]
Definition: chan_mobile.c:350
int nocallsetup
Definition: chan_mobile.c:347
struct hfp_cind cind_map
Definition: chan_mobile.c:351
int sent_alerting
Definition: chan_mobile.c:354
struct hfp_ag brsf
Definition: chan_mobile.c:348
int rport
Definition: chan_mobile.c:353
struct mbl_pvt * owner
Definition: chan_mobile.c:345
int initialized
Definition: chan_mobile.c:346
int cind_index[16]
Definition: chan_mobile.c:349
int rsock
Definition: chan_mobile.c:352
Global IO variables are now in a struct in order to be made threadsafe.
Definition: io.c:71
int group
Definition: chan_mobile.c:126
struct mbl_pvt::@1 entry
enum mbl_type type
Definition: chan_mobile.c:124
struct ast_frame fr
Definition: chan_mobile.c:120
unsigned int needring
Definition: chan_mobile.c:159
int ring_sched_id
Definition: chan_mobile.c:147
unsigned int do_alignment_detection
Definition: chan_mobile.c:142
unsigned int outgoing_sms
Definition: chan_mobile.c:155
struct ast_sched_context * sched
Definition: chan_mobile.c:149
unsigned int outgoing
Definition: chan_mobile.c:153
short alignment_samples[4]
Definition: chan_mobile.c:145
int timeout
Definition: chan_mobile.c:139
char io_buf[CHANNEL_FRAME_SIZE+AST_FRIENDLY_OFFSET]
Definition: chan_mobile.c:134
struct mbl_pvt::msg_queue msg_queue
unsigned int has_sms
Definition: chan_mobile.c:141
struct hfp_pvt * hfp
Definition: chan_mobile.c:130
struct ast_smoother * bt_in_smoother
Definition: chan_mobile.c:136
struct ast_smoother * bt_out_smoother
Definition: chan_mobile.c:135
unsigned int needchup
Definition: chan_mobile.c:158
bdaddr_t addr
Definition: chan_mobile.c:127
struct ast_channel * owner
Definition: chan_mobile.c:119
struct adapter_pvt * adapter
Definition: chan_mobile.c:128
unsigned int incoming_sms
Definition: chan_mobile.c:156
char id[31]
Definition: chan_mobile.c:125
unsigned int no_callsetup
Definition: chan_mobile.c:140
int hangupcause
Definition: chan_mobile.c:150
int rfcomm_socket
Definition: chan_mobile.c:132
unsigned int incoming
Definition: chan_mobile.c:154
char rfcomm_buf[256]
Definition: chan_mobile.c:133
struct ast_dsp * dsp
Definition: chan_mobile.c:148
unsigned int connected
Definition: chan_mobile.c:161
unsigned int answered
Definition: chan_mobile.c:160
char context[AST_MAX_CONTEXT]
Definition: chan_mobile.c:129
int rfcomm_port
Definition: chan_mobile.c:131
unsigned int blackberry
Definition: chan_mobile.c:144
unsigned int needcallerid
Definition: chan_mobile.c:157
int sco_socket
Definition: chan_mobile.c:137
ast_mutex_t lock
Definition: chan_mobile.c:121
int alignment_count
Definition: chan_mobile.c:146
pthread_t monitor_thread
Definition: chan_mobile.c:138
unsigned int alignment_detection_triggered
Definition: chan_mobile.c:143
Definition: chan_mobile.c:460
at_message_t response_to
Definition: chan_mobile.c:462
void * data
Definition: chan_mobile.c:463
at_message_t expected
Definition: chan_mobile.c:461
struct msg_queue_entry::@2 entry
Number structure.
Definition: app_followme.c:154
int value
Definition: syslog.c:37
static float dr[4]
Definition: tdd.c:58
const char * args
static struct test_val a
static struct test_val c
static int indicator
Utility functions.
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
long int ast_random(void)
Definition: utils.c:2312
#define ARRAY_LEN(a)
Definition: utils.h:666