MWSE/public/demos/video.html

149 lines
5.0 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>
<script src="/script"></script>
<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 .indicator {
position: absolute; top: 6px; right: 6px; width: 10px; height: 10px;
border-radius: 50%; background: #f44;
}
.tile.connected .indicator { background: #4c4; }
</style>
</head>
<body>
<div id="header">
<h2>MWSE Video Demo</h2>
<span id="status">Bağlanıyor…</span>
</div>
<div id="grid" id="grid"></div>
<script>
// Akış: MWSE bağlan → kamera/mikrofon aç → kendi videoyu göster →
// odaya katıl → her yeni eşle P2P WebRTC video kurulumu yap.
//
// Ölçek notu: WebRTC mesh topolojisi ~68 kişiye kadar makul çalışır.
// Daha büyük odalar (100500 kişi) için SRS tabanlı SFU gereklidir (#39).
// Bu demo o SFU mimarisinin istemci tarafı API kalıplarını gösterir.
const mwse = new MWSE({ endpoint: location.origin.replace(/^http/, 'ws') });
let localStream;
const tiles = {}; // socketId → { el, rtc }
// ---- Kamera/mikrofon ------------------------------------------------
mwse.on('scope', async () => {
status(`Bağlandı: ${mwse.me.socketId}`);
try {
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
} catch (err) {
status(`Kamera erişimi reddedildi: ${err}`);
addTile('ben (kamera yok)', null, true);
return;
}
// Kendi videoyu göster (sessiz — aksi hâlde geri besleme oluşur).
addTile(`ben (${mwse.me.socketId.slice(-6)})`, localStream, true);
// Odaya katıl.
const room = mwse.room({ name: 'video', joinType: 'free', ifexistsJoin: true });
await room.createRoom();
status(`Odada: video | ${mwse.me.socketId}`);
// Yeni katılan ile bağlantı başlat.
room.on('join', async peer => {
setTileState(peer.socketId, false);
await peer.requestPair();
});
// Otomatik eşleşme kabul.
mwse.me.on('request/pair', async peer => {
setTileState(peer.socketId, false);
await peer.acceptPair();
});
// Eşleme tamam — WebRTC video başlat.
mwse.me.on('accepted/pair', peer => startVideo(peer));
// Eş ayrıldı.
mwse.me.on('end/pair', id => removeTile(id));
});
// ---- WebRTC video kurulumu -----------------------------------------
function startVideo(peer) {
const rtc = peer.rtc;
rtc.connect();
// Kendi videomuzun tüm izlerini peer'a gönder.
if (localStream) rtc.sendStream(localStream, 'video', { kind: 'video' });
// Uzak video gelince tile'a yerleştir.
rtc.on('stream:added', ({ stream, name }) => {
if (name !== 'video') return;
const label = `${peer.socketId.slice(-6)}`;
addTile(label, stream, false);
setTileState(peer.socketId, true);
});
rtc.on('connected', () => setTileState(peer.socketId, true));
rtc.on('disconnected', () => setTileState(peer.socketId, false));
}
// ---- UI -----------------------------------------------------------
function addTile(label, stream, isMe) {
const id = isMe ? 'me' : label;
if (tiles[id]) return;
const div = document.createElement('div');
div.className = 'tile' + (isMe ? ' connected' : '');
div.innerHTML = `
<video autoplay playsinline ${isMe ? 'muted' : ''}></video>
<div class="label">${label}</div>
<div class="indicator"></div>`;
if (stream) div.querySelector('video').srcObject = stream;
document.getElementById('grid').appendChild(div);
tiles[id] = div;
}
function setTileState(peerId, connected) {
const tile = tiles[peerId.slice(-6)] || tiles[peerId];
if (tile) tile.classList.toggle('connected', connected);
}
function removeTile(peerId) {
const key = (peerId || '').slice(-6);
const tile = tiles[key] || tiles[peerId];
if (tile) { tile.remove(); delete tiles[key]; delete tiles[peerId]; }
}
function status(msg) {
document.getElementById('status').textContent = msg;
console.log('[video-demo]', msg);
}
</script>
</body>
</html>