From 51b0248d0943880540be4b2b61e7bcfacc01a8cb Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Fri, 26 Mar 2021 18:06:27 +0200 Subject: [PATCH] bluez5: update a2dp codec list when remote endpoints change --- spa/plugins/bluez5/bluez5-dbus.c | 16 ++++++++++++++- spa/plugins/bluez5/bluez5-device.c | 32 ++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index c23c0516e..43b14bc4d 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -2924,6 +2924,7 @@ static void interface_added(struct spa_bt_monitor *monitor, } else if (strcmp(interface_name, BLUEZ_MEDIA_ENDPOINT_INTERFACE) == 0) { struct spa_bt_remote_endpoint *ep; + struct spa_bt_device *d; ep = remote_endpoint_find(monitor, object_path); if (ep == NULL) { @@ -2935,6 +2936,10 @@ static void interface_added(struct spa_bt_monitor *monitor, } } remote_endpoint_update_props(ep, props_iter, NULL); + + d = ep->device; + if (d) + spa_bt_device_emit_profiles_changed(d, d->profiles, d->connected_profiles); } } @@ -2992,8 +2997,12 @@ static void interfaces_removed(struct spa_bt_monitor *monitor, DBusMessageIter * } else if (strcmp(interface_name, BLUEZ_MEDIA_ENDPOINT_INTERFACE) == 0) { struct spa_bt_remote_endpoint *ep; ep = remote_endpoint_find(monitor, object_path); - if (ep != NULL) + if (ep != NULL) { + struct spa_bt_device *d = ep->device; remote_endpoint_free(ep); + if (d) + spa_bt_device_emit_profiles_changed(d, d->profiles, d->connected_profiles); + } } dbus_message_iter_next(&it); @@ -3234,6 +3243,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us } else if (strcmp(iface, BLUEZ_MEDIA_ENDPOINT_INTERFACE) == 0) { struct spa_bt_remote_endpoint *ep; + struct spa_bt_device *d; ep = remote_endpoint_find(monitor, path); if (ep == NULL) { @@ -3244,6 +3254,10 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us spa_log_debug(monitor->log, "Properties changed in remote endpoint %s", path); remote_endpoint_update_props(ep, &it[1], NULL); + + d = ep->device; + if (d) + spa_bt_device_emit_profiles_changed(d, d->profiles, d->connected_profiles); } else if (strcmp(iface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) { struct spa_bt_transport *transport; diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c index 926c81bb0..4ff42e279 100644 --- a/spa/plugins/bluez5/bluez5-device.c +++ b/spa/plugins/bluez5/bluez5-device.c @@ -157,6 +157,16 @@ static const struct a2dp_codec *get_a2dp_codec(enum spa_bluetooth_audio_codec id return NULL; } +static const struct a2dp_codec *get_supported_a2dp_codec(struct impl *this, enum spa_bluetooth_audio_codec id) +{ + const struct a2dp_codec *a2dp_codec = NULL; + size_t i; + for (i = 0; i < this->supported_codec_count; ++i) + if (this->supported_codecs[i]->id == id) + a2dp_codec = this->supported_codecs[i]; + return a2dp_codec; +} + static unsigned int get_hfp_codec(enum spa_bluetooth_audio_codec id) { switch (id) { @@ -572,6 +582,12 @@ static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t pr if (this->switching_codec) return; + if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) { + free(this->supported_codecs); + this->supported_codecs = spa_bt_device_get_supported_a2dp_codecs( + this->bt_dev, &this->supported_codec_count); + } + switch (this->profile) { case DEVICE_PROFILE_OFF: /* Noop */ @@ -584,12 +600,16 @@ static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t pr nodes_changed); break; case DEVICE_PROFILE_A2DP: + if (get_supported_a2dp_codec(this, this->props.codec) == NULL) + this->props.codec = 0; nodes_changed = (connected_change & (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE)); spa_log_debug(this->log, NAME": profiles changed: A2DP nodes changed: %d", nodes_changed); break; case DEVICE_PROFILE_HSP_HFP: + if (spa_bt_device_supports_hfp_codec(this->bt_dev, get_hfp_codec(this->props.codec)) == 0) + this->props.codec = 0; nodes_changed = (connected_change & SPA_BT_PROFILE_HEADSET_HEAD_UNIT); spa_log_debug(this->log, NAME": profiles changed: HSP/HFP nodes changed: %d", nodes_changed); @@ -601,12 +621,6 @@ static void profiles_changed(void *userdata, uint32_t prev_profiles, uint32_t pr emit_nodes(this); } - if (connected_change & SPA_BT_PROFILE_A2DP_SINK) { - free(this->supported_codecs); - this->supported_codecs = spa_bt_device_get_supported_a2dp_codecs( - this->bt_dev, &this->supported_codec_count); - } - this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS; this->params[IDX_Profile].flags ^= SPA_PARAM_INFO_SERIAL; this->params[IDX_EnumProfile].flags ^= SPA_PARAM_INFO_SERIAL; @@ -834,11 +848,7 @@ static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder * name = spa_bt_profile_name(profile); n_sink++; if (codec) { - uint32_t i; - const struct a2dp_codec *a2dp_codec = NULL; - for (i = 0; i < this->supported_codec_count; ++i) - if (codec == this->supported_codecs[i]->id) - a2dp_codec = this->supported_codecs[i]; + const struct a2dp_codec *a2dp_codec = get_supported_a2dp_codec(this, codec); if (a2dp_codec == NULL) { errno = -EINVAL; return NULL;