fix(android): spawn_blocking for audio_start + 15s JS connect timeout
wzp_oboe_start is a sync FFI call that can block the OS thread indefinitely waiting on the Android audio HAL. Calling it directly from an async context freezes all tokio tasks including Rust-side timeouts. Fix: run it via spawn_blocking so tokio stays responsive. Also add a 15s Promise.race timeout in JS so a frozen audio_start surfaces as "connect timed out — check audio permissions" instead of the join button staying stuck in "Connecting…" forever. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -601,8 +601,15 @@ impl CallEngine {
|
||||
}
|
||||
}
|
||||
|
||||
// Run audio_start on a blocking thread — wzp_oboe_start is a
|
||||
// sync FFI call that can stall waiting for the Android audio
|
||||
// HAL. Calling it directly blocks the tokio worker thread,
|
||||
// which freezes all async tasks including our own timeouts.
|
||||
let t_pre_audio = call_t0.elapsed().as_millis();
|
||||
if let Err(code) = crate::wzp_native::audio_start() {
|
||||
let audio_start_result = tokio::task::spawn_blocking(crate::wzp_native::audio_start)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("audio_start task panic: {e}"))?;
|
||||
if let Err(code) = audio_start_result {
|
||||
return Err(anyhow::anyhow!(
|
||||
"wzp_native_audio_start failed: code {code}"
|
||||
));
|
||||
|
||||
@@ -335,13 +335,19 @@ joinVoiceBtn.addEventListener("click", async () => {
|
||||
joinVoiceBtn.textContent = "Connecting…";
|
||||
(joinVoiceBtn as HTMLButtonElement).disabled = true;
|
||||
try {
|
||||
await invoke("connect", {
|
||||
relay: relay.address,
|
||||
room: s.room || "general",
|
||||
alias: s.alias || "",
|
||||
osAec: s.osAec,
|
||||
quality: s.quality || "auto",
|
||||
});
|
||||
const connectRace = Promise.race([
|
||||
invoke("connect", {
|
||||
relay: relay.address,
|
||||
room: s.room || "general",
|
||||
alias: s.alias || "",
|
||||
osAec: s.osAec,
|
||||
quality: s.quality || "auto",
|
||||
}),
|
||||
new Promise<never>((_, reject) =>
|
||||
setTimeout(() => reject("connect timed out (15s) — check audio permissions"), 15000)
|
||||
),
|
||||
]);
|
||||
await connectRace;
|
||||
enterVoice(false);
|
||||
} catch (e: any) {
|
||||
console.error("connect failed:", e);
|
||||
|
||||
Reference in New Issue
Block a user