Interactive Beam path
The existing `/v1/streams/realtime` WebSocket path keeps browser publisher and viewer WebRTC working for live studio preview, direct viewers, and fast product demos.
Media Edge
Beam's browser WebRTC path is still useful for interactive source preview and small rooms. Public streams, slow networks, Discord watch parties, and high viewer counts need a media edge. The media edge accepts a Beam source over WHIP, serves low-latency WHEP/WebRTC playback, and exposes HLS or LL-HLS for more resilient viewers.
Beam now exposes media-edge discovery and per-stream media URLs.
GET /api/v1/media/edge
GET /api/v1/streams/{stream_id}/media
GET /api/v1/streams/{stream_id}/media?join_token=jt_xxx
Public viewers receive playback URLs. Stream owners or valid join-token publishers also receive the WHIP ingest URL.
{
"stream_id": "sess_661734e0f1c675faf937",
"media_path": "beam-sess_661734e0f1c675faf937",
"enabled": true,
"provider": "mediamtx",
"whip_url": "https://beam.be-online.ro/whip/beam-sess_661734e0f1c675faf937/whip",
"whep_url": "https://beam.be-online.ro/whep/beam-sess_661734e0f1c675faf937/whep",
"hls_url": "https://beam.be-online.ro/hls/beam-sess_661734e0f1c675faf937/index.m3u8",
"playback_protocols": ["webrtc-whep", "ll-hls", "hls", "browser-webrtc"]
}
Publish a browser game, canvas, tab, camera, or app-owned MediaStream into the media edge.
const media = canvas.captureStream(60);
const publisher = await BeamStream.publishToMediaEdge({
apiBase: "https://beam.be-online.ro/api",
streamId: "sess_661734e0f1c675faf937",
joinToken: "jt_xxx",
stream: media,
maxBitrate: 6500000,
minBitrate: 700000,
maxFramerate: 60,
simulcast: true
});
// Stop publishing when the app stops streaming.
publisher.stop();
Use WHEP or HLS playback depending on the viewer network.
const mediaInfo = await BeamStream.getStreamMedia({
apiBase: "https://beam.be-online.ro/api",
streamId: "sess_661734e0f1c675faf937"
});
// HLS playback with hls.js on browsers that need it.
const video = document.querySelector("video");
if (video.canPlayType("application/vnd.apple.mpegurl")) {
video.src = mediaInfo.hls_url;
} else {
const hls = new Hls({ lowLatencyMode: true });
hls.loadSource(mediaInfo.hls_url);
hls.attachMedia(video);
}
Set these variables on the Beam server when the media edge is deployed behind the same public origin.
BEAM_MEDIA_EDGE_ENABLED=true
BEAM_MEDIA_EDGE_PROVIDER=mediamtx
BEAM_MEDIA_EDGE_PUBLIC_BASE_URL=https://beam.be-online.ro
BEAM_MEDIA_EDGE_WHIP_BASE_URL=https://beam.be-online.ro/whip
BEAM_MEDIA_EDGE_WHEP_BASE_URL=https://beam.be-online.ro/whep
BEAM_MEDIA_EDGE_HLS_BASE_URL=https://beam.be-online.ro/hls
BEAM_MEDIA_EDGE_PATH_PREFIX=beam
BEAM_MEDIA_EDGE_LL_HLS_ENABLED=true
BEAM_MEDIA_EDGE_SFU_ENABLED=false
BEAM_MEDIA_EDGE_SIMULCAST_ENABLED=false
Set `BEAM_MEDIA_EDGE_SFU_ENABLED=true` and `BEAM_MEDIA_EDGE_SIMULCAST_ENABLED=true` only when the selected provider actually routes simulcast layers, such as an SFU deployment.
For a MediaMTX edge on localhost, proxy the edge through HTTPS so browsers do not hit mixed-content or permission problems.
location /whip/ {
proxy_pass http://127.0.0.1:8889/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
location /whep/ {
proxy_pass http://127.0.0.1:8889/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
location /hls/ {
proxy_pass http://127.0.0.1:8888/;
proxy_http_version 1.1;
proxy_set_header Host $host;
add_header Cache-Control "no-store";
}