You are not logged in.
ALSA is not weird, just a bit strange.
The default is:
$ cat /usr/share/alsa/alsa.conf
...
defaults.ctl.card 0
defaults.pcm.card 0
defaults.pcm.device 0But your "card 0" (HDMI) has "device 3", not "0"
card 0: Generic [HD-Audio Generic], device 3: HDMI 0 [S24C650]Post the output of
amixer -c 0
or
amixer -c Generic
HDMI audio devices in ALSA often lack hardware volume controls
So what is the issue with my Behringer card?
It is easy to verify. Unplug Behringer, and run
alsamixerTry alias
cat /sys/class/sound/card*/idalias mixer='alsamixer -c <id of your card>'mixerYou can add it to ~/.bashrc
mousepad ~/.bashrcA brief word of caution for those using AlsaTune or LADSPA plugins to aggressively boost the 10kHz–20kHz range. While the pursuit of "clarity" is tempting, these experiments carry a risk of irreversible biological damage.
Biological Reality: Ears Do Not Forgive
Blasting high frequencies to "see" sound better is the audio equivalent of staring into a laser to improve your vision. Software equalizers are not hearing aids; they lack the dynamic range compression and peak limiters required to prevent acoustic trauma. Cranking these bands simply accelerates the death of remaining hair cells in the cochlea.
The Dementia Connection
Hearing loss is a primary modifiable risk factor for dementia.
Cognitive Load: The brain diverts resources from memory to process sound, leading to accelerated brain aging.
Atrophy: Hearing loss is linked to faster brain shrinkage.
Scaling Risk: Mild loss doubles dementia risk; severe loss can increase it fivefold. Every 10dB drop correlates to a 16% risk increase.
The Verdict
If you must "nuke" your ALSA settings to hear clearly, please stop. You are not fixing your hearing; you are likely hastening permanent silence and cognitive decline. Seek an audiologist. Professional hearing aids mitigate these risks; a raw software EQ does the opposite.
Protect your ears. You only get one pair.
Using a software equalizer to aggressively compensate for hearing loss can potentially exacerbate existing hearing issues. Here's why you might want to consider alternative solutions:
Boosting high frequencies without proper safety mechanisms can increase the overall sound pressure level reaching your ears, which may further damage delicate hair cells in the cochlea.
Blasting the 10kHz to 20kHz range is effectively the audio equivalent of staring directly into a laser to "see better."
Biological Limits: The ears are remarkably unforgiving when subjected to high-intensity high-frequency noise.
Unlike medical hearing aids, software equalizers often lack features like dynamic range compression and peak limiters, which are designed to protect your hearing from sudden loud noises.
Extreme equalization can introduce digital distortion, resulting in an unpleasant listening experience and potentially harmful artifacts.
If you are experiencing hearing loss, consulting with an audiologist or hearing healthcare professional is the best course of action. They can provide a proper diagnosis and recommend safe and effective solutions tailored to your specific needs.
Try to read this:
ALSA software mixer enabled by default in Debian/Devuan
_https://dev1galaxy.org/viewtopic.php?id=7587
_https://dev1galaxy.org/viewtopic.php?id=7605
_https://dev1galaxy.org/viewtopic.php?id=7142
sudo /etc/init.d/alsa-utils force-reloadman alsamixerspeaker-test --channels=2fuser -av $(find /dev/snd -type c 2>/dev/null)inxi -Axxxthis Laptop has dual-boot Windows 10 - Devuan 7.0
...Understand that the Windows 10 has dedicated drivers (Atmos enabled?) and sound very much better;
but does the Linux Audio really need to sound that thin?
One might tentatively suggest that the operating system one uses could, in a rather modest sort of way, have a slight influence on how one thinks — nothing dramatic, mind you, just a small tendency to shape habits, decision-making, and the odd worldview. It’s not as if the thing actively reprograms you, of course. More like it gently nudges one’s approach to problems, file organisation, and the occasional existential crisis over software updates. Entirely unremarkable, really.
Of course. One might observe, with only mild amusement, that when a Windows user encounters a spot of bother with Linux, they often struggle to explain quite what they did — let alone articulate the nature of the problem in a way that makes the faintest bit of sense to anyone trying to help. It’s not their fault, really. They’re simply used to the machine telling them what’s wrong, in that passive-aggressive Windows fashion — “Something happened. We’ll fix it. Probably.” — rather than being expected to read a log file or, heaven forbid, recall what they actually did.
So they’ll say, “It’s broken,” with the same level of detail one might expect from a damp biscuit. No error message, no command entered, just… broken. As if the system itself has taken a turn for the worse and needs a lie down with a cool cloth.
Still, one must be charitable. It’s not their operating system’s fault if it’s never taught them to think.
To use Bluetooth audio effectively on Linux, you must understand how it works. This is not optional. Technical knowledge and genuine comprehension are prerequisites.
The detailed logging system of macOS provides a valuable insight into Bluetooth audio design.
macOS Bluetooth Audio: Complete Annotated Console Log Guide
A Step-by-Step Manual for Understanding How Bluetooth Audio Works on macOS
Test Equipment
Computer: MacBook Air (13-inch, 2018), Bluetooth 4.2
Headphones: Bowers & Wilkins Px7 S2e Bluetooth Wireless Headphones
Operating System: macOS
How to Capture Bluetooth Audio Logs
Step 1: Disconnect Your Bluetooth Headphones
Before you begin, make sure your Bluetooth headphones are disconnected from your Mac. You can do this by:
Clicking the Bluetooth icon in the menu bar (top right corner of your screen)
Finding your headphones in the list
Clicking "Disconnect"
Alternatively, turn off your headphones completely.
Step 2: Open the Console Application
The Console app is macOS's built-in log viewer. It shows you what's happening inside your system in real-time.
Method 1 - Using Terminal:
Open Terminal (Applications → Utilities → Terminal)
Type the following command and press ENTER:
open -a Console.appMethod 2 - Using Finder:
Open Finder
Go to Applications → Utilities
Double-click "Console"
Method 3 - Using Spotlight:
Press Command (⌘) + Space
Type "Console"
Press ENTER
Step 3: Configure the Search Filter
When Console opens, the window will be empty (streaming has not started yet).
Locate the search bar: Look at the top-right corner of the Console window. You'll see a search field.
Type "codec" into the search bar and press ENTER.
Change the filter type: To the left of the word "codec" in the search bar, a dropdown menu will appear. Click it and select "Message" from the list. This tells Console to search only in the message content, not in the entire log entry.
Step 4: Start Streaming Logs
In the center of the Console window toolbar, you'll see a button that says "Start streaming" (or it might show a play icon ▶). Click this button to begin capturing logs in real-time.
The Console is now watching for any system messages that contain the word "codec".
Step 5: Connect Your Bluetooth Headphones
Now, while Console is streaming logs:
Turn on your Bluetooth headphones (or click the Bluetooth menu bar icon and select your headphones to connect)
Wait a few seconds for the connection to complete
You should see log messages appearing in the Console window immediately. These messages show the entire Bluetooth audio negotiation process happening in real-time.
Step 6: Review the Captured Logs
The Console will display several log entries showing how macOS and your headphones negotiate the Bluetooth audio connection. Below is an example log with detailed explanations.
The Log: Line-by-Line Explanation
1. Device Capability Check (48 kHz Support)
default 21:33:05.750639+0100 bluetoothd Bad48KHzCodecs: Disabling 48 KHz - Device is NOT in 48 KHz AAC allowlistWhat's happening: macOS maintains an internal list of Bluetooth devices that have been tested and verified to work properly with 48 kHz audio. The Bowers & Wilkins Px7 S2e is not on this allowlist. Even if the headphones claim they support 48 kHz, macOS won't use it. This is a protective measure against devices with buggy 48 kHz implementations that could cause audio problems.
Result: Audio will be limited to 44.1 kHz (CD quality) instead of 48 kHz.
2. HFP (Hands-Free Profile) Setup - Voice Calls
default 21:33:06.121260+0100 bluetoothd Creating HFPAudioDevice for device EC:66:D1:BF:02:05 with codec: mSBCWhat's happening: While setting up music playback (A2DP profile), macOS simultaneously configures the Hands-Free Profile (HFP) for phone calls, Siri, and voice communication.
Technical details:
Device MAC address: [font=Courier New]EC:66:D1:BF:02:05[/font] (unique identifier for these headphones)
Voice codec: mSBC (modified Sub-Band Codec) - provides wideband speech at 16 kHz for better call quality than older 8 kHz narrowband codecs
Note: This is separate from music quality. Voice calls and music use different Bluetooth profiles and codecs.
3. Voice Codec Parsing (HFP Capabilities)
default 21:33:06.143723+0100 coreaudiod ParseSWCodecs uwbsMono 0, uwbsStereo 0, swbMono 0, swbStereo 0, swbStereoFake 0, mStereoSupported 0What's happening: Core Audio (macOS's audio system) is checking which advanced voice codecs the headphones support. Each "0" means "not supported", "1" would mean "supported".
Codec breakdown:
uwbsMono/uwbsStereo = Ultra-wideband speech (mono/stereo): Not supported (0)
swbMono/swbStereo = Super-wideband speech: Not supported (0)
swbStereoFake = Fake stereo super-wideband: Not supported (0)
mStereoSupported = Stereo voice calls: Not supported (0)
Translation: These headphones only support basic mono voice codecs, not the advanced high-quality or stereo voice features.
4. Available Voice Codecs Summary
default 21:33:06.145067+0100 coreaudiod Codecs available. NBS (CVSD): 1, WBS (mSBC): 1, UWBS (AAC-ELD): 0, mSWB:0, Stereo: 0What's happening: macOS summarizes which voice call codecs are available:
NBS (CVSD) = Narrowband Speech: Supported (1) - Basic 8 kHz voice quality (sounds like an old phone)
WBS (mSBC) = Wideband Speech: Supported (1) - Better 16 kHz voice quality (sounds clearer, like modern mobile phones)
UWBS (AAC-ELD) = Ultra-wideband Speech: Not supported (0) - Premium AAC-based voice codec
mSWB = Modified super-wideband: Not supported (0)
Stereo voice: Not supported (0)
For calls: macOS will use mSBC (wideband) for decent call quality.
5-8. Codec Discovery (A2DP Music Profile)
default 21:33:10.270226+0100 bluetoothd Audio Codec ID VENDOR-SPECIFIC for remote SEID 9
error 21:33:10.471543+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
default 21:33:10.471637+0100 bluetoothd Audio Codec ID VENDOR-SPECIFIC for remote SEID 7
error 21:33:10.607426+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
default 21:33:10.607626+0100 bluetoothd Audio Codec ID VENDOR-SPECIFIC for remote SEID 5
default 21:33:10.743925+0100 bluetoothd Audio Codec ID MPEG-2,4 AAC for remote SEID 3
default 21:33:10.880295+0100 bluetoothd Audio Codec ID SBC for remote SEID 1What's happening: macOS is asking the headphones: "What music codecs do you support?" The headphones respond with a list of available codecs. Each codec has a SEID (Stream Endpoint ID) - think of it as a numbered slot.
The headphones advertise 5 codec endpoints:
SEID 9, 7, 5: Vendor-specific codecs (likely proprietary Bowers & Wilkins audio processing features)
Error messages: These vendor codecs don't follow Apple's expected format correctly, so macOS rejects them as incompatible
SEID 3: AAC (MPEG-2,4 AAC) - Apple's preferred high-quality music codec ✓
SEID 1: SBC (Sub-Band Codec) - The mandatory baseline codec that all Bluetooth audio devices must support ✓
Result: Two usable music codecs: AAC and SBC. macOS will prefer AAC.
9-10. Codec Selection
default 21:33:10.880630+0100 bluetoothd Selected preferred codec AVDTP_CODEC_MPEG_AAC (0x2) out of 5 available endpoints
default 21:33:10.880740+0100 bluetoothd Selected preferred codec AVDTP_CODEC_MPEG_AAC (0x2) out of 5 available endpointsWhat's happening: macOS chooses AAC (codec ID 0x2) as the preferred codec from the 5 available endpoints.
Why twice? This message appears twice, likely confirming the selection for both audio channels or for redundancy.
Why AAC? On macOS, AAC is always preferred over SBC when available because it provides significantly better sound quality at the same bitrate.
11-12. Vendor Codec Rejection (Confirmation)
error 21:33:10.880817+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
error 21:33:10.880892+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific CodecWhat's happening: macOS confirms it's rejecting the malformed vendor-specific codecs from the headphones. These errors are harmless - they just mean the proprietary Bowers & Wilkins features aren't compatible with macOS's expectations.
13. A2DP Stream Configuration (The Main Event!)
default 21:33:11.467514+0100 bluetoothd A2DP configured at 44.1 KHz. Codec: AAC-LC, VBR max: 244 kbps. 1 frames * (12+709) bytes = 721 per RTP (max=879) every 23.22 msWhat's happening: This is the most important line - it shows the final negotiated Bluetooth music stream configuration.
Breaking it down:
A2DP configured at 44.1 KHz: Sample rate is 44.1 kHz (CD quality)
Remember: 48 kHz was disabled earlier because this device isn't on the allowlist
Codec: AAC-LC: Using AAC Low Complexity profile (the standard AAC variant)
VBR max: 244 kbps: Variable Bit Rate with a maximum of 244 kilobits per second
Note: Later logs reveal the actual encoding uses 192 kbps CBR (Constant Bit Rate), so this is just the negotiated maximum ceiling
Frame structure:
1 frame per RTP packet (RTP = Real-time Transport Protocol, the Bluetooth streaming format)
12 bytes = RTP header overhead
709 bytes = AAC-encoded audio data
721 total bytes per packet (12 + 709)
Maximum packet size: 879 bytes (extra headroom for variable bitrate bursts)
Timing: every 23.22 ms
Each packet contains 1024 audio samples
Calculation: 1024 samples ÷ 44,100 samples/second = 0.02322 seconds = 23.22 milliseconds
Translation for non-technical users: Every 23.22 milliseconds (roughly 43 times per second), your Mac sends a small packet of compressed AAC audio data (721 bytes) over Bluetooth to your headphones.
14-18. AAC Encoder Negotiation (Finding the Perfect Settings)
default 21:33:11.486010+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 1, bitrate = 128000, quality (complexity) = 64, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 0 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0What's happening: Core Audio doesn't just blindly use any AAC settings. It intelligently tests multiple encoder configurations to find the optimal balance between quality, latency, and Bluetooth packet size. Think of this as macOS trying on different "outfits" to see which fits best.
Test 1 - High Quality CBR:
srIn/srOut = 44100: Input and output sample rate both 44.1 kHz (no resampling needed - bit-perfect!)
chans = 2: Stereo (2 channels)
bitRateFormat = 1: CBR (Constant Bit Rate)
bitrate = 128000: 128 kbps (kilobits per second)
quality (complexity) = 64: High CPU complexity for better encoding quality (0-127 scale)
VBRQ = -1: VBR Quality setting not used (because this is CBR mode)
speechOptimization = 0: Disabled (music-optimized encoding, not voice-optimized)
packetSizeLimit = 0: No packet size limit in this test
packetBitSizeMin = 0: No minimum packet size
mMaxPacketSize = 1536 bytes: Maximum 1536 bytes per packet
mCodecDelay = 2112: Encoder latency is 2112 samples
Calculation: 2112 ÷ 44,100 = 47.89 milliseconds of encoding delay
drcConfiguration = 0: Dynamic Range Compression disabled
default 21:33:11.490819+0100 coreaudiod ... bitRateFormat = 1, bitrate = 128000, quality (complexity) = 32 ...Test 2 - Medium Quality CBR:
Same as Test 1, but complexity reduced to 32 (medium)
Lower complexity = faster encoding, uses less CPU, slightly lower quality
default 21:33:11.492162+0100 coreaudiod ... bitRateFormat = 3, bitrate = 128000, quality (complexity) = 32 ...Test 3 - VBR Mode:
bitRateFormat = 3: VBR (Variable Bit Rate) - bitrate can fluctuate for better efficiency
128 kbps average
Complexity 32 (medium)
default 21:33:11.493346+0100 coreaudiod ... bitRateFormat = 3, bitrate = 128000, quality (complexity) = 32, VBRQ = -1, ... packetBitSizeMin = 256 (bits) ...Test 4 - VBR with Minimum Packet Constraint:
VBR mode with minimum packet size = 256 bits (32 bytes)
This ensures packets aren't too small, which could waste Bluetooth transmission efficiency
default 21:33:11.494194+0100 coreaudiod ... bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, ... packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits) ...Test 5 - THIS IS THE WINNER! ✓
bitRateFormat = 3: VBR (Variable Bit Rate)
bitrate = 192000: 192 kbps average (significantly higher than the 128 kbps tests)
quality (complexity) = 32: Balanced CPU usage
packetSizeLimit = 5672 bits: Maximum 709 bytes per packet (5672 ÷ 8 = 709)
This matches exactly the "709 bytes" we saw in the bluetoothd configuration!
packetBitSizeMin = 256 bits: Minimum 32 bytes per packet
Why this configuration won:
Higher bitrate (192 kbps) = better sound quality
VBR mode = efficient use of bandwidth (complex music passages get more bits, simple passages use fewer)
Packet size (256-5672 bits) perfectly fits the Bluetooth MTU (Maximum Transmission Unit)
Complexity 32 = good quality without excessive CPU usage
19-23. Encoder Reconfiguration Events
default 21:35:26.865271+0100 coreaudiod ... (same 192 kbps VBR config)
default 21:37:35.865684+0100 coreaudiod ... (same 192 kbps VBR config)
default 21:37:43.660216+0100 coreaudiod ... (same 192 kbps VBR config)
default 21:38:10.692347+0100 coreaudiod ... (same 192 kbps VBR config)
default 21:38:12.218420+0100 coreaudiod ... (same 192 kbps VBR config)
default 21:40:55.879479+0100 coreaudiod ... (same 192 kbps VBR config)What's happening: These log entries show the AAC encoder being reinitialized with the same proven configuration (192 kbps VBR, complexity 32).
When does this happen?
You start or stop music playback
You switch between different audio apps (Spotify → Apple Music → YouTube)
System audio routing changes
Headphones briefly disconnect and reconnect
macOS adjusts audio priorities
Each time, macOS reinitializes the encoder with the same optimal settings it discovered during the initial tests.
Technical Configuration
| Parameter | Value | Explanation |
| ------------------ | ------------ | ---------------------------------------------- |
| Sample Rate | 44.1 kHz | CD quality; 48 kHz disabled (not on allowlist) |
| Codec | AAC-LC | Advanced Audio Coding - Low Complexity |
| Bitrate | 192 kbps CBR | Actually constant despite VBR negotiation |
| Encoder Complexity | 32 (medium) | Balanced CPU vs. quality |
| Frame Size | 1024 samples | 23.22 ms per frame |
| Packet Size | 721 bytes | 12-byte header + 709-byte AAC data |
| Codec Delay | 2112 samples | ~48 ms encoder latency |The Process macOS Follows
Check device allowlist → Disable 48 kHz (device not approved)
Set up voice profile (HFP) → Use mSBC for calls
Discover available codecs → Find AAC and SBC
Select preferred codec → Choose AAC over SBC
Negotiate stream parameters → 44.1 kHz, VBR max 244 kbps
Test encoder configurations → Try 5 different settings
Select optimal configuration → 192 kbps VBR, complexity 32
Stream audio → Send 721-byte packets every 23.22 ms
A Note on Sound Quality
It may be worth noting that, when using the same Bluetooth headphones, the sound quality on macOS is rather better than on Linux. Not enormously so, you understand, but one might say the difference is... perceptible to the discerning ear.
Both systems use AAC encoding over Bluetooth, both operate at 44.1 kHz, and both follow broadly similar technical processes. Yet the macOS implementation does seem to possess a certain refinement in its execution - perhaps in the encoder's architectural elegance, or in the rather more sophisticated manner in which Core Audio handles the signal path.
It's rather like comparing motorcars, really. A Toyota and a Rolls-Royce both have four wheels, an engine, and a steering wheel. Both will convey you from point A to point B. The fundamental principles are identical. Yet one wouldn't claim the experience is quite the same, would one?
The quality, as they say, is in the details of the realisation.
On Linux with BlueALSA:
You cannot force 320 kbps VBR or CBR - the bitrate is negotiated between the system and the headphones
Getting detailed logs like these requires modifying the BlueALSA source code with debug statements and recompiling the daemon
Both 44.1 kHz and 48 kHz are typically available (no allowlist restrictions)
You can request the AAC "afterburner" mode for maximum encoder quality using the [font=Courier New]--aac-afterburner[/font] flag
On macOS:
Logging is built-in via Console.app - no compilation required
The system automatically tests and selects optimal encoder settings
Device allowlists protect against buggy hardware implementations
The Core Audio architecture provides a cleaner signal path
This guide was created by capturing real Bluetooth connection logs and analyzing the internal behavior of macOS's Bluetooth audio stack.
default 21:33:05.750639+0100 bluetoothd Bad48KHzCodecs: Disabling 48 KHz - Device is NOT in 48 KHz AAC allowlist
default 21:33:06.121260+0100 bluetoothd Creating HFPAudioDevice for device EC:66:D1:BF:02:05 with codec: mSBC
default 21:33:06.143723+0100 coreaudiod ParseSWCodecs uwbsMono 0, uwbsStereo 0, swbMono 0, swbStereo 0, swbStereoFake 0, mStereoSupported 0
default 21:33:06.145067+0100 coreaudiod Codecs available. NBS (CVSD): 1, WBS (mSBC): 1, UWBS (AAC-ELD): 0, mSWB:0, Stereo: 0
default 21:33:10.270226+0100 bluetoothd Audio Codec ID VENDOR-SPECIFIC for remote SEID 9
error 21:33:10.471543+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
default 21:33:10.471637+0100 bluetoothd Audio Codec ID VENDOR-SPECIFIC for remote SEID 7
error 21:33:10.607426+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
default 21:33:10.607626+0100 bluetoothd Audio Codec ID VENDOR-SPECIFIC for remote SEID 5
default 21:33:10.743925+0100 bluetoothd Audio Codec ID MPEG-2,4 AAC for remote SEID 3
default 21:33:10.880295+0100 bluetoothd Audio Codec ID SBC for remote SEID 1
default 21:33:10.880630+0100 bluetoothd Selected preferred codec AVDTP_CODEC_MPEG_AAC (0x2) out of 5 available endpoints
default 21:33:10.880740+0100 bluetoothd Selected preferred codec AVDTP_CODEC_MPEG_AAC (0x2) out of 5 available endpoints
error 21:33:10.880817+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
error 21:33:10.880892+0100 bluetoothd Length of AVDTP Codec Info is too short for Apple Vendor-Specific Codec
default 21:33:11.467514+0100 bluetoothd A2DP configured at 44.1 KHz. Codec: AAC-LC, VBR max: 244 kbps. 1 frames * (12+709) bytes = 721 per RTP (max=879) every 23.22 ms
default 21:33:11.486010+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 1, bitrate = 128000, quality (complexity) = 64, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 0 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:33:11.490819+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 1, bitrate = 128000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 0 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:33:11.492162+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 128000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 0 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:33:11.493346+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 128000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 0 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:33:11.494194+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:35:26.865271+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:37:35.865684+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:37:43.660216+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:38:10.692347+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:38:12.218420+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0
default 21:40:55.879479+0100 coreaudiod ACMP4AACBaseEncoder.cpp:692 (0x7fb47f97dc40) @@@@ 'aac ' encoder configuration: srIn = 44100, srOut = 44100, chans = 2, bitRateFormat = 3, bitrate = 192000, quality (complexity) = 32, VBRQ = -1, speechOptimization = 0, packetSizeLimit = 5672 (bits), packetBitSizeMin = 256 (bits), mMaxPacketSize = 1536 (bytes), userBandwidth = 0, delayMode = 0, mCodecDelay = 2112, drcConfiguration = 0, mPrePostFillMask = 0x0An amusing discovery emerged during this research: both the Bowers & Wilkins Px7 S2e and Sennheiser HD 450BT work perfectly well on macOS—they connect, they play audio, users remain blissfully unaware of any limitation. Yet according to macOS's own logs, these devices are not supported. They are excluded from the 48 kHz AAC allowlist, relegated to 44.1 kHz like common peasants.
Which headphones, then, enjoy this privilege? The answer is as predictable as it is illuminating: Beats.
Apple acquired Beats Electronics for $3 billion in 2014. Since then, Beats headphones have shipped with Apple's proprietary wireless chips—the W1, H1, and now H2. These chips are not merely Bluetooth transceivers; they are trusted devices in the macOS ecosystem.
Headphones with H1/W1/H2 chips receive preferential treatment from bluetoothd:
48 kHz AAC support (others are capped at 44.1 kHz)
Likely higher bitrates than standard AAC-LC
Optimized audio pipeline routing
Possibly lower latency
The chips almost certainly maintain persistent encrypted connections, use custom pairing protocols beyond standard Bluetooth, and report extended capabilities that trigger allowlist matching against hardcoded device IDs.
Apple's Rationale
Quality Control – They know their chips handle 48 kHz reliably
Battery & Stability – Guaranteed experience without edge-case failures
Product Differentiation – A tangible reason to buy within the ecosystem
Ecosystem Lock-in – Yet another thread in the web
The goal is transparent: the best Bluetooth audio quality on macOS shall be delivered by Beats headphones and AirPods. The Apple audio engineers are perfectly capable of implementing this. They have simply chosen to do so exclusively for their own products.
The so-called "Bluetooth audiophiles" often insist that Beats are inferior to Sennheiser, Bowers & Wilkins, and their ilk. One might safely disregard such opinions with the same confidence one dismisses the pronouncements of fast food connoisseurs on any cuisine.
Summary
On macOS, you are graciously invited to remain within the Apple ecosystem—that is, to consume Apple products exclusively for optimal functionality.
On Linux, you are similarly encouraged to remain within the Linux ecosystem—that is, to use systemd, PulseAudio, PipeWire, ALSA, and whichever resampler happens to be fashionable this quarter, whether you like them or not.
The difference, modest though it may be, is this: on Linux, it remains possible to remove systemd, PulseAudio, and PipeWire, and enjoy the true freedom—the freedom to trust your senses and your ability to think, to understand and to solve problems.
BlueALSA Configuration
BlueALSA is already configured and ready to use. The ALSA configuration file for BlueALSA is located at:
/usr/share/alsa/alsa.conf.d/20-bluealsa.conf $ dpkg -S /usr/share/alsa/alsa.conf.d/20-bluealsa.conf
bluez-alsa:amd64: /usr/share/alsa/alsa.conf.d/20-bluealsa.confThis file contains optimal default settings that work for most users. These have been carefully selected to deliver the best performance. As audio quality is not a primary concern for Linux developers, you may wish to adjust some of the default settings.
What's Already Configured
The system already defines:
pcm.bluealsa - The main Bluetooth audio device.
ctl.bluealsa - Mixer controls for Bluetooth devices.
Note that pcm.bluealsa is a virtual PCM device, not a full virtual sound card. As such, it does not support direct use of ALSA plugins like dmix, dsnoop, or asym to enable software mixing or concurrent access. BlueALSA PCM devices are designed for direct Bluetooth audio streaming and lack built-in multi-client capabilities — only one application can use the PCM at a time.
Optimal Configuration for AAC codec
Here is the complete optimal configuration for AAC codec. Put this in ~/.asoundrc:
# File: ~/.asoundrc
defaults.pcm.rate_converter "fftrate"
defaults.bluealsa.ctl.extended "yes"
defaults.bluealsa.softvol "off"
defaults.bluealsa.codec "aac"
pcm.!default "bluealsa"What These Settings Do
defaults.pcm.rate_converter "fftrate" - Uses high-quality sample rate conversion
defaults.bluealsa.ctl.extended "yes" - Shows which codec is actually being used
defaults.bluealsa.codec "aac" - Forces AAC codec for best quality
pcm.!default "bluealsa" - Makes Bluetooth audio the system default
If you open alsamixer for the BlueALSA virtual PCM device:
alsamixer -D bluealsayou will see codec controls like:
AAC Codec Enum - Shows the currently selected AAC codec
Volume Mode - Switch between "pass-through" and "software"
Sync - Client delay adjustment
Battery - Device battery level (if supported)
The codec control lets you verify your defaults.bluealsa.codec "aac" setting is working
The following default settings work well and don't need to be changed:
Volume mode: 'pass-through' (uses device's native volume control)
Delay: +0 ms (no extra delay added)
These settings are already optimal for most users.
Important: Do not load aptX or aptX-HD codecs in bluealsad, if you intend to use the AAC codec exclusively.
This ensures only AAC (and mandatory SBC) codecs are available for a2dp playback, as SBC codec cannot be disabled — it is required by the A2DP specification and is always enabled by default in BlueALSA.
To run bluealsad from the terminal, use:
sudo -u bluealsad bluealsad -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c -sbc -c aac -c msbc --aac-afterburner --aac-bitrate=320000 --aac-vbr --aac-true-bps In the init script /etc/init.d/bluealsad, configure the options accordingly:
BA_OPTS="-S -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c -sbc -c aac -c msbc --aac-afterburner --aac-bitrate=320000 --aac-vbr --aac-true-bps"This configuration avoids codec conflicts and ensures reliable AAC usage.
How BlueALSA Handles Sample Rates (Bit Perfect)
BlueALSA does not perform resampling. When sample rate conversion is required (e.g., from DXD to 48 kHz), it is handled by ALSA using the configured resampler — such as fftrate:
$ cat ~/.asoundrc | grep rate
defaults.pcm.rate_converter "fftrate"Since the AAC codec supports both 44.1 kHz and 48 kHz, no resampling is needed, and BlueALSA preserves the original sample rate — a concept often referred to as "bit perfect" in macOS contexts. The default BlueALSA configuration avoids unnecessary audio processing that could degrade sound quality.
When your audio player changes sample rates (e.g., from 48 kHz to 44.1 kHz), BlueALSA automatically renegotiates the connection with the Bluetooth device to match the new rate.
How to configure media applications
Note that it is generally not possible to disable resampling in Chromium-based browsers.
MPV Player
$ cat ~/.config/mpv/mpv.conf
ao=alsa
alsa-resample=yes
alsa-buffer-time=160000
alsa-periods=4Celluloid:
Open the Preferences menu.
Go to the Miscellaneous tab.
Enter mpv command-line options into the "Extra MPV Options" text box:
ao=alsa alsa-resample=yes alsa-buffer-time=160000 alsa-periods=4Audacious:
go to Preferences → Audio → Buffer size
set 2000 ms
aplay and arecord
aplay -F 40000 -B 160000 input.wav
arecord -F 40000 -B 160000 -V mono -f CD output.wavFirefox
about:config
media.mediasource.webm.enabled false
media.cubeb.backend alsa
media.resampling.enabled false
media.cubeb_latency_playback_ms 160Configuration Editor for Firefox
_https://support.mozilla.org/en-US/kb/about-config-editor-firefox
The following is a simplified log of a BlueALSA session, with extraneous lines discreetly removed for clarity.
# COMMAND: Start BlueALSA with AAC codec and debug logging
sudo -u bluealsad bluealsad -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c -sbc -c aac -c msbc --aac-afterburner --aac-bitrate=320000 --aac-vbr --aac-true-bps --loglevel=debug
# DAEMON INITIALIZATION
bluealsad: [31361] D: log.c:701: FDK-AAC encoder capabilities: AAC=[AAC-LC AAC-SCAL DRC ] SBR=[SBR-PS ] DMX=[none]
bluealsad: [31361] D: log.c:701: FDK-AAC decoder capabilities: AAC=[AAC-LC HE-AAC AAC-LD AAC-ELD AAC-SCAL DRC ] SBR=[SBR-HQ SBR-PS ] DMX=[2ch 6ch 8ch ]
bluealsad: [31361] D: storage.c:86: Initializing persistent storage: /var/lib/bluealsa
bluealsad: [31361] D: main.c:707: Starting main dispatching loop
bluealsad: [31361] D: main.c:121: Acquired D-Bus service name: org.bluealsa
bluealsad: [31361] D: bluealsa-dbus.c:404: Registering BlueALSA D-Bus manager: /org/bluealsa
# AAC CODEC DISCOVERY
bluealsad: [31361] D: bluez.c:1271: Adding new Stream End-Point: EC:66:D1:BF:02:05: SNK: AAC
bluealsad: [31361] D: log.c:347: AAC_CODEC: AAC capabilities - Object Type=MPEG2-LC | MPEG4-LC, Sample Rate=8000 Hz | 11025 Hz | 12000 Hz | 16000 Hz | 22050 Hz | 24000 Hz | 32000 Hz | 44100 Hz | 48000 Hz, Channels=Mono | Stereo, VBR=enabled, Bitrate=320000
# AAC CODEC NEGOTIATION
bluealsad: [31361] D: dbus.c:43: Called: org.bluez.MediaEndpoint1.SelectConfiguration() on /org/bluez/hci0/A2DP/AAC/source/1
bluealsad: [31361] D: bluez.c:442: BlueZ endpoint select_configuration called
bluealsad: [31361] D: log.c:347: AAC_CODEC: _CODEC: A2DP peer capabilities - Object Type=MPEG2-LC | MPEG4-LC, Sample Rate=8000 Hz | 11025 Hz | 12000 Hz | 16000 Hz | 22050 Hz | 24000 Hz | 32000 Hz | 44100 Hz | 48000 Hz, Channels=Mono | Stereo, VBR=enabled, Bitrate=320000
bluealsad: [31361] D: a2dp-aac.c:664: AAC configuration_select called
bluealsad: [31361] D: dbus.c:43: Called: org.bluez.MediaEndpoint1.SetConfiguration() on /org/bluez/hci0/A2DP/AAC/source/1
bluealsad: [31361] D: log.c:347: AAC_CODEC: A2DP selected configuration - Object Type=MPEG4-LC, Sample Rate=48000 Hz, Channels=Stereo (2), VBR=enabled, Bitrate=320000
bluealsad: [31361] D: bluez.c:637: A2DP Source (AAC) configured for device EC:66:D1:BF:02:05
bluealsad: [31361] D: bluez.c:640: PCM configuration: channels=2 rate=48000
bluealsad: [31361] D: bluez.c:642: Delay reporting: unsupported
# AUDIO STREAMING SETUP
bluealsad: [31401] D: dbus.c:43: Called: org.bluealsa.PCM1.Open() on /org/bluealsa/hci0/dev_EC_66_D1_BF_02:05/a2dpsrc/sink
bluealsad: [31401] D: ba-transport.c:316: New A2DP transport: 28
bluealsad: [31401] D: ba-transport.c:317: A2DP socket MTU: 28: R:672 W:895
bluealsad: [31361] D: ba-transport.c:1082: Starting transport: A2DP Source (AAC)
bluealsad: [31361] D: ba-transport-pcm.c:287: Created BT socket duplicate: [28]: 29
bluealsad: [31361] D: ba-transport-pcm.c:366: Created new IO thread [ba-a2dp-aac]: A2DP Source (AAC)
bluealsad: [31419] D: a2dp-aac.c:332: AAC_CODEC: Encoder Info - FrameLength=1024, InputChannels=2, MaxOutBufBytes=1536, Delay=1600 samples
bluealsad: [31419] D: a2dp-aac.c:336: AAC_CODEC: Configuration - Bitrate=320000, Afterburner=enabled, VBR=enabled, Quality=VBR
bluealsad: [31419] D: a2dp-aac.c:391: PCM IO loop: START: a2dp_aac_enc_thread: A2DP Source (AAC)
# AAC Frame Monitoring
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=497, Target bitrate=320000
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=496, Target bitrate=320000
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=600, Target bitrate=320000
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=469, Target bitrate=320000 Command Line Options
sudo -u bluealsad bluealsad -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c -sbc -c aac -c msbc --aac-afterburner --aac-bitrate=320000 --aac-vbr --aac-true-bps --loglevel=debugsudo -u bluealsad: Runs the daemon under a dedicated user—nothing excessive, just sound security practice.
-p a2dp-source -p a2dp-sink: Enables bidirectional audio. One might call it thorough.
-p hfp-ag -p hfp-hf: Supports hands-free calling. Useful, if one must.
-c aac: Enables the AAC codec—rather more refined than the alternatives.
--aac-afterburner: Activates Fraunhofer’s quality enhancement. It does its work quietly.
--aac-bitrate=320000: Sets a generous bitrate. One might say it leaves nothing wanting.
--aac-vbr: Prefers variable bit rate—efficient without being showy.
--aac-true-bps: Ensures accurate bit-per-second reporting. A minor detail, but a correct one.
--loglevel=debug: Enables verbose logging. Helpful, if one is inclined to look.
NOTE: To enable debug, you have to compile bluez-alsa with --enable-debug. Then you can run bluealsad daemon with --loglevel=debug.
Security:
./configure --with-bluealsaduser=bluealsad # D-Bus policy files are automatically generated with the correct user permissionsRunning BlueALSA as the bluealsad user is not an indulgence—it is a matter of principle. The daemon operates with minimal privileges, should anything untoward occur.
Least Privilege: The bluealsad user has no unnecessary access. One might say it knows its place.
Systemd Sandboxing: Features such as ProtectSystem=strict and IPAddressDeny=any ensure the service remains discreet.
D-Bus Policy Control: Communication is limited to org.bluealsa. No eavesdropping, no surprises.
Filesystem Confinement: The daemon is restricted to /var/lib/bluealsa. One might call it tidy.
This is not paranoia—it is simply good form.
Daemon Startup Process
# FDK-AAC library capabilities - what audio formats we can encode/decode
bluealsad: [31361] D: log.c:701: FDK-AAC encoder capabilities: AAC=[AAC-LC AAC-SCAL DRC ] SBR=[SBR-PS ] DMX=[none]
bluealsad: [31361] D: log.c:701: FDK-AAC decoder capabilities: AAC=[AAC-LC HE-AAC AAC-LD AAC-ELD AAC-SCAL DRC ] SBR=[SBR-HQ SBR-PS ] DMX=[2ch 6ch 8ch ]EXPLANATION: BlueALSA checks what AAC formats your system supports. The encoder can handle basic AAC-LC and scalable coding, while the decoder supports advanced formats like HE-AAC for better compression.
# System initialization
bluealsad: [31361] D: storage.c:86: Initializing persistent storage: /var/lib/bluealsa
bluealsad: [31361] D: main.c:707: Starting main dispatching loop
bluealsad: [31361] D: main.c:121: Acquired D-Bus service name: org.bluealsa
bluealsad: [31361] D: bluealsa-dbus.c:404: Registering BlueALSA D-Bus manager: /org/bluealsaEXPLANATION: BlueALSA starts up, creates storage for remembering device settings, and registers with the Linux D-Bus system so applications can communicate with it.
AAC Codec Discovery
# Device announces its AAC support
bluealsad: [31361] D: bluez.c:1271: Adding new Stream End-Point: EC:66:D1:BF:02:05: SNK: AAC
bluealsad: [31361] D: log.c:347: AAC_CODEC: AAC capabilities - Object Type=MPEG2-LC | MPEG4-LC, Sample Rate=8000 Hz | 11025 Hz | 12000 Hz | 16000 Hz | 22050 Hz | 24000 Hz | 32000 Hz | 44100 Hz | 48000 Hz, Channels=Mono | Stereo, VBR=enabled, Bitrate=320000EXPLANATION: The Bluetooth device, that is, BT Headphones, EC:66:D1:BF:02:05 tells BlueALSA it supports AAC audio. It can handle many sample rates from 8kHz (voice quality) up to 48kHz (CD quality), supports mono and stereo, and can use Variable Bit Rate for efficient encoding.
AAC Codec Negotiation
# BlueZ asks BlueALSA to select the best AAC configuration
bluealsad: [31361] D: dbus.c:43: Called: org.bluez.MediaEndpoint1.SelectConfiguration() on /org/bluez/hci0/A2DP/AAC/source/1
bluealsad: [31361] D: bluez.c:442: BlueZ endpoint select_configuration called
bluealsad: [31361] D: log.c:347: AAC_CODEC: _CODEC: A2DP peer capabilities - Object Type=MPEG2-LC | MPEG4-LC, Sample Rate=8000 Hz | 11025 Hz | 12000 Hz | 16000 Hz | 22050 Hz | 24000 Hz | 32000 Hz | 44100 Hz | 48000 Hz, Channels=Mono | Stereo, VBR=enabled, Bitrate=320000
bluealsad: [31361] D: a2dp-aac.c:664: AAC configuration_select calledEXPLANATION: The Bluetooth system (BlueZ) asks BlueALSA to choose the best AAC settings. BlueALSA looks at what the device (that is, BT Headphones) supports and selects optimal parameters.
# Final configuration is selected and applied
bluealsad: [31361] D: dbus.c:43: Called: org.bluez.MediaEndpoint1.SetConfiguration() on /org/bluez/hci0/A2DP/AAC/source/1
bluealsad: [31361] D: log.c:347: AAC_CODEC: A2DP selected configuration - Object Type=MPEG4-LC, Sample Rate=48000 Hz, Channels=Stereo (2), VBR=enabled, Bitrate=320000
bluealsad: [31361] D: bluez.c:637: A2DP Source (AAC) configured for device EC:66:D1:BF:02:05
bluealsad: [31361] D: bluez.c:640: PCM configuration: channels=2 rate=48000
bluealsad: [31361] D: bluez.c:642: Delay reporting: unsupportedEXPLANATION: BlueALSA selects the best quality settings: MPEG4-LC at 48kHz stereo with 320kbps VBR. This provides near-CD quality audio. The PCM is configured to match these settings.
Audio Streaming Setup
# Application requests to play audio
bluealsad: [31401] D: dbus.c:43: Called: org.bluealsa.PCM1.Open() on /org/bluealsa/hci0/dev_EC_66_D1_BF_02:05/a2dpsrc/sink
bluealsad: [31401] D: ba-transport.c:316: New A2DP transport: 28
bluealsad: [31401] D: ba-transport.c:317: A2DP socket MTU: 28: R:672 W:895EXPLANATION: An application (like mpv) asks to play audio through the Bluetooth device. BlueALSA creates a transport channel with MTU (Maximum Transmission Unit) settings for efficient data transfer.
# Audio encoding starts
bluealsad: [31361] D: ba-transport.c:1082: Starting transport: A2DP Source (AAC)
bluealsad: [31361] D: ba-transport-pcm.c:287: Created BT socket duplicate: [28]: 29
bluealsad: [31361] D: ba-transport-pcm.c:366: Created new IO thread [ba-a2dp-aac]: A2DP Source (AAC)
bluealsad: [31419] D: a2dp-aac.c:332: AAC_CODEC: Encoder Info - FrameLength=1024, InputChannels=2, MaxOutBufBytes=1536, Delay=1600 samples
bluealsad: [31419] D: a2dp-aac.c:336: AAC_CODEC: Configuration - Bitrate=320000, Afterburner=enabled, VBR=enabled, Quality=VBR
bluealsad: [31419] D: a2dp-aac.c:391: PCM IO loop: START: a2dp_aac_enc_thread: A2DP Source (AAC)
bluealsad: [31361] D: ba-transport-pcm.c:473: PCM resume: 24EXPLANATION: BlueALSA starts the audio encoding process. It creates a dedicated thread for AAC encoding, with 1024-sample frames, 2-channel stereo input, and the afterburner enhancement enabled. The encoder is now ready to convert your audio into AAC format for Bluetooth transmission.
AAC Frame Monitoring
# AAC Frame Monitoring
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=497, Target bitrate=320000
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=496, Target bitrate=320000
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=600, Target bitrate=320000
bluealsad: [31419] D: a2dp-aac.c:419: AAC_CODEC: Frame - Output bytes=469, Target bitrate=320000The AAC frame monitoring shows the real-time encoding efficiency of the Fraunhofer AAC encoder as it processes audio for Bluetooth transmission.
Each line represents one AAC audio frame that has been encoded from PCM audio data. The varying output bytes (469-600) demonstrate the Variable Bit Rate (VBR) encoding at work:
Target bitrate=320000: The configured maximum bitrate of 320 kbps for high-quality audio.
Output bytes variation: Shows VBR efficiency - simpler audio passages use fewer bytes (469), complex passages use more (600)
Real-time monitoring: Each frame is logged as it's encoded in the a2dp_aac_enc_thread (a2dp-aac.c)
The real-time monitoring reveals how AAC intelligently allocates bandwidth based on audio complexity, unlike fixed-bitrate codecs that waste data on simple passages. The afterburner enhancement you enabled further optimizes this process for better audio quality. The frame-by-frame variation is quite normal and indicates the encoder is working rather efficiently, adapting to the musical content as it processes each segment of audio.
The real-time monitoring appears only when --loglevel=debug is enabled
The byte variations are typical for VBR encoding with afterburner enabled
Each frame represents approximately 1024 samples of audio data
The actual transmission rate averages around the target 320 kbps over time
Notes
This simplified log illustrates the full Bluetooth audio pipeline — from daemon startup to active streaming — with a focus on AAC codec negotiation and configuration. It demonstrates how BlueALSA serves as a bridge between Linux applications and Bluetooth audio devices, handling codec discovery, negotiation, and real-time encoding with quiet efficiency.
ALSA configuration for BlueALSA virtual PCM with AAC codec
$ cat ~/.asoundrc
defaults.pcm.rate_converter "fftrate"
defaults.bluealsa.codec "aac"
pcm.!default "bluealsa"BlueALSA Commands
bluealsactl codec $(bluealsactl list-pcms | grep a2dpsrc | head -1) aac$ bluealsactl codec $(bluealsactl list-pcms | grep a2dpsrc | head -1)
Available codecs: SBC AAC
Selected codec: AACBlueALSA preserves the original sample rate when:
The source audio is 44.1kHz or 48kHz (the A2DP mandatory rates)
The Bluetooth receiver supports the same rate
When resampling is needed (e.g., DXD to 48kHz), it is performed by the default ALSA resampler (now fftrate)
Command for Real-Time Sample Rate Monitoring
$ bluecodec
Selected: AAC:40008484e200
MPEG-2,4 AAC <hex:40008484e200> {
Object Type ( MPEG4-LC )
Dynamic Range Control ( false )
Sample Rate ( 48000 Hz )
Channel Mode ( Stereo )
VBR ( true )
Bitrate ( 320000 )
}$ bluecodec
Selected: AAC:40010484e200
MPEG-2,4 AAC <hex:40010484e200> {
Object Type ( MPEG4-LC )
Dynamic Range Control ( false )
Sample Rate ( 44100 Hz )
Channel Mode ( Stereo )
VBR ( true )
Bitrate ( 320000 )
}bluecodec() {
local pcm=$(bluealsactl list-pcms | grep a2dpsrc | head -1)
local codec=$(bluealsactl --verbose codec "$pcm" | grep "Selected codec" | awk '{print $3}')
echo "Selected: $codec"
a2dpconf "$codec"
}Technical Details
BlueALSA preserves native sample rates because the D-Bus API exposes the actual PCM rate property, and the A2DP specification mandates support for 44.1kHz and 48kHz rates . When source and sink support the same rate, no resampling occurs, maintaining optimal audio quality.
The bluecodec function provides real-time visibility into the actual negotiated configuration, showing whether BlueALSA is transmitting at 44.1kHz, 48kHz, or other supported rates based on the codec capabilities and device compatibility.
On Afterburner and CPU Usage
$ man bluealsad | grep afterburner -A2
--aac-afterburner
Enables Fraunhofer AAC afterburner feature, which is a type of analysis by synthesis algorithm. This
feature increases the audio quality at the cost of increased processing power and overall memory con‐
sumption.$ cat bluez-alsa-4.3.1-86/src/ba-config.c | grep ENABLE_AAC -A21
#if ENABLE_AAC
/* There are two issues with the afterburner: a) it uses a LOT of power,
* b) it generates larger payload. These two reasons are good enough to
* not enable afterburner by default. */
.aac_afterburner = false,
/* By default try not to not use the VBR mode. Please note, that for A2DP
* sink the VBR mode might still be used if the connection is initialized
* by a remote BT device. */
.aac_prefer_vbr = false,
/* Do not enable true "bit per second" bit rate by default because it
* violates A2DP AAC specification. */
.aac_true_bps = false,
/* For CBR mode the 220 kbps bitrate should result in an A2DP frame equal
* to 651 bytes. Such frame size should fit within writing MTU of most BT
* headsets, so it will prevent RTP fragmentation which seems not to be
* supported by every BT headset out there. */
.aac_bitrate = 220000,
/* Use newer LATM syntax by default. Please note, that some older BT
* devices might not understand this syntax, so for them it might be
* required to use LATM version 0 (ISO-IEC 14496-3 (2001)). */
.aac_latm_version = 1,
#endifThe BlueALSA documentation suggests the afterburner “uses a LOT of power.” In practice, testing on an Intel Core i3-3220 (2012) shows average CPU usage of 3.47%, peaking at 6% during playback. One might conclude that the concern is, at best, a trifle overblown.
Tested with:
ASUS USB-BT540 Bluetooth 5.4 Dongle Adapter Compatible with Linux
Sennheiser HD 450BT Bluetooth Wireless Headphones
Bowers & Wilkins Px7 S2e Bluetooth Wireless Headphones
Sound Quality
AAC over Bluetooth isn’t Hi-Res by any stretch, but with afterburner and VBR at 320 kbps, it delivers transparent, near-CD quality for most listeners. The afterburner enhances perceptual quality through analysis-by-synthesis — it does work rather well. It won’t satisfy a true audiophile, but for the average person, it’s perfectly acceptable.
With AAC, BlueALSA delivers proper AAC sound quality. If you’re unsure what that means, try it yourself using Firefox and YouTube.
Step 1: Disable WebM support in Firefox (media.mediasource.webm.enabled = false).
Step 2: Play a high-quality AAC audio source, such as:
Robert de Visée – Prélude et Allemande (Jonas Nordberg, theorbo) on YouTube: _https://youtu.be/qeUcGD4rRRc
Reference media files:
Robert de Visée Prélude et Allemande, Jonas Nordberg, theorbo
_https://youtu.be/qeUcGD4rRRc$ youtube-dl -F "https://youtu.be/qeUcGD4rRRc" | grep "audio only" 249 webm audio only audio_quality_low 52k , webm_dash container, opus (48000Hz), 1.81MiB 250 webm audio only audio_quality_low 70k , webm_dash container, opus (48000Hz), 2.43MiB 140 m4a audio only audio_quality_medium 129k , m4a_dash container, mp4a.40.2 (44100Hz), 4.47MiB 251 webm audio only audio_quality_medium 137k , webm_dash container, opus (48000Hz), 4.75MiB$ firefox 2>&1 https://youtu.be/qeUcGD4rRRc Input: 44100 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1764 Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920 Rates: 44100 --> 48000 (J: 0.00%, T: FFT, W: Vorbis) Ok.Naseer Shamma with Master Musicians in Berlin (2023)
_https://youtu.be/GfSeEevp9xo
Naseer Shamma - Oud & Composition
Thanasis Polikadriotis - Bouzouki
Hussein Zahawy - Daf (Bandir)
Ashraf Sharif Khan - Sitar
Jorge Bezzera - Various Percussions
Alex Simu - Clarinet
Emel Bostanci - Kemenche
Firefox settings for better sound quality:
Open about:config
Set media.mediasource.webm.enabled to false to force AAC (m4a) playback on YouTube
Set media.cubeb.backend to alsa for direct audio output on Linux
Disable resampling: set media.resampling.enabled to false
Adjust latency: set media.cubeb_latency_playback_ms to 160 for balanced performance
These settings help Firefox deliver cleaner, more consistent audio, especially when streaming AAC content.
about:configmedia.mediasource.webm.enabled false media.cubeb.backend alsa media.resampling.enabled false media.cubeb_latency_playback_ms 160Configuration Editor for Firefox
_https://support.mozilla.org/en-US/kb/about-config-editor-firefox
Advanced Audio Coding
_https://en.wikipedia.org/wiki/Advanced_Audio_Coding
The FDK-AAC licence
The FDK-AAC codec is open source under a permissive copyright licence that grants broad rights—allowing free redistribution, requiring source availability for binaries, permitting modifications with attribution, and imposing no royalty fees. However, it does not convey patent rights; separate licences are necessary for commercial use.
$ cat fdk-aac/NOTICE
...
AAC-ELD is considered the best-performing full-bandwidth communications codec
by independent studies and is widely deployed. AAC has been standardized by ISO
and IEC as part of the MPEG specifications.BlueALSA Logging: A Modest Affair
BlueALSA's default logging maintains a certain reserve - quite minimal by design, you see. The logging system resides in src/shared/log.c with corresponding declarations in src/shared/log.h
The Current Situation
By default, BlueALSA rather keeps to itself with basic error and warning messages. The debug macros are quite simply disabled in release builds:
#define debug(M, ...) do {} while (0)Rather tidy, though perhaps not terribly informative when things go awry.
Adding Comprehensive Logging
Should one wish for more verbose output, it's really not such a tremendous undertaking. The framework is already there - one merely
needs to sprinkle debug() statements about the codebase:
debug("Transport state changed: %s", state_name);
debug("Codec negotiation: %s selected", codec_name);The debug system handles the niceties - thread safety, priority filtering, and rather useful timestamps when built with --enable-debug-time.
A Matter of Compilation
Of course, one must remember to compile with debugging support:
./configure --enable-debug
makeQuite straightforward, really. The system then provides rather detailed output including file locations, thread IDs, and relative timing .
Notes
The understated approach to default logging keeps BlueALSA rather quiet in normal operation, though the comprehensive debug framework means adding detailed logging is merely a matter of adding a few well-placed statements here and there. Not terribly difficult, as these things go.
If nobody wants to maintain it, it's not needed.
If nobody can maintain it, it doesn't make sense.
Right, so the bluez-alsa packages in the official Devuan repository were built with --enable-systemd, which means they’ve picked up a systemd dependency — a bit of an oversight, really, given Devuan’s init-agnostic stance.
To address this, the packages were unpacked, the dependency manually adjusted, and then repackaged. They’ll install without complaint, though they might not function perfectly in the absence of systemd. It’s not ideal, but it’s a pragmatic fix.
The method used is a known workaround, documented here:
_https://dev1galaxy.org/viewtopic.php?id=7157
1. The package is not needed.
2. It is easy to compile.
The Devuan consumer community want to consume knowledge rather than packages. You should not keep them in ignorance.
Knowledge and only knowledge liberates, and absolute knowledge liberates absolutely.
Isaiah Berlin, Four Essays on Liberty (1969).
Download sourcedir:
mkdir BUILD3 && cd BUILD3 git clone https://github.com/arkq/bluez-alsa.git cd bluez-alsa && export DEBFULLNAME="John Frum" Install a template:
dh_make --createorig -p bluez-alsa_4.3.1-86 -c apache -e my@mail.org -s 1. debian/control
If you have libfreeaptx-dev installed, replace "libfreeaptx" with "libfreeaptx-dev" in Build-Depends. If you compiled libfreeaptx from git, leave it as is.
$ cat debian/control
Source: bluez-alsa
Section: libs
Priority: optional
Maintainer: John Frum <my@mail.org>
Rules-Requires-Root: no
Build-Depends:
debhelper-compat (= 13),
dh-exec,
libasound2-dev,
libbluetooth-dev (>= 5.0),
libdbus-1-dev (>= 1.6),
libfdk-aac-dev,
libfreeaptx,
libglib2.0-dev (>= 2.30),
libsbc-dev (>= 1.2),
liblc3-dev,
libldacbt-enc-dev (>= 2.0.0) [!hppa !m68k !powerpc !ppc64 !s390x !sparc64],
libldacbt-abr-dev (>= 2.0.0) [!hppa !m68k !powerpc !ppc64 !s390x !sparc64],
libmp3lame-dev,
libmpg123-dev,
libspandsp-dev,
libopus-dev,
libbsd-dev,
libreadline-dev,
check,
dbus-daemon <!nocheck>,
python3-docutils,
pkgconf
Standards-Version: 4.6.2
Homepage: https://github.com/Arkq/bluez-alsa
#Vcs-Browser: https://salsa.debian.org/debian/bluez-alsa
#Vcs-Git: https://salsa.debian.org/debian/bluez-alsa.git
Package: bluez-alsa
Architecture: linux-any
Multi-Arch: same
Section: libs
Depends:
${shlibs:Depends},
${misc:Depends},
Conflicts: bluez-alsa-utils, libasound2-plugin-bluez
Provides: bluez-alsa-utils (= 4.3.1-86-1), libasound2-plugin-bluez (= 4.3.1-86-1)
Replaces: bluez-alsa-utils, libasound2-plugin-bluez
Description: Bluetooth Audio ALSA Backend
Bluetooth Audio ALSA Backend allows bluetooth audio without PulseAudio and PipeWire.
This package provides sysVinit script for bluealsad daemon to run it without systemd.
.
This project is a rebirth of a direct integration between Bluez and ALSA.
Since Bluez >= 5, the build-in integration has been removed in favor of 3rd
party audio applications. From now on, Bluez acts as a middleware between an
audio application, which implements Bluetooth audio profile, and a Bluetooth
audio device.2. debian/rules
$ cat debian/rules
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable).
# Output every command that modifies files on the build system.
#export DH_VERBOSE = 1
# See FEATURE AREAS in dpkg-buildflags(1).
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# See ENVIRONMENT in dpkg-buildflags(1).
# Package maintainers to append CFLAGS.
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
# Package maintainers to append LDFLAGS.
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
%:
dh $@ --with autoreconf
# dh_make generated override targets.
# This is an example for Cmake (see <https://bugs.debian.org/641051>).
#override_dh_auto_configure:
# dh_auto_configure -- \
# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
override_dh_auto_configure:
dh_auto_configure -- --prefix=/usr --sysconfdir=/etc --with-bluealsaduser=bluealsad --enable-ldac --with-libfreeaptx --enable-aptx --enable-aptx-hd --enable-faststream --enable-lc3-swb --enable-mp3lame --enable-mpg123 --enable-msbc --enable-ofono --enable-midi --enable-opus --enable-upower --enable-rfcomm --enable-a2dpconf --enable-hcitop --enable-test --enable-aac --enable-manpages --disable-systemd
override_dh_installinit:
dh_installinit --name=bluealsad
override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
3. debian/bluez-alsa.bluealsad.init
$ cat cat debian/bluez-alsa.bluealsad.init
cat: cat: No such file or directory
#!/bin/sh
### BEGIN INIT INFO
# Provides: bluealsa
# Required-Start: dbus $syslog $local_fs $remote_fs bluetooth
# Required-Stop: dbus $syslog $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: BlueALSA daemon
# Description: Bluetooth ALSA audio daemon
### END INIT INFO
. /lib/lsb/init-functions
NAME=bluealsad
DESC="BlueALSA daemon"
DAEMON=/usr/bin/$NAME
PIDFILE="/var/run/$NAME.pid"
STORAGE_DIR="/var/lib/bluealsa"
USER="bluealsad"
COMMON_OPTS="--quiet --oknodo --pidfile $PIDFILE"
# Working configuration without low-quality HSP codecs
BA_OPTS="-S -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c sbc -c aac -c mp3 -c aptx -c aptx-hd -c faststream -c opus -c msbc -c lc3-swb -c ldac --aac-afterburner --aac-bitrate=320000 --aac-vbr"
# Ensure bluealsad user exists and has correct group membership
if ! id $USER >/dev/null 2>&1; then
# Create user if it doesn't exist
useradd -r -s /bin/false $USER
usermod -a -G audio $USER
else
# User exists, check if in audio group
if ! id -nG $USER | grep -qw audio; then
usermod -a -G audio $USER
fi
fi
# Ensure storage directory exists with correct ownership
if [ ! -d "$STORAGE_DIR" ]; then
mkdir -p "$STORAGE_DIR"
chown $USER:$USER "$STORAGE_DIR"
chmod 0700 "$STORAGE_DIR"
else
# Directory exists, check ownership
CURRENT_OWNER=$(stat -c "%U:%G" "$STORAGE_DIR")
if [ "$CURRENT_OWNER" != "$USER:$USER" ]; then
chown $USER:$USER "$STORAGE_DIR"
chmod 0700 "$STORAGE_DIR"
fi
fi
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
start-stop-daemon $COMMON_OPTS --start --background \
--make-pidfile --chuid $USER --exec $DAEMON -- $BA_OPTS
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
start-stop-daemon $COMMON_OPTS --stop --retry 5
log_end_msg $?
;;
restart|force-reload)
$0 stop
$0 start
;;
status)
status_of_proc $DAEMON "$NAME" || exit $?
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0chmod +x debian/bluez-alsa.bluealsad.init Create Debian source package
dpkg-source -b . Build Debian package
dpkg-buildpackage -us -uc $ cd .. && ls -1 *.deb
bluez-alsa_4.3.1-86-1_amd64.deb
bluez-alsa-dbgsym_4.3.1-86-1_amd64.deb Install
sudo dpkg -i bluez-alsa_4.3.1-86-1_amd64.deb In bureaucratic terms, you have a complete Debian package upload set or package release bundle:
$ ls -1 bluez-alsa bluez-alsa_4.3.1-86-1_amd64.buildinfo bluez-alsa_4.3.1-86-1_amd64.changes bluez-alsa_4.3.1-86-1_amd64.deb bluez-alsa_4.3.1-86-1.debian.tar.xz bluez-alsa_4.3.1-86-1.dsc bluez-alsa_4.3.1-86.orig.tar.xz bluez-alsa-dbgsym_4.3.1-86-1_amd64.debThis includes:
Source files (.dsc, .orig.tar.xz, .debian.tar.xz)
Binary packages (.deb)
Debug symbols (.dbgsym.deb)
Build metadata (.buildinfo)
Changes file (.changes) — the key control file listing all others
The .changes file defines the full set, used by Debian archive tools (like dak) to process uploads into a repository.
Configure the bluealsad service to start automatically at system boot
sudo update-rc.d bluealsad defaults $ sudo service bluealsad restart
Stopping BlueALSA daemon: bluealsad.
Starting BlueALSA daemon: bluealsad. $ sudo service bluealsad status
bluealsad is running. See also:
_https://dev1galaxy.org/viewtopic.php?id=7671
Ah, the --with-bluealsaduser=bluealsad option — very sensible. Lets you run the daemon as a dedicated user, which is ever so slightly less daft than letting it run as root. Keeps things tidy, limits the carnage if something goes wrong. Think of it as giving your Bluetooth audio a sensible hat and a laminated badge — still can’t stop it from misbehaving entirely, but at least it’s not running the whole show.
If you don’t specify a user, it defaults to root, which works — until it doesn’t. And when used with older BlueZ versions (≤ 5.50), just make sure your chosen user’s in the "bluetooth" group, or it’ll sulk and refuse to connect. Nothing dramatic — just typical Linux passive aggression.
There is, one might say, a slight oversight in the Debian bluez-alsa package: it runs as root, which is a bit like giving the keys to the house to someone just to borrow the kettle. Should a flaw exist — and history suggests they often do — it could be exploited with elevated consequences.
The good news? This doesn’t affect Devuan at all. The package simply doesn’t work without systemd, so it sits there, harmless and inert — like a very quiet paperweight.
So while Debian’s setup is perhaps more trusting than strictly necessary, Devuan users are, by design, not involved in the drama.
What is the spec of your headset, is there something like this:
- Bluetooth codecs
- aptX™ Adaptive
aptX™ HD
aptX™
AAC
SBC
- Bluetooth profiles
- A2DP
AVRCP
HFP
Debian default is low quality SBC codec.
With aptX codec, sound quality is much better.
libfreeaptx is outdated in the oldstable
_https://tracker.debian.org/pkg/libfreeaptx
git version;
$ freeaptxdec --help
aptX decoder utility 0.2.2 (using libfreeaptx 0.2.2)
This utility decodes aptX or aptX HD audio stream
from stdin to a raw 24 bit signed stereo on stdout the Debian source of bluez-alsa is outdated
_https://tracker.debian.org/pkg/bluez-alsa
The git version is now v4.3.1-86-gf1e53d3. It means that 86 bugs were fixed. In any case, everything was compiled.
All codecs available for Linux were compiled and enabled.
$ bluealsactl status
Service: org.bluealsa
Version: v4.3.1-86-gf1e53d3
Adapters: hci0
Profiles:
A2DP-source : SBC MP3 AAC aptX aptX-HD FastStream LDAC Opus
A2DP-sink : SBC MP3 AAC aptX aptX-HD FastStream Opus
HFP-AG : CVSD mSBC LC3-SWB
HFP-HF : CVSD mSBC LC3-SWBhsp codecs are not loaded with init script. They are of low quality: 8kHz sample rate.
The question is: which codecs are supported by your BT headphones?
What is your spec?
Sennheiser HD 450BT does have aptX-HD, but it has aptX
Specifications:
Bluetooth profiles: AVRCP, A2DP, HFP, HSP
Bluetooth Audio Codecs: AptX, AptX Low Latency, AAC, SBC
$ bluealsa-aplay -L
bluealsa:DEV=80:C3:BA:8B:B6:CC,PROFILE=sco,SRV=org.bluealsa
HD 450BT, trusted audio-headphones, playback
SCO (mSBC): S16_LE 1 channel 16000 Hz
bluealsa:DEV=80:C3:BA:8B:B6:CC,PROFILE=sco,SRV=org.bluealsa
HD 450BT, trusted audio-headphones, capture
SCO (mSBC): S16_LE 1 channel 16000 Hz
bluealsa:DEV=80:C3:BA:8B:B6:CC,PROFILE=a2dp,SRV=org.bluealsa
HD 450BT, trusted audio-headphones, playback
A2DP (aptX): S16_LE 2 channels 48000 HzSennheiser HDB 630
_https://www.sennheiser-hearing.com/en-DE/p/hdb-630/
Specifications
Codec support
aptX™ Adaptive™, aptX™ HD, aptX™, AAC, SBC
Enjoy high resolution with support for aptX™ HD and aptX™ Adaptive, especially when paired with the included BTD 700 Bluetooth® USB C Dongle
For the purest signal, connect via USB C or analog input for lossless listening at up to 24 bit/96 kHz.
_https://www.sennheiser-hearing.com/en-DE/p/hdb-630/
Bowers & Wilkins Px7 S2e Bluetooth Wireless Headphones
_https://www.bowerswilkins.com/en-gb/product/over-ear-headphones/px7-s2e/FP44520P.html#specifications
Specifications
Bluetooth codecs
aptX™ Adaptive
aptX™ HD
aptX™
AAC
SBC
SBC is a basic low quality codec.
aptX Adaptive is not available for Linux.
AAC in BlueALSA uses the fdk-aac library from Fraunhofer IIS, which is not completely free software.
The fdk-aac library is under Fraunhofer license which:
Is free for non-commercial use
Requires licensing for commercial applications
Has patent encumbrances in some countries
You may try high quality options: --aac-afterburner --aac-bitrate=320000 --aac-true-bps
# without -c aptx -c aptx-hd
BA_OPTS="-S -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c sbc -c aac -c mp3 -c faststream -c opus -c msbc -c lc3-swb -c ldac --aac-afterburner --aac-bitrate=320000 --aac-true-bps"AAC codec supports 8 kHz to 96 kHz including 44.1kHz and 48kHz.
While BlueALSA's automatic selection is limited to 48kHz, the codecs themselves support higher rates. For example, AAC supports up to 96kHz.
You can manually select higher sample rates using:
bluealsactl codec -r96000 PCM_PATH aacbluealsactl list-pcmsSennheiser HD 450BT does not support 96kHz sample rate with AAC codec, but it has analog audio cable with 3.5mm jack plug. It is much better than any Bluetooth codec.
It was compiled with --enable-systemd (see: debian/rules )
I have already recompiled the Debian source package.
It is outdated, and the codecs are outdated.
The git version is much better.
It does not seem to contain any init script.
I have already enabled the stable repository:
$ apt source bluez-alsa-utils
Reading package lists... Done
Picking 'bluez-alsa' as source package instead of 'bluez-alsa-utils'
NOTICE: 'bluez-alsa' packaging is maintained in the 'Git' version control system at:
https://salsa.debian.org/bluetooth-team/bluez-alsa.git
Please use:
git clone https://salsa.debian.org/bluetooth-team/bluez-alsa.git
to retrieve the latest (possibly unreleased) updates to the package.
Need to get 257 kB of source archives.
Get:1 http://deb.devuan.org/merged stable/main bluez-alsa 4.3.1-3 (dsc) [2,528 B]
Get:2 http://deb.devuan.org/merged stable/main bluez-alsa 4.3.1-3 (tar) [249 kB]
Get:3 http://deb.devuan.org/merged stable/main bluez-alsa 4.3.1-3 (diff) [6,076 B]
Fetched 257 kB in 0s (764 kB/s)
dpkg-source: info: extracting bluez-alsa in bluez-alsa-4.3.1
dpkg-source: info: unpacking bluez-alsa_4.3.1.orig.tar.xz
dpkg-source: info: unpacking bluez-alsa_4.3.1-3.debian.tar.xzThe source package is from Debian repository, configured for systemd.
bluez-alsa-utils_4.3.1-3_amd64.debwas compiled for systemd, it does not have any init script inside.
_https://pkginfo.devuan.org/cgi-bin/package-query.html?c=package&q=bluez-alsa-utils=4.3.1-3.1
Package: bluez-alsa-utils
Version: 4.3.1-3.1
Installed-Size: 521
Maintainer: Debian Bluetooth Maintainers <team+pkg-bluetooth@tracker.debian.org>Content
/etc/alsa/conf.d/20-bluealsa.conf
/etc/default/bluez-alsa
/usr/bin/a2dpconf
/usr/bin/bluealsa-aplay
/usr/bin/bluealsa-cli
/usr/bin/bluealsa-rfcomm
/usr/bin/bluealsa
/usr/bin/hcitop
/usr/lib/systemd/system/bluealsa-aplay.service
/usr/lib/systemd/system/bluealsa.service
/usr/share/dbus-1/system.d/bluealsa.conf
/usr/share/doc/bluez-alsa-utils/changelog.Debian.gz
/usr/share/doc/bluez-alsa-utils/copyright
/usr/share/man/man1/bluealsa-aplay.1.gz
/usr/share/man/man1/bluealsa-cli.1.gz
/usr/share/man/man1/bluealsa-rfcomm.1.gz
/usr/share/man/man1/hcitop.1.gz
/usr/share/man/man8/bluealsa.8.gz
It should look like this:
/etc/init.d/bluealsaIn the git version, it is already renamed to "bluealsad"
https://pkginfo.devuan.org/cgi-bin/poli … .68.126.15
An error occurred while reading CGI reply (no response received)Can you post URL of the source package?
BlueALSA is a Bluetooth audio ALSA backend that allows the use of Bluetooth-connected audio devices without the use of PulseAudio or PipeWire.
_https://wiki.debian.org/Bluetooth/Alsa
It's not entirely beyond the wit of the average person to compile BlueALSA without systemd and manage a basic init script.
Step 1: Compile libfreeaptx codec from git.
Step 2: Compile bluez-alsa from git.Tested on Devuan 5 Daedalus:
$ inxi -Sxxx System: Host: devuan Kernel: 6.1.0-41-amd64 arch: x86_64 bits: 64 compiler: gcc v: 12.2.0 Desktop: MATE v: 1.26.0 info: mate-panel wm: marco v: 1.26.1 vt: 7 dm: LightDM v: 1.26.0 Distro: Devuan GNU/Linux 5 (daedalus)
Install compilers, packaging tools, and other useful utilities:
sudo apt-get install build-essential fakeroot git sed awk apt-file command-not-found1. Compile libfreeaptx
Remove the outdated version of libfreeaptx
apt --simulate remove freeaptx-utils libfreeaptx-dev libfreeaptx0sudo apt remove freeaptx-utils libfreeaptx-dev libfreeaptx0This will remove gstreamer1.0-plugins-bad and sayonara, if they are installed. You can reinstall them later if needed.
Create a build directory:
mkdir BUIL1 && cd BUILD1Clone the repository:
git clone https://github.com/regularhunter/libfreeaptx.gitCompile:
$ cd libfreeaptx && makeInstall to ../debdir, that is, BUILD1/debdir
$ make PREFIX=/usr DESTDIR="$(dirname $(pwd))"/debdir installGo back to the BUILD1folder
$ cd .. && ls -1
debdir
libfreeaptxMake a template to run dpkg-shlibdeps
mkdir debian && echo -e "Source: libfreeaptx\nPackage: libfreeaptx\nDepends: \${shlibs:Depends}" >> debian/control Verify:
$ cat debian/control
Source: libfreeaptx
Package: libfreeaptx
Depends: ${shlibs:Depends} Run dpkg-shlibdeps to calculate dependencies
dpkg-shlibdeps -v -xlibfreeaptx -ldebdir/usr/lib --ignore-missing-info -e $(find debdir/usr -type f 2>/dev/null) Check the dependencies calculated by dpkg-shlibdeps
$ cat debian/substvars
shlibs:Depends=libc6 (>= 2.34)This means the Depends field in the DEBIAN/control file you're about to create should be:
Depends: libc6 (>= 2.34)Now you can build the Debian package from debdir.
install -vm0755 -d debdir/DEBIAN $ install -vm0755 -d debdir/DEBIAN
install: creating directory 'debdir/DEBIAN'Create DEBIAN/control with a text editor
nano debdir/DEBIAN/control$ cat debdir/DEBIAN/control
Package: libfreeaptx
Version: 0.2.2
Architecture: amd64
Priority: optional
Section: libdevel
Source: libfreeaptx
Maintainer: Devuan
Installed-Size: 24.6 kB
Conflicts: freeaptx-utils, libfreeaptx-dev, libfreeaptx0
Provides: freeaptx-utils (= 0.2.2), libfreeaptx-dev (= 0.2.2), libfreeaptx0 (= 0.2.2)
Replaces: freeaptx-utils, libfreeaptx-dev, libfreeaptx0
Depends: libc6 (>= 2.34)
Homepage: https://github.com/regularhunter/libfreeaptx
Tag: devel::library, role::devel-lib
Download-Size: 4,596 B
Description: Free implementation of aptX codec.
libfreeaptx is based on version 0.2.0 of libopenaptx with the intent of
continuing under a free license without the additional license restriction
added to libopenaptx 0.2.1.
.
This package contains the binaries, libraries, and header files for libfreeaptx.Generate DEBIAN/md5sums
cd debdir && find . -type f -not -path "./DEBIAN/*" -exec md5sum {} + | sort -k 2 | sed 's/\.\/\(.*\)/\1/' > DEBIAN/md5sumscd .. && chmod 0644 -- debdir/DEBIAN/md5sums Build the Debian package
fakeroot -- dpkg-deb -b debdir libfreeaptx_0.2.2_amd64.deb$ fakeroot -- dpkg-deb -b debdir libfreeaptx_0.2.2_amd64.deb
dpkg-deb: building package 'libfreeaptx' in 'libfreeaptx_0.2.2_amd64.deb'.$ ls *.deb
libfreeaptx_0.2.2_amd64.debInstall
sudo dpkg -i libfreeaptx_0.2.2_amd64.deb Re-install gstreamer1.0-plugins-bad and sayonara if needed
sudo apt install gstreamer1.0-plugins-bad sayonara2. Compile bluez-alsa
Install Buid-Deps:
sudo apt install libfdk-aac-dev libasound2-dev libbluetooth-dev libdbus-1-dev libglib2.0-dev libsbc-dev liblc3-dev libldacbt-enc-dev libldacbt-abr-dev libmp3lame-dev libmpg123-dev libspandsp-dev libopus-dev libbsd-dev libreadline-dev check dbus-daemon python3-docutils pkgconf libudev-dev libell-devClone the source and run autoreconf
mkdir BUILD2 && cd BUILD2git clone https://github.com/arkq/bluez-alsa.gitcd bluez-alsa && autoreconf --installCreate a build directory
mkdir ../build && cd ../buildRun the configure script from within the build directory:
"$(dirname $(pwd))"/bluez-alsa/configure --prefix=/usr --sysconfdir=/etc --with-bluealsaduser=bluealsad --enable-ldac --with-libfreeaptx --enable-aptx --enable-aptx-hd --enable-faststream --enable-lc3-swb --enable-mp3lame --enable-mpg123 --enable-msbc --enable-ofono --enable-midi --enable-opus --enable-upower --enable-rfcomm --enable-a2dpconf --enable-hcitop --enable-test --enable-aac --enable-manpages --disable-systemd Compile
makeInstall to debdir
make DESTDIR="$(dirname $(pwd))"/debdir install$ cd .. && ls -1
bluez-alsa
build
debdirinstall -vDm0644 "$(pwd)"/bluez-alsa/LICENSE "$(pwd)"/debdir/usr/share/licenses/bluez-alsa/LICENSETo run bluealsad daemon on Devuan, you need a simple init script
mkdir -vp debdir/etc/init.dnano debdir/etc/init.d/bluealsad$ cat debdir/etc/init.d/bluealsad
#!/bin/sh
### BEGIN INIT INFO
# Provides: bluealsa
# Required-Start: dbus $syslog $local_fs $remote_fs bluetooth
# Required-Stop: dbus $syslog $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: BlueALSA daemon
# Description: Bluetooth ALSA audio daemon
### END INIT INFO
. /lib/lsb/init-functions
NAME=bluealsad
DESC="BlueALSA daemon"
DAEMON=/usr/bin/$NAME
PIDFILE="/var/run/$NAME.pid"
STORAGE_DIR="/var/lib/bluealsa"
USER="bluealsad"
COMMON_OPTS="--quiet --oknodo --pidfile $PIDFILE"
# Working configuration without low-quality HSP codecs
BA_OPTS="-S -p a2dp-source -p a2dp-sink -p hfp-ag -p hfp-hf -c sbc -c aac -c mp3 -c aptx -c aptx-hd -c faststream -c opus -c msbc -c lc3-swb -c ldac --aac-afterburner --aac-bitrate=320000 --aac-vbr"
# Ensure bluealsad user exists and has correct group membership
if ! id $USER >/dev/null 2>&1; then
# Create user if it doesn't exist
useradd -r -s /bin/false $USER
usermod -a -G audio $USER
else
# User exists, check if in audio group
if ! id -nG $USER | grep -qw audio; then
usermod -a -G audio $USER
fi
fi
# Ensure storage directory exists with correct ownership
if [ ! -d "$STORAGE_DIR" ]; then
mkdir -p "$STORAGE_DIR"
chown $USER:$USER "$STORAGE_DIR"
chmod 0700 "$STORAGE_DIR"
else
# Directory exists, check ownership
CURRENT_OWNER=$(stat -c "%U:%G" "$STORAGE_DIR")
if [ "$CURRENT_OWNER" != "$USER:$USER" ]; then
chown $USER:$USER "$STORAGE_DIR"
chmod 0700 "$STORAGE_DIR"
fi
fi
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
start-stop-daemon $COMMON_OPTS --start --background \
--make-pidfile --chuid $USER --exec $DAEMON -- $BA_OPTS
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
start-stop-daemon $COMMON_OPTS --stop --retry 5
log_end_msg $?
;;
restart|force-reload)
$0 stop
$0 start
;;
status)
status_of_proc $DAEMON "$NAME" || exit $?
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0Make it executable
chmod +x debdir/etc/init.d/bluealsadMake a template
mkdir debian && echo -e "Source: bluez-alsa\nPackage: bluez-alsa\nDepends: \${shlibs:Depends}" >> debian/control $ cat debian/control
Source: bluez-alsa
Package: bluez-alsa
Depends: ${shlibs:Depends}Run dpkg-shlibdeps to calculate dependencies
dpkg-shlibdeps -v -xbluez-alsa -ldebdir/usr/lib --ignore-missing-info -e $(find debdir/usr -type f 2>/dev/null) $ cat debian/substvars
shlibs:Depends=libasound2 (>= 1.1.7), libbluetooth3 (>= 4.91), libbsd0 (>= 0.0), libc6 (>= 2.34), libdbus-1-3 (>= 1.9.14), libfdk-aac2 (>= 2.0.1), libglib2.0-0 (>= 2.67.3), liblc3-0 (>= 1.0.1), libldacbt-abr2 (>= 2.0.2), libldacbt-enc2 (>= 2.0.2), libmp3lame0 (>= 3.100), libmpg123-0 (>= 1.28.0), libncurses6 (>= 6), libopus0 (>= 1.1), libreadline8 (>= 6.0), libsbc1 (>= 2.0), libspandsp2 (>= 0.0.6~pre18), libtinfo6 (>= 6)install -vm0755 -d debdir/DEBIAN Create DEBIAN/control with a text editor
$ cat debdir/DEBIAN/control
Package: bluez-alsa
Version: 4.3.1-86
Architecture: amd64
Priority: optional
Section: utils
Source: bluez-alsa
Maintainer: Devuan
Installed-Size: 541 kB
Conflicts: bluez-alsa-utils, libasound2-plugin-bluez
Provides: bluez-alsa-utils (= 4.3.1-86), libasound2-plugin-bluez (= 4.3.1-86)
Replaces: bluez-alsa-utils, libasound2-plugin-bluez
Depends: libasound2 (>= 1.1.7), libbluetooth3 (>= 4.91), libbsd0 (>= 0.0), libc6 (>= 2.34), libdbus-1-3 (>= 1.9.14), libfdk-aac2 (>= 2.0.1), libglib2.0-0 (>= 2.67.3), liblc3-0 (>= 1.0.1), libldacbt-abr2 (>= 2.0.2), libldacbt-enc2 (>= 2.0.2), libmp3lame0 (>= 3.100), libmpg123-0 (>= 1.28.0), libncurses6 (>= 6), libopus0 (>= 1.1), libreadline8 (>= 6.0), libsbc1 (>= 2.0), libspandsp2 (>= 0.0.6~pre18), libtinfo6 (>= 6)
Homepage: https://github.com/Arkq/bluez-alsa
Description: Bluetooth Audio ALSA Backend (utils)
Bluetooth Audio ALSA Backend allows bluetooth audio without PulseAudio and PipeWire.
This package provides sysVinit script for bluealsad daemon to run it without systemd.
.
This project is a rebirth of a direct integration between Bluez and ALSA.
Since Bluez >= 5, the build-in integration has been removed in favor of 3rd
party audio applications. From now on, Bluez acts as a middleware between an
audio application, which implements Bluetooth audio profile, and a Bluetooth
audio device.Generate DEBIAN/md5sums
cd debdir && find . -type f -not -path "./DEBIAN/*" -exec md5sum {} + | sort -k 2 | sed 's/\.\/\(.*\)/\1/' > DEBIAN/md5sumscd .. && chmod 0644 -- debdir/DEBIAN/md5sums Make a Debian package
fakeroot -- dpkg-deb -b debdir bluez-alsa_4.3.1-86_amd64.deb$ fakeroot -- dpkg-deb -b debdir bluez-alsa_4.3.1-86_amd64.deb
dpkg-deb: building package 'bluez-alsa' in 'bluez-alsa_4.3.1-86_amd64.deb'.$ ls *.deb
bluez-alsa_4.3.1-86_amd64.debInstall
sudo dpkg -i bluez-alsa_4.3.1-86_amd64.debConfigure the bluealsad service to start automatically at system boot
sudo update-rc.d bluealsad defaultsStart the bluealsad service and check its status
sudo service bluealsad start
sudo service bluealsad statusIf, for some strange reason, bluealsad fails to start, restart services in the correct order:
sudo service dbus restart
sudo service dbus status
sudo service bluetooth restart
sudo service bluetooth status
sudo service bluealsad restart
sudo service bluealsad statusOr simply reboot the system to ensure all services start in the proper sequence.
3. Pair and connect Bluetooth headphones using the Blueman Manager
$ apt-cache show blueman | grep Recommends:
Recommends: pulseaudio-module-bluetoothIt will install pulseaudio and/or pipewire. if they are not pinned.
The magic command apt-mark hold can fix the problem
sudo apt-mark hold pulseaudio* pipewire*sudo apt install bluemanPut Headphones in Pairing Mode:
Turn on your headphones and press/hold the power or Bluetooth button until an indicator light flashes (usually blue/red), showing they are discoverable.
Launch Blueman Manager:
blueman-managerSearch for Devices:
In the Blueman Manager window, click the "Search" button (or magnifying glass icon) to scan for devices.
Pair the Headphones:
When your headphones appear, right-click the device name.
Select Pair. Confirm the pairing request if a prompt appears (often within 20 seconds).
Right-click again and select Trust so they connect automatically next time.
Connect and Set Audio Output:
Right-click the device in Blueman and choose Connect
You can do the same with bluetoothctl
bluetoothctl scan on
bluetoothctl pair XX:XX:XX:XX:XX:XX
bluetoothctl trust XX:XX:XX:XX:XX:XX
bluetoothctl connect XX:XX:XX:XX:XX:XX TEST:
alsamixer -D bluealsaaplay -D bluealsa /usr/share/sounds/alsa/Front_Center.wav$ bluealsad --help | grep "Available BT profiles" -A20
Available BT profiles:
- a2dp-source Advanced Audio Source (v1.4)
- a2dp-sink Advanced Audio Sink (v1.4)
- hfp-ofono Hands-Free AG/HF handled by oFono
- hfp-ag Hands-Free Audio Gateway (v1.9)
- hfp-hf Hands-Free (v1.9)
- hsp-ag Headset Audio Gateway (v1.2)
- hsp-hs Headset (v1.2)
- midi Bluetooth LE MIDI (v1.0)
Available BT audio codecs:
a2dp-source: SBC, MP3, AAC, aptX, aptX-HD, FastStream, LDAC, Opus
a2dp-sink: SBC, MP3, AAC, aptX, aptX-HD, FastStream, Opus
hfp-*: CVSD, mSBC, LC3-SWB$ bluealsactl status
Service: org.bluealsa
Version: v4.3.1-86-gf1e53d3
Adapters: hci0
Profiles:
A2DP-source : SBC MP3 AAC aptX aptX-HD FastStream LDAC Opus
A2DP-sink : SBC MP3 AAC aptX aptX-HD FastStream Opus
HFP-AG : CVSD mSBC LC3-SWB
HFP-HF : CVSD mSBC LC3-SWBRight, so not all Bluetooth codecs are supported by your headphones — it’s a bit of a mismatch, really. With the Sennheiser HD 450BT on Linux, you’re limited to SBC, AAC, and aptX, even if the device supports more in other ecosystems.
The bluealsactl output confirms this:
$ bluealsactl codec $(bluealsactl list-pcms | grep a2dpsrc | head -1)
Available codecs: SBC AAC aptX
Selected codec: aptX You can switch to AAC manually:
bluealsactl codec $(bluealsactl list-pcms | grep a2dpsrc | head -1) aac And verify:
$ bluealsactl codec $(bluealsactl list-pcms | grep a2dpsrc | head -1)
Available codecs: SBC AAC aptX
Selected codec: AAC Both aptX and aptX-HD codecs support 16kHz, 32kHz, 44.1kHz, and 48kHz sample rates with BlueALSA.
The aptX-HD implementation in src/a2dp-aptx-hd.c includes:
Sample rate support for 16kHz, 32kHz, 44.1kHz, and 48kHz
24-bit audio support
Encoder and decoder initialization functions
Tested with:
ASUS USB-BT540 Bluetooth 5.4 Dongle Adapter Compatible with Linux
Sennheiser HD 450BT
Specifications:
Bluetooth profiles: AVRCP, A2DP, HFP, HSP
Bluetooth Audio Codecs: AptX, AptX Low Latency, AAC, SBC
$ bluealsa-aplay -L
bluealsa:DEV=80:C3:BA:8B:B6:CC,PROFILE=sco,SRV=org.bluealsa
HD 450BT, trusted audio-headphones, playback
SCO (mSBC): S16_LE 1 channel 16000 Hz
bluealsa:DEV=80:C3:BA:8B:B6:CC,PROFILE=sco,SRV=org.bluealsa
HD 450BT, trusted audio-headphones, capture
SCO (mSBC): S16_LE 1 channel 16000 Hz
bluealsa:DEV=80:C3:BA:8B:B6:CC,PROFILE=a2dp,SRV=org.bluealsa
HD 450BT, trusted audio-headphones, playback
A2DP (aptX): S16_LE 2 channels 48000 Hz$ bluealsa-aplay -l
**** List of PLAYBACK Bluetooth Devices ****
hci0: 80:C3:BA:8B:B6:CC [HD 450BT], trusted audio-headphones
SCO (mSBC): S16_LE 1 channel 16000 Hz
A2DP (aptX): S16_LE 2 channels 48000 Hz
**** List of CAPTURE Bluetooth Devices ****
hci0: 80:C3:BA:8B:B6:CC [HD 450BT], trusted audio-headphones
SCO (mSBC): S16_LE 1 channel 16000 HzALSA config for BlueALSA virtual PCM device
$ cat ~/.asoundrc
defaults.pcm.rate_converter "fftrate"
pcm.!default "bluealsa"MPV Player config:
$ cat ~/.config/mpv/mpv.conf
ao=alsa
alsa-resample=yes
alsa-buffer-time=160000
alsa-periods=4Celluloid:
Open the Preferences menu.
Go to the Miscellaneous tab.
Enter mpv command-line options into the "Extra MPV Options" text box:
ao=alsa alsa-resample=yes alsa-buffer-time=160000 alsa-periods=4Audacious:
go to Preferences → Audio → Buffer size
set 2000 ms
Firefox
about:config
media.cubeb.backend alsa
media.resampling.enabled false
media.cubeb_latency_playback_ms 160TEST:
$ mpv *.dsf
(+) Audio --aid=1 (dsd_lsbf_planar 2ch 1411200Hz)
Input: 1411200 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 56448
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920
Rates: 1411200 --> 48000 (J: 0.00%, T: FFT, W: Vorbis)
Ok.
AO: [alsa] 1411200Hz stereo 2ch float
(Paused) AV: 00:00:30 / 00:04:35 (11%)$ audacious 2>&1 *.dsf
Input: 1411200 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 352800
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 12000
Rates: 1411200 --> 48000 (J: 0.00%, T: FFT, W: Vorbis)
Ok.$ MOZ_LOG="MediaDecoder:4,cubeb:5" stdbuf -oL firefox 2>&1 https://rutube.ru/video/4202a6f411ad55ea7f55e38f860e26bc/ | grep --line-buffered -E "MetadataLoaded.*rate=|FirstFrameLoaded.*rate=|CubebStreamInit output stream rate|target rate|Output hardware|Input|Output|Rates" | grep -vE "hasVideo=0|hasAudio=0"
[Child 21800: Main Thread]: D/MediaDecoder MediaDecoder[7f5208797000] MetadataLoaded, channels=2 rate=44100 hasAudio=1 hasVideo=1
[Child 21800: Main Thread]: D/MediaDecoder MediaDecoder[7f5208797000] FirstFrameLoaded, channels=2 rate=44100 hasAudio=1 hasVideo=1 mPlayState=PLAY_STATE_LOADING transportSeekable=1
[Child 21800: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 44100
[Child 21800: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 44100$ mpv 2>&1 rudra*
(+) Audio --aid=1 (flac 2ch 44100Hz)
AO: [alsa] 44100Hz stereo 2ch s16
(Paused) A: 00:00:41 / 00:18:33 (4%)It means that sample rate 44100Hz is indeed supported by aptX codec. That is why you do not see logs of fftrate, which is now the default ALSA resampler.
Buffer settings for aplayand arecord
aplay -F 40000 -B 160000 <.wav>
arecord -F 40000 -B 160000 <.wav>$ aplay -F 40000 -B 160000 1_08*
Playing WAVE '1_08-Faust - Funeral March Of A Marionette - DSD256.dsf.wav' : Signed 32 bit Little Endian, Rate 1411200 Hz, Stereo
Input: 1411200 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 56448
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920
Rates: 1411200 --> 48000 (J: 0.00%, T: FFT, W: Vorbis)
Ok.Full duplex with mSBC codec
$ arecord -F 40000 -B 160000 -D bluealsa:PROFILE=sco -V mono -f CD | aplay -F 40000 -B 160000 -D bluealsa:PROFILE=sco
Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Input: 16000 Hz, 1 ch, 's16_le' (0x2): dummy = 0, period = 640
Output: 44100 Hz, 1 ch, 's16_le' (0x2): dummy = 0, period = 1764
Rates: 16000 --> 44100 (J: 0.00%, T: FFT, W: Vorbis)
Ok.
Playing WAVE 'stdin' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Input: 44100 Hz, 1 ch, 's16_le' (0x2): dummy = 0, period = 1764
Output: 16000 Hz, 1 ch, 's16_le' (0x2): dummy = 0, period = 640
Rates: 44100 --> 16000 (J: 0.00%, T: FFT, W: Vorbis)
Ok.
################################# +| MAXmSBC codec Playback/Capture devices:
**** PLAYBACK Bluetooth Device ****
hci0: 80:C3:BA:8B:B6:CC [HD 450BT], trusted audio-headphones
SCO (mSBC): S16_LE 1 channel 16000 Hz
**** CAPTURE Bluetooth Device ****
hci0: 80:C3:BA:8B:B6:CC [HD 450BT], trusted audio-headphones
SCO (mSBC): S16_LE 1 channel 16000 Hzronn is a Markdown-like format for writing man pages. It's readable and editable in any text editor.
To enable syntax highlighting for .ronn files in VSCodium:
Open the .ronn file.
Click on "Plain Text" in the bottom-right corner of the status bar.
Select "Markdown" from the language list.
This applies Markdown highlighting, which works well for .ronn files.
Alternatively, use the command palette:
Ctrl+Shift+P → "Change Language Mode" → "Markdown".
To convert .ronn files to man format, use the ronn utility available in Devuan repositories:
$ apt-cache search ronn$
ronn - tool to build manuals from Markdown
ruby-ronn - library to build manuals from MarkdownInstall ronn:
sudo apt install ronnConvert .ronn file to man format:
ronn --roff pcm_conv.1.ronnThis generates pcm_conv.1.
View the man page:
man ./pcm_conv.1Example .ronn file:
cat pcm_conv.1.ronnPCM_CONV(1) User Commands PCM_CONV(1)
## NAME
pcm_conv - high-quality FFT/DCT-based audio resampler
## SYNOPSIS
`pcm_conv` [<input_file>] [<output_file>] [ `-c` <number> ] [ `-m` <mask> ] [ `-n` <on>`|`<off> ] [ `-I` <input_order> ] [ `-O` <output_order> ] [ `-b` <bits> ] [ `-f` <frequency> ] [ `-T` <trans> ] [ `-W` <win> ] [ `-v` ] [ `-h | --help | --help-all` ]
## DESCRIPTION
Converts WAVE files with high-quality sample rate conversion using FFT or DCT transforms.
## OPTIONS
`-c`
: Number of output channels: 1 (mono), 2 (stereo), up to 6 (3/2+SW).
`-m`
: Channel mask (may conflict with -c).
`-n`
: Normalize channel matrix (default: on).
`-I` <order>, `-O` <order>
: Input/output channel order: MS, ALSA, or OSS layout.
`-b` <bits>
: Output bit depth: 8, 16, 24, 32, 32f, or 64f.
`-f` <value of sample rate in Hz>, e.g.: `-f` 192000
: Output sample rate. The range of 6000–192000 Hz is 100% reliable. Rates above 192 kHz (e.g., 1411200 Hz) appear reliable based on testing, but require further validation with `pcm_mse`.
`-T` <dct>`|`<fft>
: Transform type (default: dct).
`-W` <vorbis>`|`<hanning>`|`<rect>
: Windowing function (default: vorbis).
`-v`
: Verbose output.
`--help-all`
: Show full help.
## FILES
/etc/fftrate.conf
: System-wide configuration.
~/.asoundrc
: User ALSA configuration (used by fftrate plugin).
## SEE ALSO
arateconf(1), fftrate(7)
## EXAMPLES
Convert a 32-bit WAV file to 192kHz, 32-bit fixed-point using FFT resampling:
$ pcm_conv -f 192000 -b 32 -T fft -v *32bit.wav Faust_192kHz_32bit_downfft.wav
Input file : 08-Faust - Funeral March Of A Marionette - 32bit.wav
Samples rate = 352800 Hz
Channels = 2
Bits per sample = 32 (actual: 32, float)
Output file: Faust_192kHz_32bit_downfft.wav
Samples rate = 192000 Hz
Channels = 2
Bits per sample = 32 (actual: 32, fixed)
FL FR
FL 1.000 -----
FR ----- 1.000
Windows : "Vorbis" (37632 => 20480)
Delay : 107 ms
Sync. : ON
Trans. : "FFT"
[|||||||||||||||||||||||||||||||||||||||||||||||||||] 99.0 %
Ok.
File duration : 275.906667 sec
Processing time: 13.305000 sec ( 4.82% of real time)
## VERSION
1.6.3
## DATE
November 2025Manual:
man ronn-format_https://rtomayko.github.io/ronn/ronn-format.7.html
So after the fox, after the fox
Off to the hunt with chains and locks
So after the fox, after the fox
Someone is always chasing after the foxAfter the Fox (1966) _https://www.youtube.com/watch?v=MrQl0VsQYtw
For the truly dedicated — those who believe their audio deserves better.
🔧 Step 0: Lock It Down
Before we begin, disable the PulseAudio backend - yes, even the rusty one:
Open Firefox and type about:config in the address bar
Search: media.cubeb.backend
Click +, set type to string, value to alsa
Now Firefox talks directly to ALSA - no middlemen.
✅ You’ve just sidestepped a surveillance-level audio framework.
🕵️ Step 1: The Smoking Gun
Firefox uses Speex Resampler under the hood - yes, that Speex.
It’s in the code: AudioConverter.cpp includes <speex/speex_resampler.h>.
_https://searchfox.org/firefox-main/source/dom/media/AudioConverter.cpp
#include "AudioConverter.h" #include <speex/speex_resampler.h>
But here’s the twist:
On macOS, cubeb logs:
Input and output sample-rate match, target rate of 48000Hz
On Linux? Silence.
Nothing. Nada. Zilch.
🚨 Suspicious?
Or is Mozilla simply not telling Linux users what it’s up to?
macOS Firefox logs:
➤ MOZ_LOG="MediaDecoder:4,cubeb:5" stdbuf -oL /Applications/Firefox\ Developer\ Edition.app/Contents/MacOS/firefox 2>&1 https://youtu.be/uO6jfQ5tQHM | ggrep --line-buffered -E "MetadataLoaded.*rate=|FirstFrameLoaded.*rate=|CubebStreamInit output stream rate|target rate|Output hardware" | ggrep -v "hasVideo=0"
[Child 4501: Main Thread]: D/MediaDecoder MediaDecoder[11631e700] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
[Child 4501: Main Thread]: D/MediaDecoder MediaDecoder[116f37300] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
[Child 4501: Main Thread]: D/MediaDecoder MediaDecoder[116f37300] FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1 mPlayState=PLAY_STATE_LOADING transportSeekable=1
[Child 4501: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 48000
[Parent 4486: AudioIPC Server RPC]: E/cubeb mod.rs:3995: (0x183e31c00) Output hardware description: AudioStreamBasicDescription { mSampleRate: 96000.0, mFormatID: 1819304813, mFormatFlags: 9, mBytesPerPacket: 8, mFramesPerPacket: 1, mBytesPerFrame: 8, mChannelsPerFrame: 2, mBitsPerChannel: 32, mReserved: 0 }
[Parent 4486: AudioIPC Server RPC]: E/cubeb cubeb_resampler_internal.h:553:Input and output sample-rate match, target rate of 48000HzOn macOS, Firefox appears to feign transparency and user-friendliness. But macOS isn’t quite Linux: applications ought to behave in a civilised manner.
Right. So Firefox has its own resampler, and cubeb has its own as well - meaning the audio could be quietly upsampled and downsampled like some sort of secret internal game of pass-the-parcel, and we’d never even see it in the logs.
Typical, really. Everything’s transparent and user-friendly - just not actually.
What's Actually Happening
Resampling: Cubeb uses its Speex-based resampler (cubeb_resampler_internal.h:199–207).
Stream initialisation: Once the target rate is determined, Cubeb sets up the stream at 48kHz (cubeb_resampler_internal.h:561–577).
Passthrough mode: When input and output rates match, Cubeb uses a passthrough resampler that simply forwards buffers without conversion (cubeb_resampler_internal.h:548–556).
The resampler selection logic in cubeb_resampler_create_internal() confirms this:
// Check if rates match - if so, use passthrough
if (((input_params && input_params->rate == target_rate) &&
(output_params && output_params->rate == target_rate)) ||
(input_params && !output_params && (input_params->rate == target_rate)) ||
(output_params && !input_params &&
(output_params->rate == target_rate))) {
LOG("Input and output sample-rate match, target rate of %dHz", target_rate);
return new passthrough_resampler<T>(...);
}When rates don’t match, it creates a cubeb_resampler_speex_one_way for conversion (cubeb_resampler_internal.h:187–203).
🔍 Step 2: The Bit Depth Conspiracy
Firefox converts everything to 32-bit float - internally.
But let’s be honest:
20 years ago, fftrate used 64-bit float.
Today, serious audio tools use 128-bit float or more.
And what does Firefox do?
sample spec: float32le 2ch 48000Hz🧠 32-bit float - the Stone Age of precision.
It works, but is it good enough?
This isn’t about whether it functions — it’s whether it respects the medium. Firefox settles for the lowest common denominator, even when the hardware and OS are ready to do better.
🧩 Step 3: Who’s Really Resampling?
You’ve set:
media.resampling.enabled falseSo Firefox should not resample.
Logs show:
MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
CubebStreamInit output stream rate 48000🛠️ Final Command: Firefox logging together with fftrate logging
➤ MOZ_LOG="MediaDecoder:4,cubeb:5" stdbuf -oL firefox 2>&1 https://youtu.be/uO6jfQ5tQHM | grep --line-buffered -E "MetadataLoaded.*rate=|FirstFrameLoaded.*rate=|CubebStreamInit output stream rate|target rate|Output hardware|Input|Output|Rates" | grep -v "hasVideo=0"
[Child 13197: Main Thread]: D/MediaDecoder MediaDecoder[7f6c62c17900] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
Input: 44100 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1764
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920
Rates: 44100 --> 48000 (J: 0.00%, T: FFT, W: Vorbis)
[Child 13197: Main Thread]: D/MediaDecoder MediaDecoder[7f6c62c17900] FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1 mPlayState=PLAY_STATE_LOADING transportSeekable=1
[Child 13197: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 48000
Input: 48000 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1920
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920
Rates: 48000 --> 48000 (J: 0.00%, T: None, W: Planar)This reflects only the observable behaviour. The full pipeline? Still hidden. As usual.
The Mystery Audio Stream
Input: 44100 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1764The Short and Curious Tale
Right then, here's what's happening: Firefox, being a proper gentleman, politely taps your audio system on the shoulder to ask, "I say, what sample rate do you prefer?" This happens through Cubeb's alsa_get_preferred_sample_rate() function.
Firefox tries 44.1kHz first (a rather common rate, don't you know), but your dmix plugin, being a bit of a stickler for rules, insists on 48kHz. So ALSA’s resampler steps in like a proper butler, converting the stream—even though Firefox requested SND_PCM_NO_AUTO_RESAMPLE.
The "dummy = 0" in your logs? That's just ALSA's way of saying "This is a real device, gov'nor, not some test dummy."
Why This Isn't Your YouTube Video
This probing happens before any actual playback — it's merely Firefox checking what your audio system can handle. The actual YouTube stream will use whatever rate this probe determines (likely 48kHz in your case).
The Bottom Line
Perfectly normal behaviour, old chap! Just Firefox being thorough and your dmix plugin being particular. The resampling you see is ALSA doing its thing, completely separate from Cubeb's internal workings. Your hardware supporting 44.1kHz doesn't stop dmix from having its own ideas about proper audio rates.
Notes
This probe stream mechanism is used across all Cubeb backends for capability detection.
The format 's32_le' is 32-bit signed integer.
The "T: FFT" indicates ALSA's FFT-based resampling algorithm.
"J: 0.00%" shows minimal jitter — the conversion is working rather well indeed.
🧙♂️ Conclusion
We cannot prove Firefox is resampling — because it doesn’t log it.
But we know:
It uses Speex resampler.
It hides resampling logs on Linux.
So is it resampling?
🔎 We may never know.
But we’ll keep watching.
Citations
File: src/cubeb_alsa.c (L1228-1272)
static int
alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
(void)ctx;
int r, dir;
snd_pcm_t * pcm;
snd_pcm_hw_params_t * hw_params;
snd_pcm_hw_params_alloca(&hw_params);
/* get a pcm, disabling resampling, so we get a rate the
* hardware/dmix/pulse/etc. supports. */
r = WRAP(snd_pcm_open)(&pcm, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NO_AUTO_RESAMPLE);
if (r < 0) {
return CUBEB_ERROR;
}
r = WRAP(snd_pcm_hw_params_any)(pcm, hw_params);
if (r < 0) {
WRAP(snd_pcm_close)(pcm);
return CUBEB_ERROR;
}
r = WRAP(snd_pcm_hw_params_get_rate)(hw_params, rate, &dir);
if (r >= 0) {
/* There is a default rate: use it. */
WRAP(snd_pcm_close)(pcm);
return CUBEB_OK;
}
/* Use a common rate, alsa may adjust it based on hw/etc. capabilities. */
*rate = 44100;
r = WRAP(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, NULL);
if (r < 0) {
WRAP(snd_pcm_close)(pcm);
return CUBEB_ERROR;
}
WRAP(snd_pcm_close)(pcm);
return CUBEB_OK;
}You may test GTK3 with WhiteSur GTK Dark Theme:
_https://dev1galaxy.org/viewtopic.php?id=7224
Yes. You can find examples here:
_https://dev1galaxy.org/viewtopic.php?pid=59689#p59689
A sort of rather simple command like this:
$ MOZ_LOG="MediaDecoder:4,cubeb:3" firefox 2>&1 https://youtu.be/uO6jfQ5tQHM | awk '!/ATT/ && !/libva/ && !/s=1/ && !/s=0/ && (!/MediaDecoder/ || /rate/)'
[Child 17205: Main Thread]: D/MediaDecoder MediaDecoder[7ff8efdfc600] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
[Child 17205: MediaSupervisor #2]: I/cubeb media.cubeb.sandbox: true
[Child 17205: Main Thread]: D/MediaDecoder MediaDecoder[7ff8efdfc600] FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1 mPlayState=PLAY_STATE_LOADING transportSeekable=1
[Child 17205: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 48000
Input: 48000 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1920
Output: 44100 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1764
Rates: 48000 --> 44100 (J: 0.00%, T: FFT, W: Vorbis)
Ok.fftrate is a project of Sergei Petrov
_https://github.com/PetrovSE/fftrate
I created man pages to help you with packaging
Info from old pcm-conv:
Short name: FFT-DCT4-MDCT
Long name : FFT, DCT4 and MDCT by Cooley-Tukey, Good-Thomas and Winograd algorithms
Version : 2.0.0.2
Build : Feb 28 2012, 19:47:28, linux-x86_64It seems that the fftrate resampler was created in 2007.
Thank you very much for packaging fftrate.
You can test it with LibreWolf browser.
_https://librewolf.net/installation/debian/
We have a repository for Debian-based distributions (Debian, Ubuntu, Mint, etc.), with which you can easily install and update LibreWolf. To add it to your system and install LibreWolf, run the following commands one by one:sudo apt update && sudo apt install extrepo -ysudo extrepo enable librewolfsudo apt update && sudo apt install librewolf -y
Disable pulse-rust backend
librewolf about:configType into "Search preference name"
media.cubeb.backendSelect "string"
Press "+"
Type "alsa" then Enter
As a result, you have a new entry in Firefox's "hidden preferences"
media.cubeb.backend alsaRe-start LibreWolf.
Zoom Zoom Extension for Browsers → Firefox Add-ons
_https://zoom.us/download
File: pcm_mse.1
.TH PCM_MSE 1 "November 2025" "1.6.3" "User Commands"
.SH NAME
pcm_mse \- compute Mean Squared Error (MSE) between two PCM WAV files
.SH SYNOPSIS
.B pcm_mse
.I <file1.wav> <file2.wav> [resid.wav]
.RB [ " -b " samples ]
.RB [ " -e " samples ]
.BR [ -h | --help | --help-all ]
.SH DESCRIPTION
Computes the MSE between two WAV files, optionally saving the residual (difference) signal.
Ideal for evaluating audio resampling quality.
.SH OPTIONS
.TP
.I file1.wav
First input WAV file.
.TP
.I file2.wav
Second input WAV file.
.TP
.I resid.wav
Optional output file for residual signal.
.TP
.BI \-b " samples"
Start comparison at sample number (default: 0).
.TP
.BI \-e " samples"
End comparison at sample number (default: end of file).
.TP
.B \-\-help-all
Show full help.
.SH EXAMPLE
.B pcm_mse 1.wav 2.wav -b 10 -e 10000000000
.PP
Compares samples 10 to 10,000,000,000.
.SH SEE ALSO
pcm_conv(1), pcm_info(1) File: pcm_info.1
.TH PCM_INFO 1 "November 2025" "1.6.3" "User Commands"
.SH NAME
pcm_info \- display audio format and metadata of a WAV file
.SH SYNOPSIS
.B pcm_info
.I <file.wav>
.SH DESCRIPTION
Displays detailed format information of a WAV file:
.IP
- Sample rate (Hz)
.IP
- Number of channels
.IP
- Bit depth (and actual storage)
.IP
- Channel mask and layout
.IP
- Total samples and duration
.SH OUTPUT
Prints to stdout:
.PP
Parameters:
.br
Samples rate = 192000 Hz
.br
Channels = 2
.br
Bits per sample = 24 (actual: 24, fixed)
.br
Extensible format: ON
.br
Channel mask: 000003 hex, 3 dec
.br
Channels : FL, FR
.br
Samples : 42.080.131
.br
Duration: 3 min 39.167349 sec
.SH EXAMPLE
.B pcm_info HiRes.wav
.SH SEE ALSO
pcm_mse(1), pcm_conv(1) Install Man Pages
sudo cp -v pcm_conv.1 /usr/share/man/man1/
sudo cp -v fftrate.7 /usr/share/man/man7/
sudo cp -v arateconf.1 /usr/share/man/man1/
sudo cp -v pcm_mse.1 /usr/share/man/man1/
sudo cp -v pcm_info.1 /usr/share/man/man1/sudo mandb # Rebuild man database Now you can view them:
man pcm_conv
man fftrate
man arateconf
man pcm_mse
man pcm_info