Files
sync_replay_project/docs/HOW-IT-WORKS.md
T
foxyzandClaude Opus 5.5 e7f33b5dc3
ci / core (push) Successful in 28s
ci / updater-windows (push) Successful in 49s
ci / server (push) Successful in 49s
Relay: a member's media through the server's buffer (proto 8)
Viewers who cannot reach the media get it through the server: a file on
any member's computer, a link passed on by a member ("Through me") or
fetched by the server ("Server fetches it", password-protected servers
only), and Jellyfin items for guests without an account, sourced by
whoever put them up with their own sign-in (or a pasted link's key),
which never leaves their machine. Fixes guests on a dedicated server
without a Jellyfin login being blocked.

The source dials /r/.../source (works behind NAT) and answers pulls with
an adaptive in-flight window (2 x rate x min RTT, 256 KiB..8 MiB). The
server keeps a memory-only buffer of 1 MiB slices sized like a viewer's
mpv buffer (pinned head/tail, 64 MiB back, 256 MiB ahead), fills it with
one sequential pull at a time (blocked viewers first, newest request
only), fetches nothing while nobody watches through it, and drops it on
the next swap or stop. Measured with mpv through shaped links
(tool/relay_e2e.dart): 400 Mbit/s seeks ~0.03 s; 40 Mbit/s no stalls,
3 viewers cost the source ~1x the bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:41:01 +03:00

89 lines
4.3 KiB
Markdown

# How it works
A five-minute tour. Details: [ARCHITECTURE.md](ARCHITECTURE.md), wire format:
[PROTOCOL.md](PROTOCOL.md).
## The pieces
```
your PC friend's PC
+-------------------+ +-------------------+
| app (mpv inside) | | app (mpv inside) |
+---------+---------+ +---------+---------+
| sync (WebSocket) | sync (WebSocket)
v v
+----------------------------------------+
| server (who is ready, where are we) |
+----------------------------------------+
video bytes come from somewhere else:
- a link (any http/https URL): each app fetches it directly
- a Jellyfin item: each app plays it with its own Jellyfin account,
friends without one through the server
- a file on the host's disk: the server streams it (/m/... endpoint)
- the relay (/r/...): a member's computer passes a file, a link or a
Jellyfin item on to the server, which keeps a few minutes in memory
and streams it to everyone who needs it
```
- **App**: the desktop window. It draws the video with mpv, shows who is
here, and sends what you do (ready, seek, chat).
- **Server**: keeps one shared clock and the list of people. It never sees
video frames, only "position 123 s, playing". There is exactly one server
and one watch session on it.
- **Jellyfin** (or any web host): where the video lives. For a Jellyfin
item the server only knows which item it is; each app signs in with its
own account and reports what it watched. For friends without an account
the member who put it up passes it on through the server (their sign-in
stays on their computer).
## Ways to run
- **Host from the app**: the app you click Host in also runs the server.
Simplest. The server lives as long as that app.
- **Dedicated server**: `watch-together-server`, a separate program in the
release tarball, for an always-on box. See the README.
Friends join either way with the Join card on Home.
## One session, start to finish
1. **Connect.** The app opens a WebSocket to the server and says hello
(version, password, name, avatar). Wrong password or version: refused with
a reason. Otherwise the server answers with a welcome and the current state.
2. **Catch up.** The app opens the current video, jumps to where the server
says we are, and buffers. A new arrival is not ready yet and never holds
anyone back.
3. **Ready gate.** Press Space to say you are ready. The server starts
playback only when everyone who is ready has at least 4 seconds buffered
(or what is left, near the end). At the end everyone stops and the server
stays finished until someone seeks back or changes the video.
If two or more people are ready, one person alone cannot start it for the
others. A lone viewer can play alone.
4. **Play.** The server owns the clock. Each app compares its mpv position
to the clock: a small lead slows mpv a little (0.95x), a big gap (over 5 s)
jumps. If someone's buffer runs dry the server pauses everyone and resumes
when they have caught up.
5. **Seek.** Anyone can seek, anytime. The server moves the clock and
everybody follows. Seeking does not change anyone's ready flag.
6. **Swap.** Anyone can change the video by pasting another link. Everybody
stops at 0, ready flags clear, and the gate runs again.
7. **Leave.** Closing or leaving drops you from the server; the others keep
going. If you vanish without saying goodbye, you are marked stale after 15 s
(stops blocking) and removed after 30 s. The app reconnects by itself and
takes over your old place (same member, ready flag and video).
There are no roles: anyone can seek, swap, force-ready others and kick
anyone except the host.
## Where video comes from
- **Link**: you paste an http(s) URL. Every app plays it directly with mpv.
A pasted Jellyfin link becomes the Jellyfin item below when possible.
- **Jellyfin item**: picked in the app's library browser. Shared as "this
item on this Jellyfin server", never as a link with someone's sign-in.
- **Local file (host only)**: you pick a file on your disk. The server
streams it to everyone, host included, over HTTP with range requests, each
with a per-person token. Nothing is stored or converted.
- No transcoding, ever. Quality is whatever the file is.