Skip to content

WebRTC Playback Demo ​

This example is for receiving a WebRTC stream, not publishing one. WHEP is the recommended playback URL; WHIP is for publishing and cannot be used as the player's URL. The normal H265webjsPlayer() API is enough.

1. Publish a real test stream first ​

Start ZLMediaKit, then publish a file to live/test. Install FFmpeg and replace ./media/live.mp4 with a real file. You can download our ordinary H.264 + AAC test video as ./media/live.mp4; the test-media guide also has a no-re-encode publishing command:

bash
ffmpeg -stream_loop -1 -re -i ./media/live.mp4 \
  -vf scale=640:360,format=yuv420p \
  -c:v libx264 -preset veryfast -tune zerolatency -bf 0 -g 30 \
  -c:a aac -ar 44100 -ac 2 -f flv \
  rtmp://127.0.0.1/live/test

Check that ZLMediaKit's WHEP endpoint is reachable. If the server runs on another machine, replace 127.0.0.1 in the code below with its address. For RTMP-to-WebRTC delivery, use the tested modify_stamp=1 setting in Get Started. The browser can only play codecs it successfully negotiates.

2. Copy index.html ​

Also place matching-build output/h265web.js, h265web_wasm.js and h265web_wasm.wasm beside the page. Serve the page over HTTP, not file://.

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>WebRTC playback demo</title>
  <script src="./output/h265web.js"></script>
</head>
<body>
  <div id="player"></div>
  <button id="play" disabled>Play</button>
  <button id="pause">Pause</button>
  <button id="sound">Enable sound</button>
  <p id="status">Waiting for WebRTC video…</p>

  <script>
    // WHEP receives media. Confirm live/test exists on ZLMediaKit first.
    const whepUrl = 'http://127.0.0.1/index/api/whep?app=live&stream=test';
    const status = document.getElementById('status');
    const playButton = document.getElementById('play');
    const player = H265webjsPlayer();

    // Bind callbacks before build() so first-frame and error events are visible.
    player.on_ready_show_done_callback = () => {
      playButton.disabled = false;
      status.textContent = 'WebRTC first frame ready. Press Play.';
    };
    player.video_probe_callback = (info) => console.log('Media info', info);
    player.on_error_callback = (error) => {
      status.textContent = `WebRTC error: ${error.message || error.code}`;
    };

    const ok = player.build({
      player_id: 'player',
      base_url: './output/',
      wasm_js_uri: 'h265web_wasm.js',
      wasm_wasm_uri: 'h265web_wasm.wasm',
      width: '100%', height: 480,
      auto_play: false, ignore_audio: false,
      // No core field: the SDK recognizes WHEP URLs automatically.
      // Add core: 'webrtc' only when you explicitly want to require WebRTC.
    });
    if (ok) {
      player.set_voice(0); // Start muted; the sound button restores audio.
      player.load_media(whepUrl);
    } else {
      status.textContent = 'Player build failed: check SDK file paths.';
    }

    playButton.onclick = () => player.play();
    document.getElementById('pause').onclick = () => player.pause();
    document.getElementById('sound').onclick = () => player.set_voice(1);
    window.addEventListener('beforeunload', () => player.release());
  </script>
</body>
</html>

3. Common mistakes ​

  • WHEP is for playback, WHIP for publishing. webrtc:// is a compatibility form; test WHEP first.
  • Native WebRTC live playback stays at 1x and does not support normal VOD seeking.
  • 127.0.0.1 means the machine opening the webpage. For remote browsers, replace it and check signaling CORS/HTTPS/ICE.
  • If video jumps, check ZLMediaKit timestamp settings and the source stream before QA WIKI.