linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH v3 6/6] a2dp: Reword LastUsed
Date: Mon,  6 May 2019 15:43:10 +0300	[thread overview]
Message-ID: <20190506124310.19151-6-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20190506124310.19151-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

In addition to storing the remote endpoint also store the local one as
well so we it can properly be restore.
---
 profiles/audio/a2dp.c  | 147 +++++++++++++++++++++++++++++++----------
 profiles/audio/avdtp.c |   5 ++
 profiles/audio/avdtp.h |   1 +
 3 files changed, 119 insertions(+), 34 deletions(-)

diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index b54c50315..046193688 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -139,6 +139,11 @@ struct a2dp_remote_sep {
 	struct avdtp_remote_sep *sep;
 };
 
+struct a2dp_last_used {
+	struct a2dp_sep *lsep;
+	struct a2dp_remote_sep *rsep;
+};
+
 struct a2dp_channel {
 	struct a2dp_server *server;
 	struct btd_device *device;
@@ -148,7 +153,7 @@ struct a2dp_channel {
 	unsigned int auth_id;
 	struct avdtp *session;
 	struct queue *seps;
-	struct a2dp_remote_sep *last_used;
+	struct a2dp_last_used *last_used;
 };
 
 static GSList *servers = NULL;
@@ -214,6 +219,8 @@ static void setup_free(struct a2dp_setup *s)
 		g_io_channel_unref(s->io);
 	}
 
+	queue_destroy(s->eps, NULL);
+
 	setups = g_slist_remove(setups, s);
 	if (s->session)
 		avdtp_unref(s->session);
@@ -844,13 +851,13 @@ static bool match_remote_sep(const void *data, const void *user_data)
 	return sep->sep == rsep;
 }
 
-static void store_last_used(struct a2dp_channel *chan,
-					struct avdtp_remote_sep *rsep)
+static void store_last_used(struct a2dp_channel *chan, uint8_t lseid,
+							uint8_t rseid)
 {
 	GKeyFile *key_file;
 	char filename[PATH_MAX];
 	char dst_addr[18];
-	char value[4];
+	char value[6];
 	char *data;
 	size_t len = 0;
 
@@ -862,7 +869,7 @@ static void store_last_used(struct a2dp_channel *chan,
 	key_file = g_key_file_new();
 	g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-	sprintf(value, "%02hhx", avdtp_get_seid(rsep));
+	sprintf(value, "%02hhx:%02hhx", lseid, rseid);
 
 	g_key_file_set_string(key_file, "Endpoints", "LastUsed", value);
 
@@ -873,21 +880,38 @@ static void store_last_used(struct a2dp_channel *chan,
 	g_key_file_free(key_file);
 }
 
-static void update_last_used(struct a2dp_channel *chan,
-						struct avdtp_stream *stream)
+static void add_last_used(struct a2dp_channel *chan, struct a2dp_sep *lsep,
+				struct a2dp_remote_sep *rsep)
+{
+	if (!chan->last_used)
+		chan->last_used = new0(struct a2dp_last_used, 1);
+
+	chan->last_used->lsep = lsep;
+	chan->last_used->rsep = rsep;
+}
+
+static void update_last_used(struct a2dp_channel *chan, struct a2dp_sep *lsep,
+					struct avdtp_stream *stream)
 {
 	struct avdtp_remote_sep *rsep;
 	struct a2dp_remote_sep *sep;
 
 	rsep = avdtp_stream_get_remote_sep(stream);
-
-	/* Update last used */
 	sep = queue_find(chan->seps, match_remote_sep, rsep);
-	if (chan->last_used == sep)
+	if (!sep) {
+		error("Unable to find remote SEP");
 		return;
+	}
+
+	/* Check if already stored then skip */
+	if (chan->last_used && (chan->last_used->lsep == lsep &&
+				chan->last_used->rsep == sep))
+		return;
+
+	add_last_used(chan, lsep, sep);
 
-	chan->last_used = sep;
-	store_last_used(chan, rsep);
+	store_last_used(chan, avdtp_sep_get_seid(lsep->lsep),
+					avdtp_get_seid(rsep));
 }
 
 static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -909,7 +933,7 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
 	setup->stream = stream;
 
 	if (!err && setup->chan)
-		update_last_used(setup->chan, stream);
+		update_last_used(setup->chan, a2dp_sep, stream);
 
 	if (setup->reconfigure)
 		setup->reconfigure = FALSE;
@@ -944,7 +968,7 @@ static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
 		if (setup->start)
 			finalize_resume(setup);
 	} else if (setup->chan)
-		update_last_used(setup->chan, stream);
+		update_last_used(setup->chan, a2dp_sep, stream);
 
 	finalize_config(setup);
 
@@ -1483,6 +1507,7 @@ static void channel_free(void *data)
 	avdtp_remove_state_cb(chan->state_id);
 
 	queue_destroy(chan->seps, remove_remote_sep);
+	free(chan->last_used);
 	g_free(chan);
 }
 
@@ -1631,6 +1656,9 @@ static int a2dp_reconfig(struct a2dp_channel *chan, const char *sender,
 	setup->sep = lsep;
 	setup->rsep = rsep;
 
+	g_slist_free_full(setup->caps, g_free);
+	setup->caps = NULL;
+
 	caps_add_codec(&setup->caps, setup->sep->codec, caps, size);
 
 	l = avdtp_get_type(rsep->sep) == AVDTP_SEP_TYPE_SINK ?
@@ -1871,11 +1899,37 @@ static bool match_seid(const void *data, const void *user_data)
 	return avdtp_get_seid(sep->sep) == *seid;
 }
 
+static int match_sep(const void *data, const void *user_data)
+{
+	struct a2dp_sep *sep = (void *) data;
+	const uint8_t *seid = user_data;
+
+	return *seid - avdtp_sep_get_seid(sep->lsep);
+}
+
+static struct a2dp_sep *find_sep_by_seid(struct a2dp_server *server,
+							uint8_t seid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(server->sources, &seid, match_sep);
+	if (l)
+		return l->data;
+
+	l = g_slist_find_custom(server->sinks, &seid, match_sep);
+	if (l)
+		return l->data;
+
+	return NULL;
+}
+
 static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 								char **seids)
 {
-	struct avdtp_remote_sep *sep;
-	uint8_t seid;
+	struct a2dp_sep *lsep;
+	struct a2dp_remote_sep *sep;
+	struct avdtp_remote_sep *rsep;
+	uint8_t lseid, rseid;
 	char *value;
 
 	if (!seids)
@@ -1884,12 +1938,12 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 	for (; *seids; seids++) {
 		uint8_t type;
 		uint8_t codec;
+		GSList *l = NULL;
 		char caps[256];
 		uint8_t data[128];
 		int i, size;
-		GSList *l = NULL;
 
-		if (sscanf(*seids, "%02hhx", &seid) != 1)
+		if (sscanf(*seids, "%02hhx", &rseid) != 1)
 			continue;
 
 		value = g_key_file_get_string(key_file, "Endpoints", *seids,
@@ -1899,7 +1953,7 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 
 		if (sscanf(value, "%02hhx:%02hhx:%s", &type, &codec,
 								caps) != 3) {
-			warn("Unable to load Endpoint: seid %u", seid);
+			warn("Unable to load Endpoint: seid %u", rseid);
 			g_free(value);
 			continue;
 		}
@@ -1908,7 +1962,8 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 			uint8_t *tmp = data + i / 2;
 
 			if (sscanf(caps + i, "%02hhx", tmp) != 1) {
-				warn("Unable to load Endpoint: seid %u", seid);
+				warn("Unable to load Endpoint: seid %u", rseid);
+				g_free(value);
 				break;
 			}
 		}
@@ -1920,23 +1975,39 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 
 		caps_add_codec(&l, codec, data, size / 2);
 
-		sep = avdtp_register_remote_sep(chan->session, seid, type, l);
-		if (!sep) {
-			warn("Unable to register Endpoint: seid %u", seid);
+		rsep = avdtp_register_remote_sep(chan->session, rseid, type, l);
+		if (!rsep) {
+			warn("Unable to register Endpoint: seid %u", rseid);
 			continue;
 		}
 
-		register_remote_sep(sep, chan);
+		register_remote_sep(rsep, chan);
 	}
 
 	value = g_key_file_get_string(key_file, "Endpoints", "LastUsed", NULL);
 	if (!value)
 		return;
 
-	if (sscanf(value, "%02hhx", &seid) != 1)
+	if (sscanf(value, "%02hhx:%02hhx", &lseid, &rseid) != 2) {
+		warn("Unable to load LastUsed");
+		return;
+	}
+
+	g_free(value);
+
+	lsep = find_sep_by_seid(chan->server, lseid);
+	if (!lsep) {
+		warn("Unable to load LastUsed: lseid %u not found", lseid);
 		return;
+	}
 
-	chan->last_used = queue_find(chan->seps, match_seid, &seid);
+	sep = queue_find(chan->seps, match_seid, &rseid);
+	if (!sep) {
+		warn("Unable to load LastUsed: rseid %u not found", rseid);
+		return;
+	}
+
+	add_last_used(chan, lsep, sep);
 }
 
 static void load_remote_seps(struct a2dp_channel *chan)
@@ -2442,7 +2513,6 @@ static void select_cb(struct a2dp_setup *setup, void *ret, int size)
 	setup->sep = queue_pop_head(setup->eps);
 	if (!setup->sep) {
 		error("Unable to select a valid configuration");
-		queue_destroy(setup->eps, NULL);
 		goto done;
 	}
 
@@ -2453,7 +2523,7 @@ static void select_cb(struct a2dp_setup *setup, void *ret, int size)
 	err = setup->sep->endpoint->select_configuration(setup->sep,
 					codec->data,
 					service->length - sizeof(*codec),
-					setup_ref(setup),
+					setup,
 					select_cb, setup->sep->user_data);
 	if (err == 0)
 		return;
@@ -2493,11 +2563,11 @@ static struct queue *a2dp_find_eps(struct avdtp *session, GSList *list,
 			seps = queue_new();
 
 		/* Prepend last used so it is preferred over others */
-		if (chan->last_used && chan->last_used->sep == rsep)
+		if (chan->last_used && (chan->last_used->lsep == sep &&
+					chan->last_used->rsep->sep == rsep))
 			queue_push_head(seps, sep);
 		else
 			queue_push_tail(seps, sep);
-
 	}
 
 	return seps;
@@ -2566,11 +2636,18 @@ static void store_remote_seps(struct a2dp_channel *chan)
 	key_file = g_key_file_new();
 	g_key_file_load_from_file(key_file, filename, 0, NULL);
 
+	data = g_key_file_get_string(key_file, "Endpoints", "LastUsed", NULL);
+
 	/* Remove current endpoints since it might have changed */
 	g_key_file_remove_group(key_file, "Endpoints", NULL);
 
 	queue_foreach(chan->seps, store_remote_sep, key_file);
 
+	if (data) {
+		g_key_file_set_string(key_file, "Endpoints", "LastUsed", data);
+		g_free(data);
+	}
+
 	data = g_key_file_to_data(key_file, &length, NULL);
 	g_file_set_contents(filename, data, length, NULL);
 
@@ -2656,10 +2733,12 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
 	codec = (struct avdtp_media_codec_capability *) service->data;
 
 	err = setup->sep->endpoint->select_configuration(setup->sep,
-					codec->data,
-					service->length - sizeof(*codec),
-					setup_ref(setup),
-					select_cb, setup->sep->user_data);
+							codec->data,
+							service->length -
+							sizeof(*codec),
+							setup_ref(setup),
+							select_cb,
+							setup->sep->user_data);
 	if (err == 0)
 		return cb_data->id;
 
diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
index f4c9a2ed8..91b1e4b96 100644
--- a/profiles/audio/avdtp.c
+++ b/profiles/audio/avdtp.c
@@ -3710,6 +3710,11 @@ avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
 	return sep->state;
 }
 
+uint8_t avdtp_sep_get_seid(struct avdtp_local_sep *sep)
+{
+	return sep->info.seid;
+}
+
 struct btd_adapter *avdtp_get_adapter(struct avdtp *session)
 {
 	return device_get_adapter(session->device);
diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h
index b03ca9030..ad2cb9bcb 100644
--- a/profiles/audio/avdtp.h
+++ b/profiles/audio/avdtp.h
@@ -296,6 +296,7 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
 int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep);
 
 avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
+uint8_t avdtp_sep_get_seid(struct avdtp_local_sep *sep);
 
 void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id);
 const char *avdtp_strerror(struct avdtp_error *err);
-- 
2.20.1


  parent reply	other threads:[~2019-05-06 12:43 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-06 12:43 [PATCH v3 1/6] a2dp: Fix crash when endpoint respond with an error Luiz Augusto von Dentz
2019-05-06 12:43 ` [PATCH v3 2/6] a2dp: Try aborting when switching endpoints Luiz Augusto von Dentz
2019-05-06 12:43 ` [PATCH v3 3/6] a2dp: Update last used on open indication Luiz Augusto von Dentz
2019-05-06 12:43 ` [PATCH v3 4/6] a2dp: Fix reconfiguring when there multiple devices connected Luiz Augusto von Dentz
2019-05-06 12:43 ` [PATCH v3 5/6] a2dp: Fix useless statement Luiz Augusto von Dentz
2019-05-06 12:43 ` Luiz Augusto von Dentz [this message]
2019-05-06 12:46   ` [PATCH v3 6/6] a2dp: Reword LastUsed Luiz Augusto von Dentz
2019-05-06 13:02     ` Pali Rohár
2019-05-07  8:52       ` Pali Rohár
2019-05-07 10:13         ` Luiz Augusto von Dentz
2019-05-07 18:57           ` Pali Rohár
2019-06-07 13:04             ` Pali Rohár
2019-06-07 15:18               ` Luiz Augusto von Dentz
2019-06-10 12:35                 ` Pali Rohár
2019-06-10 13:02                   ` Luiz Augusto von Dentz
2019-05-07 10:17 ` [PATCH v3 1/6] a2dp: Fix crash when endpoint respond with an error Luiz Augusto von Dentz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190506124310.19151-6-luiz.dentz@gmail.com \
    --to=luiz.dentz@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).