a2dp: Handle remote SEP disappearing 99/266099/1
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 21 Jan 2021 00:25:09 +0000 (16:25 -0800)
committerdh79pyun <dh79.pyun@samsung.com>
Sun, 7 Nov 2021 22:44:53 +0000 (07:44 +0900)
Some devices (Sony WH-1000XM4) seems to dinamically change its endpoints
depending on the configuration which may leave behind endpoints loaded
from cache that are no longer valid.

gh-issue: https://github.com/bluez/bluez/issues/85

Change-Id: I0e5ac965cc09da7e7d1ac1c554d77d75a0d65e22
Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
profiles/audio/a2dp.c
profiles/audio/avdtp.c
profiles/audio/avdtp.h

index 93d0460..7479683 100644 (file)
@@ -1574,6 +1574,8 @@ static void remote_sep_free(void *data)
 {
        struct a2dp_remote_sep *sep = data;
 
+       avdtp_remote_sep_set_destroy(sep->sep, NULL, NULL);
+
        free(sep->path);
        free(sep);
 }
@@ -1960,6 +1962,14 @@ static const GDBusPropertyTable sep_properties[] = {
        { }
 };
 
+static void remote_sep_destroy(void *user_data)
+{
+       struct a2dp_remote_sep *sep = user_data;
+
+       if (queue_remove(sep->chan->seps, sep))
+               remove_remote_sep(sep);
+}
+
 static void register_remote_sep(void *data, void *user_data)
 {
        struct avdtp_remote_sep *rsep = data;
@@ -1996,6 +2006,8 @@ static void register_remote_sep(void *data, void *user_data)
 
        DBG("Found remote SEP: %s", sep->path);
 
+       avdtp_remote_sep_set_destroy(rsep, sep, remote_sep_destroy);
+
 done:
        queue_push_tail(chan->seps, sep);
 }
index 9298ae1..5ae4501 100644 (file)
@@ -343,8 +343,11 @@ struct avdtp_remote_sep {
        uint8_t media_type;
        struct avdtp_service_capability *codec;
        gboolean delay_reporting;
+       bool discovered;
        GSList *caps; /* of type struct avdtp_service_capability */
        struct avdtp_stream *stream;
+       avdtp_remote_sep_destroy_t destroy;
+       void *user_data;
 };
 
 struct avdtp_local_sep {
@@ -1332,6 +1335,32 @@ static void avdtp_sep_set_state(struct avdtp *session,
                stream_free(stream);
 }
 
+static void sep_free(gpointer data)
+{
+       struct avdtp_remote_sep *sep = data;
+
+       if (sep->destroy)
+               sep->destroy(sep->user_data);
+
+       g_slist_free_full(sep->caps, g_free);
+       g_free(sep);
+}
+
+static void remove_disappeared(void *data, void *user_data)
+{
+       struct avdtp_remote_sep *sep = data;
+       struct avdtp *session = user_data;
+
+       if (sep->discovered)
+               return;
+
+       DBG("seid %d disappeared", sep->seid);
+
+       session->seps = g_slist_remove(session->seps, sep);
+
+       sep_free(sep);
+}
+
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
 void finalize_discovery(struct avdtp *session, int err)
 #else
@@ -1349,6 +1378,9 @@ static void finalize_discovery(struct avdtp *session, int err)
        if (discover->id > 0)
                g_source_remove(discover->id);
 
+       if (!err)
+               g_slist_foreach(session->seps, remove_disappeared, session);
+
        if (discover->cb)
                discover->cb(session, session->seps, err ? &avdtp_err : NULL,
                                                        discover->user_data);
@@ -1373,14 +1405,6 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
        avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
 }
 
-static void sep_free(gpointer data)
-{
-       struct avdtp_remote_sep *sep = data;
-
-       g_slist_free_full(sep->caps, g_free);
-       g_free(sep);
-}
-
 static void remove_disconnect_timer(struct avdtp *session)
 {
        if (!session->dc_timer)
@@ -3199,8 +3223,11 @@ static gboolean avdtp_discover_resp(struct avdtp *session,
 
                sep = find_remote_sep(session->seps, resp->seps[i].seid);
                if (sep && sep->type == resp->seps[i].type &&
-                               sep->media_type == resp->seps[i].media_type)
+                               sep->media_type == resp->seps[i].media_type &&
+                               sep->codec) {
+                       sep->discovered = true;
                        continue;
+               }
 
                if (resp->seps[i].inuse && !stream)
                        continue;
@@ -3212,6 +3239,7 @@ static gboolean avdtp_discover_resp(struct avdtp *session,
                sep->seid = resp->seps[i].seid;
                sep->type = resp->seps[i].type;
                sep->media_type = resp->seps[i].media_type;
+               sep->discovered = true;
 
                memset(&req, 0, sizeof(req));
                req.acp_seid = sep->seid;
@@ -3801,6 +3829,16 @@ struct avdtp_remote_sep *avdtp_register_remote_sep(struct avdtp *session,
        return sep;
 }
 
+void avdtp_remote_sep_set_destroy(struct avdtp_remote_sep *sep, void *user_data,
+                                       avdtp_remote_sep_destroy_t destroy)
+{
+       if (!sep)
+               return;
+
+       sep->user_data = user_data;
+       sep->destroy = destroy;
+}
+
 static gboolean process_discover(gpointer data)
 {
        struct avdtp *session = data;
index b8c2288..6d4c263 100755 (executable)
@@ -229,6 +229,11 @@ struct avdtp_remote_sep *avdtp_register_remote_sep(struct avdtp *session,
                                                        GSList *caps,
                                                        bool delay_reporting);
 
+typedef void (*avdtp_remote_sep_destroy_t)(void *user_data);
+
+void avdtp_remote_sep_set_destroy(struct avdtp_remote_sep *sep, void *user_data,
+                                       avdtp_remote_sep_destroy_t destroy);
+
 uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep);
 
 uint8_t avdtp_get_type(struct avdtp_remote_sep *sep);