Ich kann bei folgender Funktion nicht mein Video sehen und ich weiß nicht warum:
function renderMain() {
bigVideo.innerHTML = "";
const userKey = currentBig;
if (userKey === "local") {
const vid = document.createElement("video");
vid.autoplay = true;
vid.muted = true;
if (localVideoOn) {
vid.srcObject = localStream;
vid.play().catch(err => alert("Autoplay blockiert:", err));
} else {
// Platzhalter, statt video
const ph = document.createElement("div");
ph.classList.add("placeholder");
ph.textContent = username.charAt(0).toUpperCase();
bigVideo.append(ph);
return;
}
bigVideo.append(vid);
} else {
const p = peers[userKey];
if (p.remoteStream && !p.user.camOff) {
const vid = document.createElement("video");
vid.srcObject = p.remoteStream;
vid.autoplay = true;
bigVideo.append(vid);
} else {
const ph = document.createElement("div");
ph.classList.add("placeholder");
ph.textContent = p.user.username[0];
bigVideo.append(ph);
}
// Name & Mic-Icon
const info = document.createElement("div");
info.style.position = "absolute";
info.style.bottom = "5px";
info.style.left = "5px";
info.style.color = "#fff";
info.textContent = p.user.username;
bigVideo.append(info);
if (p.user.audioOff) {
const mic = document.createElement("span");
mic.style.position="absolute";
mic.style.bottom="5px";
mic.style.right="5px";
mic.textContent="🔇";
bigVideo.append(mic);
}
}
// Small preview
smallPreview.innerHTML = "";
const previewStream = localVideoOn ? localStream : null;
const vid2 = document.createElement("video");
if (previewStream) {
vid2.srcObject = previewStream;
vid2.play().catch(err => alert("Preview autoplay blockiert:", err));
}
vid2.autoplay = vid2.muted = true;
smallPreview.append(vid2);
}
Wie kann ich das Problem lösen? Das ist der komplette Code, falls notwendig:
// webrtc-client.js
(async ()=> {
const socket = io({ query: { room, username, gender }});
const mainC = document.getElementById("mainContainer");
const usersC = document.getElementById("usersContainer");
const bigVideo = document.getElementById("bigVideo");
const smallPreview = document.getElementById("smallPreview");
const actionBar = document.getElementById("actionBar");
const btnMic = document.getElementById("btnToggleMic");
const btnCam = document.getElementById("btnToggleCam");
const btnSwitch = document.getElementById("btnSwitchCam");
const toUsers = document.getElementById("toUsers");
const toMain = document.getElementById("toMain");
const usersGrid = document.getElementById("usersGrid");
let localStream;
try {
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
} catch (err) {
alert("Fehler beim Zugriff auf Kamera/Mikrofon:\n" + err.message);
return; // ggf. abbrechen
}
let localVideoOn = true, localAudioOn = true;
let peers = {}, currentBig = null;
// Helper: Video-Element erstellen oder Platzhalter
function makeVideoEl(stream, user) {
const container = document.createElement("div");
container.classList.add("userBox");
const mediaEl = stream
? Object.assign(document.createElement("video"), { srcObject: stream, autoplay:true, muted: user.isLocal })
: (() => {
const p = document.createElement("div");
p.classList.add("placeholder");
p.textContent = user.username[0];
return p;
})();
container.append(mediaEl);
// Icons
if (!stream && user.camOff) {
// show placeholder (already)
}
if (user.audioOff) {
const mic = document.createElement("span");
mic.classList.add("micIcon");
mic.textContent = "🔇";
container.append(mic);
}
const gender = document.createElement("span");
gender.classList.add("genderIcon");
gender.textContent = user.gender === "m" ? "♂️" : user.gender === "w" ? "♀️" : "⚧️";
container.append(gender);
const info = document.createElement("div");
info.classList.add("userInfo");
info.textContent = user.username;
container.append(info);
return container;
}
// Umschalten zwischen Main- und Users-View
toUsers.onclick = ()=> mainC.classList.replace("active",""), usersC.classList.add("active");
toMain.onclick = ()=> usersC.classList.replace("active",""), mainC.classList.add("active");
// ActionBar toggle
bigVideo.onclick = ()=> actionBar.classList.toggle("visible");
// Button-Events
btnMic.onclick = () => {
localAudioOn = !localAudioOn;
localStream.getAudioTracks()[0].enabled = localAudioOn;
btnMic.textContent = localAudioOn? "🎤":"🔇";
};
btnCam.onclick = () => {
localVideoOn = !localVideoOn;
localStream.getVideoTracks()[0].enabled = localVideoOn;
btnCam.textContent = localVideoOn? "📷":"🚫";
renderMain(); // Platzhalter ggf. neu zeichnen
};
btnSwitch.onclick = () => {
// Bei 2 Teilnehmern: Video-Swapping
if (Object.keys(peers).length === 1) {
const otherId = Object.keys(peers)[0];
currentBig = currentBig === otherId ? "local" : otherId;
renderMain();
}
};
// Peer-Verbindungen aufbauen (für jeden weiteren Teilnehmer eins)
socket.on("roomData", async data => {
// data: { socketId: { userName, gender } , … }
// entfernte Verbindungen bereinigen
for (let id in peers) {
if (!data[id]) { peers[id].close(); delete peers[id]; }
}
// neue Verbindungen
for (let id in data) {
if (id === socket.id) continue;
if (peers[id]) continue;
const pc = new RTCPeerConnection();
localStream.getTracks().forEach(t => pc.addTrack(t, localStream));
pc.onicecandidate = e => e.candidate && socket.emit("signal", { to:id, from:socket.id, data:e.candidate });
pc.ontrack = e => {
peers[id].remoteStream = e.streams[0];
renderMain();
renderUsers();
};
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
socket.emit("signal", { to:id, from:socket.id, data:pc.localDescription });
peers[id] = { pc, user: data[id], remoteStream: null };
}
// Wer spricht? (optional: per Audio-Level-Detection)
// Für 1 oder 2: currentBig setzen
if (Object.keys(peers).length <= 1) {
currentBig = Object.keys(peers)[0] || "local";
}
renderMain();
renderUsers();
});
socket.on("signal", async ({ from, data }) => {
const p = peers[from];
if (!p) return;
if (data.type) {
await p.pc.setRemoteDescription(data);
if (data.type === "offer") {
const answer = await p.pc.createAnswer();
await p.pc.setLocalDescription(answer);
socket.emit("signal", { to: from, from: socket.id, data: p.pc.localDescription });
}
} else {
await p.pc.addIceCandidate(data);
}
});
// Render-Funktionen
function renderMain() {
bigVideo.innerHTML = "";
const userKey = currentBig;
if (userKey === "local") {
const vid = document.createElement("video");
vid.autoplay = true;
vid.muted = true;
if (localVideoOn) {
vid.srcObject = localStream;
vid.play().catch(err => alert("Autoplay blockiert:", err));
} else {
// Platzhalter, statt video
const ph = document.createElement("div");
ph.classList.add("placeholder");
ph.textContent = username.charAt(0).toUpperCase();
bigVideo.append(ph);
return;
}
bigVideo.append(vid);
} else {
const p = peers[userKey];
if (p.remoteStream && !p.user.camOff) {
const vid = document.createElement("video");
vid.srcObject = p.remoteStream;
vid.autoplay = true;
bigVideo.append(vid);
} else {
const ph = document.createElement("div");
ph.classList.add("placeholder");
ph.textContent = p.user.username[0];
bigVideo.append(ph);
}
// Name & Mic-Icon
const info = document.createElement("div");
info.style.position = "absolute";
info.style.bottom = "5px";
info.style.left = "5px";
info.style.color = "#fff";
info.textContent = p.user.username;
bigVideo.append(info);
if (p.user.audioOff) {
const mic = document.createElement("span");
mic.style.position="absolute";
mic.style.bottom="5px";
mic.style.right="5px";
mic.textContent="🔇";
bigVideo.append(mic);
}
}
// Small preview
smallPreview.innerHTML = "";
const previewStream = localVideoOn ? localStream : null;
const vid2 = document.createElement("video");
if (previewStream) {
vid2.srcObject = previewStream;
vid2.play().catch(err => alert("Preview autoplay blockiert:", err));
}
vid2.autoplay = vid2.muted = true;
smallPreview.append(vid2);
}
function renderUsers() {
usersGrid.innerHTML = "";
// Alle Fremd-User
Object.entries(peers).forEach(([id, { user, remoteStream }]) => {
const box = makeVideoEl(remoteStream, { ...user, audioOff: user.audioOff, camOff: !remoteStream });
usersGrid.append(box);
});
// Mein kleines Video oben rechts
const meBox = makeVideoEl(localStream, { username, gender, isLocal:true, audioOff: !localAudioOn, camOff: !localVideoOn });
meBox.id = "meBox";
usersGrid.append(meBox);
}
// Initial render
renderMain();
renderUsers();
})();