feat(android): DualSense host->client feedback — rumble + lightbar/LEDs/triggers
M4 Android stage 1 (DualSense feedback, host->client). Two Kotlin poll threads drain the connector's rumble (0xCA) + HID-output (0xCD) planes via blocking native pulls and render in Kotlin (Option B — no JNI upcalls, Android APIs stay in Kotlin). - crates/punktfunk-android: feedback.rs — nativeNextRumble (returns (low<<16)|high, or -1) + nativeNextHidout (writes [kind][fields] into a caller's direct ByteBuffer). Ungated; no new Cargo deps (next_rumble/next_hidout are on the quic feature already). - clients/android: GamepadFeedback.kt — rumble -> VibratorManager (two-motor amplitude), HID Led -> lightbar + PlayerLeds -> player LED via LightsManager (API 33+), adaptive triggers parsed + logged (no public Android API); resolves the connected pad, emulator -> logged no-op. Started/stopped in the StreamScreen lifecycle (stop + join before nativeClose). Verified live (emulator -> synthetic host, PUNKTFUNK_TEST_FEEDBACK=1): client received + decoded the full burst -- rumble low=16384 high=32768, Led r=10 g=20 b=30, PlayerLeds bits=4 player=1, Trigger which=1 mode=0x21 -- matching the host hook exactly. Rendering is a logged no-op on the emulator (no controller); real haptics/lightbar/player-LED need a physical pad. Deferred (need a physical DualSense + device enumeration): client->host rich input (touchpad/motion send_rich_input) and DualSense controller-type negotiation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@ use jni::JNIEnv;
|
||||
mod audio;
|
||||
#[cfg(target_os = "android")]
|
||||
mod decode;
|
||||
mod feedback;
|
||||
mod session;
|
||||
|
||||
/// Initialize `android_logger` once when the JVM loads the library. Logs land in logcat under the
|
||||
|
||||
Reference in New Issue
Block a user