Three co-hosts, one stream

Engineering

Going live with friends sounds simple until you have four audio tracks, four video tracks and one viewer on a train. Kool allows a host plus three co-hosts on the same stream, rendered as corner tiles for everybody watching.

The architecture is ordinary enough: guests publish to a media server, viewers pull from it, and nobody connects directly to anybody. That indirection is what makes four publishers survivable on a phone. It is also the source of the single hardest bug we have had in this feature, and the bug is worth the whole post, because it is a class of failure rather than a mistake.

A viewer's connection is viewer-to-server. It is not viewer-to-guest. So when a guest closes their broadcast, nothing about the viewer's connection changes. The server keeps the link happily connected. The track does not end. There is no ICE state change, no track-ended callback, no event of any kind. The frames simply stop arriving.

What the viewer sees is a tile frozen on the last decoded frame. Not a black tile, not a spinner, not an error: a photograph of someone who left, sitting in the corner of the stream, indistinguishable from a person holding very still.

Every instinct says to fix this with an event, and there is one. The server sends a co-host-ended message over our socket, and when it arrives everything is tidy. But an event you rely on is a promise about a network you do not control, and the entire failure here is that a component went away without telling anyone. Building the cure out of another message from that same direction only narrows the window.

So the truth is the frames. Each guest's tile timestamps the last frame it actually received, and a tile that has not been fed for long enough is gone regardless of what any event did or did not say. The socket message remains the tidy path and takes effect immediately when it arrives. The frame watch is the backstop for when it never does, and it is the same principle we use in the calls grid.

The general lesson we keep relearning in realtime work: prefer evidence over notification. A notification tells you what some other machine believes and chose to send. Evidence, in this case a frame that did or did not decode, is a property of your own process, and it is still true when the network is lying to you or has stopped talking entirely.

Three co-hosts, one stream, and one tile that knows the difference between a still person and an absent one.

All posts