Limitations of FadCam's Remote Streaming Capabilities: 9 Critical Constraints Explained
FadCam's remote streaming only supports H.264 video, requires a minimum 2-second buffer before playback starts, maintains a hard 15-second circular buffer limit, and operates on local Wi-Fi networks by default.
FadCam is a privacy-first Android dashcam application that delivers video via HTTP Live Streaming (HLS). The implementation in anonfaded/FadCam prioritizes lightweight operation and minimal resource consumption, which creates specific technical boundaries. Understanding these limitations of FadCam's remote streaming capabilities ensures developers configure appropriate expectations for real-time video delivery.
Codec and Format Limitations
H.264 Only: No HEVC/H.265 Browser Support
FadCam exclusively supports H.264 video encoding for remote streaming. The codebase explicitly warns users when High Efficiency Video Coding (HEVC/H.265) is selected, as browsers cannot decode these streams.
In app/src/main/res/values/strings.xml at line 1971, the warning string codec_hevc_incompatible_message alerts users that "Live streaming via HLS requires H.264 codec." The streaming implementation never emits H.265 initialization segments, and the HLS playlist builder assumes H.264 formatting. Users must manually switch codecs before initiating a stream, or playback will fail to load in any browser.
Single Track Output: No Independent Audio Streams
The HLS stream contains only a single video track with embedded audio. The FragmentedMp4MuxerWrapper class forwards video fragments exclusively, mixing audio directly into the fMP4 container without exposing separate tracks.
This architecture prevents clients from independently muting audio or selecting alternative audio tracks. All audio remains embedded within the video fragments, limiting flexibility for viewers who might want audio-only streams or subtitle overlays.
Buffer and Timing Constraints
Two-Second Minimum Buffer Requirement
Playback cannot begin until at least two media fragments are buffered. In RemoteStreamManager.java at lines 78-82, the getStatusJson() method checks if bufferedCount < 2 and reports a "buffering" state to connected clients.
The playlist generator returns null when fewer than two fragments exist (lines 74-77). This creates an unavoidable startup delay of approximately 2 seconds, during which the stream URL is active but video remains unavailable. The constraint ensures clients receive complete initialization data before rendering begins.
15-Second Circular Buffer Limit
The streaming buffer maintains a maximum of 15 one-second fragments defined by BUFFER_SIZE = 15 in RemoteStreamManager.java at lines 42-45. When the buffer reaches capacity, older fragments are automatically evicted to bound memory usage.
This limitation means viewers joining a live stream can only access approximately 15 seconds of recent video history. Older data is permanently discarded, making FadCam unsuitable for applications requiring extended DVR-style playback buffers or time-shifted viewing.
Connectivity and Session Requirements
Recording-Dependent Streaming Lifecycle
Remote streaming requires an active recording session. The setStreamingEnabled(true) method starts the HTTP server, but the stream only enters "ready" state when isRecording() returns true and an initialization segment exists, as implemented at lines 66-78 in RemoteStreamManager.java.
If the user stops recording or the application enters the background, the stream immediately shuts down and the HLS URL ceases serving data. This coupling ensures streaming only occurs when privacy consent is explicitly granted through the recording interface, but prevents "camera-only" monitoring modes without file storage.
Local Network Restriction Without Cloud Relay
By default, streaming operates exclusively on local Wi-Fi subnets. The HLS endpoint construction in WatchRemoteFragment.java at line 116 uses the device's Wi-Fi IP address to build URLs like http://192.168.x.x:8080/live.m3u8.
Cloud relay functionality exists but remains disabled unless explicitly activated in settings. Without this relay, remote viewers attempting access from outside the local network will fail to connect, as the server binds to local interfaces only. This design prioritizes privacy by minimizing external exposure but limits flexibility for remote monitoring.
Quality and Scalability Limitations
Static Bitrate: No Adaptive Streaming
FadCam streams use a single static quality configuration stored in StreamQuality.java. The implementation lacks adaptive bitrate (ABR) algorithms or multi-resolution ladder support found in enterprise streaming platforms.
All connected clients receive identical bitrate and frame rate settings regardless of their available bandwidth or device capabilities. Network fluctuations may cause buffering or quality degradation without automatic adjustment, and mobile clients on constrained connections cannot request lower-quality variants.
Device-Dependent Concurrent Client Limits
While clientMetricsMap tracks connected clients, the codebase imposes no explicit hard limit on concurrent viewers. Practical capacity depends entirely on the host device's CPU, RAM, and network stack performance.
In real-world usage, most Android devices support only a handful of simultaneous connections before experiencing thermal throttling or network congestion. This makes FadCam suitable for personal monitoring or small-scale sharing but unsuitable for broadcast scenarios requiring dozens of concurrent viewers.
Staleness Detection and Frozen Streams
The server pushes status updates every 2 seconds, but lastRelayUploadMs only updates when segment uploads succeed in cloud mode (lines 1000-1005 in RemoteStreamManager.java). If the device freezes, stalls, or loses network connectivity, the playlist stops updating while the HTTP server remains responsive.
Viewers may encounter frozen video without immediate error messages, and the dashboard uses the stale timestamp to indicate stream death only after extended delays. This creates a "zombie stream" condition where connections appear active but deliver no new data.
Practical Implementation Examples
Enabling Remote Streaming in Your Application
// Initialize the stream manager singleton
val manager = RemoteStreamManager.getInstance()
manager.setContext(requireContext())
manager.setStreamingEnabled(true)
manager.setStreamingMode(RemoteStreamManager.StreamingMode.STREAM_AND_SAVE)
// Start the foreground service to maintain recording
startService(Intent(requireContext(), RemoteStreamService::class.java))
The singleton construction resides at lines 40-68, with server enabling logic at lines 60-73 in RemoteStreamManager.java.
Constructing the Local HLS Playback URL
// Retrieve the device's Wi-Fi IP address
String localIp = RemoteStreamService.getLocalIpAddress();
String hlsUrl = "http://" + localIp + ":8080/live.m3u8";
This URL construction pattern appears in WatchRemoteFragment.java at line 116, defaulting to port 8080.
Checking Stream Health via the Status Endpoint
curl http://<device_ip>:8080/status
A healthy stream returns JSON similar to:
{
"streaming": true,
"state": "ready",
"message": "Stream is ready for playback.",
"fragmentsBuffered": 8,
"hasInitSegment": true
}
The getStatusJson() method at lines 1717-1760 caches responses for 1 second to prevent excessive polling overhead.
Handling Codec Warnings in the UI
When users select HEVC recording, the application displays the warning defined in strings.xml:
<string name="codec_hevc_incompatible_message">
📡 Live streaming via HLS requires H.264 codec.
Please switch codecs to enable remote viewing.
</string>
Summary
- H.264 required: HEVC/H.265 streams are incompatible with browser-based HLS playback.
- 2-second startup delay: Streams require two buffered fragments before the playlist becomes available.
- 15-second history limit: The circular buffer automatically discards fragments older than 15 seconds.
- Recording dependency: Streaming stops when recording stops or the app backgrounds.
- Local network default: Internet access requires explicit cloud relay configuration.
- Static quality: No adaptive bitrate or resolution selection for varying network conditions.
- Limited concurrency: Practical viewer counts depend on device hardware capabilities.
- No separate audio tracks: Audio is embedded in video fragments only.
Frequently Asked Questions
Why does the stream buffer for 2 seconds before playing?
FadCam requires at least two one-second media fragments before generating the HLS playlist. According to the source code in RemoteStreamManager.java at lines 74-82, the getStatusJson() method checks bufferedCount < 2 and returns a buffering state until sufficient data exists. This ensures clients receive complete initialization segments before attempting playback.
Can I stream FadCam video over the internet without a cloud relay?
No, local Wi-Fi networks are required by default. The HLS endpoint in WatchRemoteFragment.java (line 116) constructs URLs using the device's local Wi-Fi IP address. Without enabling the optional cloud relay in settings, the HTTP server only binds to local network interfaces, blocking external internet access while maintaining privacy.
Why does my stream stop when I close the application or stop recording?
FadCam's streaming architecture ties the HTTP server lifecycle to the active recording session. The isRecording() check at lines 66-78 in RemoteStreamManager.java controls the "ready" state, and stopping recording triggers immediate server shutdown. This design ensures streaming only occurs during explicit recording sessions with user consent.
Does FadCam support 4K or high-bitrate streaming?
FadCam supports high resolutions only within the constraints of H.264 encoding and static bitrate configuration. The StreamQuality.java file stores a single quality preset without adaptive variants. While 4K H.264 streams are technically possible, the 15-second buffer limit and lack of bandwidth adaptation may cause playback issues on constrained networks.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →