Document device media paths and direct transfer requirements

This commit is contained in:
Jonathan Sykes
2026-10-03 20:24:10 +08:00
parent d93fc0d70f
commit ef70da1806

69
docs/p2p-transfer.md Normal file
View File

@@ -0,0 +1,69 @@
# Direct device media transfers
## Existing paths (audit before implementation)
| Path | Existing media-byte route | Relevant code |
| --- | --- | --- |
| Paired remote | Controls only; the host plays its own source. No existing file-send action. | `frontend/app.js` Remote; `server/remote.js` |
| Presenter and OBS | Lyrics, timing and metadata only; neither currently plays host media. | Presenter and overlay modules; remote relay |
| Watch Party playback | Each guest loads independently through normal server/YouTube playback, unless already saved locally. | Party `applyState`, `Player.loadVideo`; `server/party.js` |
| Watch Party voice | Direct WebRTC audio; server forwards SDP/ICE only. | Party voice mesh, party `rtc` relay |
| On other devices / failed playback | Existing verified-file DataChannel download, 64 KiB frames, SHA-256 validation, worker writes OPFS. Only offered after server failure in playback. | `p2p-transfer.js`, `p2p-recv-worker.js`, `getFromPeers` |
| Save / preload | Server download first, then OPFS. | `preload`, `API.cacheDownload`, download endpoints |
| Export to Files / Photos | Local OPFS first, server URL next, peer fallback last. Native share is an OS export, not paired-device transfer. | `exportToDevice`, `export.js` |
| Profile / playlist share and send | Metadata only. Sending a playlist does not transfer its media files. | Profile/playlist sync APIs |
| Verify & share | Explicit device upload to server intake; hash and media validation admit it into the server cache. | `P2PClient.contribute`, `p2p-intake.js` |
| Automatic rehydration | Server requests a holder to upload its full file to intake. This is an implicit media-byte server path. | `createRehydrator`, client `upload-request` handler |
| Admin uploads / original YouTube downloads | Intentional server ingestion of original media; separate from direct device transfer. | Upload and media-cache endpoints |
| VLC / external player URLs | HTTP server media URLs; these players cannot consume this application's DataChannel. | External player actions |
The current file protocol has no resume: its receiver truncates partial files and
removes them on failure. Connection timeout is 20 seconds per holder. Device
signalling authenticates a device, but does not constrain its destination to a
verified profile or paired room. Profile names supplied at device registration
are not proof of profile membership. Existing server-verified holdings also
exclude files whose bytes the server has never admitted.
## Implementation design
Reuse ordered RTCDataChannel transfers with public STUN only. The WebSocket
server carries bounded, validated signalling and metadata, never file chunks.
Pair authorization must come from an authenticated remote/party room or a
verified profile session, not an arbitrary client-supplied profile name.
A receiver explicitly accepts an invitation before saving. A cryptographically
random, expiring, one-use invitation binds sender, receiver and file identity;
subsequent signalling remains bound to that pair. Reject replay, mismatched
identities, binary WebSocket messages and unrecognized protocol fields.
Send 64 KiB chunks with bufferedAmount backpressure. Persist a partial OPFS file
and resume at its exact committed byte offset. Rehash the retained prefix before
continuing and verify total size and SHA-256 before promoting the file into the
saved store; only then record metadata. A changed hash/size cannot reuse a partial.
Use a 10-second connection deadline and an explicit, clearly labelled server
fallback offer. Direct mode must not silently rehydrate server media from a
device. Register “Direct device transfer (P2P)” in Settings, default on.
Party playback should request a host's saved file when announced, then play the
receiver's OPFS copy. Remote controls and presenter lyrics retain their existing
behaviour; add explicit receive/play actions rather than automatically starting
media in a control-only screen. A manual send action targets authenticated peers.
Ordinary faststart MP4 cannot safely be appended as arbitrary MediaSource chunks.
Progressive playback requires supported fragmented media and codec detection;
otherwise use the completed, verified file (including iOS). Do not claim that
raw MP4 chunks provide progressive playback.
## Verification required before release
Pure tests cover protocol parsing, chunk bounds, offsets, invitation replay and
pair authorization. A two-page localhost browser test must transfer real bytes
into OPFS through WebRTC and assert that server HTTP/WS logs contain only
signalling and metadata. Exercise interruption/resume and explicit fallback.
Review real iPhone foreground/background behaviour and restrictive NAT failure.
## Implementation status
This document records the pre-implementation audit and design. Transport,
authorization and UI changes described above are not yet implemented.