[svn-commits] mnicholson: branch mnicholson/chan-mobile-refactor r812 - /team/mnicholson/ch...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Mar 18 16:34:32 CDT 2009
Author: mnicholson
Date: Wed Mar 18 16:34:28 2009
New Revision: 812
URL: http://svn.digium.com/svn-view/asterisk-addons?view=rev&rev=812
Log:
Updated HSP profile handing.
This commit improves the way chan_mobile handles and services HSP connections.
Modified:
team/mnicholson/chan-mobile-refactor/channels/chan_mobile.c
Modified: team/mnicholson/chan-mobile-refactor/channels/chan_mobile.c
URL: http://svn.digium.com/svn-view/asterisk-addons/team/mnicholson/chan-mobile-refactor/channels/chan_mobile.c?view=diff&rev=812&r1=811&r2=812
==============================================================================
--- team/mnicholson/chan-mobile-refactor/channels/chan_mobile.c (original)
+++ team/mnicholson/chan-mobile-refactor/channels/chan_mobile.c Wed Mar 18 16:34:28 2009
@@ -151,7 +151,9 @@
unsigned int blackberry:1;
short alignment_samples[4];
int alignment_count;
+ int ring_sched_id;
struct ast_dsp *dsp;
+ struct sched_context *sched;
/* flags */
unsigned int outgoing:1; /*!< outgoing call */
@@ -160,6 +162,7 @@
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 sent_answer:1; /*!< we sent an answer */
unsigned int connected:1; /*!< do we have an rfcomm connection to a device */
@@ -236,6 +239,8 @@
static void *do_sco_listen(void *data);
static int sdp_search(char *addr, int profile);
+
+static int headset_send_ring(const void *data);
/*
* bluetooth handsfree profile helpers
@@ -913,18 +918,31 @@
ast_debug(1, "Calling %s on %s\n", dest, ast->name);
+ ast_mutex_lock(&pvt->lock);
if (pvt->type == MBL_TYPE_PHONE) {
- ast_mutex_lock(&pvt->lock);
if (hfp_send_atd(pvt->hfp, dest_num)) {
ast_mutex_unlock(&pvt->lock);
ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
return -1;
}
msg_queue_push(pvt, AT_OK, AT_D);
- ast_mutex_unlock(&pvt->lock);
} else {
- pvt->state = MBL_STATE_RING;
- }
+ if (hsp_send_ring(pvt->rfcomm_socket)) {
+ ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
+ ast_mutex_unlock(&pvt->lock);
+ return -1;
+ }
+
+ if ((pvt->ring_sched_id = ast_sched_add(pvt->sched, 6000, headset_send_ring, pvt)) == -1) {
+ ast_log(LOG_ERROR, "[%s] error ringing device\n", pvt->id);
+ ast_mutex_unlock(&pvt->lock);
+ return -1;
+ }
+
+ pvt->outgoing = 1;
+ pvt->needring = 1;
+ }
+ ast_mutex_unlock(&pvt->lock);
return 0;
@@ -958,6 +976,8 @@
pvt->needchup = 0;
}
+ pvt->outgoing = 0;
+ pvt->incoming = 0;
pvt->owner = NULL;
ast->tech_pvt = NULL;
@@ -975,6 +995,9 @@
struct mbl_pvt *pvt;
pvt = ast->tech_pvt;
+
+ if (pvt->type == MBL_TYPE_HEADSET)
+ return 0;
ast_mutex_lock(&pvt->lock);
if (pvt->incoming) {
@@ -1587,6 +1610,9 @@
return -1;
}
+/* XXX this does not work with the do_sco_listen() thread (which also bind()s
+ * to this address). Also I am not sure if it is necessary. */
+#if 0
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, &src);
@@ -1595,6 +1621,7 @@
close(s);
return -1;
}
+#endif
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
@@ -3382,6 +3409,33 @@
return NULL;
}
+static int headset_send_ring(const void *data)
+{
+ struct mbl_pvt *pvt = (struct mbl_pvt *) data;
+ ast_mutex_lock(&pvt->lock);
+ if (!pvt->needring) {
+ ast_mutex_unlock(&pvt->lock);
+ return 0;
+ }
+ ast_mutex_unlock(&pvt->lock);
+
+ if (hsp_send_ring(pvt->rfcomm_socket)) {
+ ast_debug(1, "[%s] error sending RING\n", pvt->id);
+ return 0;
+ }
+ return 1;
+}
+
+/*!
+ * \brief Handle rfcomm data.
+ * Currently this function does nothing, it is merely used to interrupt
+ * ast_io_wait().
+ */
+static int headset_handle_rfcomm(int *id, int fd, short events, void *data)
+{
+ return 1;
+}
+
static void *do_monitor_headset(void *data)
{
@@ -3390,90 +3444,139 @@
int t, zero = 0;
at_message_t at_msg;
struct io_context *io = NULL;
+ struct ast_channel *chan = NULL;
if (!(io = io_context_create())) {
ast_log(LOG_ERROR, "Unable to create I/O context for headset audio connections\n");
goto e_cleanup;
}
- pvt->state = MBL_STATE_PREIDLE;
+ if (!ast_io_add(io, pvt->rfcomm_socket, headset_handle_rfcomm, AST_IO_IN, pvt)) {
+ ast_log(LOG_ERROR, "[%s] error moitoring rfcomm connection\n", pvt->id);
+ goto e_cleanup;
+ }
+
+ ast_verb(3, "Bluetooth Device %s initialised and ready.\n", pvt->id);
while (!check_unloading()) {
- if (pvt->state == MBL_STATE_RING2)
- t = 2000;
- else
- t = 1000;
-
- if (!ast_io_wait(io, t) && rfcomm_wait(pvt->rfcomm_socket, &zero)) {
- if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
- if (strerror_r(errno, buf, sizeof(buf)))
- ast_debug(1, "[%s] error reading from device\n", pvt->id);
- else
- ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno);
-
+ t = ast_sched_wait(pvt->sched);
+ if (t == -1) {
+ t = 6000;
+ }
+
+ if (ast_io_wait(io, t) == -1) {
+ ast_debug(1, "[%s] error when waiting for audio from device\n", pvt->id);
+ goto e_cleanup;
+ }
+
+ ast_sched_runq(pvt->sched);
+
+ if (rfcomm_wait(pvt->rfcomm_socket, &zero) == 0)
+ continue;
+
+ if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
+ if (strerror_r(errno, buf, sizeof(buf)))
+ ast_debug(1, "[%s] error reading from device\n", pvt->id);
+ else
+ ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno);
+
+ goto e_cleanup;
+ }
+ ast_debug(1, "[%s] %s\n", pvt->id, buf);
+
+ switch (at_msg) {
+ case AT_VGS:
+ case AT_VGM:
+ /* XXX volume change requested, we will just
+ * pretend to do something with it */
+ if (hsp_send_ok(pvt->rfcomm_socket)) {
+ ast_debug(1, "[%s] error sending AT message 'OK'\n", pvt->id);
goto e_cleanup;
}
- ast_debug(1, "[%s] %s\n", pvt->id, buf);
-
- switch (pvt->state) {
- case MBL_STATE_RING2:
- if (at_msg == AT_CKPD) {
+ break;
+ case AT_CKPD:
+ ast_mutex_lock(&pvt->lock);
+ if (pvt->outgoing) {
+ pvt->needring = 1;
+ hsp_send_ok(pvt->rfcomm_socket);
+ if (pvt->sent_answer) {
+ /* we have an answered call up to the
+ * HS, he wants to hangup */
+ mbl_queue_hangup(pvt);
+ } else {
+ /* we have an outgoing call to the HS,
+ * he wants to answer */
+ if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
+ ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
+ mbl_queue_hangup(pvt);
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
+ }
+
+ if (!ast_io_add(io, pvt->sco_socket, sco_read, AST_IO_IN, pvt)) {
+ ast_log(LOG_ERROR, "[%s] error servicing audio connection\n", pvt->id);
+ mbl_queue_hangup(pvt);
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
+ }
+
mbl_queue_control(pvt, AST_CONTROL_ANSWER);
- pvt->state = MBL_STATE_INCOMING;
+ pvt->sent_answer = 1;
+
if (hsp_send_vgs(pvt->rfcomm_socket, 13) || hsp_send_vgm(pvt->rfcomm_socket, 13)) {
ast_debug(1, "[%s] error sending VGS/VGM\n", pvt->id);
+ mbl_queue_hangup(pvt);
+ ast_mutex_unlock(&pvt->lock);
goto e_cleanup;
}
}
- break;
- case MBL_STATE_INCOMING:
- if (at_msg == AT_CKPD) {
- mbl_queue_control(pvt, AST_CONTROL_HANGUP);
+ } else if (pvt->incoming) {
+ /* we have an incoming call from the
+ * HS, he wants to hang up */
+ mbl_queue_hangup(pvt);
+ } else {
+ /* no call is up, HS wants to dial */
+ hsp_send_ok(pvt->rfcomm_socket);
+
+ if ((pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr)) == -1) {
+ ast_log(LOG_ERROR, "[%s] unable to create audio connection\n", pvt->id);
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
}
- break;
- default:
- break;
- }
- if (at_msg == AT_VGS || at_msg == AT_VGM) {
- /* XXX should we respond ok here? We don't
- * actually do anything with the command...
- */
- hsp_send_ok(pvt->rfcomm_socket);
- } else if (at_msg == AT_UNKNOWN) {
- if (hsp_send_error(pvt->rfcomm_socket)) {
- ast_debug(1, "[%s] error sending ERROR\n", pvt->id);
+
+ if (!ast_io_add(io, pvt->sco_socket, sco_read, AST_IO_IN, pvt)) {
+ ast_log(LOG_ERROR, "[%s] error servicing audio connection\n", pvt->id);
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
+ }
+
+ pvt->incoming = 1;
+
+ if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL))) {
+ ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
+ ast_mutex_unlock(&pvt->lock);
+ goto e_cleanup;
+ }
+
+ ast_string_copy(chan->exten, "s", AST_MAX_EXTENSION);
+ if (ast_pbx_start(chan)) {
+ ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
+ ast_hangup(chan);
+ ast_mutex_unlock(&pvt->lock);
goto e_cleanup;
}
}
- } else { /* Timeouts */
- if (pvt->state == MBL_STATE_PREIDLE) {
- pvt->connected = 1;
- ast_verb(3, "Bluetooth Device %s initialised and ready.\n", pvt->id);
- pvt->state = MBL_STATE_IDLE;
- } else if (pvt->state == MBL_STATE_RING) {
- pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr);
- if (pvt->sco_socket > -1) {
- if (!ast_io_add(io, pvt->sco_socket, sco_read, AST_IO_IN, pvt)) {
- ast_log(LOG_ERROR, "error monitoring new audio connection for device %s\n", pvt->id);
- mbl_queue_control(pvt, AST_CONTROL_HANGUP);
- close(pvt->sco_socket);
- goto e_cleanup;
- }
- ast_setstate(pvt->owner, AST_STATE_RINGING);
- mbl_queue_control(pvt, AST_CONTROL_RINGING);
- pvt->state = MBL_STATE_RING2;
- } else {
- mbl_queue_control(pvt, AST_CONTROL_HANGUP);
- }
- } else if (pvt->state == MBL_STATE_RING2) {
- if (hsp_send_ring(pvt->rfcomm_socket)) {
- ast_debug(1, "[%s] error sending RING\n", pvt->id);
- goto e_cleanup;
- }
+ ast_mutex_unlock(&pvt->lock);
+ break;
+ default:
+ ast_debug(1, "[%s] received unknown AT command: %s (%s)\n", pvt->id, buf, at_msg2str(at_msg));
+ if (hsp_send_error(pvt->rfcomm_socket)) {
+ ast_debug(1, "[%s] error sending AT message 'ERROR'\n", pvt->id);
+ goto e_cleanup;
}
- }
-
+ break;
+ }
}
e_cleanup:
@@ -3492,6 +3595,10 @@
pvt->sco_socket = -1;
pvt->connected = 0;
+
+ pvt->needring = 0;
+ pvt->outgoing = 0;
+ pvt->incoming = 0;
pvt->adapter->inuse = 0;
ast_mutex_unlock(&pvt->lock);
@@ -3781,6 +3888,7 @@
pvt->rfcomm_port = atoi(port);
pvt->sco_socket = -1;
pvt->monitor_thread = AST_PTHREADT_NULL;
+ pvt->ring_sched_id = -1;
/* setup the smoother */
if (!(pvt->smoother = ast_smoother_new(DEVICE_FRAME_SIZE))) {
@@ -3792,6 +3900,12 @@
if (!(pvt->dsp = ast_dsp_new())) {
ast_log(LOG_ERROR, "Skipping device %s. Error setting up dsp for dtmf detection.\n", cat);
goto e_free_smoother;
+ }
+
+ /* setup the scheduler */
+ if (!(pvt->sched = sched_context_create())) {
+ ast_log(LOG_ERROR, "Unable to create scheduler context for headset device\n");
+ goto e_free_dsp;
}
ast_dsp_set_features(pvt->dsp, DSP_FEATURE_DIGIT_DETECT);
@@ -3821,7 +3935,7 @@
if (pvt->type == MBL_TYPE_PHONE) {
if (!(pvt->hfp = ast_calloc(1, sizeof(*pvt->hfp)))) {
ast_log(LOG_ERROR, "Skipping device %s. Error allocating memory.\n", pvt->id);
- goto e_free_dsp;
+ goto e_free_sched;
}
pvt->hfp->owner = pvt;
@@ -3837,6 +3951,8 @@
return pvt;
+e_free_sched:
+ sched_context_destroy(pvt->sched);
e_free_dsp:
ast_dsp_free(pvt->dsp);
e_free_smoother:
@@ -3973,6 +4089,7 @@
ast_smoother_free(pvt->smoother);
ast_dsp_free(pvt->dsp);
+ sched_context_destroy(pvt->sched);
ast_free(pvt);
}
AST_RWLIST_UNLOCK(&devices);
More information about the svn-commits
mailing list