You are not logged in.
Some time ago, I used Bluetooth configuration through wireplumber in Arch Linux. At that time, I set the codec to LDAC and several possible sampling frequencies. I believe that during the installation, there were configuration files somewhere in /usr/share/wireplumber that could be copied to appropriate directories such as /etc/wireplumber/... Recently, I had to reinstall the system and now wanted to repeat the configuration. However, I can't find those "sample" files that could be copied to /etc/... I found this on the Arch wiki:
Low audio quality on Bluetooth
and:
Changing the allowed sample rate(s) However, I'm not sure if I should configure these files, such as 51-bluez-config.lua, from scratch? I'd like to use aptx adaptive, but it seems it's currently not supported. Can you advise if I'm thinking correctly? Should I simply create a file:
/etc/wireplumber/bluetooth.lua.d/51-bluez-config.lua
And paste into it:
bluez_monitor.properties = {
["bluez5.enable-sbc-xq"] = true,
["bluez5.enable-msbc"] = true,
["bluez5.codecs"] = "[sbc sbc_xq]",
}
?
I'm not sure how to change the frequency.
Offline
lua configs are deprecated and will not work, so you should just use /etc/wireplumber/bluetooth.lua.d/51-bluez-config.conf instead.
see https://pipewire.pages.freedesktop.org/ … properties for the correct properties/syntax
Offline
I am trying to connect FIIO BTR15 to PC with pipewire 1:1.4.9-1 + wireplumber Compiled with libwireplumber 0.5.12. = latest update for Arch.
lua configs are deprecated and will not work, so you should just use /etc/wireplumber/bluetooth.lua.d/51-bluez-config.conf instead.
see https://pipewire.pages.freedesktop.org/ … properties for the correct properties/syntax
Could you please explain how to setup for Bluetooth connection in 2025 default Sample Rate 96K instead 48K - the end goal - while playing 32 bit 192KHz to have at least 96K.
The following options are not working at all:
pw-top shows while playing with mpv 32 bit 192KHz file
R 85 1024 88200 120.8us 212.3us 0.01 0.02 0 F32LE 2 48000 bluez_output.40_ED_98_1C_1D_08.1
R 69 0 88200 51.7us 36.5us 0.00 0.00 0 S32LE 2 192000 + mpv
On BTR15 Display is 48K (but should be 96K). Reasonable to mention that BTR15 shows 96K for the same file when Android phone connected to it with LDAC via Bluetooth. Also pipewire works perfect with FIIO K7 via usb, it setups sample rates accordingly played file. The concreate problem - only with bluetooth constantly 48K :(
CONFIGS (V1 and V2 and even both have tried keeping in both places)
cat /etc/wireplumber/bluetooth.conf.d/51-bluez-config.conf
bluez5.properties = {
["bluez5.ldac-quality"] = "ultra", -- LDAC high-bitrate
["bluez5.preferred-sample-rate"] = 96000, -- request 96kHz internal node rate
["bluez5.preferred-sample-format"] = "S32LE"
}
also SECOND alternative (attempt) in ~/.config/: has no any success.
cat bluetooth.lua.d/10-ldac-quality.conf
-- Force LDAC high/ultra quality for all devices
ldac_quality = "ultra"
cat bluetooth.lua.d/50-bluez-config.conf
properties = {
["node.clock.rate"] = 96000,
["node.clock.allowed-rates"] = {44100,48000,88200,96000,176400,192000},
}
btmon | grep dlen shows dlen 677 (is it ultra and >48K?) but pw-mon only 48K for bluez_output.
bluetoothd[1426331]: < ACL Data TX:.. flags 0x02 dlen 677 #445 [hci0]
Many thanks in advance for help. May be someone could share real working configs for the Bluetooth case or explain the core logic?
Last edited by niam (2025-10-14 02:38:17)
Offline
BT is a fickle protocol, you could well be limited by your BT adapter.
But none of the properties you are using exist according to the documentation that I linked (are those ShitGPT generated? Know you know why you shouldn't listen to ShitGPT).
The equivalent of what you're attempting to do should be
monitor.bluez.properties = {
bluez5.default.rate = 96000
}
monitor.bluez.rules = [
{
matches = [
{
## This matches all bluetooth devices.
device.name = "~bluez_card.*"
}
]
actions = {
update-props = {
bluez5.a2dp.ldac.quality = "hq"
}
}
}
]
since you are not operating on an actual device, you are not going to have node clocks you can manipulate. BT is always some form of conversion.
Last edited by V1del (2025-10-14 15:48:36)
Offline
BT is a fickle protocol, you could well be limited by your BT adapter.
.
Thank you for your reply, but unfortunately it is still like a miracle:
BT Adapter is BT5.0:
lsusb | grep -i bluetooth
Bus 001 Device 007: ID 8087:0aaa Intel Corp. Bluetooth 9460/9560 Jefferson Peak (JfP)
bluetoothctl showController 8C:C6:81:E8:D9:91 (public)
Manufacturer: 0x0002 (2)
Version: 0x0a (10)
Name: HOST
Alias: HOSTALIAS
Class: 0x006c010c (7078156)
Powered: yes
PowerState: on
Discoverable: no
DiscoverableTimeout: 0x00000000 (0)
Pairable: yes
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Handsfree Audio Gateway (0000111f-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: Device Information (0000180a-0000-1000-8000-00805f9b34fb)
UUID: Vendor specific (03b80e5a-ede8-4b33-a751-6ce34ec4c700)
UUID: Handsfree (0000111e-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0554
Discovering: no
Roles: central
Roles: peripheral
Advertising Features:
ActiveInstances: 0x00 (0)
SupportedInstances: 0x06 (6)
SupportedIncludes: tx-power
SupportedIncludes: appearance
SupportedIncludes: local-name
SupportedSecondaryChannels: 1M
SupportedSecondaryChannels: 2M
SupportedCapabilities.MinTxPower: 0xffffffde (-34)
SupportedCapabilities.MaxTxPower: 0x0007 (7)
SupportedCapabilities.MaxAdvLen: 0xfb (251)
SupportedCapabilities.MaxScnRspLen: 0xfb (251)
SupportedFeatures: CanSetTxPower
SupportedFeatures: HardwareOffload
hci0: Primary controller
addr 8C:C6:81:E8:D9:91 version 10 manufacturer 2 class 0x6c010c
supported settings: powered connectable fast-connectable discoverable bondable link-security ssp br/edr le advertising secure-conn debug-keys privacy configuration static-addr phy-configuration wide-band-speech
current settings: powered bondable ssp br/edr le secure-conn wide-band-speech
name h4os
short name
hci0: Configuration options
supported options: public-address
missing options:
version 10 - Means BT 5.1!
Then with even above config:
cat /etc/pipewire/pipewire.conf.d/11-bt.conf
monitor.bluez.properties = {
bluez5.default.rate = 96000
}
monitor.bluez.rules = [
{
matches = [
{
## This matches all bluetooth devices.
device.name = "~bluez_card.*"
}
]
actions = {
update-props = {
bluez5.a2dp.ldac.quality = "hq"
->>>>>>>>> even have tried with extra: bluez5.default.rate = 96000
}
}
}
]
It is still the same story: pactl list sinks
Sink #90
State: RUNNING
->>>>>>>>>>>> Name: bluez_output.40_ED_98_1C_1D_08.1
Description: FIIO BTR15
Driver: PipeWire
->>>>>>>>>>>> Sample Specification: float32le 2ch 48000Hz
Channel Map: front-left,front-right
Owner Module: 4294967295
Mute: no
Volume: front-left: 47841 / 73% / -8.20 dB, front-right: 47841 / 73% / -8.20 dB
balance 0.00
Base Volume: 65536 / 100% / 0.00 dB
Monitor Source: bluez_output.40_ED_98_1C_1D_08.1.monitor
Latency: 0 usec, configured 0 usec
Flags: HARDWARE HW_VOLUME_CTRL DECIBEL_VOLUME LATENCY
Properties:
api.bluez5.address = "40:ED:98:1C:1D:08"
api.bluez5.codec = "ldac"
api.bluez5.profile = "a2dp-sink"
api.bluez5.transport = ""
bluez5.loopback = "false"
card.profile.device = "1"
device.id = "70"
device.routes = "1"
factory.name = "api.bluez5.a2dp.sink"
device.description = "FIIO BTR15"
node.name = "bluez_output.40_ED_98_1C_1D_08.1"
node.pause-on-idle = "false"
priority.driver = "1010"
priority.session = "1010"
spa.object.id = "1"
factory.id = "12"
clock.quantum-limit = "8192"
device.api = "bluez5"
media.class = "Audio/Sink"
media.name = "FIIO BTR15"
node.driver = "true"
port.group = "stream.0"
node.loop.name = "data-loop.0"
library.name = "audioconvert/libspa-audioconvert"
object.id = "81"
object.serial = "90"
client.id = "49"
api.bluez5.class = "0x240418"
api.bluez5.connection = "connected"
api.bluez5.device = ""
api.bluez5.icon = "audio-headphones"
api.bluez5.path = "/org/bluez/hci0/dev_40_ED_98_1C_1D_08"
bluez5.profile = "off"
device.alias = "FIIO BTR15"
device.bus = "bluetooth"
device.form_factor = "headphone"
device.icon_name = "audio-headphones-bluetooth"
device.name = "bluez_card.40_ED_98_1C_1D_08"
device.product.id = "0xffff"
device.string = "40:ED:98:1C:1D:08"
device.vendor.id = "bluetooth:000a"
Ports:
headphone-output: Headphone (type: Headphones, priority: 0, available)
Active Port: headphone-output
Formats:
pcm
pw-top:
R 81 8192 705600 186.6us 470.3us 0.02 0.04 0 F32LE 2 48000 bluez_output.40_ED_98_1C_1D_08.1
R 84 0 705600 44.2us 124.3us 0.00 0.01 0 S32LE 2 705600 + mpv
48000
https://moisescardona.me/enabling-96khz … replumber/ - very good article, but outdated .
Last edited by niam (2025-10-16 02:53:05)
Offline
Digging the topic forward:
In Arch: /usr/share/doc/wireplumber/examples/wireplumber.conf.d/bluetooth.conf - example for wireplumber.
Unfortunately even simplest config: cat ~/.config/wireplumber/wireplumber.conf.d/10-bt.conf
monitor.bluez.properties = {
bluez5.default.rate = 96000
}
does nothing
but, there is 2 thought, which I still have not yet reseached:
Dirrection 1:
The property is only a stub / placeholder in config, not fully wired up in code
1. It may be accepted in config parsing but never actually used in the logic that builds the Bluetooth transport or negotiates sample rate.
2. Codec / transport negotiation logic overrides or ignores it
3. The code that sets up A2DP parameters might insist on using device-advertised rates or enforce a fallback, disregarding an externally configured “default rate.”
4. Quirks / special-case code that forces 48 kHz
There may be code paths detecting certain hardware or limitations and ignoring your override, always falling back to 48000.
Challenge: not clear where and what (logs, traces, etc) to check whether "always falling back to 48000" due hardware, strange, taking into account BT 5.1!
Direction 2: I have even compiled pipewire-git 1.5 and there is there spa section (libs), due wich "hypotetically" above mentioned parameter will be not ignored. It is not certainly clear neither how to enable it nor how to at the same time to debug it. So it didnot help to switch into pipewire 1.5
old school times, "DIY", may be even recompile hardcording instead 48K 96K, not clear what and where to hardcode.
Last edited by niam (2025-10-17 23:44:38)
Offline
./pipewire-git/src/pipewire/spa/plugins/bluez5/bluez5-dbus.c
at bluez5-dbus.c | grep -A4 -B4 default.rate
if ((str = spa_dict_lookup(info, "api.bluez5.connection-info")) != NULL &&
spa_atob(str))
this->connection_info_supported = true;
if ((str = spa_dict_lookup(info, "bluez5.default.rate")) != NULL &&
(tmp = atoi(str)) > 0)
this->default_audio_info.rate = tmp; <------------------- so may be just here to hardcode 96000.
Offline
BT is a fickle protocol, you could well be limited by your BT adapter.
But none of the properties you are using exist according to the documentation that I linked (are those ShitGPT generated? Know you know why you shouldn't listen to ShitGPT).
since you are not operating on an actual device, you are not going to have node clocks you can manipulate. BT is always some form of conversion.
;-) KISS approach is finally a solution or dedicated to old school *nix audiophiles.
So: WORKING! solution for the: current Archlinux: pipewire Compiled with libpipewire 1.4.9 wireplumber Compiled with libwireplumber 0.5.12
cat ~/.config/wireplumber/wireplumber.conf.d/10-bt.conf
monitor.bluez.properties = {
bluez5.default.rate = 96000
bluez5.default.channels = 2
bluez5.roles = [ a2dp_sink a2dp_source bap_sink bap_source]
bluez5.codecs = [ ldac ]
}
PS: what a pitty how not ShitGPT but ShitDOCs are nowadays! or never give up and *GPT will be your slave.
PS2: Meiner Meinung nach: switch from 48000 to 96000 on Audiophileheadphones is very clear recognizable!
R 75 4096 192000 128.0us 370.5us 0.01 0.02 0 F32LE 2 96000 bluez_output.40_ED_98_1C_1D_08.1
R 81 0 192000 26.6us 82.4us 0.00 0.00 0 S32LE 2 192000 + mpv
Important note: Drawback or to improve - this is "hardcoded" 96000 for Bluetooth, if your source is 44100 it means - resampling + may be shitty quality, but my goal was opposite: only hires audiophile sources. So unfortunately no dynamic on the fly changing s_frequency for BT!
Last edited by niam (Yesterday 02:22:50)
Offline
one more update, for the case if you need to connect others headphones: it just setups their frequency downgraded from 96K and in scope of available codecs for them.
cat ~/.config/wireplumber/wireplumber.conf.d/10-bt.conf
monitor.bluez.properties = {
bluez5.default.rate = 96000
bluez5.default.channels = 2
bluez5.roles = [ a2dp_sink a2dp_source bap_sink bap_source]
## Enabled A2DP codecs (default: all).
bluez5.codecs = [ sbc sbc_xq aac ldac aptx aptx_hd aptx_ll aptx_ll_duplex faststream faststream_duplex ]
bluez5.a2dp.ldac.quality = "hq"
}
Offline