fix: eliminate all native thread creation — run everything single-threaded

pthread_create crashes on Android due to static bionic __init_tcb stubs
in the Rust std prebuilt rlibs. This is unfixable without rebuilding std.

Solution: run the entire call (QUIC connect, handshake, media send/recv)
on a single tokio current_thread runtime. The JNI startCall() now blocks,
so Kotlin dispatches it to Dispatchers.IO (JVM thread, not pthread).

Audio pipeline temporarily simplified to silence frames — will restore
once threading is solved (either via Java Thread or rebuilding std).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude
2026-04-05 09:52:28 +00:00
parent bae03365da
commit af85a49e86
3 changed files with 203 additions and 340 deletions

View File

@@ -56,12 +56,22 @@ class CallViewModel : ViewModel(), WzpCallback {
engineInitialized = true
}
_callState.value = 1 // Connecting
val result = engine?.startCall(relayAddr, room) ?: -1
if (result == 0) {
startStatsPolling()
} else {
_callState.value = 0
_errorMessage.value = "Failed to start call (code $result)"
startStatsPolling()
// startCall blocks (runs tokio on calling thread), so dispatch
// to a background coroutine. Using Dispatchers.IO which uses
// Java threads (not native pthread_create).
viewModelScope.launch(kotlinx.coroutines.Dispatchers.IO) {
try {
val result = engine?.startCall(relayAddr, room) ?: -1
if (result != 0) {
_callState.value = 0
_errorMessage.value = "Failed to start call (code $result)"
}
} catch (e: Exception) {
_callState.value = 0
_errorMessage.value = "Engine error: ${e.message}"
}
}
} catch (e: Exception) {
_callState.value = 0