79217eb93d
apple / swift (push) Successful in 52s
ci / docs-site (push) Successful in 27s
android / android (push) Successful in 4m52s
ci / web (push) Successful in 26s
ci / bench (push) Successful in 1m33s
ci / rust (push) Successful in 6m56s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 4m54s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 4m29s
deb / build-publish (push) Successful in 6m46s
docker / deploy-docs (push) Successful in 22s
Rust-heavy client model (like punktfunk-client-linux): a new cdylib crate crates/punktfunk-android links punktfunk-core and exposes the JNI seam; Kotlin (clients/android) owns only the Android-framework surface. Kotlin can't import the C header the way Swift can, so the bridge is written in Rust to reuse the Linux client's orchestration rather than re-port it. - crates/punktfunk-android: JNI bridge — abiVersion/coreVersion native-link proof + session connect/close handle; plane pumps stubbed for M4 stage 1. - clients/android: Gradle project — :app (Compose) + :kit (Android library with a cargo-ndk Exec task -> jniLibs). AGP 9.2 / Gradle 9.4.1 / Kotlin 2.3.21 / Compose BOM 2026.05.01 / compileSdk 37 / targetSdk 36 / minSdk 31, shipping arm64-v8a + x86_64. Phone + TV (leanback) installable. README rewritten. - .gitea/workflows/android.yml: CI mirroring apple.yml on a Linux runner. - punktfunk-core: switch rcgen to the ring backend so the whole quic tree is aws-lc-free (smaller client .so, cmake-free cross-compile; a win for all targets). Validated on this box: :app:assembleDebug -> APK with both ABIs; emulator first-light renders the bridge linked (core ABI v2) with logcat confirmation; clippy -D warnings + cargo fmt clean; core tests green on the ring backend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
2.9 KiB
Rust
68 lines
2.9 KiB
Rust
//! punktfunk Android client — the JNI bridge ("nativecore") over `punktfunk-core`.
|
|
//!
|
|
//! Architecture: the **Rust-heavy** client model (like `punktfunk-client-linux`, *not* the
|
|
//! thin-native-over-C-ABI Apple model). This `cdylib` links `punktfunk-core` directly and drives
|
|
//! the whole `punktfunk/1` protocol through [`punktfunk_core::client::NativeClient`]; Kotlin owns
|
|
//! only the Android-framework surface (Compose UI, `SurfaceView` lifecycle, input capture,
|
|
//! `NsdManager` discovery, Keystore). The JNI seam below is the one place the two languages meet.
|
|
//!
|
|
//! Why Rust-heavy: Kotlin cannot `import` the cbindgen C header the way Swift can, so a native
|
|
//! bridge is unavoidable. Writing it in Rust lets the Android client reuse the Linux client's
|
|
//! orchestration verbatim — audio jitter ring, the VK keymap inverse, latency/skew math, the
|
|
//! input capture state machine, trust/pairing logic — instead of re-porting it into Kotlin.
|
|
//!
|
|
//! JNI symbols map to `io.unom.punktfunk.kit.NativeBridge` in the `:kit` Gradle module
|
|
//! (`clients/android`). The current surface is the scaffold's native-link proof
|
|
//! (`abiVersion`/`coreVersion`) plus the session handle lifecycle in [`session`]; the per-plane
|
|
//! pumps (video → AMediaCodec, audio → Oboe), input, audio, pairing and mode renegotiation are
|
|
//! the next milestone (see the TODOs in [`session`]).
|
|
|
|
use jni::objects::JObject;
|
|
use jni::sys::jint;
|
|
use jni::JNIEnv;
|
|
|
|
mod session;
|
|
|
|
/// Initialize `android_logger` once when the JVM loads the library. Logs land in logcat under the
|
|
/// `punktfunk` tag. Android-only — there is no JVM (and no logcat) on the host build.
|
|
#[cfg(target_os = "android")]
|
|
#[no_mangle]
|
|
pub extern "system" fn JNI_OnLoad(
|
|
_vm: *mut jni::sys::JavaVM,
|
|
_reserved: *mut std::ffi::c_void,
|
|
) -> jint {
|
|
android_logger::init_once(
|
|
android_logger::Config::default()
|
|
.with_max_level(log::LevelFilter::Info)
|
|
.with_tag("punktfunk"),
|
|
);
|
|
log::info!(
|
|
"punktfunk_android loaded (core ABI v{})",
|
|
punktfunk_core::ABI_VERSION
|
|
);
|
|
jni::sys::JNI_VERSION_1_6
|
|
}
|
|
|
|
/// `NativeBridge.abiVersion(): Int` — the core's C-ABI version. A non-error return is the
|
|
/// scaffold's proof that `System.loadLibrary` found the `.so`, the JNI symbol resolved, and the
|
|
/// linked `punktfunk-core` is the one we expect.
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_io_unom_punktfunk_kit_NativeBridge_abiVersion(
|
|
_env: JNIEnv,
|
|
_this: JObject,
|
|
) -> jint {
|
|
punktfunk_core::ABI_VERSION as jint
|
|
}
|
|
|
|
/// `NativeBridge.coreVersion(): String` — the crate version, proving JNI string marshaling works.
|
|
#[no_mangle]
|
|
pub extern "system" fn Java_io_unom_punktfunk_kit_NativeBridge_coreVersion<'local>(
|
|
env: JNIEnv<'local>,
|
|
_this: JObject<'local>,
|
|
) -> jni::sys::jstring {
|
|
match env.new_string(env!("CARGO_PKG_VERSION")) {
|
|
Ok(s) => s.into_raw(),
|
|
Err(_) => JObject::null().into_raw(),
|
|
}
|
|
}
|