mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: pass per-device settings to codec handler, make 'bluez5.sbc-xq-support' a per-device setting
This commit is contained in:
parent
af8272fe08
commit
374180e211
7 changed files with 71 additions and 27 deletions
|
|
@ -707,7 +707,8 @@ static int do_start(struct impl *this)
|
|||
this->codec_data = this->codec->init(this->codec, 0,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
&port->current_format, NULL,
|
||||
&port->current_format,
|
||||
this->transport->device->settings,
|
||||
this->transport->write_mtu);
|
||||
if (this->codec_data == NULL)
|
||||
return -EIO;
|
||||
|
|
|
|||
|
|
@ -569,7 +569,8 @@ static int transport_start(struct impl *this)
|
|||
this->codec_data = this->codec->init(this->codec, 0,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
&port->current_format, NULL,
|
||||
&port->current_format,
|
||||
this->transport->device->settings,
|
||||
this->transport->read_mtu);
|
||||
if (this->codec_data == NULL)
|
||||
return -EIO;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ struct spa_bt_backend {
|
|||
struct spa_source sco;
|
||||
|
||||
struct spa_list rfcomm_list;
|
||||
unsigned int msbc_support_enabled_in_config:1;
|
||||
unsigned int defer_setup_enabled:1;
|
||||
};
|
||||
|
||||
struct transport_data {
|
||||
|
|
@ -90,6 +90,7 @@ struct rfcomm {
|
|||
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
|
||||
unsigned int slc_configured:1;
|
||||
unsigned int codec_negotiation_supported:1;
|
||||
unsigned int msbc_support_enabled_in_config:1;
|
||||
unsigned int msbc_supported_by_hfp:1;
|
||||
enum hfp_hf_state hf_state;
|
||||
unsigned int codec;
|
||||
|
|
@ -336,7 +337,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
This should be done when
|
||||
a) mSBC support is enabled in config file and
|
||||
b) the computers bluetooth adapter supports the necessary transport mode */
|
||||
if ((backend->msbc_support_enabled_in_config == true) &&
|
||||
if ((rfcomm->msbc_support_enabled_in_config == true) &&
|
||||
(device_supports_required_mSBC_transport_modes(backend, rfcomm->device))) {
|
||||
|
||||
/* set the feature bit that indicates AG (=computer) supports codec negotiation */
|
||||
|
|
@ -877,7 +878,7 @@ static void sco_listen_event(struct spa_source *source)
|
|||
}
|
||||
|
||||
spa_log_debug(backend->log, NAME": transport %p: codec=%u", t, t->codec);
|
||||
if (backend->msbc_support_enabled_in_config) {
|
||||
if (backend->defer_setup_enabled) {
|
||||
/* In BT_DEFER_SETUP mode, when a connection is accepted, the listening socket is unblocked but
|
||||
* the effective connection setup happens only on first receive, allowing to configure the
|
||||
* accepted socket. */
|
||||
|
|
@ -950,10 +951,11 @@ static int sco_listen(struct spa_bt_backend *backend)
|
|||
goto fail_close;
|
||||
}
|
||||
|
||||
if (backend->msbc_support_enabled_in_config &&
|
||||
setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &defer, sizeof(defer)) < 0) {
|
||||
if (setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &defer, sizeof(defer)) < 0) {
|
||||
spa_log_warn(backend->log, NAME": Can't enable deferred setup: %s", strerror(errno));
|
||||
goto fail_close;
|
||||
backend->defer_setup_enabled = 0;
|
||||
} else {
|
||||
backend->defer_setup_enabled = 1;
|
||||
}
|
||||
|
||||
spa_log_debug(backend->log, NAME": doing listen");
|
||||
|
|
@ -987,7 +989,7 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
struct spa_bt_backend *backend = userdata;
|
||||
DBusMessage *r;
|
||||
DBusMessageIter it[5];
|
||||
const char *handler, *path;
|
||||
const char *handler, *path, *str;
|
||||
enum spa_bt_profile profile = SPA_BT_PROFILE_NULL;
|
||||
struct rfcomm *rfcomm;
|
||||
struct spa_bt_device *d;
|
||||
|
|
@ -1046,6 +1048,11 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
rfcomm->source.mask = SPA_IO_IN;
|
||||
rfcomm->source.rmask = 0;
|
||||
|
||||
if (d->settings && (str = spa_dict_lookup(d->settings, "bluez5.msbc-support")))
|
||||
rfcomm->msbc_support_enabled_in_config = strcmp(str, "true") == 0 || atoi(str) == 1;
|
||||
else
|
||||
rfcomm->msbc_support_enabled_in_config = false;
|
||||
|
||||
if (profile == SPA_BT_PROFILE_HSP_HS || profile == SPA_BT_PROFILE_HSP_AG) {
|
||||
t = _transport_create(rfcomm);
|
||||
if (t == NULL) {
|
||||
|
|
@ -1066,7 +1073,7 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
This should be done when
|
||||
a) mSBC support is enabled in config file and
|
||||
b) the bluetooth adapter supports the necessary transport mode */
|
||||
if ((backend->msbc_support_enabled_in_config == true) &&
|
||||
if ((rfcomm->msbc_support_enabled_in_config == true) &&
|
||||
(device_supports_required_mSBC_transport_modes(backend, rfcomm->device))) {
|
||||
/* set the feature bit that indicates HF supports codec negotiation */
|
||||
hf_features |= SPA_BT_HFP_HF_FEATURE_CODEC_NEGOTIATION;
|
||||
|
|
@ -1288,9 +1295,9 @@ static int register_profile(struct spa_bt_backend *backend, const char *profile,
|
|||
dbus_message_iter_close_container(&it[1], &it[2]);
|
||||
} else if (strcmp(uuid, SPA_BT_UUID_HFP_AG) == 0) {
|
||||
str = "Features";
|
||||
features = SPA_BT_HFP_SDP_AG_FEATURE_NONE;
|
||||
if (backend->msbc_support_enabled_in_config == true)
|
||||
features |= SPA_BT_HFP_SDP_AG_FEATURE_WIDEBAND_SPEECH;
|
||||
|
||||
/* We announce wideband speech support anyway */
|
||||
features = SPA_BT_HFP_SDP_AG_FEATURE_WIDEBAND_SPEECH;
|
||||
dbus_message_iter_open_container(&it[1], DBUS_TYPE_DICT_ENTRY, NULL, &it[2]);
|
||||
dbus_message_iter_append_basic(&it[2], DBUS_TYPE_STRING, &str);
|
||||
dbus_message_iter_open_container(&it[2], DBUS_TYPE_VARIANT, "q", &it[3]);
|
||||
|
|
@ -1309,9 +1316,9 @@ static int register_profile(struct spa_bt_backend *backend, const char *profile,
|
|||
dbus_message_iter_close_container(&it[1], &it[2]);
|
||||
} else if (strcmp(uuid, SPA_BT_UUID_HFP_HF) == 0) {
|
||||
str = "Features";
|
||||
features = SPA_BT_HFP_SDP_HF_FEATURE_NONE;
|
||||
if (backend->msbc_support_enabled_in_config == true)
|
||||
features |= SPA_BT_HFP_SDP_HF_FEATURE_WIDEBAND_SPEECH;
|
||||
|
||||
/* We announce wideband speech support anyway */
|
||||
features = SPA_BT_HFP_SDP_HF_FEATURE_WIDEBAND_SPEECH;
|
||||
dbus_message_iter_open_container(&it[1], DBUS_TYPE_DICT_ENTRY, NULL, &it[2]);
|
||||
dbus_message_iter_append_basic(&it[2], DBUS_TYPE_STRING, &str);
|
||||
dbus_message_iter_open_container(&it[2], DBUS_TYPE_VARIANT, "q", &it[3]);
|
||||
|
|
@ -1486,7 +1493,6 @@ struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor,
|
|||
uint32_t n_support)
|
||||
{
|
||||
struct spa_bt_backend *backend;
|
||||
const char *str;
|
||||
|
||||
static const DBusObjectPathVTable vtable_profile = {
|
||||
.message_function = profile_handler,
|
||||
|
|
@ -1505,11 +1511,6 @@ struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor,
|
|||
|
||||
spa_list_init(&backend->rfcomm_list);
|
||||
|
||||
if (info && (str = spa_dict_lookup(info, "bluez5.msbc-support")))
|
||||
backend->msbc_support_enabled_in_config = strcmp(str, "true") == 0 || atoi(str) == 1;
|
||||
else
|
||||
backend->msbc_support_enabled_in_config = false;
|
||||
|
||||
if (parse_headset_roles(backend, info) < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
|
|||
|
|
@ -432,6 +432,11 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu
|
|||
|
||||
codec = a2dp_endpoint_to_codec(path);
|
||||
if (codec != NULL)
|
||||
/* FIXME: We can't determine which device the SelectConfiguration()
|
||||
* call is associated with, therefore device settings are not passed.
|
||||
* This causes inconsistency with SelectConfiguration() triggered
|
||||
* by codec switching.
|
||||
*/
|
||||
res = codec->select_config(codec, 0, cap, size, NULL, config);
|
||||
else
|
||||
res = -ENOTSUP;
|
||||
|
|
@ -1856,7 +1861,7 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s
|
|||
goto next;
|
||||
}
|
||||
|
||||
res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, NULL, config);
|
||||
res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, sw->device->settings, config);
|
||||
if (res < 0) {
|
||||
spa_log_debug(sw->device->monitor->log, NAME": a2dp codec switch %p: incompatible capabilities (%d), try next",
|
||||
sw, res);
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@ struct impl {
|
|||
const struct a2dp_codec **supported_codecs;
|
||||
size_t supported_codec_count;
|
||||
|
||||
#define MAX_SETTINGS 32
|
||||
struct spa_dict_item setting_items[MAX_SETTINGS];
|
||||
struct spa_dict setting_dict;
|
||||
|
||||
struct node nodes[2];
|
||||
};
|
||||
|
||||
|
|
@ -1200,10 +1204,20 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
|
|||
static int impl_clear(struct spa_handle *handle)
|
||||
{
|
||||
struct impl *this = (struct impl *) handle;
|
||||
const struct spa_dict_item *it;
|
||||
|
||||
free(this->supported_codecs);
|
||||
if (this->bt_dev)
|
||||
if (this->bt_dev) {
|
||||
this->bt_dev->settings = NULL;
|
||||
spa_hook_remove(&this->bt_dev_listener);
|
||||
}
|
||||
|
||||
spa_dict_for_each(it, &this->setting_dict) {
|
||||
if(it->key)
|
||||
free((void *)it->key);
|
||||
if(it->value)
|
||||
free((void *)it->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1215,6 +1229,24 @@ impl_get_size(const struct spa_handle_factory *factory,
|
|||
return sizeof(struct impl);
|
||||
}
|
||||
|
||||
static const struct spa_dict*
|
||||
filter_bluez_device_setting(struct impl *this, const struct spa_dict *dict)
|
||||
{
|
||||
uint32_t n_items = 0;
|
||||
for (uint32_t i = 0
|
||||
; i < dict->n_items && n_items < SPA_N_ELEMENTS(this->setting_items)
|
||||
; i++)
|
||||
{
|
||||
const struct spa_dict_item *it = &dict->items[i];
|
||||
if (it->key != NULL && strncmp(it->key, "bluez", 5) == 0 && it->value != NULL) {
|
||||
this->setting_items[n_items++] =
|
||||
SPA_DICT_ITEM_INIT(strdup(it->key), strdup(it->value));
|
||||
}
|
||||
}
|
||||
this->setting_dict = SPA_DICT_INIT(this->setting_items, n_items);
|
||||
return &this->setting_dict;
|
||||
}
|
||||
|
||||
static int
|
||||
impl_init(const struct spa_handle_factory *factory,
|
||||
struct spa_handle *handle,
|
||||
|
|
@ -1242,6 +1274,9 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
spa_log_error(this->log, "a device is needed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
this->bt_dev->settings = filter_bluez_device_setting(this, info);
|
||||
|
||||
this->device.iface = SPA_INTERFACE_INIT(
|
||||
SPA_TYPE_INTERFACE_Device,
|
||||
SPA_VERSION_DEVICE,
|
||||
|
|
|
|||
|
|
@ -415,6 +415,8 @@ struct spa_bt_device {
|
|||
struct spa_hook_list listener_list;
|
||||
bool added;
|
||||
|
||||
const struct spa_dict *settings;
|
||||
|
||||
DBusPendingCall *battery_pending_call;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
# Bluez monitor config file #
|
||||
|
||||
properties = {
|
||||
# MSBC is not expected to work on all headset + adapter combinations.
|
||||
#bluez5.msbc-support = true
|
||||
#bluez5.sbc-xq-support = true
|
||||
|
||||
# Enabled headset roles (default: [ hsp_hs hfp_ag ]), this
|
||||
|
|
@ -35,7 +33,8 @@ rules = [
|
|||
actions = {
|
||||
# Actions can update properties on the matched object.
|
||||
update-props = {
|
||||
#device.nick = "My Device"
|
||||
# MSBC is not expected to work on all headset + adapter combinations.
|
||||
#bluez5.msbc-support = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue