From: Archie Pusaka <apusaka@xxxxxxxxxxxx> Sometimes the response of RegisterNotification for volume change event came before we create the transport for the corresponding device. If that happens, we lose the volume information. After the transport is created, the volume is also potentially stuck to an uninitialized invalid value. The property Volume of MediaTransport1 will also be left unaccessible. This patch stores the value of the volume notification response. When the transport is initialized, we try to match the device with the previously stored volume and assign that value instead. Reviewed-by: Howard Chung <howardchung@xxxxxxxxxx> --- profiles/audio/media.c | 17 +---------- profiles/audio/transport.c | 61 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/profiles/audio/media.c b/profiles/audio/media.c index 993ecb3b3..be1ca18ee 100644 --- a/profiles/audio/media.c +++ b/profiles/audio/media.c @@ -1202,27 +1202,12 @@ static uint32_t get_duration(void *user_data) static void set_volume(uint8_t volume, struct btd_device *dev, void *user_data) { struct media_player *mp = user_data; - GSList *l; if (mp->volume == volume) return; mp->volume = volume; - - for (l = mp->adapter->endpoints; l; l = l->next) { - struct media_endpoint *endpoint = l->data; - struct media_transport *transport; - - /* Volume is A2DP only */ - if (endpoint->sep == NULL) - continue; - - transport = find_device_transport(endpoint, dev); - if (transport == NULL) - continue; - - media_transport_update_volume(transport, volume); - } + media_transport_update_device_volume(dev, volume); } static bool media_player_send(struct media_player *mp, const char *name) diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c index a32073380..2fd04dd42 100644 --- a/profiles/audio/transport.c +++ b/profiles/audio/transport.c @@ -56,6 +56,7 @@ #define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1" #define UNINITIALIZED_VOLUME_VALUE 128 +#define PEND_DEVICE_VOLUME_TIMEOUT 1 typedef enum { TRANSPORT_STATE_IDLE, /* Not acquired and suspended */ @@ -116,7 +117,13 @@ struct media_transport { void *data; }; +struct pending_device_volume { + struct btd_device *device; + uint8_t volume; +}; + static GSList *transports = NULL; +static GSList *pending_device_volumes; static const char *state2str(transport_state_t state) { @@ -810,6 +817,52 @@ static void source_state_changed(struct btd_service *service, transport_update_playing(transport, FALSE); } +static uint8_t get_pending_device_volume(struct btd_device *dev) +{ + GSList *l; + + for (l = pending_device_volumes; l; l = l->next) { + struct pending_device_volume *pend = l->data; + + if (pend->device == dev) + return pend->volume; + } + + return UNINITIALIZED_VOLUME_VALUE; +} + +static gboolean remove_pending_device_volume(gpointer user_data) +{ + struct pending_device_volume *pend = user_data; + + pending_device_volumes = g_slist_remove(pending_device_volumes, pend); + g_free(pend); + + return FALSE; +} + +static void add_pending_device_volume(struct btd_device *dev, uint8_t volume) +{ + GSList *l; + struct pending_device_volume *pend; + + for (l = pending_device_volumes; l; l = l->next) { + pend = l->data; + + if (pend->device == dev) { + pend->volume = volume; + return; + } + } + + pend = g_new0(struct pending_device_volume, 1); + pend->device = dev; + pend->volume = volume; + g_timeout_add_seconds(PEND_DEVICE_VOLUME_TIMEOUT, + remove_pending_device_volume, pend); + pending_device_volumes = g_slist_append(pending_device_volumes, pend); +} + static int media_transport_init_source(struct media_transport *transport) { struct btd_service *service; @@ -827,7 +880,7 @@ static int media_transport_init_source(struct media_transport *transport) transport->data = a2dp; transport->destroy = destroy_a2dp; - a2dp->volume = UNINITIALIZED_VOLUME_VALUE; + a2dp->volume = get_pending_device_volume(transport->device); transport->sink_watch = sink_add_state_cb(service, sink_state_changed, transport); @@ -990,9 +1043,13 @@ void media_transport_update_device_volume(struct btd_device *dev, continue; /* Volume is A2DP only */ - if (media_endpoint_get_sep(transport->endpoint)) + if (media_endpoint_get_sep(transport->endpoint)) { media_transport_update_volume(transport, volume); + return; + } } + + add_pending_device_volume(dev, volume); } bool media_transport_volume_valid(uint8_t volume) -- 2.27.0.383.g050319c2ae-goog