fix(android): run set_audio_mode_communication on Tauri main thread
spawn_blocking uses arbitrary thread-pool threads that don't have the Android JNI context initialized, causing ndk_context::android_context() to panic. Switch to run_on_main_thread (where the context is always valid) via a oneshot channel, with a 2s timeout. Panic is caught and forwarded as an Err so the debug log captures it rather than crashing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -96,6 +96,35 @@ pub fn set_audio_mode_communication() -> Result<(), String> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run `set_audio_mode_communication` on Tauri's main thread, where the
|
||||||
|
/// Android context is initialized. Calling it from arbitrary Tokio blocking
|
||||||
|
/// workers panics inside `ndk_context::android_context()`.
|
||||||
|
pub async fn set_audio_mode_communication_on_main(
|
||||||
|
app: tauri::AppHandle,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
|
app.run_on_main_thread(move || {
|
||||||
|
let result = std::panic::catch_unwind(set_audio_mode_communication)
|
||||||
|
.map_err(|panic| {
|
||||||
|
if let Some(s) = panic.downcast_ref::<&str>() {
|
||||||
|
format!("panic: {s}")
|
||||||
|
} else if let Some(s) = panic.downcast_ref::<String>() {
|
||||||
|
format!("panic: {s}")
|
||||||
|
} else {
|
||||||
|
"panic: unknown".to_string()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and_then(|r| r);
|
||||||
|
let _ = tx.send(result);
|
||||||
|
})
|
||||||
|
.map_err(|e| format!("run_on_main_thread: {e}"))?;
|
||||||
|
|
||||||
|
tokio::time::timeout(std::time::Duration::from_secs(2), rx)
|
||||||
|
.await
|
||||||
|
.map_err(|_| "set_audio_mode_communication timed out after 2s".to_string())?
|
||||||
|
.map_err(|_| "set_audio_mode_communication result channel closed".to_string())?
|
||||||
|
}
|
||||||
|
|
||||||
/// Restore `AudioManager.MODE_NORMAL`. Call when a VoIP call ends.
|
/// Restore `AudioManager.MODE_NORMAL`. Call when a VoIP call ends.
|
||||||
pub fn set_audio_mode_normal() -> Result<(), String> {
|
pub fn set_audio_mode_normal() -> Result<(), String> {
|
||||||
let (vm, activity) = jvm_and_activity()?;
|
let (vm, activity) = jvm_and_activity()?;
|
||||||
|
|||||||
@@ -663,15 +663,13 @@ impl CallEngine {
|
|||||||
"connect:audio_mode_start",
|
"connect:audio_mode_start",
|
||||||
serde_json::json!({ "t_ms": call_t0.elapsed().as_millis() }),
|
serde_json::json!({ "t_ms": call_t0.elapsed().as_millis() }),
|
||||||
);
|
);
|
||||||
let audio_mode_task =
|
match crate::android_audio::set_audio_mode_communication_on_main(app.clone()).await {
|
||||||
tokio::task::spawn_blocking(crate::android_audio::set_audio_mode_communication);
|
Ok(()) => crate::emit_call_debug(
|
||||||
match tokio::time::timeout(std::time::Duration::from_secs(2), audio_mode_task).await {
|
|
||||||
Ok(Ok(Ok(()))) => crate::emit_call_debug(
|
|
||||||
&app,
|
&app,
|
||||||
"connect:audio_mode_done",
|
"connect:audio_mode_done",
|
||||||
serde_json::json!({ "t_ms": call_t0.elapsed().as_millis() }),
|
serde_json::json!({ "t_ms": call_t0.elapsed().as_millis() }),
|
||||||
),
|
),
|
||||||
Ok(Ok(Err(e))) => {
|
Err(e) => {
|
||||||
tracing::warn!("set_audio_mode_communication failed: {e}");
|
tracing::warn!("set_audio_mode_communication failed: {e}");
|
||||||
crate::emit_call_debug(
|
crate::emit_call_debug(
|
||||||
&app,
|
&app,
|
||||||
@@ -682,26 +680,6 @@ impl CallEngine {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
|
||||||
crate::emit_call_debug(
|
|
||||||
&app,
|
|
||||||
"connect:audio_mode_panic",
|
|
||||||
serde_json::json!({
|
|
||||||
"t_ms": call_t0.elapsed().as_millis(),
|
|
||||||
"error": e.to_string(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
crate::emit_call_debug(
|
|
||||||
&app,
|
|
||||||
"connect:audio_mode_timeout",
|
|
||||||
serde_json::json!({
|
|
||||||
"t_ms": call_t0.elapsed().as_millis(),
|
|
||||||
"timeout_ms": 2000,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user