Egress
Egress records a broadcast to your storage, and sends it to streaming services, while someone reads its path. A composite of every broadcast under a prefix is made on one page, in a participant's tab or by Egress itself, so recording also runs with nobody's tab open.
Paths
| Path (from the reader's root) | While it is read |
|---|---|
.egress/{source}/{dest} |
Sends the broadcast {source} to {dest} |
.egress/{prefix}/.composite/{dest} |
Composes the broadcasts under {prefix} and sends the composite to {dest} |
{dest} is the last segment: record, or {name} for a project variable EXPORT_{NAME}_URL (EXPORT_YOUTUBE_URL gives youtube). Reading .egress/{source}/… sends {source} out of the project, so grant it as you grant {source}.
// Recording and streaming through Egress: while .egress/{source}/{dest} is read, Egress records
// {source} (dest record) or sends it to the destination a project variable names (EXPORT_{DEST}_URL).
import { type Connection, json } from 'tablebox.io';
export async function egress(connection: Connection, source: string, dest: string, show: (status: unknown) => void) {
const output = await connection.read(`.egress/${source}/${dest}`);
const status = new json.Snapshot.Consumer({ track: output.track('status.json').subscribe() });
void (async () => { for await (const now of status) show(now); })();
// Closing the read stops it 20 s later, unless someone else still reads it.
return () => output.close();
}While read
Egress works from the first read of the path until 20 s after its last reader leaves, and every reader of a path shares one recording or one push. A backend that holds the read records with no person present; an app that reads the path when its people arrive records automatically.
The output has one track, status.json, a JSON snapshot track: {"state", "code"?, "message"?, "file"?}.
state |
Meaning |
|---|---|
waiting |
The source is not published yet, or its catalog lists no rendition yet |
active |
Sending or recording; for record, file is the recording's key |
retrying |
The destination or the storage failed; Egress tries again with growing delays up to 30 s |
failed |
Egress cannot start: code is missing-variable (message names the variable), bad-request (the source's codecs do not suit the destination, or the destination is on an internal address) or failed |
Streaming
EXPORT_{NAME}_URL holds an rtmp://, rtmps:// or srt:// URL with its stream key. A single source goes out as it is published, without re-encoding, once its catalog lists a video and an audio rendition, or 5 s after it lists the first of them. Streaming services take H.264 and AAC, which composites, Ingress streams from OBS, and browsers publishing with those codecs (Publishing and reading) have.
Recording
record writes an MP4 file to your storage, with Persistence's storage variables, at {STORAGE_PREFIX}{project path of source}/{UTC start as YYYYMMDDTHHMMSSZ}.mp4. Each appearance of the source is its own file, complete when the source ends or the egress stops; any player opens it.
Composites
A composite is the video of every hang broadcast under {prefix} whose name ends in .hang, outside paths with a . segment, in a grid in path order at 1280x720 and 30 fps, with all their audio mixed, as one broadcast of H.264 and AAC (48 kHz, stereo). Broadcasts that come and go join and leave the grid.
Reading .egress/{prefix}/.composite/{dest} makes Egress open the composition page itself. The same page also runs in a participant's tab, at https://{egress host}/composite#relay={url}&token={token}&prefix={prefix}&path={path} (the Egress host is in Reference): it composes {prefix} on that participant's device and publishes the composite at {path} with that token, whose publish covers {path}; reading .egress/{path}/{dest} then sends it.
Failures
- A variable is missing:
failedwith its name, until it is set; setting it starts the egress without a new read. - The destination refuses or drops the stream, or storage fails:
retryingwhile the path is read. - The source leaves:
waiting; the recording's file completes. - The source's codecs do not suit the destination (for example VP9 video to SRT, or Opus audio to a service that takes AAC only):
failedwithbad-request, orretryingwhen the service refuses. - The host of
EXPORT_{NAME}_URL, or ofSTORAGE_ENDPOINTforrecord, is or resolves to an address inside a network rather than on the internet (as for Persistence):failedwithbad-request,messagenaming the variable, until a variable changes. - A composition page crashes:
retryingwhile Egress opens it again. - An instance stops: reads end, and reading again reaches the instance that takes over, where reading a path again starts the push again or a new file; the file being written when the instance stopped can be lost.