From c5b0d6e252a0801ec9869dbeb7bf503d46a98914 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 20 Jan 2021 16:25:09 -0800 Subject: [PATCH] a2dp: Handle remote SEP disappearing 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 --- profiles/audio/a2dp.c | 12 +++++++++++ profiles/audio/avdtp.c | 56 ++++++++++++++++++++++++++++++++++++++++++-------- profiles/audio/avdtp.h | 5 +++++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c index 93d0460..7479683 100644 --- a/profiles/audio/a2dp.c +++ b/profiles/audio/a2dp.c @@ -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); } diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index 9298ae1..5ae4501 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -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; diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h index b8c2288..6d4c263 100755 --- a/profiles/audio/avdtp.h +++ b/profiles/audio/avdtp.h @@ -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); -- 2.7.4