[asterisk-addons-commits] mnicholson: branch mnicholson/chan-mobile-refactor r812 - /team/mnicholson/ch...

SVN commits to the Asterisk addons project asterisk-addons-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 asterisk-addons-commits mailing list