@livedesk/hub 0.1.9 → 0.1.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livedesk/hub",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "LiveDesk local Hub API and browser frame bridge",
5
5
  "type": "module",
6
6
  "main": "src/server.js",
package/src/remote-hub.js CHANGED
@@ -158,12 +158,14 @@ const DEFAULT_PUBLIC_IP_TIMEOUT_MS = 1800;
158
158
  const DUPLICATE_DEVICE_ACTIVE_REJECT_MS = 15000;
159
159
  const DUPLICATE_DEVICE_LOG_THROTTLE_MS = 60000;
160
160
  const DUPLICATE_DEVICE_RETRY_AFTER_MS = 30000;
161
- const AGENT_BINARY_INGRESS_QUEUE_PACKETS = 8;
162
- const MODE5_AGENT_BINARY_INGRESS_QUEUE_PACKETS = 2;
163
- // Native capture backends can emit short bursts (ScreenCaptureKit commonly
164
- // queues up to eight frames). Drain one frame per event-loop turn so a burst
165
- // cannot immediately overflow the smaller Hub-to-browser send lanes.
166
- const AGENT_BINARY_INGRESS_DRAIN_BUDGET_PACKETS = 1;
161
+ const AGENT_BINARY_INGRESS_QUEUE_PACKETS = 16;
162
+ const MODE5_AGENT_BINARY_INGRESS_QUEUE_PACKETS = 2;
163
+ // Native capture backends can emit short bursts (ScreenCaptureKit plus the
164
+ // Agent handoff can hold two eight-frame batches). Drain the complete bounded
165
+ // ingress lane in one event-loop turn. The Hub-to-browser lanes remain
166
+ // independently bounded and own browser backpressure; throttling ingress one
167
+ // packet per turn only drops dependent H.264 deltas before those lanes.
168
+ const AGENT_BINARY_INGRESS_DRAIN_BUDGET_PACKETS = 64;
167
169
  const SYNTHETIC_FRAME_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAYAAAD0In+KAAAADElEQVR42mP8z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC';
168
170
  const SYNTHETIC_FRAME_PAYLOAD = Buffer.from(SYNTHETIC_FRAME_DATA_URL.split(',')[1], 'base64');
169
171
  const SYNTHETIC_FRAME_HASH = crypto.createHash('sha256').update(SYNTHETIC_FRAME_PAYLOAD).digest('hex').slice(0, 16);
@@ -3864,10 +3866,23 @@ export function createRemoteHub(options = {}) {
3864
3866
  agentSendGapMs: Number.isFinite(Number(message.agentSendGapMs)) ? Number(message.agentSendGapMs) : 0,
3865
3867
  agentSendDurationMs: Number.isFinite(Number(message.agentSendDurationMs)) ? Number(message.agentSendDurationMs) : 0,
3866
3868
  agentSendDurationFrameSeq: Number.isFinite(Number(message.agentSendDurationFrameSeq)) ? Number(message.agentSendDurationFrameSeq) : 0,
3867
- agentPaceMs: Number.isFinite(Number(message.agentPaceMs)) ? Number(message.agentPaceMs) : 0,
3868
- agentQueueBeforePaceMs: Number.isFinite(Number(message.agentQueueBeforePaceMs)) ? Number(message.agentQueueBeforePaceMs) : 0,
3869
- agentFrameAgeMs: Number.isFinite(Number(message.agentFrameAgeMs)) ? Number(message.agentFrameAgeMs) : 0,
3870
- droppedByAgent: Number.isFinite(Number(message.droppedByAgent)) ? Number(message.droppedByAgent) : 0,
3869
+ agentPaceMs: Number.isFinite(Number(message.agentPaceMs)) ? Number(message.agentPaceMs) : 0,
3870
+ agentQueueBeforePaceMs: Number.isFinite(Number(message.agentQueueBeforePaceMs)) ? Number(message.agentQueueBeforePaceMs) : 0,
3871
+ agentFrameAgeMs: Number.isFinite(Number(message.agentFrameAgeMs)) ? Number(message.agentFrameAgeMs) : 0,
3872
+ nativeCaptureTelemetryAvailable: message.nativeCaptureTelemetryAvailable === true,
3873
+ nativeEncoderHardwareAccelerationKnown: message.nativeEncoderHardwareAccelerationKnown === true,
3874
+ nativeEncoderHardwareAccelerated: typeof message.nativeEncoderHardwareAccelerated === 'boolean'
3875
+ ? message.nativeEncoderHardwareAccelerated
3876
+ : null,
3877
+ nativeEncoderHardwareQueryStatus: safeString(message.nativeEncoderHardwareQueryStatus, 80),
3878
+ nativeCaptureFps: Number.isFinite(Number(message.nativeCaptureFps)) ? Number(message.nativeCaptureFps) : 0,
3879
+ nativeEncodedFps: Number.isFinite(Number(message.nativeEncodedFps)) ? Number(message.nativeEncodedFps) : 0,
3880
+ nativeCaptureSampleCount: Number.isFinite(Number(message.nativeCaptureSampleCount)) ? Number(message.nativeCaptureSampleCount) : 0,
3881
+ nativeEncodableFrameCount: Number.isFinite(Number(message.nativeEncodableFrameCount)) ? Number(message.nativeEncodableFrameCount) : 0,
3882
+ nativeSkippedFrameCount: Number.isFinite(Number(message.nativeSkippedFrameCount)) ? Number(message.nativeSkippedFrameCount) : 0,
3883
+ nativeEncodedFrameCount: Number.isFinite(Number(message.nativeEncodedFrameCount)) ? Number(message.nativeEncodedFrameCount) : 0,
3884
+ nativeCaptureTelemetryAt: safeString(message.nativeCaptureTelemetryAt, 80),
3885
+ droppedByAgent: Number.isFinite(Number(message.droppedByAgent)) ? Number(message.droppedByAgent) : 0,
3871
3886
  hardwareEncoder: safeString(message.hardwareEncoder, 80),
3872
3887
  platformProfile: safeString(message.platformProfile, 80),
3873
3888
  transferProtocol: transfer.transferProtocol,
@@ -4228,9 +4243,22 @@ export function createRemoteHub(options = {}) {
4228
4243
  agentSendGapMs: Number.isFinite(Number(message.agentSendGapMs)) ? Number(message.agentSendGapMs) : 0,
4229
4244
  agentSendDurationMs: Number.isFinite(Number(message.agentSendDurationMs)) ? Number(message.agentSendDurationMs) : 0,
4230
4245
  agentSendDurationFrameSeq: Number.isFinite(Number(message.agentSendDurationFrameSeq)) ? Number(message.agentSendDurationFrameSeq) : 0,
4231
- agentPaceMs: Number.isFinite(Number(message.agentPaceMs)) ? Number(message.agentPaceMs) : 0,
4232
- agentQueueBeforePaceMs: Number.isFinite(Number(message.agentQueueBeforePaceMs)) ? Number(message.agentQueueBeforePaceMs) : 0,
4233
- agentFrameAgeMs: Number.isFinite(Number(message.agentFrameAgeMs)) ? Number(message.agentFrameAgeMs) : 0,
4246
+ agentPaceMs: Number.isFinite(Number(message.agentPaceMs)) ? Number(message.agentPaceMs) : 0,
4247
+ agentQueueBeforePaceMs: Number.isFinite(Number(message.agentQueueBeforePaceMs)) ? Number(message.agentQueueBeforePaceMs) : 0,
4248
+ agentFrameAgeMs: Number.isFinite(Number(message.agentFrameAgeMs)) ? Number(message.agentFrameAgeMs) : 0,
4249
+ nativeCaptureTelemetryAvailable: message.nativeCaptureTelemetryAvailable === true,
4250
+ nativeEncoderHardwareAccelerationKnown: message.nativeEncoderHardwareAccelerationKnown === true,
4251
+ nativeEncoderHardwareAccelerated: typeof message.nativeEncoderHardwareAccelerated === 'boolean'
4252
+ ? message.nativeEncoderHardwareAccelerated
4253
+ : null,
4254
+ nativeEncoderHardwareQueryStatus: safeString(message.nativeEncoderHardwareQueryStatus, 80),
4255
+ nativeCaptureFps: Number.isFinite(Number(message.nativeCaptureFps)) ? Number(message.nativeCaptureFps) : 0,
4256
+ nativeEncodedFps: Number.isFinite(Number(message.nativeEncodedFps)) ? Number(message.nativeEncodedFps) : 0,
4257
+ nativeCaptureSampleCount: Number.isFinite(Number(message.nativeCaptureSampleCount)) ? Number(message.nativeCaptureSampleCount) : 0,
4258
+ nativeEncodableFrameCount: Number.isFinite(Number(message.nativeEncodableFrameCount)) ? Number(message.nativeEncodableFrameCount) : 0,
4259
+ nativeSkippedFrameCount: Number.isFinite(Number(message.nativeSkippedFrameCount)) ? Number(message.nativeSkippedFrameCount) : 0,
4260
+ nativeEncodedFrameCount: Number.isFinite(Number(message.nativeEncodedFrameCount)) ? Number(message.nativeEncodedFrameCount) : 0,
4261
+ nativeCaptureTelemetryAt: safeString(message.nativeCaptureTelemetryAt, 80),
4234
4262
  droppedByAgent: Number.isFinite(Number(message.droppedByAgent)) ? Number(message.droppedByAgent) : 0,
4235
4263
  hubIngressDropped: Number.isFinite(Number(message.hubIngressDropped)) ? Number(message.hubIngressDropped) : 0,
4236
4264
  udpIncompleteFrames: Number.isFinite(Number(message.udpIncompleteFrames)) ? Number(message.udpIncompleteFrames) : 0,
package/src/server.js CHANGED
@@ -61,8 +61,13 @@ const runtimeManager = createHubRuntime({
61
61
  });
62
62
  runtimeManager.emit('runtime.started', { role: runtimeRole, pid: process.pid });
63
63
  const frameBackpressureBytes = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_BACKPRESSURE_BYTES', 8 * 1024 * 1024);
64
- const frameClientQueuePackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_QUEUE_PACKETS', 8);
65
- const controlFrameClientQueuePackets = readPositiveIntegerEnv('LIVEDESK_CONTROL_FRAME_WS_QUEUE_PACKETS', 2);
64
+ // ScreenCaptureKit and the native Agent handoff can release two bounded
65
+ // eight-frame batches together. Keep the Wall lane large enough to retain the
66
+ // complete dependent H.264 burst. Control is normally a single target, but its
67
+ // macOS Agent handoff can release eight dependent H.264 frames together; keep
68
+ // that complete bounded burst instead of stalling until the next recovery key.
69
+ const frameClientQueuePackets = readPositiveIntegerEnv('LIVEDESK_FRAME_WS_QUEUE_PACKETS', 16);
70
+ const controlFrameClientQueuePackets = readPositiveIntegerEnv('LIVEDESK_CONTROL_FRAME_WS_QUEUE_PACKETS', 8);
66
71
  const frameStreamStopGraceMs = readPositiveIntegerEnv('LIVEDESK_FRAME_STREAM_STOP_GRACE_MS', 1500);
67
72
  const mode5FrameBackpressureBytes = readPositiveIntegerEnv('LIVEDESK_MODE5_WS_BACKPRESSURE_BYTES', 2 * 1024 * 1024);
68
73
  const mode5FrameQueuePackets = readPositiveIntegerEnv('LIVEDESK_MODE5_WS_QUEUE_PACKETS', 2);
@@ -2050,9 +2055,22 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
2050
2055
  agentSendGapMs: Number(frame.agentSendGapMs || 0) || 0,
2051
2056
  agentSendDurationMs: Number(frame.agentSendDurationMs || 0) || 0,
2052
2057
  agentSendDurationFrameSeq: Number(frame.agentSendDurationFrameSeq || 0) || 0,
2053
- agentPaceMs: Number(frame.agentPaceMs || 0) || 0,
2054
- agentQueueBeforePaceMs: Number(frame.agentQueueBeforePaceMs || 0) || 0,
2055
- agentFrameAgeMs: Number(frame.agentFrameAgeMs || 0) || 0,
2058
+ agentPaceMs: Number(frame.agentPaceMs || 0) || 0,
2059
+ agentQueueBeforePaceMs: Number(frame.agentQueueBeforePaceMs || 0) || 0,
2060
+ agentFrameAgeMs: Number(frame.agentFrameAgeMs || 0) || 0,
2061
+ nativeCaptureTelemetryAvailable: frame.nativeCaptureTelemetryAvailable === true,
2062
+ nativeEncoderHardwareAccelerationKnown: frame.nativeEncoderHardwareAccelerationKnown === true,
2063
+ nativeEncoderHardwareAccelerated: typeof frame.nativeEncoderHardwareAccelerated === 'boolean'
2064
+ ? frame.nativeEncoderHardwareAccelerated
2065
+ : null,
2066
+ nativeEncoderHardwareQueryStatus: frame.nativeEncoderHardwareQueryStatus || '',
2067
+ nativeCaptureFps: Number(frame.nativeCaptureFps || 0) || 0,
2068
+ nativeEncodedFps: Number(frame.nativeEncodedFps || 0) || 0,
2069
+ nativeCaptureSampleCount: Number(frame.nativeCaptureSampleCount || 0) || 0,
2070
+ nativeEncodableFrameCount: Number(frame.nativeEncodableFrameCount || 0) || 0,
2071
+ nativeSkippedFrameCount: Number(frame.nativeSkippedFrameCount || 0) || 0,
2072
+ nativeEncodedFrameCount: Number(frame.nativeEncodedFrameCount || 0) || 0,
2073
+ nativeCaptureTelemetryAt: frame.nativeCaptureTelemetryAt || '',
2056
2074
  droppedByAgent: Number(frame.droppedByAgent || 0) || 0,
2057
2075
  hubIngressDropped: Number(frame.hubIngressDropped || 0) || 0,
2058
2076
  hubClientDropped: Number(diagnostics.hubClientDropped || 0) || 0,