livedesk 0.1.82 → 0.1.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hub/src/remote-hub.js +50 -2
- package/hub/src/server.js +16 -2
- package/package.json +1 -1
package/hub/src/remote-hub.js
CHANGED
|
@@ -22,6 +22,9 @@ const RECENT_THUMBNAIL_FRAME_CACHE_LIMIT = 4;
|
|
|
22
22
|
const RECENT_LIVE_FRAME_CACHE_LIMIT = 80;
|
|
23
23
|
const RECENT_THUMBNAIL_FRAME_CACHE_MAX_BYTES = 3 * 1024 * 1024;
|
|
24
24
|
const RECENT_LIVE_FRAME_CACHE_MAX_BYTES = 24 * 1024 * 1024;
|
|
25
|
+
const LIVE_STREAM_PENDING_REUSE_MS = 5000;
|
|
26
|
+
const LIVE_STREAM_MIN_FRESH_MS = 3000;
|
|
27
|
+
const LIVE_STREAM_MAX_FRESH_MS = 12000;
|
|
25
28
|
const REMOTE_PROTOCOL_VERSION = 2;
|
|
26
29
|
const REMOTE_AGENT_PROTOCOL = 'mindexec.remote.agent';
|
|
27
30
|
const REMOTE_FRAME_PROTOCOL = 'mindexec.remote.frame.v2';
|
|
@@ -3872,7 +3875,37 @@ export function createRemoteHub(options = {}) {
|
|
|
3872
3875
|
return false;
|
|
3873
3876
|
}
|
|
3874
3877
|
const startedAt = Date.parse(activeLiveStream.startedAt || '');
|
|
3875
|
-
return Number.isFinite(startedAt) && Date.now() - startedAt <
|
|
3878
|
+
return Number.isFinite(startedAt) && Date.now() - startedAt < LIVE_STREAM_PENDING_REUSE_MS;
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
function getLiveStreamFreshWindowMs(activeLiveStream) {
|
|
3882
|
+
const fps = Number(activeLiveStream?.fps || 0);
|
|
3883
|
+
const frameMs = Number.isFinite(fps) && fps > 0 ? 1000 / fps : 500;
|
|
3884
|
+
return Math.max(
|
|
3885
|
+
LIVE_STREAM_MIN_FRESH_MS,
|
|
3886
|
+
Math.min(LIVE_STREAM_MAX_FRESH_MS, Math.round(frameMs * 20))
|
|
3887
|
+
);
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
function getLiveStreamIdleMs(activeLiveStream) {
|
|
3891
|
+
const lastFrameAt = Date.parse(activeLiveStream?.lastFrameAt || activeLiveStream?.openedAt || activeLiveStream?.startedAt || '');
|
|
3892
|
+
if (!Number.isFinite(lastFrameAt)) {
|
|
3893
|
+
return Infinity;
|
|
3894
|
+
}
|
|
3895
|
+
return Math.max(0, Date.now() - lastFrameAt);
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
function liveStreamIsReusable(activeLiveStream) {
|
|
3899
|
+
if (!activeLiveStream?.active) {
|
|
3900
|
+
return false;
|
|
3901
|
+
}
|
|
3902
|
+
if (liveStreamStartStillPending(activeLiveStream)) {
|
|
3903
|
+
return true;
|
|
3904
|
+
}
|
|
3905
|
+
if (activeLiveStream.open !== true) {
|
|
3906
|
+
return false;
|
|
3907
|
+
}
|
|
3908
|
+
return getLiveStreamIdleMs(activeLiveStream) <= getLiveStreamFreshWindowMs(activeLiveStream);
|
|
3876
3909
|
}
|
|
3877
3910
|
|
|
3878
3911
|
function liveStreamMatchesOptions(activeLiveStream, normalized) {
|
|
@@ -3976,7 +4009,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3976
4009
|
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
3977
4010
|
if (device.activeLiveStream?.streamId === streamId
|
|
3978
4011
|
&& liveStreamMatchesOptions(device.activeLiveStream, normalized)
|
|
3979
|
-
&& (device.activeLiveStream
|
|
4012
|
+
&& liveStreamIsReusable(device.activeLiveStream)) {
|
|
3980
4013
|
emitRemoteEvent('RemoteLiveStreamStartReused', device, {
|
|
3981
4014
|
streamId,
|
|
3982
4015
|
fps,
|
|
@@ -3995,6 +4028,21 @@ export function createRemoteHub(options = {}) {
|
|
|
3995
4028
|
reused: true
|
|
3996
4029
|
};
|
|
3997
4030
|
}
|
|
4031
|
+
if (device.activeLiveStream?.streamId === streamId
|
|
4032
|
+
&& liveStreamMatchesOptions(device.activeLiveStream, normalized)
|
|
4033
|
+
&& device.activeLiveStream.open === true
|
|
4034
|
+
&& !liveStreamIsReusable(device.activeLiveStream)) {
|
|
4035
|
+
emitRemoteEvent('RemoteLiveStreamStaleRestart', device, {
|
|
4036
|
+
streamId,
|
|
4037
|
+
fps,
|
|
4038
|
+
mode: transfer.mode,
|
|
4039
|
+
frameMode: transfer.frameMode,
|
|
4040
|
+
monitorIndex,
|
|
4041
|
+
idleMs: getLiveStreamIdleMs(device.activeLiveStream),
|
|
4042
|
+
staleAfterMs: getLiveStreamFreshWindowMs(device.activeLiveStream),
|
|
4043
|
+
lastFrameAt: device.activeLiveStream.lastFrameAt || ''
|
|
4044
|
+
});
|
|
4045
|
+
}
|
|
3998
4046
|
if (device.activeLiveStream?.active && device.activeLiveStream.streamId && device.activeLiveStream.streamId !== streamId) {
|
|
3999
4047
|
sendCommand(deviceId, {
|
|
4000
4048
|
command: 'stream.stop',
|
package/hub/src/server.js
CHANGED
|
@@ -27,6 +27,7 @@ const audioClients = new Set();
|
|
|
27
27
|
let frameClientSeq = 0;
|
|
28
28
|
let inputClientSeq = 0;
|
|
29
29
|
let audioClientSeq = 0;
|
|
30
|
+
const FRAME_LIVE_WATCHDOG_MS = 2500;
|
|
30
31
|
|
|
31
32
|
function handleRemoteHubEvent(type, event) {
|
|
32
33
|
if (type !== 'RemoteDeviceConnected') {
|
|
@@ -246,6 +247,9 @@ function startFrameSubscriptionLive(ws, reason = 'subscribe', onlyDeviceId = '')
|
|
|
246
247
|
skipped.push({ deviceId, reason: result?.error || 'start-failed' });
|
|
247
248
|
}
|
|
248
249
|
}
|
|
250
|
+
if (reason === 'watchdog' && !started.some(item => item.reused !== true)) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
249
253
|
sendJson(ws, {
|
|
250
254
|
type: 'RemoteFrameLiveAutoStart',
|
|
251
255
|
timestamp: new Date().toISOString(),
|
|
@@ -702,6 +706,16 @@ httpServer.on('upgrade', (req, socket, head) => {
|
|
|
702
706
|
frameWss.on('connection', (ws, req) => {
|
|
703
707
|
frameClients.add(ws);
|
|
704
708
|
ws.liveDeskFrameClientId = `rfws-${++frameClientSeq}`;
|
|
709
|
+
const liveWatchdog = setInterval(() => {
|
|
710
|
+
if (ws.readyState === 1) {
|
|
711
|
+
startFrameSubscriptionLive(ws, 'watchdog');
|
|
712
|
+
}
|
|
713
|
+
}, FRAME_LIVE_WATCHDOG_MS);
|
|
714
|
+
liveWatchdog.unref?.();
|
|
715
|
+
const cleanup = () => {
|
|
716
|
+
clearInterval(liveWatchdog);
|
|
717
|
+
frameClients.delete(ws);
|
|
718
|
+
};
|
|
705
719
|
try {
|
|
706
720
|
const parsed = new URL(req.url || '/', `http://${req.headers.host || '127.0.0.1'}`);
|
|
707
721
|
updateFrameSubscription(ws, { deviceIds: parsed.searchParams.get('devices') || '' });
|
|
@@ -718,8 +732,8 @@ frameWss.on('connection', (ws, req) => {
|
|
|
718
732
|
sendJson(ws, { type: 'RemoteFrameSubscriptionError', error: 'invalid-message' });
|
|
719
733
|
}
|
|
720
734
|
});
|
|
721
|
-
ws.on('close',
|
|
722
|
-
ws.on('error',
|
|
735
|
+
ws.on('close', cleanup);
|
|
736
|
+
ws.on('error', cleanup);
|
|
723
737
|
sendJson(ws, {
|
|
724
738
|
type: 'RemoteFrameSocketReady',
|
|
725
739
|
protocol: 'livedesk.remote.frames.binary.v1',
|