JustOnAir docs
View as Markdown

Sending video

Go live from OBS, ffmpeg, a hardware encoder or a browser, and the limits every publisher has to stay within.

A stream accepts video over RTMP (OBS, ffmpeg, vMix, Wirecast, most hardware encoders) or WHIP (browsers and WebRTC encoders). Both are in the response to creating a stream. Use one publisher at a time: a second connection with the same key is refused while the first is live.

Settings that matter

SettingUseWhy
Video codecH.264Your top quality is copied to viewers untouched, which needs H.264.
Keyframe interval2 secondsViewers' video comes in 4-second pieces that must start on a keyframe. Longer intervals make quality switching stutter; ingest.keyframe_warning turns true above 2.5 s.
BitrateUp to 6000 KbpsAbove 7.5 Mbps sustained (audio and overhead included), the stream ends after a 20-second warning.
ResolutionAt most your max_resolutionDeclare the tallest video you'll send: 480, 720 (default) or 1080. Sending more ends the stream after a 20-second warning. Portrait video is fine: 720×1280 counts as 720.
AudioAAC, 48 kHz128–160 Kbps is plenty.

OBS Studio

Settings → Stream: Service Custom, Server = rtmp_url, Stream Key = stream_key.

Settings → Output (Output Mode: Advanced), Streaming tab:

FieldValue
Encoderx264, or your hardware H.264 encoder (NVENC, Apple VT, QuickSync)
Rate ControlCBR
Bitrate2500 Kbps for 720p, 4500–6000 for 1080p
Keyframe Interval2 s (not 0)

Settings → Video: Output (Scaled) Resolution no taller than your max_resolution; 30 fps is enough for talks and classes, 60 for sport and games.

ffmpeg

From a file, looping, without re-encoding if the file is already H.264 with 2-second keyframes:

Shell
ffmpeg -re -stream_loop -1 -i talk.mp4 -c copy -f flv "$RTMP_URL/$STREAM_KEY"

From a camera or any source, encoding with the right settings:

Shell
ffmpeg -re -i input.mp4 \
  -c:v libx264 -preset veryfast -b:v 2500k -maxrate 2500k -bufsize 5000k \
  -g 60 -keyint_min 60 -sc_threshold 0 -pix_fmt yuv420p -vf "scale=-2:720" \
  -c:a aac -b:a 128k -ar 48000 \
  -f flv "$RTMP_URL/$STREAM_KEY"

-g 60 is a keyframe every 60 frames, which is 2 seconds at 30 fps; use -g 120 at 60 fps. Quote the address: the stream key contains a ?.

From a browser (WHIP)

whip_url accepts a standard WHIP offer from any page: your own site, a web app, a studio tool. What to send:

  • One video track, H.264. Browsers prefer VP8 unless told otherwise; set H.264 as the preferred codec in the offer. A publish with more than one video layer (simulcast) is refused and the stream ends with simulcast_not_supported.
  • The declared resolution from the start. Browsers start small and raise the resolution over about 15 seconds. Set degradationPreference: 'maintain-resolution' on the sender to avoid it. JustOnAir encodes a browser's top quality at your declared size either way, so viewers never see the ramp.
  • Networks that block UDP. A TURN relay over TCP runs on port 3478 of the host in whip_url: turn:<host>:3478?transport=tcp, username ome, credential airen.

Two WHIP response headers aren't readable from another origin: Location (so a page can't send the WHIP DELETE; closing the peer connection ends the publish just as well) and the TURN Link header (so pass the TURN server yourself, as above).

When the connection drops

If the publisher disconnects, the stream stays live for 60 seconds and accepts the same key again. OBS reconnects on its own. A publisher whose old connection is still half-open is refused once while the old one is cleared, then let in on the next try, usually within about 10 seconds. After 60 seconds without a publisher the stream ends with end_reason: "disconnected".

If you lose the stream key

The key is shown once. While the stream is still pending, replace it: the old key stops working at once. Once live, the key can't change, because it is how a reconnecting publisher proves it is the same one.

Adaptive or passthrough

profile: "abr_basic" (the default) gives viewers the quality you send plus smaller ones: 480p below a 720p source, 720p and 480p below 1080p. Viewers on weak connections switch down instead of buffering.

profile: "passthrough" delivers exactly what you send and nothing else, for a sixth of the encoding price. Choose it when your viewers have good connections, or when you already send several qualities yourself in a different way.