diff --git a/doc/dox/config/pipewire-props.7.md b/doc/dox/config/pipewire-props.7.md index ed82b2f41..52ac3e369 100644 --- a/doc/dox/config/pipewire-props.7.md +++ b/doc/dox/config/pipewire-props.7.md @@ -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@ monitor-prop 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. diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index 5c4a2b785..4d14183e7 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -63,6 +63,9 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.bluez5.native"); #define RFCOMM_MESSAGE_MAX_LENGTH 256 +#define BT_CODEC_CVSD 0x02 +#define BT_CODEC_MSBC 0x05 + enum { HFP_AG_INITIAL_CODEC_SETUP_NONE = 0, HFP_AG_INITIAL_CODEC_SETUP_SEND, @@ -112,6 +115,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 +301,33 @@ static const struct media_codec *codec_list_best(struct impl *backend, struct sp return NULL; } +static void sco_offload_btcodec(struct impl *backend, int sock, bool msbc) +{ + int err; + char buffer[255]; + struct bt_codecs *codecs; + + if (backend->hfphsp_sco_datapath == HFP_SCO_DEFAULT_DATAPATH) + return; + + spa_log_info(backend->log, "sock(%d) msbc(%d)", sock, msbc); + + memset(buffer, 0, sizeof(buffer)); + codecs = (void *)buffer; + if (msbc) + codecs->codecs[0].id = BT_CODEC_MSBC; + else + codecs->codecs[0].id = BT_CODEC_CVSD; + codecs->num_codecs = 1; + codecs->codecs[0].data_path_id = backend->hfphsp_sco_datapath; + + err = setsockopt(sock, SOL_BLUETOOTH, BT_CODEC, codecs, sizeof(buffer)); + if (err < 0) + spa_log_error(backend->log, "ERROR: %s (%d)", strerror(errno), errno); + else + spa_log_info(backend->log, "set offload codec succeeded"); +} + static DBusHandlerResult profile_release(DBusConnection *conn, DBusMessage *m, void *userdata) { if (!reply_with_error(conn, m, BLUEZ_PROFILE_INTERFACE ".Error.NotImplemented", "Method not implemented")) @@ -2595,6 +2626,8 @@ static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapte } } + sco_offload_btcodec(backend, sock, transparent); + return spa_steal_fd(sock); } @@ -4101,6 +4134,14 @@ 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) +{ + backend->hfphsp_sco_datapath = HFP_SCO_DEFAULT_DATAPATH; + + spa_atou32(spa_dict_lookup(info, "bluez5.hw-offload-datapath"), + &backend->hfphsp_sco_datapath, 10); +} + static const struct spa_bt_backend_implementation backend_impl = { SPA_VERSION_BT_BACKEND_IMPLEMENTATION, .free = backend_native_free, @@ -4163,6 +4204,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, diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 3efec465a..afc56c920 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -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 */