← Back to work
Work

An ffmpeg relay between every camera and Cloudflare

A court's stream ran only while a paid session did, through three pipelines in turn, the last one on the platform's own server.

↓

The constraint

Encoding and recording were billed per minute, and a camera fixed to a court streamed whether or not a session was in progress. A session started by QR code and ran for a set time. The stream had to start with it and stop with it.

MediaLive

  • One channel per court, reconfigured inside the web request that started the session: stop, wait for idle, push encoder settings, wait again, start, wait for running.
  • Each wait was allowed up to three minutes.
  • A new input was created at every session start and the old one left in place; idle inputs accumulated and kept billing.

Mux

  • Mux was adopted seventeen days in. It handled ingest and adaptive bitrate and reported finished recordings by webhook.
  • A cron cleared sessions whose recording stayed in the processing state.
  • Recordings were deleted after a retention period to limit storage cost.

Cloudflare Stream and the relay

  • Cloudflare Stream replaced Mux after delivery because it priced delivery and storage lower.
  • Cameras pushed RTMP to an nginx on the platform's server. The backend started an ffmpeg relay to Cloudflare only while a session ran, and switched recording on with the relay and off after it.
  • No webhook event covered this flow, so finished recordings were found by polling.
  • Recordings moved to R2 storage after four days.

Faults at the relay

  • A camera that dropped for a second could not reconnect: the dead connection held its stream key for about two hours. A 30-second idle timeout in nginx fixed that in November.
  • The same dropout killed the relay, and a relay started for a camera that was not publishing exited with no error. Reconnect flags and an ffprobe check before launch fixed both the following March.

Left open

The relay's state was a map in one process's memory. The backend ran as one process.

Up next
Liquidation that ran only when the client polled→