livedesk 0.1.365 → 0.1.367
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 +265 -99
- package/hub/src/server.js +11 -8
- package/package.json +5 -5
- package/web/dist/assets/index-BGyMH9o5.js +16 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-DSUJrX8t.js +0 -16
package/hub/src/remote-hub.js
CHANGED
|
@@ -617,11 +617,12 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
617
617
|
const location = Number(input.location ?? input.Location);
|
|
618
618
|
const monitorIndex = Number(input.monitorIndex ?? input.MonitorIndex ?? input.screenIndex ?? input.ScreenIndex ?? input.displayIndex ?? input.DisplayIndex);
|
|
619
619
|
const inputSeq = Number(input.inputSeq ?? input.InputSeq);
|
|
620
|
-
const issuedAtEpochMs = Number(input.issuedAtEpochMs ?? input.IssuedAtEpochMs);
|
|
621
|
-
const hubReceivedAtEpochMs = Number(input.hubReceivedAtEpochMs ?? input.HubReceivedAtEpochMs);
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
620
|
+
const issuedAtEpochMs = Number(input.issuedAtEpochMs ?? input.IssuedAtEpochMs);
|
|
621
|
+
const hubReceivedAtEpochMs = Number(input.hubReceivedAtEpochMs ?? input.HubReceivedAtEpochMs);
|
|
622
|
+
const captureGeneration = Number(input.captureGeneration ?? input.CaptureGeneration);
|
|
623
|
+
return {
|
|
624
|
+
type,
|
|
625
|
+
monitorIndex: Number.isFinite(monitorIndex) ? normalizeMonitorIndex(monitorIndex) : 0,
|
|
625
626
|
normalizedX: Number.isFinite(normalizedX) ? Math.max(0, Math.min(1, normalizedX)) : undefined,
|
|
626
627
|
normalizedY: Number.isFinite(normalizedY) ? Math.max(0, Math.min(1, normalizedY)) : undefined,
|
|
627
628
|
button: safeString(input.button || input.Button, 24),
|
|
@@ -636,9 +637,13 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
636
637
|
shiftKey: input.shiftKey === true || input.ShiftKey === true,
|
|
637
638
|
ctrlKey: input.ctrlKey === true || input.ControlKey === true || input.CtrlKey === true,
|
|
638
639
|
altKey: input.altKey === true || input.AltKey === true,
|
|
639
|
-
metaKey: input.metaKey === true || input.MetaKey === true || input.commandKey === true || input.CommandKey === true,
|
|
640
|
-
controlLeaseId: safeString(input.controlLeaseId || input.ControlLeaseId, 128),
|
|
641
|
-
|
|
640
|
+
metaKey: input.metaKey === true || input.MetaKey === true || input.commandKey === true || input.CommandKey === true,
|
|
641
|
+
controlLeaseId: safeString(input.controlLeaseId || input.ControlLeaseId, 128),
|
|
642
|
+
controlSessionId: safeString(input.controlSessionId || input.sessionId || input.ControlSessionId || input.SessionId, 160),
|
|
643
|
+
controlCommandId: safeString(input.controlCommandId || input.commandId || input.ControlCommandId || input.CommandId, 128),
|
|
644
|
+
captureGeneration: Number.isSafeInteger(captureGeneration) && captureGeneration > 0 ? captureGeneration : 0,
|
|
645
|
+
hubConnectionId: safeString(input.hubConnectionId || input.HubConnectionId, 128),
|
|
646
|
+
inputSeq: Number.isSafeInteger(inputSeq) && inputSeq > 0 ? inputSeq : 0,
|
|
642
647
|
requestAck: input.requestAck !== false && input.RequestAck !== false,
|
|
643
648
|
issuedAtEpochMs: Number.isFinite(issuedAtEpochMs) ? issuedAtEpochMs : 0,
|
|
644
649
|
hubReceivedAtEpochMs: Number.isFinite(hubReceivedAtEpochMs) ? hubReceivedAtEpochMs : 0,
|
|
@@ -3397,9 +3402,9 @@ export function createRemoteHub(options = {}) {
|
|
|
3397
3402
|
const activatingPendingGeneration = isPendingGeneration && commandId !== activeCommandId;
|
|
3398
3403
|
const transfer = buildRemoteFrameTransferDescriptorFromMessage(message, streamState.mode || DEFAULT_REMOTE_FRAME_MODE);
|
|
3399
3404
|
const openedAt = safeString(message.openedAt, 80) || device.lastSeenAt || new Date().toISOString();
|
|
3400
|
-
const nextStreamState = {
|
|
3401
|
-
...streamState,
|
|
3402
|
-
commandId: activatingPendingGeneration ? commandId : streamState.commandId,
|
|
3405
|
+
const nextStreamState = {
|
|
3406
|
+
...streamState,
|
|
3407
|
+
commandId: activatingPendingGeneration ? commandId : streamState.commandId,
|
|
3403
3408
|
pendingCommandId: activatingPendingGeneration ? '' : streamState.pendingCommandId,
|
|
3404
3409
|
pendingStartedAt: activatingPendingGeneration ? '' : streamState.pendingStartedAt,
|
|
3405
3410
|
pendingRestartToken: activatingPendingGeneration ? '' : streamState.pendingRestartToken,
|
|
@@ -3419,10 +3424,14 @@ export function createRemoteHub(options = {}) {
|
|
|
3419
3424
|
height: Number.isFinite(Number(message.height)) ? Number(message.height) : Number(streamState.height || 0),
|
|
3420
3425
|
sourceWidth: Number.isFinite(Number(message.sourceWidth)) ? Number(message.sourceWidth) : Number(streamState.sourceWidth || 0),
|
|
3421
3426
|
sourceHeight: Number.isFinite(Number(message.sourceHeight)) ? Number(message.sourceHeight) : Number(streamState.sourceHeight || 0),
|
|
3422
|
-
monitorIndex: Number.isFinite(Number(message.monitorIndex)) ? normalizeMonitorIndex(message.monitorIndex) : Number(streamState.monitorIndex || 0),
|
|
3423
|
-
monitorCount: Number.isFinite(Number(message.monitorCount)) ? clampNumber(message.monitorCount, 1, 64, 1) : Number(streamState.monitorCount || 1),
|
|
3424
|
-
|
|
3425
|
-
|
|
3427
|
+
monitorIndex: Number.isFinite(Number(message.monitorIndex)) ? normalizeMonitorIndex(message.monitorIndex) : Number(streamState.monitorIndex || 0),
|
|
3428
|
+
monitorCount: Number.isFinite(Number(message.monitorCount)) ? clampNumber(message.monitorCount, 1, 64, 1) : Number(streamState.monitorCount || 1),
|
|
3429
|
+
streamPurpose: safeString(message.streamPurpose || streamState.streamPurpose, 24) || 'wall',
|
|
3430
|
+
captureGeneration: Number.isSafeInteger(Number(message.captureGeneration)) && Number(message.captureGeneration) > 0
|
|
3431
|
+
? Number(message.captureGeneration)
|
|
3432
|
+
: Number(streamState.captureGeneration || 0),
|
|
3433
|
+
openedFrameSeq: Number.isFinite(Number(message.frameSeq)) ? Number(message.frameSeq) : Number(streamState.openedFrameSeq || 0)
|
|
3434
|
+
};
|
|
3426
3435
|
setDeviceLiveStream(device, nextStreamState);
|
|
3427
3436
|
emitRemoteEvent('RemoteLiveStreamOpened', device, {
|
|
3428
3437
|
streamId,
|
|
@@ -3457,9 +3466,9 @@ export function createRemoteHub(options = {}) {
|
|
|
3457
3466
|
});
|
|
3458
3467
|
return false;
|
|
3459
3468
|
}
|
|
3460
|
-
const activeCommandId = safeString(streamState.commandId, 128);
|
|
3461
|
-
const pendingCommandId = safeString(streamState.pendingCommandId, 128);
|
|
3462
|
-
const isActiveGeneration = !commandId || !activeCommandId || commandId === activeCommandId;
|
|
3469
|
+
const activeCommandId = safeString(streamState.commandId, 128);
|
|
3470
|
+
const pendingCommandId = safeString(streamState.pendingCommandId, 128);
|
|
3471
|
+
const isActiveGeneration = !commandId || !activeCommandId || commandId === activeCommandId;
|
|
3463
3472
|
if (!isActiveGeneration) {
|
|
3464
3473
|
device.counters.liveFramesDropped += 1;
|
|
3465
3474
|
emitRemoteEvent('RemoteFrameDropped', device, {
|
|
@@ -3471,8 +3480,25 @@ export function createRemoteHub(options = {}) {
|
|
|
3471
3480
|
frameSeq: Number.isFinite(frameSeq) ? frameSeq : null,
|
|
3472
3481
|
transport
|
|
3473
3482
|
});
|
|
3474
|
-
return false;
|
|
3475
|
-
}
|
|
3483
|
+
return false;
|
|
3484
|
+
}
|
|
3485
|
+
const frameCaptureGeneration = Number(message.captureGeneration || streamState.captureGeneration || 0);
|
|
3486
|
+
const activeCaptureGeneration = Number(streamState.captureGeneration || 0);
|
|
3487
|
+
if (activeCaptureGeneration > 0
|
|
3488
|
+
&& frameCaptureGeneration > 0
|
|
3489
|
+
&& frameCaptureGeneration !== activeCaptureGeneration) {
|
|
3490
|
+
device.counters.liveFramesDropped += 1;
|
|
3491
|
+
emitRemoteEvent('RemoteFrameDropped', device, {
|
|
3492
|
+
reason: 'stale-capture-generation-frame',
|
|
3493
|
+
streamId,
|
|
3494
|
+
commandId,
|
|
3495
|
+
captureGeneration: frameCaptureGeneration,
|
|
3496
|
+
activeCaptureGeneration,
|
|
3497
|
+
frameSeq: Number.isFinite(frameSeq) ? frameSeq : null,
|
|
3498
|
+
transport
|
|
3499
|
+
});
|
|
3500
|
+
return false;
|
|
3501
|
+
}
|
|
3476
3502
|
|
|
3477
3503
|
const byteLength = normalizeFrameByteLength(framePayload, frameData);
|
|
3478
3504
|
if ((!Buffer.isBuffer(framePayload) && !frameData)
|
|
@@ -3511,9 +3537,12 @@ export function createRemoteHub(options = {}) {
|
|
|
3511
3537
|
device.latestLiveFrame = {
|
|
3512
3538
|
streamId,
|
|
3513
3539
|
frameSeq,
|
|
3514
|
-
streamFrameSeq: Number.isFinite(Number(message.streamFrameSeq)) ? Number(message.streamFrameSeq) : frameSeq,
|
|
3515
|
-
commandId,
|
|
3516
|
-
|
|
3540
|
+
streamFrameSeq: Number.isFinite(Number(message.streamFrameSeq)) ? Number(message.streamFrameSeq) : frameSeq,
|
|
3541
|
+
commandId,
|
|
3542
|
+
sessionId: device.sessionId,
|
|
3543
|
+
captureGeneration: activeCaptureGeneration || frameCaptureGeneration,
|
|
3544
|
+
streamPurpose: safeString(message.streamPurpose || streamState.streamPurpose, 24) || 'wall',
|
|
3545
|
+
width: Number.isFinite(Number(message.width)) ? Number(message.width) : 0,
|
|
3517
3546
|
height: Number.isFinite(Number(message.height)) ? Number(message.height) : 0,
|
|
3518
3547
|
sourceWidth: Number.isFinite(Number(message.sourceWidth)) ? Number(message.sourceWidth) : Number(message.width || 0),
|
|
3519
3548
|
sourceHeight: Number.isFinite(Number(message.sourceHeight)) ? Number(message.sourceHeight) : Number(message.height || 0),
|
|
@@ -4667,17 +4696,49 @@ export function createRemoteHub(options = {}) {
|
|
|
4667
4696
|
const denied = policyError(device, 'allowControl');
|
|
4668
4697
|
if (denied) return { ok: false, error: denied };
|
|
4669
4698
|
|
|
4670
|
-
if (!readCapabilityFlag(device.capabilities, 'control')) {
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4699
|
+
if (!readCapabilityFlag(device.capabilities, 'control')) {
|
|
4700
|
+
const permissionMissing = device.capabilities?.controlPermission === false
|
|
4701
|
+
|| device.capabilities?.accessibilityPermission === false;
|
|
4702
|
+
return { ok: false, error: permissionMissing ? 'INPUT_PERMISSION_DENIED' : 'device-input-control-unavailable' };
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
const normalized = normalizeRemoteInputEvent(input);
|
|
4706
|
+
if (!normalized.type) {
|
|
4707
|
+
return { ok: false, error: 'missing-input-type' };
|
|
4708
|
+
}
|
|
4709
|
+
const controlStream = getActiveControlStream(device);
|
|
4710
|
+
if (!controlStream
|
|
4711
|
+
|| controlStream.open !== true
|
|
4712
|
+
|| !safeString(controlStream.commandId, 128)
|
|
4713
|
+
|| Number(controlStream.captureGeneration || 0) <= 0) {
|
|
4714
|
+
return { ok: false, error: 'CONTROL_NOT_READY' };
|
|
4715
|
+
}
|
|
4716
|
+
if (!normalized.controlSessionId
|
|
4717
|
+
|| normalized.controlSessionId !== safeString(device.sessionId, 160)) {
|
|
4718
|
+
return {
|
|
4719
|
+
ok: false,
|
|
4720
|
+
error: 'STALE_CONTROL_SESSION',
|
|
4721
|
+
activeSessionId: safeString(device.sessionId, 160)
|
|
4722
|
+
};
|
|
4723
|
+
}
|
|
4724
|
+
if (!normalized.controlCommandId
|
|
4725
|
+
|| normalized.controlCommandId !== safeString(controlStream.commandId, 128)) {
|
|
4726
|
+
return {
|
|
4727
|
+
ok: false,
|
|
4728
|
+
error: 'STALE_CONTROL_SESSION',
|
|
4729
|
+
activeCommandId: safeString(controlStream.commandId, 128)
|
|
4730
|
+
};
|
|
4731
|
+
}
|
|
4732
|
+
if (normalized.captureGeneration !== Number(controlStream.captureGeneration || 0)) {
|
|
4733
|
+
return {
|
|
4734
|
+
ok: false,
|
|
4735
|
+
error: 'STALE_CAPTURE_GENERATION',
|
|
4736
|
+
activeCaptureGeneration: Number(controlStream.captureGeneration || 0)
|
|
4737
|
+
};
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
const inputSocket = device.inputSocket;
|
|
4741
|
+
if (inputSocket && !inputSocket.destroyed) {
|
|
4681
4742
|
const sent = writeJsonLine(inputSocket, {
|
|
4682
4743
|
type: 'input.control',
|
|
4683
4744
|
payload: {
|
|
@@ -4687,22 +4748,21 @@ export function createRemoteHub(options = {}) {
|
|
|
4687
4748
|
}
|
|
4688
4749
|
});
|
|
4689
4750
|
if (sent) {
|
|
4690
|
-
device.counters.commandsSent += 1;
|
|
4691
|
-
device.inputLastSeenAt = new Date().toISOString();
|
|
4692
|
-
return {
|
|
4693
|
-
|
|
4751
|
+
device.counters.commandsSent += 1;
|
|
4752
|
+
device.inputLastSeenAt = new Date().toISOString();
|
|
4753
|
+
return {
|
|
4754
|
+
ok: true,
|
|
4755
|
+
inputSocket: true,
|
|
4756
|
+
sessionId: device.sessionId,
|
|
4757
|
+
commandId: controlStream.commandId,
|
|
4758
|
+
captureGeneration: controlStream.captureGeneration
|
|
4759
|
+
};
|
|
4760
|
+
}
|
|
4694
4761
|
|
|
4695
4762
|
detachInputSocket(inputSocket, 'input-socket-write-failed');
|
|
4696
4763
|
}
|
|
4697
4764
|
|
|
4698
|
-
return
|
|
4699
|
-
command: 'input.control',
|
|
4700
|
-
payload: {
|
|
4701
|
-
...normalized,
|
|
4702
|
-
hubForwardedAtEpochMs: Date.now(),
|
|
4703
|
-
issuedAt: normalized.issuedAt || new Date().toISOString()
|
|
4704
|
-
}
|
|
4705
|
-
});
|
|
4765
|
+
return { ok: false, error: 'CONTROL_NOT_READY', detail: 'input-channel-not-connected' };
|
|
4706
4766
|
}
|
|
4707
4767
|
|
|
4708
4768
|
function notifyAgentProgress(deviceIds, progress = {}) {
|
|
@@ -5061,11 +5121,83 @@ export function createRemoteHub(options = {}) {
|
|
|
5061
5121
|
}
|
|
5062
5122
|
}
|
|
5063
5123
|
|
|
5064
|
-
function makeStableLiveStreamId(deviceId, purpose = 'wall') {
|
|
5065
|
-
const hash = crypto.createHash('sha1').update(String(deviceId || 'device')).digest('hex').slice(0, 16);
|
|
5066
|
-
const role = safeString(purpose, 24).toLowerCase().replace(/[^a-z0-9_-]+/g, '-') || 'wall';
|
|
5067
|
-
return `${role}-${hash}`;
|
|
5068
|
-
}
|
|
5124
|
+
function makeStableLiveStreamId(deviceId, purpose = 'wall') {
|
|
5125
|
+
const hash = crypto.createHash('sha1').update(String(deviceId || 'device')).digest('hex').slice(0, 16);
|
|
5126
|
+
const role = safeString(purpose, 24).toLowerCase().replace(/[^a-z0-9_-]+/g, '-') || 'wall';
|
|
5127
|
+
return `${role}-${hash}`;
|
|
5128
|
+
}
|
|
5129
|
+
|
|
5130
|
+
function getActiveLiveStreams(device) {
|
|
5131
|
+
if (!device || typeof device !== 'object') {
|
|
5132
|
+
return [];
|
|
5133
|
+
}
|
|
5134
|
+
return [...ensureDeviceLiveStreams(device).values()].filter(stream => stream?.active === true);
|
|
5135
|
+
}
|
|
5136
|
+
|
|
5137
|
+
function getActiveControlStream(device) {
|
|
5138
|
+
return getActiveLiveStreams(device).find(stream =>
|
|
5139
|
+
safeString(stream?.streamPurpose, 24).toLowerCase() === 'control') || null;
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
function stopCompetingMacCaptureStreams(deviceId, device, nextStreamId, nextPurpose) {
|
|
5143
|
+
if (normalizeLivePlatform(device?.platform) !== 'macos') {
|
|
5144
|
+
return { ok: true, stopped: [] };
|
|
5145
|
+
}
|
|
5146
|
+
|
|
5147
|
+
const activeControl = getActiveControlStream(device);
|
|
5148
|
+
if (nextPurpose !== 'control'
|
|
5149
|
+
&& activeControl
|
|
5150
|
+
&& activeControl.streamId !== nextStreamId) {
|
|
5151
|
+
return {
|
|
5152
|
+
ok: true,
|
|
5153
|
+
suppressed: true,
|
|
5154
|
+
reason: 'CONTROL_CAPTURE_OWNS_DEVICE',
|
|
5155
|
+
ownerStreamId: activeControl.streamId,
|
|
5156
|
+
ownerCommandId: activeControl.commandId,
|
|
5157
|
+
captureGeneration: Number(activeControl.captureGeneration || 0)
|
|
5158
|
+
};
|
|
5159
|
+
}
|
|
5160
|
+
|
|
5161
|
+
const stopped = [];
|
|
5162
|
+
for (const stream of getActiveLiveStreams(device)) {
|
|
5163
|
+
if (!stream?.streamId || stream.streamId === nextStreamId) {
|
|
5164
|
+
continue;
|
|
5165
|
+
}
|
|
5166
|
+
const stopCommandId = crypto.randomUUID();
|
|
5167
|
+
const result = sendCommand(deviceId, {
|
|
5168
|
+
command: 'stream.stop',
|
|
5169
|
+
commandId: stopCommandId,
|
|
5170
|
+
payload: {
|
|
5171
|
+
streamId: stream.streamId,
|
|
5172
|
+
requestedAt: new Date().toISOString(),
|
|
5173
|
+
reason: `mac-capture-owner-transition:${nextPurpose}`
|
|
5174
|
+
}
|
|
5175
|
+
});
|
|
5176
|
+
if (!result.ok) {
|
|
5177
|
+
return {
|
|
5178
|
+
ok: false,
|
|
5179
|
+
error: 'CAPTURE_TRANSITION_IN_PROGRESS',
|
|
5180
|
+
streamId: stream.streamId,
|
|
5181
|
+
detail: result.error || 'stream-stop-dispatch-failed'
|
|
5182
|
+
};
|
|
5183
|
+
}
|
|
5184
|
+
stream.active = false;
|
|
5185
|
+
stream.pendingCommandId = '';
|
|
5186
|
+
stream.pendingStartedAt = '';
|
|
5187
|
+
stream.pendingRestartToken = '';
|
|
5188
|
+
stream.stoppedAt = new Date().toISOString();
|
|
5189
|
+
stream.stopReason = `mac-capture-owner-transition:${nextPurpose}`;
|
|
5190
|
+
stopped.push({ streamId: stream.streamId, commandId: stopCommandId });
|
|
5191
|
+
}
|
|
5192
|
+
return { ok: true, stopped };
|
|
5193
|
+
}
|
|
5194
|
+
|
|
5195
|
+
function nextCaptureGeneration(device) {
|
|
5196
|
+
const current = Number(device?.captureGenerationCounter || 0);
|
|
5197
|
+
const next = Number.isSafeInteger(current) && current > 0 ? current + 1 : 1;
|
|
5198
|
+
device.captureGenerationCounter = next;
|
|
5199
|
+
return next;
|
|
5200
|
+
}
|
|
5069
5201
|
|
|
5070
5202
|
function normalizeLivePlatform(value) {
|
|
5071
5203
|
const normalized = safeString(value, 32).toLowerCase();
|
|
@@ -5158,11 +5290,11 @@ export function createRemoteHub(options = {}) {
|
|
|
5158
5290
|
}
|
|
5159
5291
|
|
|
5160
5292
|
const now = new Date().toISOString();
|
|
5161
|
-
const normalized = normalizeLiveStreamStartOptions({ fps: 2, ...options, platform: device.platform });
|
|
5162
|
-
const { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose } = normalized;
|
|
5163
|
-
const streamId = safeString(options.streamId, 128) || makeStableLiveStreamId(deviceId, streamPurpose);
|
|
5164
|
-
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
5165
|
-
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
5293
|
+
const normalized = normalizeLiveStreamStartOptions({ fps: 2, ...options, platform: device.platform });
|
|
5294
|
+
const { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose } = normalized;
|
|
5295
|
+
const streamId = safeString(options.streamId, 128) || makeStableLiveStreamId(deviceId, streamPurpose);
|
|
5296
|
+
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
5297
|
+
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
5166
5298
|
if (activeLiveStream
|
|
5167
5299
|
&& liveStreamMatchesOptions(activeLiveStream, normalized)
|
|
5168
5300
|
&& (activeLiveStream.open === true || liveStreamStartStillPending(activeLiveStream))) {
|
|
@@ -5173,13 +5305,15 @@ export function createRemoteHub(options = {}) {
|
|
|
5173
5305
|
fps,
|
|
5174
5306
|
mode: transfer.mode,
|
|
5175
5307
|
frameMode: transfer.frameMode,
|
|
5176
|
-
monitorIndex,
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5308
|
+
monitorIndex,
|
|
5309
|
+
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
5310
|
+
synthetic: true,
|
|
5311
|
+
reused: true
|
|
5312
|
+
};
|
|
5313
|
+
}
|
|
5314
|
+
const captureGeneration = nextCaptureGeneration(device);
|
|
5315
|
+
device.counters.commandsSent += 1;
|
|
5316
|
+
setDeviceLiveStream(device, {
|
|
5183
5317
|
streamId,
|
|
5184
5318
|
commandId,
|
|
5185
5319
|
active: true,
|
|
@@ -5204,11 +5338,12 @@ export function createRemoteHub(options = {}) {
|
|
|
5204
5338
|
startedAt: now,
|
|
5205
5339
|
stoppedAt: '',
|
|
5206
5340
|
stopReason: '',
|
|
5207
|
-
lastFrameAt: '',
|
|
5208
|
-
lastFrameSeq: 0,
|
|
5209
|
-
framesReceived: 0,
|
|
5210
|
-
streamPurpose
|
|
5211
|
-
|
|
5341
|
+
lastFrameAt: '',
|
|
5342
|
+
lastFrameSeq: 0,
|
|
5343
|
+
framesReceived: 0,
|
|
5344
|
+
streamPurpose,
|
|
5345
|
+
captureGeneration
|
|
5346
|
+
});
|
|
5212
5347
|
device.counters.liveStreamsStarted += 1;
|
|
5213
5348
|
applySyntheticLiveFrame(device, streamId, {
|
|
5214
5349
|
commandId,
|
|
@@ -5224,7 +5359,7 @@ export function createRemoteHub(options = {}) {
|
|
|
5224
5359
|
mode: transfer.mode,
|
|
5225
5360
|
synthetic: true
|
|
5226
5361
|
});
|
|
5227
|
-
return { ok: true, commandId, streamId, fps, mode: transfer.mode, frameMode: transfer.frameMode, monitorIndex, synthetic: true };
|
|
5362
|
+
return { ok: true, commandId, streamId, fps, mode: transfer.mode, frameMode: transfer.frameMode, monitorIndex, captureGeneration, synthetic: true };
|
|
5228
5363
|
}
|
|
5229
5364
|
|
|
5230
5365
|
if (!device?.socket || device.socket.destroyed || !device.connected) {
|
|
@@ -5235,11 +5370,35 @@ export function createRemoteHub(options = {}) {
|
|
|
5235
5370
|
}
|
|
5236
5371
|
|
|
5237
5372
|
const now = new Date().toISOString();
|
|
5238
|
-
const normalized = normalizeLiveStreamStartOptions({ ...options, platform: device.platform });
|
|
5239
|
-
const { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose } = normalized;
|
|
5240
|
-
const streamId = safeString(options.streamId, 128) || makeStableLiveStreamId(deviceId, streamPurpose);
|
|
5241
|
-
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
5242
|
-
|
|
5373
|
+
const normalized = normalizeLiveStreamStartOptions({ ...options, platform: device.platform });
|
|
5374
|
+
const { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose } = normalized;
|
|
5375
|
+
const streamId = safeString(options.streamId, 128) || makeStableLiveStreamId(deviceId, streamPurpose);
|
|
5376
|
+
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
5377
|
+
const macTransition = stopCompetingMacCaptureStreams(deviceId, device, streamId, streamPurpose);
|
|
5378
|
+
if (!macTransition.ok) {
|
|
5379
|
+
return macTransition;
|
|
5380
|
+
}
|
|
5381
|
+
if (macTransition.suppressed) {
|
|
5382
|
+
emitRemoteEvent('RemoteLiveStreamStartSuppressed', device, {
|
|
5383
|
+
streamId,
|
|
5384
|
+
streamPurpose,
|
|
5385
|
+
reason: macTransition.reason,
|
|
5386
|
+
ownerStreamId: macTransition.ownerStreamId,
|
|
5387
|
+
ownerCommandId: macTransition.ownerCommandId,
|
|
5388
|
+
captureGeneration: macTransition.captureGeneration
|
|
5389
|
+
});
|
|
5390
|
+
return {
|
|
5391
|
+
ok: true,
|
|
5392
|
+
suppressed: true,
|
|
5393
|
+
streamId,
|
|
5394
|
+
streamPurpose,
|
|
5395
|
+
reason: macTransition.reason,
|
|
5396
|
+
ownerStreamId: macTransition.ownerStreamId,
|
|
5397
|
+
ownerCommandId: macTransition.ownerCommandId,
|
|
5398
|
+
captureGeneration: macTransition.captureGeneration
|
|
5399
|
+
};
|
|
5400
|
+
}
|
|
5401
|
+
if (activeLiveStream?.pendingCommandId) {
|
|
5243
5402
|
if (liveStreamReplacementStillPending(activeLiveStream)) {
|
|
5244
5403
|
emitRemoteEvent('RemoteLiveStreamRestartPending', device, {
|
|
5245
5404
|
streamId,
|
|
@@ -5253,11 +5412,12 @@ export function createRemoteHub(options = {}) {
|
|
|
5253
5412
|
streamId,
|
|
5254
5413
|
fps: Number(activeLiveStream.fps || fps),
|
|
5255
5414
|
mode: activeLiveStream.mode || transfer.mode,
|
|
5256
|
-
frameMode: activeLiveStream.frameMode || transfer.frameMode,
|
|
5257
|
-
monitorIndex: Number(activeLiveStream.monitorIndex || monitorIndex),
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5415
|
+
frameMode: activeLiveStream.frameMode || transfer.frameMode,
|
|
5416
|
+
monitorIndex: Number(activeLiveStream.monitorIndex || monitorIndex),
|
|
5417
|
+
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
5418
|
+
pending: true,
|
|
5419
|
+
reused: true
|
|
5420
|
+
};
|
|
5261
5421
|
}
|
|
5262
5422
|
activeLiveStream.pendingCommandId = '';
|
|
5263
5423
|
activeLiveStream.pendingStartedAt = '';
|
|
@@ -5275,10 +5435,11 @@ export function createRemoteHub(options = {}) {
|
|
|
5275
5435
|
streamId,
|
|
5276
5436
|
fps: Number(activeLiveStream.fps || fps),
|
|
5277
5437
|
mode: activeLiveStream.mode || transfer.mode,
|
|
5278
|
-
frameMode: activeLiveStream.frameMode || transfer.frameMode,
|
|
5279
|
-
monitorIndex: Number(activeLiveStream.monitorIndex || monitorIndex),
|
|
5280
|
-
|
|
5281
|
-
|
|
5438
|
+
frameMode: activeLiveStream.frameMode || transfer.frameMode,
|
|
5439
|
+
monitorIndex: Number(activeLiveStream.monitorIndex || monitorIndex),
|
|
5440
|
+
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
5441
|
+
reused: true
|
|
5442
|
+
};
|
|
5282
5443
|
}
|
|
5283
5444
|
if (activeLiveStream
|
|
5284
5445
|
&& options.forceRestart !== true
|
|
@@ -5299,10 +5460,11 @@ export function createRemoteHub(options = {}) {
|
|
|
5299
5460
|
streamId,
|
|
5300
5461
|
fps,
|
|
5301
5462
|
mode: transfer.mode,
|
|
5302
|
-
frameMode: transfer.frameMode,
|
|
5303
|
-
monitorIndex,
|
|
5304
|
-
|
|
5305
|
-
|
|
5463
|
+
frameMode: transfer.frameMode,
|
|
5464
|
+
monitorIndex,
|
|
5465
|
+
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
5466
|
+
reused: true
|
|
5467
|
+
};
|
|
5306
5468
|
}
|
|
5307
5469
|
if (options.forceRestart === true && activeLiveStream) {
|
|
5308
5470
|
emitRemoteEvent('RemoteLiveStreamForcedRestart', device, {
|
|
@@ -5329,10 +5491,11 @@ export function createRemoteHub(options = {}) {
|
|
|
5329
5491
|
lastFrameAt: activeLiveStream.lastFrameAt || ''
|
|
5330
5492
|
});
|
|
5331
5493
|
}
|
|
5332
|
-
const
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5494
|
+
const captureGeneration = nextCaptureGeneration(device);
|
|
5495
|
+
const result = sendCommand(deviceId, {
|
|
5496
|
+
command: 'stream.start',
|
|
5497
|
+
commandId,
|
|
5498
|
+
payload: {
|
|
5336
5499
|
streamId,
|
|
5337
5500
|
mode: transfer.mode,
|
|
5338
5501
|
frameMode: transfer.frameMode,
|
|
@@ -5347,10 +5510,12 @@ export function createRemoteHub(options = {}) {
|
|
|
5347
5510
|
maxWidth,
|
|
5348
5511
|
maxHeight,
|
|
5349
5512
|
quality,
|
|
5350
|
-
monitorIndex,
|
|
5351
|
-
streamPurpose,
|
|
5352
|
-
|
|
5353
|
-
|
|
5513
|
+
monitorIndex,
|
|
5514
|
+
streamPurpose,
|
|
5515
|
+
captureGeneration,
|
|
5516
|
+
sessionId: device.sessionId,
|
|
5517
|
+
requestedAt: now
|
|
5518
|
+
}
|
|
5354
5519
|
});
|
|
5355
5520
|
|
|
5356
5521
|
if (!result.ok) {
|
|
@@ -5392,9 +5557,10 @@ export function createRemoteHub(options = {}) {
|
|
|
5392
5557
|
stopReason: '',
|
|
5393
5558
|
lastFrameAt: '',
|
|
5394
5559
|
lastFrameSeq: 0,
|
|
5395
|
-
framesReceived: 0,
|
|
5396
|
-
streamPurpose
|
|
5397
|
-
|
|
5560
|
+
framesReceived: 0,
|
|
5561
|
+
streamPurpose,
|
|
5562
|
+
captureGeneration
|
|
5563
|
+
});
|
|
5398
5564
|
device.counters.liveStreamsStarted += 1;
|
|
5399
5565
|
emitRemoteEvent('RemoteLiveStreamStarted', device, {
|
|
5400
5566
|
streamId,
|
|
@@ -5407,7 +5573,7 @@ export function createRemoteHub(options = {}) {
|
|
|
5407
5573
|
monitorIndex
|
|
5408
5574
|
});
|
|
5409
5575
|
|
|
5410
|
-
return { ok: true, commandId, streamId, fps, mode: transfer.mode, frameMode: transfer.frameMode, monitorIndex };
|
|
5576
|
+
return { ok: true, commandId, streamId, fps, mode: transfer.mode, frameMode: transfer.frameMode, monitorIndex, captureGeneration };
|
|
5411
5577
|
}
|
|
5412
5578
|
|
|
5413
5579
|
function stopLiveStream(deviceId, options = {}) {
|
package/hub/src/server.js
CHANGED
|
@@ -1756,10 +1756,13 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
|
|
|
1756
1756
|
kind: frameEvent.kind || 'live',
|
|
1757
1757
|
deviceId: frameEvent.deviceId || frame.deviceId || '',
|
|
1758
1758
|
frameSeq: Number(frame.frameSeq || 0) || 0,
|
|
1759
|
-
streamFrameSeq: Number(frame.streamFrameSeq || 0) || 0,
|
|
1760
|
-
streamId: frame.streamId || '',
|
|
1761
|
-
commandId: frame.commandId || '',
|
|
1762
|
-
|
|
1759
|
+
streamFrameSeq: Number(frame.streamFrameSeq || 0) || 0,
|
|
1760
|
+
streamId: frame.streamId || '',
|
|
1761
|
+
commandId: frame.commandId || '',
|
|
1762
|
+
sessionId: frame.sessionId || '',
|
|
1763
|
+
captureGeneration: Number(frame.captureGeneration || 0) || 0,
|
|
1764
|
+
streamPurpose: frame.streamPurpose || '',
|
|
1765
|
+
width: Number(frame.width || 0) || 0,
|
|
1763
1766
|
height: Number(frame.height || 0) || 0,
|
|
1764
1767
|
sourceWidth: Number(frame.sourceWidth || 0) || 0,
|
|
1765
1768
|
sourceHeight: Number(frame.sourceHeight || 0) || 0,
|
|
@@ -3844,10 +3847,10 @@ inputWss.on('connection', ws => {
|
|
|
3844
3847
|
sendJson(ws, { type: 'RemoteInputError', error: 'invalid-json' });
|
|
3845
3848
|
return;
|
|
3846
3849
|
}
|
|
3847
|
-
const deviceId = String(payload?.deviceId || '').trim();
|
|
3848
|
-
const input = payload?.input && typeof payload.input === 'object'
|
|
3849
|
-
? { ...payload.input, hubReceivedAtEpochMs: Date.now() }
|
|
3850
|
-
: { ...payload, hubReceivedAtEpochMs: Date.now() };
|
|
3850
|
+
const deviceId = String(payload?.deviceId || '').trim();
|
|
3851
|
+
const input = payload?.input && typeof payload.input === 'object'
|
|
3852
|
+
? { ...payload.input, hubConnectionId: ws.liveDeskInputClientId, hubReceivedAtEpochMs: Date.now() }
|
|
3853
|
+
: { ...payload, hubConnectionId: ws.liveDeskInputClientId, hubReceivedAtEpochMs: Date.now() };
|
|
3851
3854
|
const result = remoteHub.sendInputControl(deviceId, input);
|
|
3852
3855
|
const inputType = String(input?.type || '').toLowerCase();
|
|
3853
3856
|
const fireAndForget = payload?.fireAndForget === true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livedesk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.367",
|
|
4
4
|
"buildFlavor": "production",
|
|
5
5
|
"description": "LiveDesk Hub and client launcher",
|
|
6
6
|
"type": "module",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"ws": "^8.18.3"
|
|
49
49
|
},
|
|
50
50
|
"optionalDependencies": {
|
|
51
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
52
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
53
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
54
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
51
|
+
"@livedesk/fast-linux-x64": "0.1.367",
|
|
52
|
+
"@livedesk/fast-osx-arm64": "0.1.367",
|
|
53
|
+
"@livedesk/fast-osx-x64": "0.1.367",
|
|
54
|
+
"@livedesk/fast-win-x64": "0.1.367"
|
|
55
55
|
},
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|