mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-01-26 06:07:53 +00:00
bluez5/backend-native: Add HFP/HSP hardware offload datapath configuration
Add support for configuring the SCO hardware offload data path for HFP/HSP profiles using the Bluetooth SIG-specified procedure. This enables vendor-specific SCO offload integrations. Changes: - Add `bluez5.hw-offload-datapath` configuration property (default: 0) - Implement `sco_offload_btcodec()` to set BT_CODEC socket option - Add `SPA_BT_FEATURE_HW_OFFLOAD` quirk feature flag - Apply offload configuration when creating SCO sockets if quirk enabled - Document new property in pipewire-props.7.md The datapath ID is configurable via device parameters and only applied when the hardware offload feature flag is set in quirks, allowing platform-specific SCO offload implementations.
This commit is contained in:
parent
35817c0d85
commit
db7c74a042
@ -1171,6 +1171,15 @@ in a platform-specific way. See `tests/examples/bt-pinephone.lua` in WirePlumber
|
||||
Do not enable this setting if you don't know what all this means, as it won't work.
|
||||
\endparblock
|
||||
|
||||
@PAR@ device-param bluez5.hw-offload-datapath # integer
|
||||
\parblock
|
||||
HFP/HSP hardware offload data path ID (default: 0).
|
||||
|
||||
This feature configures the SCO hardware‑offload data path for HFP/HSP using the Bluetooth
|
||||
SIG–specified procedure. It is intended for advanced setups and vendor integrations. Do not
|
||||
edit this unless required; incorrect values can disable SCO offload.
|
||||
\endparblock
|
||||
|
||||
@PAR@ monitor-prop bluez5.a2dp.opus.pro.channels = 3 # integer
|
||||
PipeWire Opus Pro audio profile channel count.
|
||||
|
||||
|
||||
@ -112,6 +112,7 @@ struct impl {
|
||||
int hfp_default_speaker_volume;
|
||||
|
||||
struct spa_source sco;
|
||||
unsigned int hfphsp_sco_datapath;
|
||||
|
||||
const struct spa_bt_quirks *quirks;
|
||||
|
||||
@ -297,6 +298,32 @@ static const struct media_codec *codec_list_best(struct impl *backend, struct sp
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sco_offload_btcodec(struct impl *backend, int sock, bool msbc)
|
||||
{
|
||||
int err;
|
||||
char buffer[255];
|
||||
struct bt_codecs *codecs;
|
||||
|
||||
spa_log_info(backend->log, "%s: sock(%d) msbc(%d)", __func__, sock, msbc);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
codecs = (void *)buffer;
|
||||
if (msbc)
|
||||
codecs->codecs[0].id = 0x05;
|
||||
else
|
||||
codecs->codecs[0].id = 0x02;
|
||||
codecs->num_codecs = 1;
|
||||
codecs->codecs[0].data_path_id = backend->hfphsp_sco_datapath;
|
||||
codecs->codecs[0].num_caps = 0x00;
|
||||
|
||||
err = setsockopt(sock, SOL_BLUETOOTH, BT_CODEC, codecs, sizeof(buffer));
|
||||
if (err < 0)
|
||||
spa_log_error(backend->log, "%s: ERROR: %s (%d)", __func__, strerror(errno), errno);
|
||||
else
|
||||
spa_log_info(backend->log, "%s: set offload codec succeeded", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static DBusHandlerResult profile_release(DBusConnection *conn, DBusMessage *m, void *userdata)
|
||||
{
|
||||
if (!reply_with_error(conn, m, BLUEZ_PROFILE_INTERFACE ".Error.NotImplemented", "Method not implemented"))
|
||||
@ -2564,6 +2591,7 @@ static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapte
|
||||
struct sockaddr_sco addr;
|
||||
socklen_t len;
|
||||
bdaddr_t src;
|
||||
uint32_t bt_features;
|
||||
|
||||
spa_autoclose int sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_SCO);
|
||||
if (sock < 0) {
|
||||
@ -2595,6 +2623,11 @@ static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapte
|
||||
}
|
||||
}
|
||||
|
||||
if (backend->quirks &&
|
||||
(spa_bt_quirks_get_features(backend->quirks, NULL, NULL, &bt_features) == 0) &&
|
||||
((bt_features & (SPA_BT_FEATURE_HW_OFFLOAD)) != 0))
|
||||
sco_offload_btcodec(backend, sock, transparent);
|
||||
|
||||
return spa_steal_fd(sock);
|
||||
}
|
||||
|
||||
@ -4101,6 +4134,18 @@ static void parse_hfp_default_volumes(struct impl *backend, const struct spa_dic
|
||||
backend->hfp_default_speaker_volume = SPA_BT_VOLUME_HS_MAX;
|
||||
}
|
||||
|
||||
static void parse_sco_datapath(struct impl *backend, const struct spa_dict *info)
|
||||
{
|
||||
uint32_t tmp;
|
||||
const char *str;
|
||||
|
||||
backend->hfphsp_sco_datapath = HFP_SCO_DEFAULT_DATAPATH;
|
||||
|
||||
if ((str = spa_dict_lookup(info, "bluez5.hw-offload-datapath")) != NULL &&
|
||||
(tmp = atoi(str)) > 0)
|
||||
backend->hfphsp_sco_datapath = tmp;
|
||||
}
|
||||
|
||||
static const struct spa_bt_backend_implementation backend_impl = {
|
||||
SPA_VERSION_BT_BACKEND_IMPLEMENTATION,
|
||||
.free = backend_native_free,
|
||||
@ -4163,6 +4208,7 @@ struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor,
|
||||
parse_hfp_disable_nrec(backend, info);
|
||||
parse_hfp_default_volumes(backend, info);
|
||||
parse_hfp_pts(backend, info);
|
||||
parse_sco_datapath(backend, info);
|
||||
|
||||
#ifdef HAVE_BLUEZ_5_BACKEND_HSP_NATIVE
|
||||
if (!dbus_connection_register_object_path(backend->conn,
|
||||
|
||||
@ -135,7 +135,8 @@ extern "C" {
|
||||
#define PROFILE_HFP_AG "/Profile/HFPAG"
|
||||
#define PROFILE_HFP_HF "/Profile/HFPHF"
|
||||
|
||||
#define HSP_HS_DEFAULT_CHANNEL 3
|
||||
#define HSP_HS_DEFAULT_CHANNEL 3
|
||||
#define HFP_SCO_DEFAULT_DATAPATH 0
|
||||
|
||||
#define SOURCE_ID_BLUETOOTH 0x1 /* Bluetooth SIG */
|
||||
#define SOURCE_ID_USB 0x2 /* USB Implementer's Forum */
|
||||
@ -809,6 +810,7 @@ enum spa_bt_feature {
|
||||
SPA_BT_FEATURE_SBC_XQ = (1 << 5),
|
||||
SPA_BT_FEATURE_FASTSTREAM = (1 << 6),
|
||||
SPA_BT_FEATURE_A2DP_DUPLEX = (1 << 7),
|
||||
SPA_BT_FEATURE_HW_OFFLOAD = (1 << 8),
|
||||
};
|
||||
|
||||
struct spa_bt_quirks;
|
||||
|
||||
@ -52,6 +52,7 @@ struct spa_bt_quirks {
|
||||
int force_sbc_xq;
|
||||
int force_faststream;
|
||||
int force_a2dp_duplex;
|
||||
int force_hw_offload;
|
||||
|
||||
char *device_rules;
|
||||
char *adapter_rules;
|
||||
@ -69,6 +70,7 @@ static enum spa_bt_feature parse_feature(const char *str)
|
||||
{ "sbc-xq", SPA_BT_FEATURE_SBC_XQ },
|
||||
{ "faststream", SPA_BT_FEATURE_FASTSTREAM },
|
||||
{ "a2dp-duplex", SPA_BT_FEATURE_A2DP_DUPLEX },
|
||||
{ "hw-offload", SPA_BT_FEATURE_HW_OFFLOAD },
|
||||
};
|
||||
SPA_FOR_EACH_ELEMENT_VAR(feature_keys, f) {
|
||||
if (spa_streq(str, f->key))
|
||||
@ -228,6 +230,7 @@ struct spa_bt_quirks *spa_bt_quirks_create(const struct spa_dict *info, struct s
|
||||
this->force_hw_volume = parse_force_flag(info, "bluez5.enable-hw-volume");
|
||||
this->force_faststream = parse_force_flag(info, "bluez5.enable-faststream");
|
||||
this->force_a2dp_duplex = parse_force_flag(info, "bluez5.enable-a2dp-duplex");
|
||||
this->force_hw_offload = parse_force_flag(info, "bluez5.hw-offload-sco");
|
||||
|
||||
if ((str = spa_dict_lookup(info, "bluez5.hardware-database")) != NULL) {
|
||||
spa_log_debug(this->log, "loading session manager provided data");
|
||||
@ -385,6 +388,9 @@ static int get_features(const struct spa_bt_quirks *this,
|
||||
if (this->force_a2dp_duplex != -1)
|
||||
SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_A2DP_DUPLEX, this->force_a2dp_duplex);
|
||||
|
||||
if (this->force_hw_offload != -1)
|
||||
SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_HW_OFFLOAD, this->force_hw_offload);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user