# Android Cast (POC) Minimal LAN screen-casting proof of concept in **Java**. Captures screen + playback audio, encodes **H.264 + AAC**, streams over **TCP or UDP** to a receiver that decodes and plays back. ## Features - UDP broadcast discovery on the local network - TCP or UDP stream transport (selectable; must match on both devices) - PIN auth (SHA-256 hash, default `1234`) - Screen capture → H.264 (AVC) with quality presets and scaled capture resolution - Playback audio capture (API 29+) → AAC-LC - Runtime notification permission (Android 13+) ## Quick start 1. Install the same APK on two devices on the **same Wi‑Fi**. 2. **Receiver** (TV): **Receive** → match transport (TCP/UDP) & options → tap **Start listening** (notification appears; service keeps running). 3. **Sender** (tablet): **Send** → **same transport** → pick receiver → PIN → approve screen capture. 4. Watch the **notification** on both devices for connection status (not only the toast). 5. Stop from the notification **Stop** action. ### If video never appears - Transport must match on both sides (e.g. both TCP). - Receiver must show *Listening* or *Ready* in the notification before you cast. - Sender notification should reach *Casting via TCP · WxH* — if it shows *Screen capture data missing*, reinstall and try again (Android 13+ intent fix). - Keep the receiver UI open once so the video `Surface` attaches (or return to it after rotation). ## Build Use **JDK 17 or 21** (Gradle does not run on JDK 25 yet): ```bash export JAVA_HOME=/usr/lib/jvm/openjdk-bin-21 cd "/home/foxx/repos/My Projects/android cast" ./gradlew assembleDebug adb install -r app/build/outputs/apk/debug/app-debug.apk ``` ## Stream options | Option | Effect | |--------|--------| | **Transport TCP** | Reliable delivery; default | | **Transport UDP** | Lower latency, may drop frames (POC) | | **Quality Low/Med/High** | Video bitrate 0.8 / 2 / 4 Mbps and FPS 20 / 24 / 30 | | **Resolution** | Scales VirtualDisplay before encode (full, 75%, 50%, or max 720p height) | | **Audio** | `AudioPlaybackCapture` + AAC (Android 10+) | ## Protocol | Step | Description | |------|-------------| | Discovery | UDP `41234`, JSON with `magic`, `name`, `port`, `transport` | | Connect | TCP or UDP port `41235` | | Auth | `HELLO` → `AUTH` → `AUTH_OK` → `CAST_SETTINGS` | | Stream | `STREAM_CONFIG`, `VIDEO_FRAME`, `AUDIO_CONFIG`, `AUDIO_FRAME` | UDP frames use `ACUD` header and fragmentation for payloads > ~1.2 KB. ## Bluetooth / BLE **Not viable for this video stream.** Practical throughput: - **BLE**: ~100–300 kb/s — fine for control/metadata only - **Bluetooth Classic (SPP)**: often ~1–3 Mb/s theoretical — still far below 720p H.264 (~2–8 Mb/s), with high latency A phone cannot “passthrough” a live encoded screen stream over BLE to another device for playback without a custom high-bandwidth profile (which consumer Android does not expose for arbitrary apps). Use **Wi‑Fi** for media; BT could be added later only for discovery/pairing if needed. ## Persistent services (AIDL) Casting runs in **foreground services** with tray notifications: | Service | Role | |---------|------| | `ScreenCastService` | Sender — capture, encode, stream | | `ReceiverCastService` | Receiver — listen, decode, play | Activities bind via AIDL (`ICastSenderService` / `ICastReceiverService`) for status updates and (on the receiver) attaching the video `Surface`. Rotating the screen or leaving the app does **not** stop the receiver listener; the sender keeps casting until you tap **Stop** in the notification. ## Limitations - No TLS encryption (LAN cleartext POC) - UDP mode may glitch under load - Audio captures **playback** routed through the system (not microphone); some apps may be silent by policy - Single sender → single receiver