phase 3(android): wire CallEngine::start to wzp-native audio FFI
Replaces the Android-side CallEngine::start() stub with a real implementation that mirrors the desktop start() body but routes all PCM through the standalone wzp-native cdylib loaded at startup via libloading instead of using CPAL. - desktop/src-tauri/src/wzp_native.rs: new module with a static OnceLock<libloading::Library> + cached raw fn pointers for every symbol we need (version, hello, audio_start/stop, read_capture, write_playout, is_running, capture/playout_latency_ms). init() resolves everything once at startup; accessors return default values if init() never ran. - desktop/src-tauri/src/lib.rs: drop the inline dlopen smoke test, add `mod wzp_native;` behind target_os="android", and invoke wzp_native::init() from the Tauri setup() callback so the library is loaded + all symbols cached before any CallEngine can touch audio. - desktop/src-tauri/src/engine.rs: the Android #[cfg] branch of CallEngine::start() now does the full QUIC handshake + signal loop + Opus send/recv tasks, calling wzp_native::audio_start() / audio_read_capture() / audio_write_playout() instead of the desktop CPAL rings. SyncWrapper now holds a placeholder Box<()> on Android because the audio backend lives in a process-global singleton inside libwzp_native.so rather than being owned per-engine. Next step: build #39 on the remote docker builder and smoke-test on Pixel 6 that the Connect button in the UI successfully brings up Oboe and streams audio through the dlopen boundary.
This commit is contained in:
@@ -7,10 +7,16 @@
|
||||
)]
|
||||
|
||||
// Call engine — now compiled on every platform. On desktop it runs the real
|
||||
// CPAL/VPIO audio pipeline; on Android `CallEngine::start()` currently returns
|
||||
// an error stub (see engine.rs — that's step C of the Oboe integration).
|
||||
// CPAL/VPIO audio pipeline; on Android the engine calls into the standalone
|
||||
// wzp-native cdylib (via the wzp_native module) for Oboe-backed audio.
|
||||
mod engine;
|
||||
|
||||
// Android runtime binding to libwzp_native.so (Oboe audio backend, built as
|
||||
// a standalone cdylib with cargo-ndk to avoid the Tauri staticlib symbol
|
||||
// leak — see docs/incident-tauri-android-init-tcb.md).
|
||||
#[cfg(target_os = "android")]
|
||||
mod wzp_native;
|
||||
|
||||
// CallEngine is only referenced from the non-Android connect/disconnect/etc
|
||||
// commands; the Android stubs return errors directly.
|
||||
#[cfg(not(target_os = "android"))]
|
||||
@@ -536,40 +542,24 @@ pub fn run() {
|
||||
tracing::info!("app data dir: {data_dir:?}");
|
||||
let _ = APP_DATA_DIR.set(data_dir);
|
||||
|
||||
// Phase 1 smoke test of the separate-cdylib approach to the
|
||||
// __init_tcb crash (see docs/incident-tauri-android-init-tcb.md):
|
||||
// dlopen the sibling libwzp_native.so that gradle dropped into
|
||||
// our jniLibs directory and call its exported wzp_native_version()
|
||||
// + wzp_native_hello() functions. If this logs
|
||||
// "wzp-native dlopen OK: version=42 msg=...",
|
||||
// we've validated the whole cdylib-split pipeline and can move
|
||||
// to Phase 2 (port the Oboe bridge into wzp-native).
|
||||
// Load the standalone wzp-native cdylib (Oboe audio bridge) and
|
||||
// cache its exported function pointers. The library handle is
|
||||
// kept alive in a 'static OnceLock for the lifetime of the
|
||||
// process, so CallEngine::start() can invoke its audio FFI
|
||||
// from anywhere. See src/wzp_native.rs and the incident report
|
||||
// in docs/incident-tauri-android-init-tcb.md.
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
match unsafe { libloading::Library::new("libwzp_native.so") } {
|
||||
Ok(lib) => {
|
||||
unsafe {
|
||||
match lib.get::<unsafe extern "C" fn() -> i32>(b"wzp_native_version") {
|
||||
Ok(version_fn) => {
|
||||
let v = version_fn();
|
||||
let mut buf = [0u8; 64];
|
||||
let msg = match lib.get::<unsafe extern "C" fn(*mut u8, usize) -> usize>(b"wzp_native_hello") {
|
||||
Ok(hello_fn) => {
|
||||
let n = hello_fn(buf.as_mut_ptr(), buf.len());
|
||||
String::from_utf8_lossy(&buf[..n]).into_owned()
|
||||
}
|
||||
Err(e) => format!("<no hello: {e}>"),
|
||||
};
|
||||
tracing::info!("wzp-native dlopen OK: version={v} msg=\"{msg}\"");
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("wzp-native loaded but dlsym(wzp_native_version) failed: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
match wzp_native::init() {
|
||||
Ok(()) => {
|
||||
tracing::info!(
|
||||
"wzp-native loaded: version={} msg=\"{}\"",
|
||||
wzp_native::version(),
|
||||
wzp_native::hello()
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("wzp-native dlopen failed: {e}");
|
||||
tracing::warn!("wzp-native init failed: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user