130 Widgets

Building tools. Learning to build tools. Learning to build learning tools.

7. Low-Latency Streaming Options Network

Getting the stream to open at all — overcoming the self-signed certificate — was the primary challenge. But there’s a secondary challenge: making the stream feel live. A 3D printer camera is for monitoring. If the feed is 10 seconds behind reality, you can’t tell whether the print just failed or whether that was yesterday. The streaming options in CameraView are a deliberate set of tradeoffs tuned for minimum latency.

KSOptions: The Configuration Object

All KSPlayer configuration flows through a KSOptions instance passed to KSPlayerLayer:

let options = KSOptions()
options.avOptions["rtsp_transport"] = "tcp"
options.avOptions["tls_verify"] = "0"
options.nobuffer = true
options.codecLowDelay = true
options.maxAnalyzeDuration = 1_000_000
options.probesize = 500_000
options.registerRemoteControll = false
options.canStartPictureInPictureAutomaticallyFromInline = true

avOptions is a [String: Any] dictionary passed directly to FFmpeg’s AVFormatContext as RTSP protocol options. The other properties are KSPlayer-level settings that control its own buffering and decode pipeline. Let’s go through each one.

rtsp_transport: TCP vs UDP

RTSP uses a separate channel to carry the actual video data (RTP packets). By default, FFmpeg tries UDP for this channel, because UDP has lower overhead than TCP. But UDP is a fire-and-forget protocol — packets can be lost, duplicated, or arrive out of order.

On a home network, UDP is generally fine. But there are common scenarios where it fails:

Setting rtsp_transport = "tcp" tells FFmpeg to interleave the RTP video data inside the existing RTSP TCP connection, rather than opening a separate UDP port. This is slower in theory, but far more reliable in practice for LAN camera monitoring.

tls_verify: Bypassing Certificate Validation

As established in Section 1, this is the whole reason KSPlayer was chosen:

options.avOptions["tls_verify"] = "0"

This passes FFmpeg’s tls_verify option to the TLS layer, disabling certificate chain verification. The TLS handshake still occurs — encryption keys are negotiated, traffic is encrypted — but the server’s certificate is not checked against any trust store.

Security Note

Disabling TLS certificate verification opens the connection to a man-in-the-middle attack: someone on the same network could intercept the connection and present their own certificate, and the app would accept it. For a device on your home LAN, this risk is generally acceptable — you control the network. If you were connecting over the internet, or on an untrusted network, certificate pinning would be the right approach instead. Certificate pinning means embedding the printer’s specific public key in the app and validating against that, rather than the CA chain.

nobuffer and codecLowDelay: Minimizing Latency

Video players buffer incoming data by default. Buffering smooths over network jitter — if packets arrive unevenly, the player drains from the buffer at a steady rate, so playback doesn’t stutter. This is great for watching a movie over a slow connection. For a printer camera, it introduces unnecessary delay.

options.nobuffer = true
options.codecLowDelay = true

The combined effect of these two settings typically reduces end-to-end latency from 2–5 seconds (default buffering) to under 1 second on a good Wi-Fi connection.

maxAnalyzeDuration and probesize: Faster Connection

When FFmpeg opens a stream, it spends time probing: reading a chunk of data to figure out the stream’s format, codec, bitrate, and timing information. This probing is why there’s a delay between “connecting” and “first frame.”

options.maxAnalyzeDuration = 1_000_000   // microseconds = 1 second
options.probesize = 500_000              // bytes

The default values are much larger — FFmpeg may analyze up to 5–10 seconds of data before deciding a stream is ready. Since the Bambu Lab stream is a known-format H.264 feed, we can afford to cut this short:

Together, these settings tell FFmpeg: “make a decision within 1 second using at most 500 KB of probe data.” For a reliable H.264 RTSP source, this is always sufficient. The result is noticeably faster stream startup.

registerRemoteControll: Silence the Media Controls

options.registerRemoteControll = false  // note: KSPlayer misspells "control"

iOS has a “Now Playing” system that shows media controls on the Lock Screen and in Control Center when any audio or video is playing. For a music or podcast app, this is essential. For a printer camera feed, it’s odd and distracting — you don’t want your printer to appear as a media source that you can “pause” from the Lock Screen.

Setting registerRemoteControll = false tells KSPlayer not to register with the Remote Command Center, keeping the printer stream invisible to the system media controls.

Summary

The streaming options are a deliberate stack of latency and reliability tradeoffs. TCP transport avoids UDP firewall issues. tls_verify: 0 handles the self-signed certificate. nobuffer and codecLowDelay minimize end-to-end latency. Reduced probe settings speed up stream startup. The result is a stream that typically goes live in under two seconds and stays within a second of real-time.