a2dp: Reword LastUsed
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 6 May 2019 12:39:36 +0000 (15:39 +0300)
committerhimanshu <h.himanshu@samsung.com>
Tue, 11 Feb 2020 08:57:47 +0000 (14:27 +0530)
In addition to storing the remote endpoint also store the local one as
well so we it can properly be restore.

Change-Id: If1716c9ee146fcfd47f9542b00816bbd8326f8c2
Signed-off-by: himanshu <h.himanshu@samsung.com>
profiles/audio/a2dp.c
profiles/audio/avdtp.c
profiles/audio/avdtp.h

index 56f0886..e688e99 100644 (file)
@@ -149,6 +149,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;
@@ -158,7 +163,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;
@@ -224,6 +229,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);
@@ -900,13 +907,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;
 
@@ -918,7 +925,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);
 
@@ -929,21 +936,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;
 
-       chan->last_used = sep;
-       store_last_used(chan, rsep);
+       add_last_used(chan, lsep, sep);
+
+       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,
@@ -965,7 +989,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;
@@ -1000,7 +1024,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);
 
@@ -1575,6 +1599,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);
 }
 
@@ -1723,6 +1748,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 ?
@@ -1963,11 +1991,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)
@@ -1976,12 +2030,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,
@@ -1991,7 +2045,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;
                }
@@ -2000,7 +2054,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;
                        }
                }
@@ -2012,23 +2067,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;
+       }
+
+       sep = queue_find(chan->seps, match_seid, &rseid);
+       if (!sep) {
+               warn("Unable to load LastUsed: rseid %u not found", rseid);
+               return;
+       }
 
-       chan->last_used = queue_find(chan->seps, match_seid, &seid);
+       add_last_used(chan, lsep, sep);
 }
 
 static void load_remote_seps(struct a2dp_channel *chan)
@@ -2576,7 +2647,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;
        }
 
@@ -2587,7 +2657,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;
@@ -2656,7 +2726,8 @@ static struct queue *a2dp_find_eps(struct avdtp *session, GSList *list,
                        seps = queue_new();
 #endif
                /* 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);     
@@ -2735,11 +2806,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);
 
@@ -2825,10 +2903,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;
 
index 94ac61a..6238d7e 100644 (file)
@@ -4271,6 +4271,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);
index d8928ff..e777178 100755 (executable)
@@ -303,6 +303,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);