From 84e6845aa68e3f992c3a624f27003e814ef17a21 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Thu, 16 Apr 2026 22:51:51 +0300 Subject: [PATCH] bluez5: add quirk for LC3-24kHz for HFP MT7925 fails to setup a SCO connection that results to working LC3-24kHz audio. Other controllers (Intel etc) appear to work OK. Add quirk for disabling this codec, and disable it for this Mediatek controller. --- spa/plugins/bluez5/backend-native.c | 7 ++++++- spa/plugins/bluez5/bluez-hardware.conf | 4 ++++ spa/plugins/bluez5/defs.h | 1 + spa/plugins/bluez5/quirks.c | 6 ++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index f4bb37995..1cb2235ff 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -904,7 +904,7 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de { int res; bool alt6_ok = true, alt1_ok = true; - bool msbc_alt6_ok = true, msbc_alt1_ok = true; + bool msbc_alt6_ok = true, msbc_alt1_ok = true, lc3_a127_ok = true; uint32_t bt_features; if (device->adapter == NULL) @@ -913,6 +913,7 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de if (backend->quirks && spa_bt_quirks_get_features(backend->quirks, device->adapter, device, &bt_features) == 0) { msbc_alt1_ok = (bt_features & (SPA_BT_FEATURE_MSBC_ALT1 | SPA_BT_FEATURE_MSBC_ALT1_RTL)); msbc_alt6_ok = (bt_features & SPA_BT_FEATURE_MSBC); + lc3_a127_ok = (bt_features & SPA_BT_FEATURE_LC3_A127); } switch (codec) { @@ -922,6 +923,10 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de alt1_ok = msbc_alt1_ok; alt6_ok = msbc_alt6_ok; break; + case SPA_BLUETOOTH_AUDIO_CODEC_LC3_A127: + alt1_ok = false; + alt6_ok = lc3_a127_ok; + break; case SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB: default: /* LC3-SWB has same transport requirements as msbc. diff --git a/spa/plugins/bluez5/bluez-hardware.conf b/spa/plugins/bluez5/bluez-hardware.conf index d08ff0bb9..799f8e795 100644 --- a/spa/plugins/bluez5/bluez-hardware.conf +++ b/spa/plugins/bluez5/bluez-hardware.conf @@ -15,6 +15,7 @@ # sbc-xq "nonstandard" SBC codec setting with better sound quality # faststream FastStream codec support # a2dp-duplex A2DP duplex codec support +# lc3-a127 HFP LC3-24KHz codec support # # Features are disabled with the key "no-features" whose value is an # array of strings in the match rule. @@ -83,6 +84,9 @@ bluez5.features.adapter = [ # Realtek Semiconductor Corp. { bus-type = "usb", vendor-id = "usb:0bda" }, + # Mediatek MT7925, #pipewire-5213 + { bus-type = "usb", vendor-id = "usb:0e8d", product-id = "e025", no-features = [ lc3-a127 ] }, + # Generic USB adapters { bus-type = "usb", no-features = [ msbc-alt1-rtl ] }, diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 24a85a5c9..5e69bb757 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -811,6 +811,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_LC3_A127 = (1 << 8), }; struct spa_bt_quirks; diff --git a/spa/plugins/bluez5/quirks.c b/spa/plugins/bluez5/quirks.c index c4b293e68..23bcec0d4 100644 --- a/spa/plugins/bluez5/quirks.c +++ b/spa/plugins/bluez5/quirks.c @@ -52,6 +52,7 @@ struct spa_bt_quirks { int force_sbc_xq; int force_faststream; int force_a2dp_duplex; + int force_lc3_a127; 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 }, + { "lc3-a127", SPA_BT_FEATURE_LC3_A127 }, }; 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_lc3_a127 = parse_force_flag(info, "bluez5.enable-lc3-a127"); 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_lc3_a127 != -1) + SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_LC3_A127, this->force_lc3_a127); + return 0; }