A bare minimal stream.place example showing you how to show a stream live on your website
Something went wrong. Try again.
minimal-stream-place.html
· Created 7mo ago ·5.4 kB · 141 lines
HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142<!doctype html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Stream.place example</title> </head> <body> <video id="video" autoplay playsinline muted></video>
<script> // Your atmosphere handle const handle = "pokemon.evil.gay"; let pc = null; const video = document.getElementById("video");
async function connect() { if (pc) disconnect();
const whepUrl = `https://stream.place/api/playback/${encodeURIComponent(handle)}/webrtc?rendition=source`;
console.log("Connecting\u2026"); console.log(`WHEP endpoint: ${whepUrl}`);
try { pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }], bundlePolicy: "max-bundle", });
pc.addTransceiver("video", { direction: "recvonly" }); pc.addTransceiver("audio", { direction: "recvonly" });
pc.ontrack = (event) => { console.log( `Track received: ${event.track.kind}`, "success", ); if (event.streams && event.streams[0]) { video.srcObject = event.streams[0]; } else { if (!video.srcObject) { video.srcObject = new MediaStream(); } video.srcObject.addTrack(event.track); } video.play().catch(() => {}); };
pc.oniceconnectionstatechange = () => { console.log(`ICE: ${pc.iceConnectionState}`); if ( pc.iceConnectionState === "connected" || pc.iceConnectionState === "completed" ) { } else if ( pc.iceConnectionState === "failed" || pc.iceConnectionState === "disconnected" ) { console.log("Connection lost", "error"); } };
pc.onconnectionstatechange = () => { console.log(`Connection: ${pc.connectionState}`); if (pc.connectionState === "failed") { console.log("PeerConnection failed", "error"); } };
const offer = await pc.createOffer(); await pc.setLocalDescription(offer); await waitForIceGathering(pc, 2000);
console.log("Sending SDP offer\u2026");
const resp = await fetch(whepUrl, { method: "POST", headers: { "Content-Type": "application/sdp" }, body: pc.localDescription.sdp, });
if (!resp.ok) { const errText = await resp.text(); throw new Error(`WHEP ${resp.status}: ${errText}`); }
const answerSdp = await resp.text(); console.log("Received SDP answer", "success");
await pc.setRemoteDescription({ type: "answer", sdp: answerSdp, }); console.log( "Remote description set, waiting for media\u2026", ); } catch (err) { console.log(`Error: ${err.message}`, "error"); setStatus("Error", "error"); console.error(err); } }
function disconnect() { if (pc) { pc.close(); pc = null; } video.srcObject = null;
console.log("Disconnected"); }
function waitForIceGathering(peerConnection, timeout) { return new Promise((resolve) => { if (peerConnection.iceGatheringState === "complete") { resolve(); return; } const timer = setTimeout(() => { console.log( "ICE gathering timed out, proceeding with candidates", ); resolve(); }, timeout);
peerConnection.onicegatheringstatechange = () => { if (peerConnection.iceGatheringState === "complete") { clearTimeout(timer); console.log("ICE gathering complete"); resolve(); } }; }); }
connect(); </script> </body></html>