From 7d6328db0f0babf06689c63f7e4b894303bac2b5 Mon Sep 17 00:00:00 2001 From: Edison Jwa Date: Wed, 10 Jun 2026 19:56:36 +0900 Subject: [PATCH] fix(audio): create CoreML/ONNX VAD worker on backend switch Root cause: when VadBackend::SileroOnnx was selected, the capture callback set the worker to None but never called try_new() to create a replacement. The desktop path (engine.rs) correctly calls SileroOnnxVadWorker::try_new(), but the iOS (CoreML) and Android (ONNX) mobile paths only cleared the old worker without spawning a new one. The VAD stayed stuck at 'warming up' forever, using the WebRTC fallback for all voice activity detection. Fix: - iOS: call AppleCoreMlVadWorker::try_new() when SileroOnnx backend is selected; mark fallback only on failure - Android: call SileroOnnxVadWorker::try_new() with the model bundle path when SileroOnnx backend is selected; same fallback logic --- crates/chanora_audio/src/android_voice_unit.rs | 13 ++++++++++--- crates/chanora_audio/src/ios_voice_unit.rs | 12 +++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/chanora_audio/src/android_voice_unit.rs b/crates/chanora_audio/src/android_voice_unit.rs index 75ed66f..0253035 100644 --- a/crates/chanora_audio/src/android_voice_unit.rs +++ b/crates/chanora_audio/src/android_voice_unit.rs @@ -354,9 +354,16 @@ impl AndroidCaptureState { self.fallback_warned_backend = None; match vad_backend { crate::VadBackend::SileroOnnx => { - self.silero_vad_worker = None; - self.mark_vad_fallback_active(crate::VadBackend::SileroOnnx); - self.audio_processing_stats.set_vad_fallback_active(true); + let model_path = crate::vad::silero_model_bundle_path(); + self.silero_vad_worker = + crate::vad::silero_onnx::SileroOnnxVadWorker::try_new(&model_path); + if self.silero_vad_worker.is_some() { + self.fallback_warned_backend = None; + self.audio_processing_stats.set_vad_fallback_active(false); + } else { + self.mark_vad_fallback_active(crate::VadBackend::SileroOnnx); + self.audio_processing_stats.set_vad_fallback_active(true); + } } _ => { self.silero_vad_worker = None; diff --git a/crates/chanora_audio/src/ios_voice_unit.rs b/crates/chanora_audio/src/ios_voice_unit.rs index b730325..9466599 100644 --- a/crates/chanora_audio/src/ios_voice_unit.rs +++ b/crates/chanora_audio/src/ios_voice_unit.rs @@ -351,9 +351,15 @@ impl IosCaptureState { self.current_vad_backend = vad_backend; self.fallback_warned_backend = None; if vad_backend == crate::VadBackend::SileroOnnx { - self.silero_coreml_worker = None; - self.mark_vad_fallback_active(crate::VadBackend::SileroOnnx); - self.audio_processing_stats.set_vad_fallback_active(true); + self.silero_coreml_worker = + crate::vad::apple_coreml::AppleCoreMlVadWorker::try_new(); + if self.silero_coreml_worker.is_some() { + self.fallback_warned_backend = None; + self.audio_processing_stats.set_vad_fallback_active(false); + } else { + self.mark_vad_fallback_active(crate::VadBackend::SileroOnnx); + self.audio_processing_stats.set_vad_fallback_active(true); + } } else { self.silero_coreml_worker = None; self.audio_processing_stats.set_vad_fallback_active(false);