Skip to content

WebRTC Server - Monibuca WHIP/WHEP Low-Latency

WebRTC is the standard technology for ultra-low latency audio/video communication in browsers. Monibuca V6 implements publishing and subscribing based on the WHIP (WebRTC-HTTP Ingestion Protocol) and WHEP (WebRTC-HTTP Egress Protocol) standards, powered by the rustrtc engine for full ICE/DTLS/SRTP support.

PropertyValue
Signaling TransportHTTP (WHIP/WHEP)
Media TransportUDP / optional TCP ICE (ICE/DTLS/SRTP)
Publish✅ Supported (WHIP)
Subscribe✅ Supported (WHEP)
Latency< 500ms
Config sectionwebrtc

The plugin is included in official binaries; configure it in config.yaml:

webrtc:
enable: true
# UDP only (default). Dual ICE: "udp:9000-9100,tcp:9101-9200"
port_range: "udp:9000-9100"
pli_interval: 2
nack_buffer_size: 200
prefer_srflx_over_natted_host: false
public_ip: ""
enable_cors: true
cors_origins:
- "*"
ice_servers:
- urls:
- "stun:stun.l.google.com:19302"
OptionTypeDefaultDescription
enablebooltrueWhether to enable the WebRTC plugin
port_rangestring"udp:9000-9100"ICE media ports: udp:A-B, tcp:A-B, or dual udp:A-B,tcp:C-D (default UDP-only)
pli_intervalu642PLI (keyframe request) interval (seconds)
nack_buffer_sizeusize200NACK retransmit history size; RFC 4588 RTX used when browser offers apt= (rustrtc ≥0.3.92)
prefer_srflx_over_natted_hostboolfalsePrefer srflx over private host in ICE check order
public_ipstring""Public IP rewritten into host candidates
enable_corsbooltrueWhether to enable CORS
cors_originsVec["*"]Allowed cross-origin sources
ice_serversVec[]STUN/TURN list

When UDP is blocked, gather both UDP host and TCP passive candidates (opt-in):

webrtc:
port_range: "udp:9000-9100,tcp:9101-9200"
public_ip: "203.0.113.10"

Open 9000-9100/udp and 9101-9200/tcp on the firewall. TCP-only: port_range: "tcp:9101-9200".

ice_servers:
- urls:
- "stun:stun.l.google.com:19302"
- urls:
- "turn:turn.example.com:3478?transport=udp"
- "turn:turn.example.com:3478?transport=tcp"
username: "user"
credential: "pass"

Minimal coturn sidecar (not embedded in Monibuca):

services:
coturn:
image: coturn/coturn:latest
network_mode: host
command:
- "-n"
- "--log-file=stdout"
- "--listening-port=3478"
- "--fingerprint"
- "--lt-cred-mech"
- "--user=user:pass"
- "--realm=example.com"

Configure the same iceServers on the browser WHIP/WHEP client.

Full Compose reference stack (origin + coturn): repo deploy/compose/.

TypeCodecDescription
VideoH.264Widely supported
VideoH.265Supported by some browsers
AudioOpusWebRTC standard audio codec
POST /webrtc/whip/{streamPath}
Content-Type: application/sdp

The request body is an SDP Offer, and the response returns an SDP Answer.

FFmpeg 6.1+ supports WHIP publishing:

Terminal window
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset ultrafast -tune zerolatency \
-c:a libopus \
-f whip "http://localhost:8080/webrtc/whip/live/test"

OBS 30+ has built-in WHIP support:

  1. Go to SettingsStream
  2. Select WHIP for the service
  3. Enter the server URL: http://your-server:8080/webrtc/whip/live/test
  4. Click Start Streaming
POST /webrtc/whep/{streamPath}
Content-Type: application/sdp

The request body is an SDP Offer, and the response returns an SDP Answer.

async function play(streamPath) {
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
pc.addTransceiver('video', { direction: 'recvonly' });
pc.addTransceiver('audio', { direction: 'recvonly' });
pc.ontrack = (event) => {
document.getElementById('player').srcObject = event.streams[0];
};
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const response = await fetch(`/webrtc/whep/${streamPath}`, {
method: 'POST',
headers: { 'Content-Type': 'application/sdp' },
body: offer.sdp,
});
const answer = await response.text();
await pc.setRemoteDescription({ type: 'answer', sdp: answer });
}
play('live/test');

Monibuca provides built-in WebRTC test pages for quick feature verification:

PageURLDescription
Publish Test/webrtc/test/publishPublish using camera/screen
Subscribe Test/webrtc/test/subscribePlay an existing WebRTC stream

Simply access the URLs in your browser to use them.

In network environments with NAT, proper configuration is required to ensure WebRTC connectivity:

webrtc:
public_ip: "203.0.113.1" # Server's public IP
webrtc:
ice_servers:
- urls:
- "stun:stun.l.google.com:19302"
- urls:
- "turn:turn.example.com:3478"
username: "user"
credential: "pass"

Ensure the UDP port range configured in port_range is open in your firewall:

Terminal window
# Open UDP port range
sudo ufw allow 9000:9100/udp

After publishing via WebRTC, you can subscribe through other protocols:

Terminal window
# After WebRTC WHIP publishing...
# Subscribe via RTMP (Opus automatically transcoded to AAC)
ffplay rtmp://localhost:1935/live/test
# Subscribe via HTTP-FLV
ffplay http://localhost:8080/flv/live/test.flv
# Subscribe via HLS
ffplay http://localhost:8080/hls/live/test/index.m3u8