Skip to content
Snippets Groups Projects
chan_mobile.c 125 KiB
Newer Older
/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 1999 - 2006, Digium, Inc.
 *
 * Mark Spencer <markster@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

 * \file
 * \brief Bluetooth Mobile Device channel driver
 *
 * \author Dave Bowerman <david.bowerman@gmail.com>
 *
 * \ingroup channel_drivers
 */

Andrew Latham's avatar
Andrew Latham committed
/*! \li \ref chan_mobile.c uses the configuration file \ref chan_mobile.conf
 * \addtogroup configuration_file Configuration Files
 */

/*!
 * \page chan_mobile.conf chan_mobile.conf
 * \verbinclude chan_mobile.conf.sample
 */

/*** MODULEINFO
	<depend>bluetooth</depend>
	<defaultenabled>no</defaultenabled>
	<support_level>extended</support_level>
 ***/

#include "asterisk.h"

#include <pthread.h>
#include <signal.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sco.h>
#include <bluetooth/l2cap.h>

#include "asterisk/compat.h"
#include "asterisk/lock.h"
#include "asterisk/callerid.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
#include "asterisk/cli.h"
#include "asterisk/devicestate.h"
#include "asterisk/causes.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/io.h"
#include "asterisk/smoother.h"
#include "asterisk/format_cache.h"
#define MBL_CONFIG "chan_mobile.conf"
#define MBL_CONFIG_OLD "mobile.conf"
#define DEVICE_FRAME_FORMAT ast_format_slin
#define CHANNEL_FRAME_SIZE 320

static int discovery_interval = 60;			/* The device discovery interval, default 60 seconds. */
static pthread_t discovery_thread = AST_PTHREADT_NULL;	/* The discovery thread */
static sdp_session_t *sdp_session;

AST_MUTEX_DEFINE_STATIC(unload_mutex);
static int unloading_flag = 0;
static inline int check_unloading(void);
static inline void set_unloading(void);

enum mbl_type {
	MBL_TYPE_PHONE,
	MBL_TYPE_HEADSET
};

struct adapter_pvt {
	int dev_id;					/* device id */
	int hci_socket;					/* device descriptor */
	char id[31];					/* the 'name' from mobile.conf */
	bdaddr_t addr;					/* adddress of adapter */
	unsigned int inuse:1;				/* are we in use ? */
Josh Soref's avatar
Josh Soref committed
	unsigned int alignment_detection:1;		/* do alignment detection on this adapter? */
	struct io_context *io;				/*!< io context for audio connections */
	struct io_context *accept_io;			/*!< io context for sco listener */
	int *sco_id;					/*!< the io context id of the sco listener socket */
	int sco_socket;					/*!< sco listener socket */
	pthread_t sco_listener_thread;			/*!< sco listener thread */
	AST_LIST_ENTRY(adapter_pvt) entry;
};

static AST_RWLIST_HEAD_STATIC(adapters, adapter_pvt);

struct msg_queue_entry;
struct hfp_pvt;
struct mbl_pvt {
	struct ast_channel *owner;			/* Channel we belong to, possibly NULL */
	struct ast_frame fr;				/* "null" frame */
	ast_mutex_t lock;				/*!< pvt lock */
	/*! queue for messages we are expecting */
	AST_LIST_HEAD_NOLOCK(msg_queue, msg_queue_entry) msg_queue;
	enum mbl_type type;				/* Phone or Headset */
	char id[31];					/* The id from mobile.conf */
	int group;					/* group number for group dialling */
	bdaddr_t addr;					/* address of device */
	struct adapter_pvt *adapter;			/* the adapter we use */
	char context[AST_MAX_CONTEXT];			/* the context for incoming calls */
	struct hfp_pvt *hfp;				/*!< hfp pvt */
	int rfcomm_port;				/* rfcomm port number */
	int rfcomm_socket;				/* rfcomm socket descriptor */
	char rfcomm_buf[256];
	char io_buf[CHANNEL_FRAME_SIZE + AST_FRIENDLY_OFFSET];
	struct ast_smoother *bt_out_smoother;			/* our bt_out_smoother, for making 48 byte frames */
	struct ast_smoother *bt_in_smoother;			/* our smoother, for making "normal" CHANNEL_FRAME_SIZEed byte frames */
	int sco_socket;					/* sco socket descriptor */
	pthread_t monitor_thread;			/* monitor thread handle */
	int timeout;					/*!< used to set the timeout for rfcomm data (may be used in the future) */
	unsigned int no_callsetup:1;
	unsigned int has_sms:1;
	unsigned int do_alignment_detection:1;
	unsigned int alignment_detection_triggered:1;
	unsigned int blackberry:1;
	short alignment_samples[4];
	int alignment_count;
	int ring_sched_id;
	struct ast_dsp *dsp;
	struct ast_sched_context *sched;
	int hangupcause;

	/* flags */
	unsigned int outgoing:1;	/*!< outgoing call */
	unsigned int incoming:1;	/*!< incoming call */
	unsigned int outgoing_sms:1;	/*!< outgoing sms */
	unsigned int incoming_sms:1;	/*!< outgoing sms */
	unsigned int needcallerid:1;	/*!< we need callerid */
	unsigned int needchup:1;	/*!< we need to send a chup */
	unsigned int needring:1;	/*!< we need to send a RING */
	unsigned int answered:1;	/*!< we sent/received an answer */
	unsigned int connected:1;	/*!< do we have an rfcomm connection to a device */

	AST_LIST_ENTRY(mbl_pvt) entry;
};

/*! Structure used by hfp_parse_clip to return two items */
struct cidinfo {
	char *cnum;
	char *cnam;
};

static AST_RWLIST_HEAD_STATIC(devices, mbl_pvt);

static int handle_response_ok(struct mbl_pvt *pvt, char *buf);
static int handle_response_error(struct mbl_pvt *pvt, char *buf);
static int handle_response_ciev(struct mbl_pvt *pvt, char *buf);
static int handle_response_clip(struct mbl_pvt *pvt, char *buf);
static int handle_response_ring(struct mbl_pvt *pvt, char *buf);
static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
static int handle_response_busy(struct mbl_pvt *pvt);
static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf);
static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf);
static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);

/* CLI stuff */
static char *handle_cli_mobile_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *handle_cli_mobile_rfcomm(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *handle_cli_mobile_cusd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);

static struct ast_cli_entry mbl_cli[] = {
	AST_CLI_DEFINE(handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices"),
	AST_CLI_DEFINE(handle_cli_mobile_search,       "Search for Bluetooth Cell / Mobile devices"),
	AST_CLI_DEFINE(handle_cli_mobile_rfcomm,       "Send commands to the rfcomm port for debugging"),
	AST_CLI_DEFINE(handle_cli_mobile_cusd,         "Send CUSD commands to the mobile"),
Loading
Loading full blame...