fix: connect A2DP after pairing and enable JustWorksRepairing for BT headsets#730
fix: connect A2DP after pairing and enable JustWorksRepairing for BT headsets#730carroarmato0 wants to merge 9 commits into
Conversation
…dsets The XRadio BT controller firmware generates link keys with store_hint=0, meaning BlueZ never persists the key to disk. This caused two symptoms: 1. Earbuds disconnect ~2s after pairing: after the BR/EDR bond completes, nothing initiates the A2DP audio profile connection. The earbuds time out waiting for the host to open the audio channel and disconnect (reason 2 = remote terminated). Fixed by calling `bluetoothctl connect` immediately after `bluetoothctl pair` in PLAT_bluetoothPair(). 2. No sound after sleep/wake (fixes LoveRetro#467): bt_init.sh stop/start clears the controller's volatile key memory. On wake, earbuds try to reconnect but BlueZ rejects them (no stored key, JustWorksRepairing=never default). Fixed by patching main.conf to set JustWorksRepairing=always before bluetoothd starts, allowing earbuds to re-initiate the bond from their side without user interaction. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tg5050 (TrimUI Smart Pro S) uses an AIC8800 BT chip, not XRadio. Remove the chip-specific attribution from the comment so it accurately describes the symptom rather than incorrectly referencing XRadio. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When earbuds power off abruptly, BlueZ may have already cleared the device's service cache by the time audiomon processes the disconnect signal. The previous hasUUID() call on disconnect would return false in that race, silently skipping the audio switch-back to the internal speaker. Fix by caching the connected A2DP device MAC at connect time and comparing against it on disconnect, avoiding the BlueZ query entirely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…witch ALSA caches its PCM configuration. After BT disconnects and .asoundrc is deleted, setting AUDIODEV=default still resolves through the cached config which may still point to bluealsa — causing SDL to open a dead PCM and producing no or garbled audio from the speaker. Fix by naming both endpoints explicitly, matching the same pattern already used for BT (bluealsa): - Speaker: plughw:0 (card 0, with format/rate conversion) - USB DAC: plughw:1 (card 1, with format/rate conversion) - Bluetooth: bluealsa (unchanged) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… audio switch" This reverts commit f1a7932.
|
I'm not sure this is working as expected. BT is always a bit of a clusterfuck, but at least with my XM-6s I do not get automatic reconnect after sleep with this patch. |
I've recently come in possession of a Smart Pro thx for a benefactor. I'll perform some extra tests and see what comes up. 😄 |
|
As I mentioned yesterday on Discord, I started fresh without this PR:
After reapplying my PR: both devices were able to pair with the Raycon earbuds. On both devices, while playing a game (GB game through Gambatte), the sound works through BLE. When I disconnect the earbuds while the game is still on, I can see visually on the both devices that the disconnect happened (the volume bar appears, and shows the regular AMP symbol rather than bluetooth). When I turn the ear buds back on, they stay in pairing mode. They do not attempt to reconnect with the device, and the device does not attempt to reconnect as well. Which I think makes sense because when the device disconnects, it's removed from the cache code that I introduced. Maybe I should look into that. |
|
Two remaining issues found during testing that are out of scope for this PR: Audio doesn't switch back to internal speakers mid-game The disconnect is detected correctly (the volume bar updates to show the amp icon), so audiomon is doing its thing. The problem is that minarch opens the ALSA device at startup and holds onto it — when audiomon rewrites Earbuds don't reconnect after manual power-off/on Sleep/resume works because Both are worth tracking as follow-up issues, but the current PR does it's job to pair successfully with my ear buds. |
|
@frysee what's in your /etc/bluetooth/main.conf and which device are you on? |
Brick, and the defaults. |
Ok, so same chip (XRadio), same device, patch applied, pairing works, but sleep/resume reconnect fails specifically with the XM-6s. According to Jean-Claude: |
|
BT just is a joy to work on, everything is so consistent. |
BlueZ loads paired device records on startup but never reaches out to them — it waits for the remote device to initiate. Budget earbuds (Raycon) handle this by connecting from their side; premium headphones (Sony XM-6s, etc.) expect the host to initiate and won't fall back to JustWorks re-pairing when authentication fails. Fix by scanning /var/lib/bluetooth/ after BT stack init and calling bluetoothctl connect for each trusted device advertising the A2DP Sink UUID (0000110b). Runs in background with a 5s delay to avoid blocking startup. Uses stored link keys, so no JustWorks re-pairing is needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@frysee I submitted another patch. It looks like the device does not attempt itself to reconnect. So give this a try, hopefully works for you |
bt_init.sh: - Remove Trusted=true filter from proactive reconnect loop. The bluetoothctl trust call was only added in this branch, so any device paired on a previous version would be silently skipped. The A2DP Sink UUID (0000110b) is sufficient to identify audio devices. - Use '.*JustWorksRepairing.*' instead of exact '#JustWorksRepairing = never' in sed, so the patch applies regardless of whether the line is commented, already set to a different value, or has different spacing. audiomon.cpp: - Restore connected_a2dp_mac from .asoundrc at startup. audiomon only tracked BT state via D-Bus events, so if it started (or restarted) after a BT device was already connected it would never populate the MAC cache, causing a subsequent abrupt disconnect to go undetected and leaving audio stuck on Bluetooth. .asoundrc already contains the MAC because audiomon wrote it — reading it back on init closes this gap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The function was placed before log() causing 'not declared in this scope' compile error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
PLAT_bluetoothPair()now callsbluetoothctl connectafterbluetoothctl pairso the A2DP audio profile is opened immediately after bonding. Without this, earbuds time out (~2 s) waiting for the host to initiate the audio channel and disconnect themselves (BlueZreason 2 = remote terminated).bt_init.shnow setsJustWorksRepairing = alwaysinmain.confbefore startingbluetoothd. The XRadio BT controller firmware generates link keys withstore_hint=0, so BlueZ never persists the key to disk. After a sleep/wake cycle the key is gone; withJustWorksRepairing=never(the BlueZ default) earbuds can't reconnect without the user re-pairing manually. Setting it toalwayslets the earbuds re-initiate the bond from their side on wake.Fixes #467 (no sound after sleep when using BT headphones).
Root cause
The XRadio chip used in TrimUI devices sets
store_hint=0in the MGMTNEW_LINK_KEYevent. BlueZ respects this flag and skips writing[LinkKey]to the device info file, so the device is never consideredPaired=true. This means:Files changed
workspace/all/common/generic_bt.cbluetoothctl connectafterbluetoothctl pairinPLAT_bluetoothPair()skeleton/SYSTEM/tg5040/etc/bluetooth/bt_init.shmain.conftoJustWorksRepairing=alwaysbefore bluetoothd startsskeleton/SYSTEM/tg5050/etc/bluetooth/bt_init.shI've tested this using my Raycon Earbuds and seems to work reliably. Before this fix the earbuds would simply not connect (or get disconnected immediately)