mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: backend-native: use quirks + usb adapter caps for checking msbc
Use the quirks database to check whether to enable MSBC codec for each device. If quirks don't allow ALT1 mode for an USB adapter, check whether the adapter has an usable ALT6 mode and disable MSBC if not.
This commit is contained in:
parent
b57ae8c2a6
commit
5e0b63b149
4 changed files with 157 additions and 22 deletions
|
|
@ -323,6 +323,11 @@ sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option
|
|||
pulseaudio_dep = dependency('libpulse', required : get_option('libpulse'))
|
||||
avahi_dep = dependency('avahi-client', required : get_option('avahi'))
|
||||
|
||||
libusb_dep = dependency('libusb-1.0', required : get_option('libusb'))
|
||||
if libusb_dep.found()
|
||||
cdata.set('HAVE_LIBUSB', 1)
|
||||
endif
|
||||
|
||||
cap_lib = dependency('libcap', required : false)
|
||||
if cap_lib.found()
|
||||
cdata.set('HAVE_LIBCAP', 1)
|
||||
|
|
|
|||
|
|
@ -191,6 +191,10 @@ option('echo-cancel-webrtc',
|
|||
description : 'Enable WebRTC-based echo canceller',
|
||||
type : 'feature',
|
||||
value : 'auto')
|
||||
option('libusb',
|
||||
description: 'Enable code that depends on libusb',
|
||||
type: 'feature',
|
||||
value: 'auto')
|
||||
option('media-session',
|
||||
description: 'Build and install pipewire-media-session',
|
||||
type: 'feature',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/sco.h>
|
||||
|
|
@ -44,6 +47,10 @@
|
|||
|
||||
#include "defs.h"
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
#include <libusb.h>
|
||||
#endif
|
||||
|
||||
#define NAME "native"
|
||||
|
||||
#define PROP_KEY_HEADSET_ROLES "bluez5.headset-roles"
|
||||
|
|
@ -125,7 +132,6 @@ 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;
|
||||
unsigned int hfp_ag_switching_codec:1;
|
||||
unsigned int hfp_ag_initial_codec_setup:2;
|
||||
|
|
@ -413,24 +419,135 @@ static bool rfcomm_hsp_hs(struct spa_source *source, char* buf)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
static bool check_usb_altsetting_6(struct impl *backend, uint16_t vendor_id, uint16_t product_id)
|
||||
{
|
||||
libusb_context *ctx = NULL;
|
||||
struct libusb_config_descriptor *cfg = NULL;
|
||||
libusb_device **devices = NULL;
|
||||
|
||||
ssize_t ndev, idev;
|
||||
int res;
|
||||
bool ok = false;
|
||||
|
||||
if ((res = libusb_init(&ctx)) < 0) {
|
||||
ctx = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ndev = libusb_get_device_list(ctx, &devices)) < 0) {
|
||||
res = ndev;
|
||||
devices = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (idev = 0; idev < ndev; ++idev) {
|
||||
libusb_device *dev = devices[idev];
|
||||
struct libusb_device_descriptor desc;
|
||||
int icfg;
|
||||
|
||||
libusb_get_device_descriptor(dev, &desc);
|
||||
if (vendor_id != desc.idVendor || product_id != desc.idProduct)
|
||||
continue;
|
||||
|
||||
/* Check the device has Bluetooth isoch. altsetting 6 interface */
|
||||
|
||||
for (icfg = 0; icfg < desc.bNumConfigurations; ++icfg) {
|
||||
int iiface;
|
||||
|
||||
if ((res = libusb_get_config_descriptor(dev, icfg, &cfg)) != 0) {
|
||||
cfg = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (iiface = 0; iiface < cfg->bNumInterfaces; ++iiface) {
|
||||
const struct libusb_interface *iface = &cfg->interface[iiface];
|
||||
int ialt;
|
||||
|
||||
for (ialt = 0; ialt < iface->num_altsetting; ++ialt) {
|
||||
const struct libusb_interface_descriptor *idesc = &iface->altsetting[ialt];
|
||||
int iep;
|
||||
|
||||
if (idesc->bInterfaceClass != LIBUSB_CLASS_WIRELESS ||
|
||||
idesc->bInterfaceSubClass != 1 /* RF */ ||
|
||||
idesc->bInterfaceProtocol != 1 /* Bluetooth */ ||
|
||||
idesc->bAlternateSetting != 6)
|
||||
continue;
|
||||
|
||||
for (iep = 0; iep < idesc->bNumEndpoints; ++iep) {
|
||||
const struct libusb_endpoint_descriptor *ep = &idesc->endpoint[iep];
|
||||
if ((ep->bmAttributes & 0x3) == LIBUSB_ENDPOINT_TRANSFER_TYPE_ISOCHRONOUS) {
|
||||
ok = true;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_config_descriptor(cfg);
|
||||
cfg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (cfg)
|
||||
libusb_free_config_descriptor(cfg);
|
||||
if (devices)
|
||||
libusb_free_device_list(devices, 0);
|
||||
if (ctx)
|
||||
libusb_exit(ctx);
|
||||
return ok;
|
||||
|
||||
fail:
|
||||
spa_log_info(backend->log, NAME": failed to acquire USB device info: %d (%s)",
|
||||
res, libusb_strerror(res));
|
||||
ok = false;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
|
||||
static bool device_supports_required_mSBC_transport_modes(
|
||||
struct impl *backend, struct spa_bt_device *device) {
|
||||
bdaddr_t src;
|
||||
uint8_t features[8], max_page = 0;
|
||||
struct hci_dev_info di;
|
||||
int device_id;
|
||||
int sock;
|
||||
bool msbc_ok, msbc_alt1_ok;
|
||||
uint32_t bt_features;
|
||||
|
||||
if (device->adapter == NULL)
|
||||
return false;
|
||||
|
||||
spa_log_debug(backend->log, NAME": Entering function");
|
||||
|
||||
if (backend->quirks && spa_bt_quirks_get_features(backend->quirks, device->adapter, device, &bt_features) == 0) {
|
||||
msbc_ok = bt_features & SPA_BT_FEATURE_MSBC;
|
||||
msbc_alt1_ok = bt_features & (SPA_BT_FEATURE_MSBC_ALT1 | SPA_BT_FEATURE_MSBC_ALT1_RTL);
|
||||
} else {
|
||||
msbc_ok = true;
|
||||
msbc_alt1_ok = true;
|
||||
}
|
||||
|
||||
spa_log_info(backend->log,
|
||||
NAME": bluez-monitor/hardware.conf: msbc:%d msbc-alt1:%d", (int)msbc_ok, (int)msbc_alt1_ok);
|
||||
|
||||
if (!msbc_ok && !msbc_alt1_ok)
|
||||
return false;
|
||||
|
||||
str2ba(device->adapter->address, &src);
|
||||
|
||||
device_id = hci_get_route(&src);
|
||||
|
||||
if (hci_devinfo(device_id, &di) < 0) {
|
||||
spa_log_error(backend->log, NAME": Error getting device info for hci%d: %s (%d)\n",
|
||||
device_id, strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
sock = hci_open_dev(device_id);
|
||||
if (sock < 0) {
|
||||
if (sock < 0) {
|
||||
spa_log_error(backend->log, NAME": Error opening device hci%d: %s (%d)\n",
|
||||
device_id, strerror(errno), errno);
|
||||
return false;
|
||||
|
|
@ -459,11 +576,29 @@ static bool device_supports_required_mSBC_transport_modes(
|
|||
} else {
|
||||
spa_log_info(backend->log,
|
||||
NAME": bluetooth host adapter supports eSCO link and Transparent Data mode" );
|
||||
return true;
|
||||
}
|
||||
|
||||
spa_log_debug(backend->log, NAME": Fallthrough - we should not be here");
|
||||
return false;
|
||||
if ((di.type & 0x0f) == HCI_USB && !msbc_alt1_ok && msbc_ok) {
|
||||
/* Check if USB ALT6 is really available on the device */
|
||||
#if HAVE_LIBUSB
|
||||
if (device->adapter->source_id == SOURCE_ID_USB) {
|
||||
msbc_ok = check_usb_altsetting_6(backend, device->adapter->vendor_id,
|
||||
device->adapter->product_id);
|
||||
} else {
|
||||
msbc_ok = false;
|
||||
}
|
||||
if (!msbc_ok)
|
||||
spa_log_info(backend->log, NAME": bluetooth host adapter does not support USB ALT6");
|
||||
#else
|
||||
spa_log_info(backend->log,
|
||||
NAME": compiled without libusb; can't check if bluetooth adapter has USB ALT6");
|
||||
msbc_ok = false;
|
||||
#endif
|
||||
}
|
||||
if ((di.type & 0x0f) != HCI_USB)
|
||||
msbc_alt1_ok = false;
|
||||
|
||||
return msbc_ok || msbc_alt1_ok;
|
||||
}
|
||||
|
||||
static int codec_switch_start_timer(struct rfcomm *rfcomm, int timeout_msec);
|
||||
|
|
@ -489,11 +624,8 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf)
|
|||
rfcomm->has_volume = (features & SPA_BT_HFP_HF_FEATURE_REMOTE_VOLUME_CONTROL);
|
||||
|
||||
/* Decide if we want to signal that the computer supports mSBC negotiation
|
||||
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 ((rfcomm->msbc_support_enabled_in_config == true) &&
|
||||
(device_supports_required_mSBC_transport_modes(backend, rfcomm->device))) {
|
||||
This should be done when the computers bluetooth adapter supports the necessary transport mode */
|
||||
if (device_supports_required_mSBC_transport_modes(backend, rfcomm->device)) {
|
||||
|
||||
/* set the feature bit that indicates AG (=computer) supports codec negotiation */
|
||||
ag_features |= SPA_BT_HFP_AG_FEATURE_CODEC_NEGOTIATION;
|
||||
|
|
@ -1265,7 +1397,6 @@ static int backend_native_supports_codec(void *data, struct spa_bt_device *devic
|
|||
return (codec == HFP_AUDIO_CODEC_MSBC &&
|
||||
(rfcomm->profile == SPA_BT_PROFILE_HFP_AG ||
|
||||
rfcomm->profile == SPA_BT_PROFILE_HFP_HF) &&
|
||||
rfcomm->msbc_support_enabled_in_config &&
|
||||
rfcomm->msbc_supported_by_hfp &&
|
||||
rfcomm->codec_negotiation_supported) ? 1 : 0;
|
||||
#else
|
||||
|
|
@ -1413,7 +1544,7 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
struct impl *backend = userdata;
|
||||
DBusMessage *r;
|
||||
DBusMessageIter it[5];
|
||||
const char *handler, *path, *str;
|
||||
const char *handler, *path;
|
||||
enum spa_bt_profile profile = SPA_BT_PROFILE_NULL;
|
||||
struct rfcomm *rfcomm;
|
||||
struct spa_bt_device *d;
|
||||
|
|
@ -1483,11 +1614,6 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
spa_loop_add_source(backend->main_loop, &rfcomm->source);
|
||||
spa_list_append(&backend->rfcomm_list, &rfcomm->link);
|
||||
|
||||
if (d->settings && (str = spa_dict_lookup(d->settings, "bluez5.msbc-support")))
|
||||
rfcomm->msbc_support_enabled_in_config = spa_atob(str);
|
||||
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) {
|
||||
|
|
@ -1510,11 +1636,8 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag
|
|||
char *cmd;
|
||||
|
||||
/* Decide if we want to signal that the HF supports mSBC negotiation
|
||||
This should be done when
|
||||
a) mSBC support is enabled in config file and
|
||||
b) the bluetooth adapter supports the necessary transport mode */
|
||||
if ((rfcomm->msbc_support_enabled_in_config == true) &&
|
||||
(device_supports_required_mSBC_transport_modes(backend, rfcomm->device))) {
|
||||
This should be done when the bluetooth adapter supports the necessary transport mode */
|
||||
if (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;
|
||||
rfcomm->msbc_supported_by_hfp = true;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ if fdk_aac_dep.found()
|
|||
endif
|
||||
|
||||
if not get_option('bluez5-backend-hsp-native').disabled() or not get_option('bluez5-backend-hfp-native').disabled()
|
||||
if libusb_dep.found()
|
||||
bluez5_deps += libusb_dep
|
||||
endif
|
||||
bluez5_sources += ['backend-native.c']
|
||||
endif
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue