bluez5: pass global setting dict to codec select_config / preference_cmp

The device is not know at SelectConfiguration time, so the settings
argument in select_config is currently unused. Pass on a global settings
dict instead, so that codec parameters can be configured.

Also add settings argument to caps_preference_cmp.

Bump codec API version.
This commit is contained in:
Pauli Virtanen 2022-06-04 19:01:51 +03:00 committed by Wim Taymans
parent a8eb146d39
commit 92b2b44954
5 changed files with 49 additions and 12 deletions

View file

@ -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, 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 conf1, conf2;
a2dp_lc3plus_hr_t *conf; a2dp_lc3plus_hr_t *conf;

View file

@ -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, 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 conf1, conf2;
a2dp_sbc_t *conf; a2dp_sbc_t *conf;

View file

@ -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, bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id,
const void *caps, size_t caps_size, 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]; uint8_t config[A2DP_MAX_CAPS_SIZE];
int res; int res;
@ -73,7 +74,7 @@ bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id
if (caps == NULL) if (caps == NULL)
return false; 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) if (res < 0)
return false; return false;

View file

@ -43,7 +43,7 @@
#define SPA_TYPE_INTERFACE_Bluez5CodecA2DP SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:A2DP:Private" #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_bluez5_codec_a2dp {
struct spa_interface iface; struct spa_interface iface;
@ -97,7 +97,7 @@ struct a2dp_codec {
int (*select_config) (const struct a2dp_codec *codec, uint32_t flags, int (*select_config) (const struct a2dp_codec *codec, uint32_t flags,
const void *caps, size_t caps_size, 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 *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, int (*enum_config) (const struct a2dp_codec *codec, uint32_t flags,
const void *caps, size_t caps_size, uint32_t id, uint32_t idx, const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
struct spa_pod_builder *builder, struct spa_pod **param); struct spa_pod_builder *builder, struct spa_pod **param);
@ -111,7 +111,8 @@ struct a2dp_codec {
* otherwise not checked beforehand. * otherwise not checked beforehand.
*/ */
int (*caps_preference_cmp) (const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, 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 *(*init_props) (const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings);
void (*clear_props) (void *); 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); uint32_t cap, int preferred_value);
bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, 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 #endif

View file

@ -125,6 +125,10 @@ struct spa_bt_monitor {
struct spa_bt_quirks *quirks; 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. */ /* A reference audio info for A2DP codec configuration. */
struct a2dp_codec_audio_info default_audio_info; 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 * This causes inconsistency with SelectConfiguration() triggered
* by codec switching. * 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 else
res = -ENOTSUP; 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) { spa_list_for_each(ep, &device->remote_endpoint_list, device_link) {
if (a2dp_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len, 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; 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, res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len,
&sw->device->monitor->default_audio_info, &sw->device->monitor->default_audio_info,
sw->device->settings, config); &sw->device->monitor->global_settings, config);
if (res < 0) { if (res < 0) {
spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: incompatible capabilities (%d), try next", spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: incompatible capabilities (%d), try next",
sw, res); 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; 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, 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 */ /* 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_device *d;
struct spa_bt_remote_endpoint *ep; struct spa_bt_remote_endpoint *ep;
struct spa_bt_transport *t; struct spa_bt_transport *t;
const struct spa_dict_item *it;
size_t i; size_t i;
monitor = (struct spa_bt_monitor *) handle; monitor = (struct spa_bt_monitor *) handle;
@ -4339,6 +4346,11 @@ static int impl_clear(struct spa_handle *handle)
monitor->backends[i] = NULL; 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); free((void*)monitor->enabled_codecs.items);
spa_zero(monitor->enabled_codecs); spa_zero(monitor->enabled_codecs);
@ -4475,6 +4487,26 @@ fallback:
return 0; 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 static int
impl_init(const struct spa_handle_factory *factory, impl_init(const struct spa_handle_factory *factory,
struct spa_handle *handle, struct spa_handle *handle,
@ -4568,6 +4600,8 @@ impl_init(const struct spa_handle_factory *factory,
this->backend_selection = BACKEND_NATIVE; this->backend_selection = BACKEND_NATIVE;
get_global_settings(this, info);
if (info) { if (info) {
const char *str; const char *str;
uint32_t tmp; uint32_t tmp;