fix(webapp): prime remote live streams before viewing

This commit is contained in:
2026-04-09 11:15:00 +01:00
parent 92b25a8bac
commit 933f3d0b25

View File

@@ -98,6 +98,7 @@ let clientVideoElement = null;
const peerConnections = new Map();
const remoteStreams = new Map();
const hiddenClientStreamElements = new Map();
const pendingCandidatesMap = new Map();
const streamTimers = new Map();
const connectedPeers = new Set();
@@ -536,6 +537,33 @@ const attachClientStreamToElement = () => {
});
};
const primeClientStreamPlayback = (streamSessionId, stream) => {
if (!streamSessionId || !stream) return;
let hiddenVideoElement = hiddenClientStreamElements.get(streamSessionId);
if (!hiddenVideoElement && typeof document !== 'undefined') {
hiddenVideoElement = document.createElement('video');
hiddenVideoElement.muted = true;
hiddenVideoElement.autoplay = true;
hiddenVideoElement.playsInline = true;
hiddenVideoElement.style.position = 'fixed';
hiddenVideoElement.style.width = '1px';
hiddenVideoElement.style.height = '1px';
hiddenVideoElement.style.opacity = '0';
hiddenVideoElement.style.pointerEvents = 'none';
hiddenVideoElement.style.left = '-9999px';
hiddenVideoElement.style.top = '-9999px';
document.body.appendChild(hiddenVideoElement);
hiddenClientStreamElements.set(streamSessionId, hiddenVideoElement);
}
if (!hiddenVideoElement) return;
if (hiddenVideoElement.srcObject !== stream) {
hiddenVideoElement.srcObject = stream;
}
void hiddenVideoElement.play().catch(() => {});
};
const startCameraPreview = async (cameraInputId = getAppState().selectedCameraInputId) => {
if (!navigator.mediaDevices?.getUserMedia) {
pushToast('Camera API is not available in this browser', 'error');
@@ -1121,6 +1149,12 @@ const teardownPeerConnection = (streamSessionId) => {
}
peerConnections.clear();
remoteStreams.clear();
for (const hiddenVideoElement of hiddenClientStreamElements.values()) {
hiddenVideoElement.pause();
hiddenVideoElement.srcObject = null;
hiddenVideoElement.remove();
}
hiddenClientStreamElements.clear();
pendingCandidatesMap.clear();
connectedPeers.clear();
setConnectedStreamSessionIds();
@@ -1134,6 +1168,15 @@ const teardownPeerConnection = (streamSessionId) => {
peerConnections.delete(streamSessionId);
}
remoteStreams.delete(streamSessionId);
if (hiddenClientStreamElements.has(streamSessionId)) {
const hiddenVideoElement = hiddenClientStreamElements.get(streamSessionId);
hiddenVideoElement?.pause();
if (hiddenVideoElement) {
hiddenVideoElement.srcObject = null;
hiddenVideoElement.remove();
}
hiddenClientStreamElements.delete(streamSessionId);
}
pendingCandidatesMap.delete(streamSessionId);
connectedPeers.delete(streamSessionId);
setConnectedStreamSessionIds();
@@ -1236,7 +1279,10 @@ const ensurePeerConnection = async ({ streamSessionId, targetDeviceId, asCamera
if (getAppState().activeStreamSessionId === streamSessionId) {
attachClientStreamToElement();
setClientStreamMode('video');
return;
}
primeClientStreamPlayback(streamSessionId, stream);
};
if (asCamera) {