livedesk 0.1.244 → 0.1.246

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/server.js CHANGED
@@ -41,12 +41,14 @@ const httpPort = Number(process.env.LIVEDESK_HUB_HTTP_PORT || process.env.PORT |
41
41
  const frameBackpressureBytes = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_BACKPRESSURE_BYTES', 64 * 1024 * 1024);
42
42
  const frameClientQueuePackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_QUEUE_PACKETS', 256);
43
43
  const frameClientDrainBudgetPackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_DRAIN_BUDGET_PACKETS', 64);
44
+ const frameStreamStopGraceMs = readPositiveIntegerEnv('LIVEDESK_FRAME_STREAM_STOP_GRACE_MS', 1500);
44
45
  const mode5FrameBackpressureBytes = readPositiveIntegerEnv('LIVEDESK_MODE5_WS_BACKPRESSURE_BYTES', 2 * 1024 * 1024);
45
46
  const mode5FrameQueuePackets = readPositiveIntegerEnv('LIVEDESK_MODE5_WS_QUEUE_PACKETS', 2);
46
47
  const audioBackpressureBytes = readPositiveIntegerEnv('LIVEDESK_AUDIO_WS_BACKPRESSURE_BYTES', 96 * 1024);
47
- const frameClients = new Set();
48
- const frameClientsByDeviceId = new Map();
49
- const frameWildcardClients = new Set();
48
+ const frameClients = new Set();
49
+ const frameClientsByDeviceId = new Map();
50
+ const frameWildcardClients = new Set();
51
+ const pendingFrameStreamStops = new Map();
50
52
  const atlasClients = new Map();
51
53
  const inputClients = new Set();
52
54
  const audioClients = new Set();
@@ -1056,6 +1058,40 @@ function hasOtherFrameStreamOwner(ws, deviceId, streamId, streamPurpose = '') {
1056
1058
  return false;
1057
1059
  }
1058
1060
 
1061
+ function frameStreamStopKey(deviceId, streamId, streamPurpose) {
1062
+ return `${deviceId}\u0000${streamId}\u0000${streamPurpose}`;
1063
+ }
1064
+
1065
+ function cancelPendingFrameStreamStop(deviceId, streamId, streamPurpose) {
1066
+ const key = frameStreamStopKey(deviceId, streamId, streamPurpose);
1067
+ const pending = pendingFrameStreamStops.get(key);
1068
+ if (!pending) {
1069
+ return;
1070
+ }
1071
+ clearTimeout(pending.timer);
1072
+ pendingFrameStreamStops.delete(key);
1073
+ }
1074
+
1075
+ function scheduleFrameStreamStop(deviceId, streamId, streamPurpose) {
1076
+ const key = frameStreamStopKey(deviceId, streamId, streamPurpose);
1077
+ cancelPendingFrameStreamStop(deviceId, streamId, streamPurpose);
1078
+ const timer = setTimeout(() => {
1079
+ pendingFrameStreamStops.delete(key);
1080
+ if (hasOtherFrameStreamOwner(null, deviceId, streamId, streamPurpose)) {
1081
+ return;
1082
+ }
1083
+ const result = remoteHub.stopLiveStream(deviceId, {
1084
+ streamId,
1085
+ streamPurpose,
1086
+ reason: 'frame-client-closed'
1087
+ });
1088
+ if (result?.ok && !result.alreadyStopped) {
1089
+ console.log(`[LiveDesk Hub] stopped ${streamPurpose} stream after frame client closed device=${deviceId} stream=${streamId}`);
1090
+ }
1091
+ }, frameStreamStopGraceMs);
1092
+ pendingFrameStreamStops.set(key, { timer });
1093
+ }
1094
+
1059
1095
  function stopFrameClientStreams(ws) {
1060
1096
  const streams = ws.liveDeskStreamIdsByDeviceId instanceof Map
1061
1097
  ? ws.liveDeskStreamIdsByDeviceId
@@ -1068,14 +1104,7 @@ function stopFrameClientStreams(ws) {
1068
1104
  if (!streamId || hasOtherFrameStreamOwner(ws, deviceId, streamId, streamPurpose)) {
1069
1105
  continue;
1070
1106
  }
1071
- const result = remoteHub.stopLiveStream(deviceId, {
1072
- streamId,
1073
- streamPurpose,
1074
- reason: 'frame-client-closed'
1075
- });
1076
- if (result?.ok && !result.alreadyStopped) {
1077
- console.log(`[LiveDesk Hub] stopped ${streamPurpose} stream after frame client closed device=${deviceId} stream=${streamId}`);
1078
- }
1107
+ scheduleFrameStreamStop(deviceId, streamId, streamPurpose);
1079
1108
  }
1080
1109
  streams.clear();
1081
1110
  }
@@ -1302,9 +1331,10 @@ function startFrameSubscriptionLive(ws, reason = 'subscribe', onlyDeviceId = '',
1302
1331
  && (liveOptions.reuseExisting === true || reason === 'subscribe' || reason === 'watchdog'),
1303
1332
  silentReuse: reason === 'watchdog' && liveOptions.forceRestart !== true
1304
1333
  });
1305
- if (result?.ok) {
1306
- ws.liveDeskStreamIdsByDeviceId.set(deviceId, result.streamId);
1307
- started.push({ deviceId, streamId: result.streamId, fps: result.fps, reused: result.reused === true });
1334
+ if (result?.ok) {
1335
+ ws.liveDeskStreamIdsByDeviceId.set(deviceId, result.streamId);
1336
+ cancelPendingFrameStreamStop(deviceId, result.streamId, String(liveOptions.streamPurpose || 'wall'));
1337
+ started.push({ deviceId, streamId: result.streamId, fps: result.fps, reused: result.reused === true });
1308
1338
  } else {
1309
1339
  ws.liveDeskStreamIdsByDeviceId.delete(deviceId);
1310
1340
  skipped.push({ deviceId, reason: result?.error || 'start-failed' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livedesk",
3
- "version": "0.1.244",
3
+ "version": "0.1.246",
4
4
  "description": "LiveDesk Hub and client launcher",
5
5
  "type": "module",
6
6
  "bin": {