NexusIRL is a free, open-source IRL live streaming app for Android: SRTLA bonding of mobile data and Wi-Fi, adaptive bitrate, SRT and RTMP, Twitch and Kick chat, OBS remote control. An Android port of Moblin.
SUPERSEDED (2026-10-19): this spec is replaced by docs/PORT_PLAN.md, which is based on the reverse-engineered Moblin architecture. See PORT_PLAN.md §2 for what changed and why. Kept for history only.
Role: Lead Android Systems Architect / Senior Mobile Systems Engineer
Objective: Replicate the ultra-low latency, professional-grade streaming capabilities of Moblin (iOS) for the Android ecosystem.
Primary Goal: Sub-100ms latency for SRT/RTMP streaming with manual hardware camera control.
To match iOS performance, the media engine must bypass the JVM for packetization.
libsrt (C++) integration via NDK.librtmp and openssl.MediaCodec with:
KEY_LATENCY = 0 (Zero-latency mode)KEY_PRIORITY = 1 (Real-time priority)CaptureRequest for:
PowerManager.getThermalHeadroom to trigger dynamic bitrate/FPS downscaling before thermal throttling occurs.Library: Google Oboe (C++)
Logic:
A custom C++ mixer to handle raw PCM buffers from:
Target: sub-10ms round-trip latency
root/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── cpp/ # Native C++ Logic (Oboe, libsrt, FFmpeg)
│ │ │ │ ├── mixer/ # Low-latency Audio Mixer
│ │ │ │ ├── streaming/ # Protocol implementations
│ │ │ │ └── CMakeLists.txt
│ │ │ ├── java/com/moblin/
│ │ │ │ ├── core/ # Permissions, Battery, Thermal logic
│ │ │ │ ├── data/ # Local Storage (DataStore, Room)
│ │ │ │ ├── domain/ # Interfaces and UseCases
│ │ │ │ │ ├── model/ # Kotlin Entities
│ │ │ │ │ └── repository/ # Interface Protocols
│ │ │ │ ├── ui/ # Jetpack Compose Screens/ViewModels
│ │ │ │ └── service/ # Foreground Service (Streaming process)
│ │ │ └── res/ # UI Resources
└── build.gradle.kts # Dependency Version Catalog
| iOS Framework | Android Equivalent | Library/Tool |
|---|---|---|
| AVFoundation | Camera2 + Oboe | Google Oboe / Camera2 API |
| Metal | OpenGL ES 3.2 | GLSurfaceView / EGL Context |
| Combine / Swift Concurrency | Coroutines + Flow | Kotlin Coroutines |
| SwiftUI | Jetpack Compose | Compose 1.5+ |
| UserDefaults | Jetpack DataStore | DataStore Preferences |
| CoreMotion | SensorManager | Android Sensor Framework |
data class StreamProfile(
val id: UUID = UUID.randomUUID(),
val name: String,
val endpointUrl: String,
val protocol: ProtocolType, // SRT, RTMP
val bitrate: Int, // bps
val resolution: Size, // e.g., 1920x1080
val fps: Int,
val srtLatency: Int // ms
)
data class CameraCaptureState(
val iso: Int,
val shutterSpeed: Long,
val whiteBalance: Int,
val thermalLevel: Int
)
interface StreamEngine {
fun start(profile: StreamProfile)
fun stop()
fun getStreamMetrics(): Flow<StreamStats>
}
interface AudioMixer {
fun setInputGain(volume: Float)
fun toggleSource(sourceId: String, enabled: Boolean)
}
Viewfinder Performance:
Never use TextureView. Use SurfaceView for direct-to-display rendering.
Memory Safety:
Enforce RAII (Resource Acquisition Is Initialization) in C++.
HandlerThread orDispatchers.DefaultDraggable orSwipeable modifierscom.moblin.core
com.moblin.data
com.moblin.domain
com.moblin.ui
com.moblin.service
arm64-v8astartStream()stopStream()pushVideoFrame()pushAudioFrame()StreamEngine:
Camera → GL → MediaCodec → Native Stream Engine
End of Specification