fix(webapp): avoid overlapping client stream sessions
This commit is contained in:
@@ -766,6 +766,23 @@ const clearClientStream = () => {
|
|||||||
setClientStreamMode('none');
|
setClientStreamMode('none');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const endClientStreamSession = async (streamSessionId, { teardown = true } = {}) => {
|
||||||
|
if (!streamSessionId) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await api.streams.end(streamSessionId);
|
||||||
|
} catch (error) {
|
||||||
|
const message = error?.message || '';
|
||||||
|
if (!/cannot be ended|not found/i.test(message)) {
|
||||||
|
console.warn('Failed ending client stream session', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (teardown) {
|
||||||
|
teardownPeerConnection(streamSessionId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const hasReusableClientStreamSession = (streamSessionId) =>
|
const hasReusableClientStreamSession = (streamSessionId) =>
|
||||||
Boolean(streamSessionId && (remoteStreams.has(streamSessionId) || streamTimers.has(streamSessionId)));
|
Boolean(streamSessionId && (remoteStreams.has(streamSessionId) || streamTimers.has(streamSessionId)));
|
||||||
|
|
||||||
@@ -1700,13 +1717,6 @@ const pollClientData = async () => {
|
|||||||
recordings: recs.recordings || [],
|
recordings: recs.recordings || [],
|
||||||
linkedCameras
|
linkedCameras
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const link of linkedCameras) {
|
|
||||||
if (!requestedStreams.has(link.cameraDeviceId)) {
|
|
||||||
requestedStreams.add(link.cameraDeviceId);
|
|
||||||
void actions.requestStream(link.cameraDeviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const startPolling = () => {
|
const startPolling = () => {
|
||||||
@@ -2109,17 +2119,22 @@ const actions = {
|
|||||||
|
|
||||||
async requestStream(cameraDeviceId) {
|
async requestStream(cameraDeviceId) {
|
||||||
try {
|
try {
|
||||||
|
requestedStreams.add(cameraDeviceId);
|
||||||
await api.streams.request(cameraDeviceId);
|
await api.streams.request(cameraDeviceId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
requestedStreams.delete(cameraDeviceId);
|
||||||
pushToast(error.message || 'Failed to request stream', 'error');
|
pushToast(error.message || 'Failed to request stream', 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
selectCamera(cameraDeviceId) {
|
async selectCamera(cameraDeviceId) {
|
||||||
const currentState = getAppState();
|
const currentState = getAppState();
|
||||||
const sessions = currentState.cameraSessions || {};
|
const sessions = currentState.cameraSessions || {};
|
||||||
const existingSessionId = sessions[cameraDeviceId] || null;
|
const existingSessionId = sessions[cameraDeviceId] || null;
|
||||||
const reusableSessionId = hasReusableClientStreamSession(existingSessionId) ? existingSessionId : null;
|
const reusableSessionId = hasReusableClientStreamSession(existingSessionId) ? existingSessionId : null;
|
||||||
|
const previousActiveStreamSessionId = currentState.activeStreamSessionId;
|
||||||
|
const isSwitchingStreams =
|
||||||
|
Boolean(previousActiveStreamSessionId) && previousActiveStreamSessionId !== reusableSessionId;
|
||||||
|
|
||||||
if (currentState.activeCameraDeviceId !== cameraDeviceId || currentState.activeStreamSessionId !== reusableSessionId) {
|
if (currentState.activeCameraDeviceId !== cameraDeviceId || currentState.activeStreamSessionId !== reusableSessionId) {
|
||||||
clearClientStream();
|
clearClientStream();
|
||||||
@@ -2131,6 +2146,10 @@ const actions = {
|
|||||||
openLinkedCameraMenuId: null
|
openLinkedCameraMenuId: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isSwitchingStreams) {
|
||||||
|
void endClientStreamSession(previousActiveStreamSessionId, { teardown: false });
|
||||||
|
}
|
||||||
|
|
||||||
if (reusableSessionId) {
|
if (reusableSessionId) {
|
||||||
attachClientStreamToElement();
|
attachClientStreamToElement();
|
||||||
setClientStreamMode(remoteStreams.has(reusableSessionId) ? 'video' : 'connecting');
|
setClientStreamMode(remoteStreams.has(reusableSessionId) ? 'video' : 'connecting');
|
||||||
@@ -2138,12 +2157,14 @@ const actions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setClientStreamMode('connecting');
|
setClientStreamMode('connecting');
|
||||||
void actions.requestStream(cameraDeviceId);
|
await actions.requestStream(cameraDeviceId);
|
||||||
},
|
},
|
||||||
|
|
||||||
closeStreamViewer() {
|
closeStreamViewer() {
|
||||||
|
const streamSessionId = getAppState().activeStreamSessionId;
|
||||||
setAppState({ activeCameraDeviceId: null, activeStreamSessionId: null });
|
setAppState({ activeCameraDeviceId: null, activeStreamSessionId: null });
|
||||||
clearClientStream();
|
clearClientStream();
|
||||||
|
void endClientStreamSession(streamSessionId, { teardown: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
async openRecording(recordingId) {
|
async openRecording(recordingId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user