[PATCH] Fix using invalid data from previous headset connection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Data notiated in a session should be reset once disconnected, to fix this
a new structure is introduced called headset_session is introduced to hold
the session data which is freed when disconnected.
---
 audio/headset.c |  187 +++++++++++++++++++++++++++++++------------------------
 1 files changed, 106 insertions(+), 81 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index 7002a3a..4decc18 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -128,6 +128,25 @@ struct pending_connect {
 	uint16_t svclass;
 };

+struct headset_session {
+	char buf[BUF_SIZE];
+	int data_start;
+	int data_length;
+
+	gboolean cli_active;
+	gboolean cme_enabled;
+	gboolean cwa_enabled;
+	gboolean pending_ring;
+	gboolean inband_ring;
+	gboolean nrec;
+	gboolean nrec_req;
+
+	int sp_gain;
+	int mic_gain;
+
+	unsigned int hf_features;
+};
+
 struct headset {
 	uint32_t hsp_handle;
 	uint32_t hfp_handle;
@@ -144,28 +163,14 @@ struct headset {

 	guint dc_timer;

-	char buf[BUF_SIZE];
-	int data_start;
-	int data_length;
-
 	gboolean hfp_active;
 	gboolean search_hfp;
-	gboolean cli_active;
-	gboolean cme_enabled;
-	gboolean cwa_enabled;
-	gboolean pending_ring;
-	gboolean inband_ring;
-	gboolean nrec;
-	gboolean nrec_req;

 	headset_state_t state;
 	struct pending_connect *pending;

-	int sp_gain;
-	int mic_gain;
-
-	unsigned int hf_features;
 	headset_lock_t lock;
+	struct headset_session *session;
 };

 struct event {
@@ -338,14 +343,15 @@ static int headset_send(struct headset *hs, char
*format, ...)
 static int supported_features(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;
 	int err;

 	if (strlen(buf) < 9)
 		return -EINVAL;

-	hs->hf_features = strtoul(&buf[8], NULL, 10);
+	session->hf_features = strtoul(&buf[8], NULL, 10);

-	print_hf_features(hs->hf_features);
+	print_hf_features(session->hf_features);

 	err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
 	if (err < 0)
@@ -534,10 +540,12 @@ static void send_foreach_headset(GSList *devices,

 static int cli_cmp(struct headset *hs)
 {
+	struct headset_session *session = hs->session;
+
 	if (!hs->hfp_active)
 		return -1;

-	if (hs->cli_active)
+	if (session->cli_active)
 		return 0;
 	else
 		return -1;
@@ -560,6 +568,7 @@ static void sco_connect_cb(GIOChannel *chan,
GError *err, gpointer user_data)
 	int sk;
 	struct audio_device *dev = user_data;
 	struct headset *hs = dev->headset;
+	struct headset_session *session = hs->session;
 	struct pending_connect *p = hs->pending;

 	if (err) {
@@ -599,12 +608,12 @@ static void sco_connect_cb(GIOChannel *chan,
GError *err, gpointer user_data)

 	headset_set_state(dev, HEADSET_STATE_PLAYING);

-	if (hs->pending_ring) {
+	if (session->pending_ring) {
 		ring_timer_cb(NULL);
 		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
 						ring_timer_cb,
 						NULL);
-		hs->pending_ring = FALSE;
+		session->pending_ring = FALSE;
 	}
 }

@@ -684,9 +693,10 @@ static void hfp_slc_complete(struct audio_device *dev)
 static int telephony_generic_rsp(struct audio_device *device, cme_error_t err)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;

 	if (err != CME_ERROR_NONE) {
-		if (hs->cme_enabled)
+		if (session->cme_enabled)
 			return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
 		else
 			return headset_send(hs, "\r\nERROR\r\n");
@@ -699,6 +709,7 @@ int telephony_event_reporting_rsp(void
*telephony_device, cme_error_t err)
 {
 	struct audio_device *device = telephony_device;
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;
 	int ret;

 	if (err != CME_ERROR_NONE)
@@ -711,7 +722,7 @@ int telephony_event_reporting_rsp(void
*telephony_device, cme_error_t err)
 	if (hs->state != HEADSET_STATE_CONNECTING)
 		return 0;

-	if (hs->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
+	if (session->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
 			ag.features & AG_FEATURE_THREE_WAY_CALLING)
 		return 0;

@@ -865,11 +876,12 @@ static int terminate_call(struct audio_device
*device, const char *buf)
 static int cli_notification(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;

 	if (strlen(buf) < 9)
 		return -EINVAL;

-	hs->cli_active = buf[8] == '1' ? TRUE : FALSE;
+	session->cli_active = buf[8] == '1' ? TRUE : FALSE;

 	return headset_send(hs, "\r\nOK\r\n");
 }
@@ -937,6 +949,7 @@ static int dial_number(struct audio_device
*device, const char *buf)
 static int signal_gain_setting(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;
 	const char *property;
 	const char *name;
 	dbus_uint16_t gain;
@@ -955,18 +968,18 @@ static int signal_gain_setting(struct
audio_device *device, const char *buf)

 	switch (buf[5]) {
 	case HEADSET_GAIN_SPEAKER:
-		if (hs->sp_gain == gain)
+		if (session->sp_gain == gain)
 			goto ok;
 		name = "SpeakerGainChanged";
 		property = "SpeakerGain";
-		hs->sp_gain = gain;
+		session->sp_gain = gain;
 		break;
 	case HEADSET_GAIN_MICROPHONE:
-		if (hs->mic_gain == gain)
+		if (session->mic_gain == gain)
 			goto ok;
 		name = "MicrophoneGainChanged";
 		property = "MicrophoneGain";
-		hs->mic_gain = gain;
+		session->mic_gain = gain;
 		break;
 	default:
 		error("Unknown gain setting");
@@ -1030,15 +1043,16 @@ static int list_current_calls(struct
audio_device *device, const char *buf)
 static int extended_errors(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;

 	if (strlen(buf) < 9)
 		return -EINVAL;

 	if (buf[8] == '1') {
-		hs->cme_enabled = TRUE;
+		session->cme_enabled = TRUE;
 		debug("CME errors enabled for headset %p", hs);
 	} else {
-		hs->cme_enabled = FALSE;
+		session->cme_enabled = FALSE;
 		debug("CME errors disabled for headset %p", hs);
 	}

@@ -1048,15 +1062,16 @@ static int extended_errors(struct audio_device
*device, const char *buf)
 static int call_waiting_notify(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;

 	if (strlen(buf) < 9)
 		return -EINVAL;

 	if (buf[8] == '1') {
-		hs->cwa_enabled = TRUE;
+		session->cwa_enabled = TRUE;
 		debug("Call waiting notification enabled for headset %p", hs);
 	} else {
-		hs->cwa_enabled = FALSE;
+		session->cwa_enabled = FALSE;
 		debug("Call waiting notification disabled for headset %p", hs);
 	}

@@ -1077,9 +1092,10 @@ int telephony_nr_and_ec_rsp(void
*telephony_device, cme_error_t err)
 {
 	struct audio_device *device = telephony_device;
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;

 	if (err == CME_ERROR_NONE)
-		hs->nrec = hs->nrec_req;
+		session->nrec = hs->session->nrec_req;

 	return telephony_generic_rsp(telephony_device, err);
 }
@@ -1123,16 +1139,17 @@ static int operator_selection(struct
audio_device *device, const char *buf)
 static int nr_and_ec(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;

 	if (strlen(buf) < 9)
 		return -EINVAL;

 	if (buf[8] == '0')
-		hs->nrec_req = FALSE;
+		session->nrec_req = FALSE;
 	else
-		hs->nrec_req = TRUE;
+		session->nrec_req = TRUE;

-	telephony_nr_and_ec_req(device, hs->nrec_req);
+	telephony_nr_and_ec_req(device, session->nrec_req);

 	return 0;
 }
@@ -1214,6 +1231,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan,
GIOCondition cond,
 				struct audio_device *device)
 {
 	struct headset *hs;
+	struct headset_session *session;
 	unsigned char buf[BUF_SIZE];
 	gsize bytes_read = 0;
 	gsize free_space;
@@ -1222,6 +1240,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan,
GIOCondition cond,
 		return FALSE;

 	hs = device->headset;
+	session = hs->session;

 	if (cond & (G_IO_ERR | G_IO_HUP)) {
 		debug("ERR or HUP on RFCOMM socket");
@@ -1232,7 +1251,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan,
GIOCondition cond,
 				&bytes_read) != G_IO_ERROR_NONE)
 		return TRUE;

-	free_space = sizeof(hs->buf) - hs->data_start - hs->data_length - 1;
+	free_space = sizeof(session->buf) - session->data_start -
+			session->data_length - 1;

 	if (free_space < bytes_read) {
 		/* Very likely that the HS is sending us garbage so
@@ -1241,45 +1261,45 @@ static gboolean rfcomm_io_cb(GIOChannel *chan,
GIOCondition cond,
 		goto failed;
 	}

-	memcpy(&hs->buf[hs->data_start], buf, bytes_read);
-	hs->data_length += bytes_read;
+	memcpy(&session->buf[session->data_start], buf, bytes_read);
+	session->data_length += bytes_read;

 	/* Make sure the data is null terminated so we can use string
 	 * functions */
-	hs->buf[hs->data_start + hs->data_length] = '\0';
+	session->buf[session->data_start + session->data_length] = '\0';

-	while (hs->data_length > 0) {
+	while (session->data_length > 0) {
 		char *cr;
 		int err;
 		off_t cmd_len;

-		cr = strchr(&hs->buf[hs->data_start], '\r');
+		cr = strchr(&session->buf[session->data_start], '\r');
 		if (!cr)
 			break;

-		cmd_len = 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start];
+		cmd_len = 1 + (off_t) cr - (off_t) &session->buf[session->data_start];
 		*cr = '\0';

 		if (cmd_len > 1)
-			err = handle_event(device, &hs->buf[hs->data_start]);
+			err = handle_event(device, &session->buf[session->data_start]);
 		else
 			/* Silently skip empty commands */
 			err = 0;

 		if (err == -EINVAL) {
 			error("Badly formated or unrecognized command: %s",
-					&hs->buf[hs->data_start]);
+					&session->buf[session->data_start]);
 			err = headset_send(hs, "\r\nERROR\r\n");
 		} else if (err < 0)
 			error("Error handling command %s: %s (%d)",
-						&hs->buf[hs->data_start],
+						&session->buf[session->data_start],
 						strerror(-err), -err);

-		hs->data_start += cmd_len;
-		hs->data_length -= cmd_len;
+		session->data_start += cmd_len;
+		session->data_length -= cmd_len;

-		if (!hs->data_length)
-			hs->data_start = 0;
+		if (!session->data_length)
+			session->data_start = 0;
 	}

 	return TRUE;
@@ -1337,6 +1357,9 @@ void headset_connect_cb(GIOChannel *chan, GError
*err, gpointer user_data)

 	debug("%s: Connected to %s", dev->path, hs_address);

+	hs->session = g_new0(struct headset_session, 1);
+	hs->session->nrec = TRUE;
+
 	/* In HFP mode wait for Service Level Connection */
 	if (hs->hfp_active)
 		return;
@@ -1811,10 +1834,11 @@ static DBusMessage
*hs_get_speaker_gain(DBusConnection *conn,
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;
 	DBusMessage *reply;
 	dbus_uint16_t gain;

-	if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0)
+	if (hs->state < HEADSET_STATE_CONNECTED || session == NULL)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
 						"Operation not Available");

@@ -1822,7 +1846,7 @@ static DBusMessage
*hs_get_speaker_gain(DBusConnection *conn,
 	if (!reply)
 		return NULL;

-	gain = (dbus_uint16_t) hs->sp_gain;
+	gain = (dbus_uint16_t) session->sp_gain;

 	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
 					DBUS_TYPE_INVALID);
@@ -1836,10 +1860,11 @@ static DBusMessage
*hs_get_mic_gain(DBusConnection *conn,
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;
 	DBusMessage *reply;
 	dbus_uint16_t gain;

-	if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0)
+	if (hs->state < HEADSET_STATE_CONNECTED || session == NULL)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
 						"Operation not Available");

@@ -1847,7 +1872,7 @@ static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
 	if (!reply)
 		return NULL;

-	gain = (dbus_uint16_t) hs->mic_gain;
+	gain = (dbus_uint16_t) session->mic_gain;

 	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
 					DBUS_TYPE_INVALID);
@@ -1862,6 +1887,7 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
+	struct headset_session *session = hs->session;
 	DBusMessage *reply;
 	int err;

@@ -1891,14 +1917,14 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,

 done:
 	if (type == HEADSET_GAIN_SPEAKER) {
-		hs->sp_gain = gain;
+		session->sp_gain = gain;
 		g_dbus_emit_signal(conn, device->path,
 					AUDIO_HEADSET_INTERFACE,
 					"SpeakerGainChanged",
 					DBUS_TYPE_UINT16, &gain,
 					DBUS_TYPE_INVALID);
 	} else {
-		hs->mic_gain = gain;
+		session->mic_gain = gain;
 		g_dbus_emit_signal(conn, device->path,
 					AUDIO_HEADSET_INTERFACE,
 					"MicrophoneGainChanged",
@@ -1975,11 +2001,13 @@ static DBusMessage
*hs_get_properties(DBusConnection *conn,

 	/* SpeakerGain */
 	dict_append_entry(&dict, "SpeakerGain",
-				DBUS_TYPE_UINT16, &device->headset->sp_gain);
+				DBUS_TYPE_UINT16,
+				&device->headset->session->sp_gain);

 	/* MicrophoneGain */
 	dict_append_entry(&dict, "MicrophoneGain",
-				DBUS_TYPE_UINT16, &device->headset->mic_gain);
+				DBUS_TYPE_UINT16,
+				&device->headset->session->mic_gain);

 done:
 	dbus_message_iter_close_container(&iter, &dict);
@@ -2118,10 +2146,8 @@ static int headset_close_rfcomm(struct audio_device *dev)
 		hs->rfcomm = NULL;
 	}

-	hs->data_start = 0;
-	hs->data_length = 0;
-
-	hs->nrec = TRUE;
+	g_free(hs->session);
+	hs->session = NULL;

 	return 0;
 }
@@ -2176,12 +2202,7 @@ struct headset *headset_init(struct
audio_device *dev, uint16_t svc,

 	hs = g_new0(struct headset, 1);
 	hs->rfcomm_ch = -1;
-	hs->sp_gain = -1;
-	hs->mic_gain = -1;
 	hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID);
-	hs->hfp_active = FALSE;
-	hs->cli_active = FALSE;
-	hs->nrec = TRUE;

 	record = btd_device_get_record(dev->btd_dev, uuidstr);
 	if (!record)
@@ -2424,18 +2445,19 @@ int headset_connect_rfcomm(struct audio_device
*dev, GIOChannel *io)
 int headset_connect_sco(struct audio_device *dev, GIOChannel *io)
 {
 	struct headset *hs = dev->headset;
+	struct headset_session *session = hs->session;

 	if (hs->sco)
 		return -EISCONN;

 	hs->sco = g_io_channel_ref(io);

-	if (hs->pending_ring) {
+	if (session->pending_ring) {
 		ring_timer_cb(NULL);
 		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
 						ring_timer_cb,
 						NULL);
-		hs->pending_ring = FALSE;
+		session->pending_ring = FALSE;
 	}

 	return 0;
@@ -2454,6 +2476,7 @@ static void disconnect_cb(struct btd_device
*btd_dev, gboolean removal,
 void headset_set_state(struct audio_device *dev, headset_state_t state)
 {
 	struct headset *hs = dev->headset;
+	struct headset_session *session = hs->session;
 	gboolean value;
 	const char *state_str;
 	headset_state_t old_state = hs->state;
@@ -2499,9 +2522,9 @@ void headset_set_state(struct audio_device *dev,
headset_state_t state)
 					DBUS_TYPE_STRING, &state_str);
 		if (hs->state < state) {
 			if (ag.features & AG_FEATURE_INBAND_RINGTONE)
-				hs->inband_ring = TRUE;
+				session->inband_ring = TRUE;
 			else
-				hs->inband_ring = FALSE;
+				session->inband_ring = FALSE;
 			g_dbus_emit_signal(dev->conn, dev->path,
 						AUDIO_HEADSET_INTERFACE,
 						"Connected",
@@ -2546,10 +2569,10 @@ void headset_set_state(struct audio_device
*dev, headset_state_t state)
 					AUDIO_HEADSET_INTERFACE, "Playing",
 					DBUS_TYPE_BOOLEAN, &value);

-		if (hs->sp_gain >= 0)
-			headset_send(hs, "\r\n+VGS=%u\r\n", hs->sp_gain);
-		if (hs->mic_gain >= 0)
-			headset_send(hs, "\r\n+VGM=%u\r\n", hs->mic_gain);
+		if (session->sp_gain >= 0)
+			headset_send(hs, "\r\n+VGS=%u\r\n", session->sp_gain);
+		if (session->mic_gain >= 0)
+			headset_send(hs, "\r\n+VGM=%u\r\n", session->mic_gain);
 		break;
 	}

@@ -2658,7 +2681,7 @@ gboolean headset_get_nrec(struct audio_device *dev)
 {
 	struct headset *hs = dev->headset;

-	return hs->nrec;
+	return hs->session->nrec;
 }

 gboolean headset_get_sco_hci(struct audio_device *dev)
@@ -2715,6 +2738,7 @@ int telephony_incoming_call_ind(const char
*number, int type)
 {
 	struct audio_device *dev;
 	struct headset *hs;
+	struct headset_session *session;

 	if (!active_devices)
 		return -ENODEV;
@@ -2722,6 +2746,7 @@ int telephony_incoming_call_ind(const char
*number, int type)
 	/* Get the latest connected device */
 	dev = active_devices->data;
 	hs = dev->headset;
+	session = hs->session;

 	if (ag.ring_timer) {
 		debug("telephony_incoming_call_ind: already calling");
@@ -2730,16 +2755,16 @@ int telephony_incoming_call_ind(const char
*number, int type)

 	/* With HSP 1.2 the RING messages should *not* be sent if inband
 	 * ringtone is being used */
-	if (!hs->hfp_active && hs->inband_ring)
+	if (!hs->hfp_active && session->inband_ring)
 		return 0;

 	g_free(ag.number);
 	ag.number = g_strdup(number);
 	ag.number_type = type;

-	if (hs->inband_ring && hs->hfp_active &&
+	if (session->inband_ring && hs->hfp_active &&
 					hs->state != HEADSET_STATE_PLAYING) {
-		hs->pending_ring = TRUE;
+		session->pending_ring = TRUE;
 		return 0;
 	}

@@ -2765,10 +2790,10 @@ int telephony_calling_stopped_ind(void)
 	/* In case SCO isn't fully up yet */
 	dev = active_devices->data;

-	if (!dev->headset->pending_ring && !ag.ring_timer)
+	if (!dev->headset->session->pending_ring && !ag.ring_timer)
 		return -EINVAL;

-	dev->headset->pending_ring = FALSE;
+	dev->headset->session->pending_ring = FALSE;

 	return 0;
 }
@@ -2826,7 +2851,7 @@ static int cwa_cmp(struct headset *hs)
 	if (!hs->hfp_active)
 		return -1;

-	if (hs->cwa_enabled)
+	if (hs->session->cwa_enabled)
 		return 0;
 	else
 		return -1;
-- 
1.6.3.3

-- 
Luiz Augusto von Dentz
Computer Engineer
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux