Android Cast (POC)
Roadmap & alpha scope: docs/ROADMAP.md · USB-C/HDMI: docs/USB_HDMI_CAST.md · Commercial (dev-gated): docs/COMMERCIAL.md
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
- Install the same APK on two devices on the same Wi‑Fi.
- Receiver (TV): Receive → match transport (TCP/UDP) & options → tap Start listening (notification appears; service keeps running).
- Sender (tablet): Send → same transport → pick receiver → PIN → approve screen capture.
- Watch the notification on both devices for connection status (not only the toast).
- 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
Surfaceattaches (or return to it after rotation).
Build
Use JDK 17 or 21 (Gradle does not run on JDK 25 yet):
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