Chusko Blog · 2026-08-12
How Chusko casts video peer-to-peer
Chusko is P2P casting: a Projector streams local media straight to a Screen over WebRTC. Here's how pairing, the relay, and playback actually work.
Chusko casts video on a deliberately simple model: one device has the file, another device displays it, and nothing in between ever touches the media. The web app and the native Android apps all speak the same protocol. This post walks through how it works, from the 6-character room code to the encrypted byte stream.
Two roles: Projector and Screen
Chusko splits the job into two roles, and the terms matter:
- Projector. The device that holds the local media files and controls playback. It picks the file and drives play, pause, seek, volume, and ±10 second skips.
- Screen. The device that displays the stream. It's passive: it receives the file bytes and plays them, but has no transport controls of its own.
One room has exactly one projector and as many screens as you like, handy when several displays should show the same thing.
Pairing: a room code and a QR deep link
A screen hosts a room, which produces a 6-character code drawn from an unambiguous alphabet (no confusingI/O or 0/1). The other device enters the code, or scans a QR code, whose deep link pre-fills the code so there's nothing to type. On Android TV, rooms hosted on the same network appear automatically, so joining can take one tap. The code is the pairing: whoever holds it joins the room.
The relay only sets up the connection
The only server in Chusko is a small signaling relay. It does two things: it hands the peers a room to meet in, and it forwards one offer and one answer blob so the WebRTC connection can be established. That handshake is a few kilobytes. Once the peer connection opens, the relay is out of the path entirely. It never carried media in the first place.
If the devices can't connect directly (both behind strict network address translation), the connection falls back to a TURN relay that forwards packets. Those packets are the WebRTC stream, which is encrypted end to end, so the relay forwards bytes it cannot read.
Streaming: raw bytes, native playback, no remuxing
The video travels over a single WebRTC data channel as raw file bytes. The screen stores them in its browser's IndexedDB, keyed by file offset, and serves them to its own <video> element with standard HTTP Range semantics. The browser's native demuxer does the rest.
That design choice is what makes Chusko format-agnostic:
- MP4, MOV, WebM, MKV, Ogg. Anything the screen device plays natively.
- No fragmentation requirement. Files don't need to be "faststart" or fragmented; even MP4s with the moov atom at the end play correctly.
- Movies of any size, because received pieces are disk-backed blobs, not memory.
When both ends run the native apps on the same network, the stream gets a free upgrade: the projector serves the file over plain HTTP range requests and the screen pulls it at full local network speed. The protocol is the same either way, so web and native devices still interoperate.
Playback control and seeking
The projector sends short control messages over the same channel: play, pause, seek, volume, end-of-stream. Seek is a plain byte-offset computation, no container alignment step, and the screen can answer from bytes it already holds, so skipping back is instant and skipping forward re-streams only the missing range.
Sessions are also resumable. A screen that reloads keeps the bytes it already received and continues instead of restarting the transfer, and the projector remembers its playhead across a reload. The philosophy throughout: the bytes live on the devices, so reconnects cost only what's missing.
What it adds up to
Pairing with a code, a handshake through a tiny relay, encrypted bytes straight between your devices, native playback of any format. That's the whole system, and that's why your media never touches a server. For the short version, see the FAQ.