fix(bluetooth): wait for SCO link before Oboe restart + detect A2DP devices

Three fixes for Bluetooth audio not working:

1. is_bluetooth_available() now checks for TYPE_BLUETOOTH_A2DP (8) in
   addition to TYPE_BLUETOOTH_SCO (7) — many headsets only register as
   A2DP until SCO is explicitly started.

2. set_bluetooth_sco(on=true) polls isBluetoothScoOn() for up to 3s
   before restarting Oboe. startBluetoothSco() is async — the SCO link
   takes 500ms-2s to establish. Without waiting, Oboe opens against
   earpiece and audio goes nowhere.

3. Frontend skips redundant set_speakerphone(false) when transitioning
   to BT — start_bluetooth_sco() handles speaker-off internally,
   avoiding a double Oboe restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-12 16:46:56 +04:00
parent a798634b3d
commit 7e8dc400dc
3 changed files with 30 additions and 7 deletions

View File

@@ -779,6 +779,10 @@ async fn is_speakerphone_on() -> Result<bool, String> {
/// Enable or disable Bluetooth SCO audio routing. Like speakerphone toggling,
/// this requires an Oboe stream restart so AAudio picks up the new route.
///
/// `startBluetoothSco()` is asynchronous — the SCO link takes 500ms-2s to
/// establish. We poll `isBluetoothScoOn()` up to 3 seconds before restarting
/// Oboe, so the streams open against the BT device rather than earpiece.
#[tauri::command]
#[allow(unused_variables)]
async fn set_bluetooth_sco(on: bool) -> Result<(), String> {
@@ -786,6 +790,21 @@ async fn set_bluetooth_sco(on: bool) -> Result<(), String> {
{
if on {
android_audio::start_bluetooth_sco()?;
// Wait for SCO link to actually connect before restarting Oboe.
// startBluetoothSco() is async — jumping straight to Oboe restart
// would open streams against earpiece, not the BT device.
let mut connected = false;
for i in 0..30 {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
if android_audio::is_bluetooth_sco_on().unwrap_or(false) {
tracing::info!(polls = i + 1, "set_bluetooth_sco: SCO connected");
connected = true;
break;
}
}
if !connected {
tracing::warn!("set_bluetooth_sco: SCO did not connect within 3s, proceeding anyway");
}
} else {
android_audio::stop_bluetooth_sco()?;
}