diff --git a/spa/plugins/bluez5/a2dp-codec-lc3plus.c b/spa/plugins/bluez5/a2dp-codec-lc3plus.c index 6aa06c6a4..40ca0e0db 100644 --- a/spa/plugins/bluez5/a2dp-codec-lc3plus.c +++ b/spa/plugins/bluez5/a2dp-codec-lc3plus.c @@ -151,7 +151,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, } static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info) + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, const struct spa_dict *global_settings) { a2dp_lc3plus_hr_t conf1, conf2; a2dp_lc3plus_hr_t *conf; diff --git a/spa/plugins/bluez5/a2dp-codec-sbc.c b/spa/plugins/bluez5/a2dp-codec-sbc.c index 1bc85914d..35d55355a 100644 --- a/spa/plugins/bluez5/a2dp-codec-sbc.c +++ b/spa/plugins/bluez5/a2dp-codec-sbc.c @@ -230,7 +230,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, } static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info) + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, const struct spa_dict *global_settings) { a2dp_sbc_t conf1, conf2; a2dp_sbc_t *conf; diff --git a/spa/plugins/bluez5/a2dp-codecs.c b/spa/plugins/bluez5/a2dp-codecs.c index c78b2f261..42c7a193c 100644 --- a/spa/plugins/bluez5/a2dp-codecs.c +++ b/spa/plugins/bluez5/a2dp-codecs.c @@ -62,7 +62,8 @@ int a2dp_codec_select_config(const struct a2dp_codec_config configs[], size_t n, bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, const void *caps, size_t caps_size, - const struct a2dp_codec_audio_info *info) + const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings) { uint8_t config[A2DP_MAX_CAPS_SIZE]; int res; @@ -73,7 +74,7 @@ bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id if (caps == NULL) return false; - res = codec->select_config(codec, 0, caps, caps_size, info, NULL, config); + res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config); if (res < 0) return false; diff --git a/spa/plugins/bluez5/a2dp-codecs.h b/spa/plugins/bluez5/a2dp-codecs.h index 4e393df12..90bca0268 100644 --- a/spa/plugins/bluez5/a2dp-codecs.h +++ b/spa/plugins/bluez5/a2dp-codecs.h @@ -43,7 +43,7 @@ #define SPA_TYPE_INTERFACE_Bluez5CodecA2DP SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:A2DP:Private" -#define SPA_VERSION_BLUEZ5_CODEC_A2DP 2 +#define SPA_VERSION_BLUEZ5_CODEC_A2DP 3 struct spa_bluez5_codec_a2dp { struct spa_interface iface; @@ -97,7 +97,7 @@ struct a2dp_codec { int (*select_config) (const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct a2dp_codec_audio_info *info, - const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]); + const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE]); int (*enum_config) (const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *builder, struct spa_pod **param); @@ -111,7 +111,8 @@ struct a2dp_codec { * otherwise not checked beforehand. */ int (*caps_preference_cmp) (const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info); + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings); void *(*init_props) (const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings); void (*clear_props) (void *); @@ -157,6 +158,7 @@ int a2dp_codec_select_config(const struct a2dp_codec_config configs[], size_t n, uint32_t cap, int preferred_value); bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, - const void *caps, size_t caps_size, const struct a2dp_codec_audio_info *info); + const void *caps, size_t caps_size, const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings); #endif diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index 3234de3a3..fcd980a85 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -125,6 +125,10 @@ struct spa_bt_monitor { struct spa_bt_quirks *quirks; +#define MAX_SETTINGS 128 + struct spa_dict_item global_setting_items[MAX_SETTINGS]; + struct spa_dict global_settings; + /* A reference audio info for A2DP codec configuration. */ struct a2dp_codec_audio_info default_audio_info; }; @@ -512,7 +516,8 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu * This causes inconsistency with SelectConfiguration() triggered * by codec switching. */ - res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info, NULL, config); + res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info, + &monitor->global_settings, config); else res = -ENOTSUP; @@ -1584,7 +1589,7 @@ bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struc spa_list_for_each(ep, &device->remote_endpoint_list, device_link) { if (a2dp_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len, - &ep->monitor->default_audio_info)) + &ep->monitor->default_audio_info, &monitor->global_settings)) return true; } @@ -2639,7 +2644,7 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len, &sw->device->monitor->default_audio_info, - sw->device->settings, config); + &sw->device->monitor->global_settings, config); if (res < 0) { spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: incompatible capabilities (%d), try next", sw, res); @@ -2909,7 +2914,8 @@ static int a2dp_codec_switch_cmp(const void *a, const void *b) flags = spa_streq(ep1->uuid, SPA_BT_UUID_A2DP_SOURCE) ? A2DP_CODEC_FLAG_SINK : 0; return codec->caps_preference_cmp(codec, flags, ep1->capabilities, ep1->capabilities_len, - ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info); + ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info, + &sw->device->monitor->global_settings); } /* Ensure there's a transport for at least one of the listed codecs */ @@ -4308,6 +4314,7 @@ static int impl_clear(struct spa_handle *handle) struct spa_bt_device *d; struct spa_bt_remote_endpoint *ep; struct spa_bt_transport *t; + const struct spa_dict_item *it; size_t i; monitor = (struct spa_bt_monitor *) handle; @@ -4339,6 +4346,11 @@ static int impl_clear(struct spa_handle *handle) monitor->backends[i] = NULL; } + spa_dict_for_each(it, &monitor->global_settings) { + free((void *)it->key); + free((void *)it->value); + } + free((void*)monitor->enabled_codecs.items); spa_zero(monitor->enabled_codecs); @@ -4475,6 +4487,26 @@ fallback: return 0; } +static void get_global_settings(struct spa_bt_monitor *this, const struct spa_dict *dict) +{ + uint32_t n_items = 0; + uint32_t i; + + if (dict == NULL) { + this->global_settings = SPA_DICT_INIT(this->global_setting_items, 0); + return; + } + + for (i = 0; i < dict->n_items && n_items < SPA_N_ELEMENTS(this->global_setting_items); i++) { + const struct spa_dict_item *it = &dict->items[i]; + if (spa_strstartswith(it->key, "bluez5.") && it->value != NULL) + this->global_setting_items[n_items++] = + SPA_DICT_ITEM_INIT(strdup(it->key), strdup(it->value)); + } + + this->global_settings = SPA_DICT_INIT(this->global_setting_items, n_items); +} + static int impl_init(const struct spa_handle_factory *factory, struct spa_handle *handle, @@ -4568,6 +4600,8 @@ impl_init(const struct spa_handle_factory *factory, this->backend_selection = BACKEND_NATIVE; + get_global_settings(this, info); + if (info) { const char *str; uint32_t tmp;