MWSE/public/demos/video.html

125 lines
4.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>MWSE — Video Demo</title>
<style>
* { box-sizing: border-box; }
body { font-family: sans-serif; margin: 0; background: #111; color: #eee; }
#header { padding: 10px 16px; background: #1a1a1a; display: flex; align-items: center; gap: 12px; }
#header h2 { margin: 0; font-size: 1.1rem; }
#status { font-size: .8rem; color: #aaa; }
#grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 6px; padding: 10px; }
.tile { background: #222; border-radius: 6px; overflow: hidden; position: relative;
aspect-ratio: 16/9; }
.tile video { width: 100%; height: 100%; object-fit: cover; background: #000; }
.tile .label { position: absolute; bottom: 6px; left: 6px; font-size: .75rem;
background: rgba(0,0,0,.6); padding: 2px 6px; border-radius: 3px; }
.tile .dot { position: absolute; top: 6px; right: 6px; width: 10px; height: 10px;
border-radius: 50%; background: #f44; }
.tile.ok .dot { background: #4c4; }
</style>
</head>
<body>
<div id="header">
<h2>MWSE Video Demo</h2>
<span id="status">Bağlanıyor…</span>
</div>
<div id="grid"></div>
<script type="module">
import MWSE from '/sdk/index.js';
// Akış: bağlan → kamera aç → kendi tile'ı ekle → odaya katıl →
// her eşle P2P WebRTC bağlantısı kur.
// Ölçek notu: mesh topolojisi ~68 kişiye makul çalışır.
// Daha büyük odalar için SFU (SRS) gerekir — bkz. #39.
const mwse = new MWSE();
let localStream;
const tiles = {};
mwse.on('scope', async () => {
setStatus(`Bağlandı: ${mwse.me.socketId}`);
try {
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
addTile('ben', localStream, true);
} catch (err) {
setStatus(`Kamera erişimi reddedildi: ${err.message}`);
}
const room = mwse.room({ name: 'video', joinType: 'free', ifexistsJoin: true });
await room.createRoom();
setStatus(`Odada: video | ${mwse.me.socketId.slice(-8)}`);
room.on('join', async peer => {
await peer.requestPair();
});
mwse.me.on('request/pair', async peer => {
await peer.acceptPair();
});
mwse.me.on('accepted/pair', peer => startVideo(peer));
mwse.me.on('end/pair', id => removeTile(id));
});
function startVideo(peer) {
const rtc = peer.rtc;
const polite = mwse.me.socketId < peer.socketId;
rtc.connect({ polite });
if (localStream) rtc.addStream('cam', localStream);
rtc.on('track', (track, streams) => {
if (track.kind !== 'video') return;
const stream = streams?.[0] ?? new MediaStream([track]);
addTile(peer.socketId.slice(-8), stream, false);
setOk(peer.socketId, true);
});
rtc.on('connected', () => setOk(peer.socketId, true));
rtc.on('disconnected', () => setOk(peer.socketId, false));
}
function addTile(label, stream, isMe) {
const key = isMe ? 'me' : label;
if (tiles[key]) return;
const div = document.createElement('div');
div.className = 'tile' + (isMe ? ' ok' : '');
const video = document.createElement('video');
video.autoplay = true;
video.playsInline = true;
if (isMe) video.muted = true;
if (stream) video.srcObject = stream;
const lbl = document.createElement('div');
lbl.className = 'label';
lbl.textContent = isMe ? `${label}` : label;
const dot = document.createElement('div');
dot.className = 'dot';
div.append(video, lbl, dot);
document.getElementById('grid').appendChild(div);
tiles[key] = div;
}
function setOk(id, ok) {
const tile = tiles[id.slice(-8)] ?? tiles[id];
if (tile) tile.classList.toggle('ok', ok);
}
function removeTile(id) {
const key = (id || '').slice(-8);
for (const k of [key, id]) {
if (tiles[k]) { tiles[k].remove(); delete tiles[k]; }
}
}
function setStatus(msg) {
document.getElementById('status').textContent = msg;
}
</script>
</body>
</html>