livedesk 0.1.431 → 0.1.432
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/client/package.json +5 -5
- package/client/src/runtime/client-runtime-server.js +32 -2
- package/hub/src/remote-hub.js +100 -24
- package/hub/src/server.js +15 -5
- package/package.json +6 -6
- package/web/dist/assets/index-DNSD69O9.js +25 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-B959xLYx.js +0 -25
package/client/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livedesk/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.190",
|
|
4
4
|
"description": "LiveDesk local remote client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"ws": "^8.18.3"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
45
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
46
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
47
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
44
|
+
"@livedesk/fast-linux-x64": "0.1.397",
|
|
45
|
+
"@livedesk/fast-osx-arm64": "0.1.397",
|
|
46
|
+
"@livedesk/fast-osx-x64": "0.1.397",
|
|
47
|
+
"@livedesk/fast-win-x64": "0.1.397"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -49,7 +49,20 @@ function normalizeAccountAvatarUrl(value) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function readAccessTokenProfile(accessToken) {
|
|
53
|
+
const token = normalizeString(accessToken, 8192);
|
|
54
|
+
const payloadSegment = token.split('.')[1] || '';
|
|
55
|
+
if (!payloadSegment) return {};
|
|
56
|
+
try {
|
|
57
|
+
const payload = JSON.parse(Buffer.from(payloadSegment, 'base64url').toString('utf8'));
|
|
58
|
+
return payload && typeof payload === 'object' ? payload : {};
|
|
59
|
+
} catch {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
function readClientAccountProfile(sessionOrUser) {
|
|
65
|
+
const tokenProfile = readAccessTokenProfile(sessionOrUser?.access_token);
|
|
53
66
|
const user = sessionOrUser?.user && typeof sessionOrUser.user === 'object'
|
|
54
67
|
? sessionOrUser.user
|
|
55
68
|
: sessionOrUser && typeof sessionOrUser === 'object'
|
|
@@ -58,12 +71,19 @@ function readClientAccountProfile(sessionOrUser) {
|
|
|
58
71
|
const metadata = user.user_metadata && typeof user.user_metadata === 'object'
|
|
59
72
|
? user.user_metadata
|
|
60
73
|
: {};
|
|
61
|
-
const
|
|
74
|
+
const tokenMetadata = tokenProfile.user_metadata && typeof tokenProfile.user_metadata === 'object'
|
|
75
|
+
? tokenProfile.user_metadata
|
|
76
|
+
: {};
|
|
77
|
+
const email = normalizeString(user.email || tokenProfile.email, 320);
|
|
62
78
|
const name = normalizeString(
|
|
63
79
|
metadata.full_name
|
|
64
80
|
|| metadata.name
|
|
65
81
|
|| metadata.preferred_username
|
|
82
|
+
|| tokenMetadata.full_name
|
|
83
|
+
|| tokenMetadata.name
|
|
84
|
+
|| tokenMetadata.preferred_username
|
|
66
85
|
|| user.name
|
|
86
|
+
|| tokenProfile.name
|
|
67
87
|
|| email
|
|
68
88
|
|| user.id,
|
|
69
89
|
160
|
|
@@ -71,6 +91,8 @@ function readClientAccountProfile(sessionOrUser) {
|
|
|
71
91
|
const avatarUrl = normalizeAccountAvatarUrl(
|
|
72
92
|
metadata.avatar_url
|
|
73
93
|
|| metadata.picture
|
|
94
|
+
|| tokenMetadata.avatar_url
|
|
95
|
+
|| tokenMetadata.picture
|
|
74
96
|
|| user.avatar_url
|
|
75
97
|
|| user.picture
|
|
76
98
|
);
|
|
@@ -79,7 +101,11 @@ function readClientAccountProfile(sessionOrUser) {
|
|
|
79
101
|
|
|
80
102
|
function mergeClientAccountProfile(session, sourceUser) {
|
|
81
103
|
const profile = readClientAccountProfile(sourceUser);
|
|
104
|
+
const existingUserMetadata = session?.user?.user_metadata && typeof session.user.user_metadata === 'object'
|
|
105
|
+
? session.user.user_metadata
|
|
106
|
+
: {};
|
|
82
107
|
const userMetadata = {
|
|
108
|
+
...existingUserMetadata,
|
|
83
109
|
...(profile.name ? { full_name: profile.name } : {}),
|
|
84
110
|
...(profile.avatarUrl ? { avatar_url: profile.avatarUrl } : {})
|
|
85
111
|
};
|
|
@@ -1275,7 +1301,11 @@ export function createClientRuntimeServer(options = {}) {
|
|
|
1275
1301
|
setImmediate(() => {
|
|
1276
1302
|
void (async () => {
|
|
1277
1303
|
try {
|
|
1278
|
-
|
|
1304
|
+
// Older persisted sessions kept only id/email on `user`, while
|
|
1305
|
+
// Supabase still carries Google name/avatar claims in the
|
|
1306
|
+
// access-token payload. Recover those display-only claims
|
|
1307
|
+
// locally before any best-effort network hydration.
|
|
1308
|
+
const normalizedSession = mergeClientAccountProfile(saved.session, savedSession);
|
|
1279
1309
|
const hydratedSession = await hydrateClientAccountProfile(normalizedSession);
|
|
1280
1310
|
if (!writeSavedSession(hydratedSession)) throw new Error('refresh-token-required');
|
|
1281
1311
|
state.auth.persisted = true;
|
package/hub/src/remote-hub.js
CHANGED
|
@@ -685,7 +685,9 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
685
685
|
const captureGeneration = Number(input.captureGeneration ?? input.CaptureGeneration);
|
|
686
686
|
return {
|
|
687
687
|
type,
|
|
688
|
-
|
|
688
|
+
// A missing monitor is not equivalent to the primary display. Control
|
|
689
|
+
// input must prove the exact monitor owned by its capture generation.
|
|
690
|
+
monitorIndex: Number.isFinite(monitorIndex) ? normalizeMonitorIndex(monitorIndex) : null,
|
|
689
691
|
normalizedX: Number.isFinite(normalizedX) ? Math.max(0, Math.min(1, normalizedX)) : undefined,
|
|
690
692
|
normalizedY: Number.isFinite(normalizedY) ? Math.max(0, Math.min(1, normalizedY)) : undefined,
|
|
691
693
|
button: safeString(input.button || input.Button, 24),
|
|
@@ -2144,9 +2146,12 @@ export function createRemoteHub(options = {}) {
|
|
|
2144
2146
|
byteLength: frame.byteLength
|
|
2145
2147
|
});
|
|
2146
2148
|
streamState.latestFrame = frame;
|
|
2147
|
-
streamState.lastFrameAt = frame.receivedAt;
|
|
2148
|
-
streamState.lastFrameSeq = frame.frameSeq;
|
|
2149
|
-
streamState.framesReceived = (streamState.framesReceived || 0) + 1;
|
|
2149
|
+
streamState.lastFrameAt = frame.receivedAt;
|
|
2150
|
+
streamState.lastFrameSeq = frame.frameSeq;
|
|
2151
|
+
streamState.framesReceived = (streamState.framesReceived || 0) + 1;
|
|
2152
|
+
// A synthetic PNG is a complete independently decodable surface and
|
|
2153
|
+
// therefore key-frame equivalent for Control readiness.
|
|
2154
|
+
streamState.readyFrameReceived = true;
|
|
2150
2155
|
device.lastSeenAt = frame.receivedAt;
|
|
2151
2156
|
device.counters.liveFramesReceived += 1;
|
|
2152
2157
|
emitRemoteEvent('RemoteFrameReceived', device, {
|
|
@@ -3337,6 +3342,13 @@ export function createRemoteHub(options = {}) {
|
|
|
3337
3342
|
|| result.InputType
|
|
3338
3343
|
|| pending?.inputType,
|
|
3339
3344
|
48),
|
|
3345
|
+
monitorIndex: Number(
|
|
3346
|
+
message.monitorIndex
|
|
3347
|
+
?? message.MonitorIndex
|
|
3348
|
+
?? result.monitorIndex
|
|
3349
|
+
?? result.MonitorIndex
|
|
3350
|
+
?? pending?.monitorIndex
|
|
3351
|
+
?? 0) || 0,
|
|
3340
3352
|
issuedAtEpochMs: Number(
|
|
3341
3353
|
message.issuedAtEpochMs
|
|
3342
3354
|
?? message.IssuedAtEpochMs
|
|
@@ -3602,13 +3614,35 @@ export function createRemoteHub(options = {}) {
|
|
|
3602
3614
|
: 0;
|
|
3603
3615
|
}
|
|
3604
3616
|
|
|
3605
|
-
function readFrameStageMs(message, property) {
|
|
3606
|
-
const value = Number(message?.[property]);
|
|
3607
|
-
return Number.isFinite(value) && value >= 0
|
|
3608
|
-
? Math.round(value)
|
|
3609
|
-
: 0;
|
|
3610
|
-
}
|
|
3611
|
-
|
|
3617
|
+
function readFrameStageMs(message, property) {
|
|
3618
|
+
const value = Number(message?.[property]);
|
|
3619
|
+
return Number.isFinite(value) && value >= 0
|
|
3620
|
+
? Math.round(value)
|
|
3621
|
+
: 0;
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3624
|
+
function readOptionalFrameStageMs(message, property) {
|
|
3625
|
+
const rawValue = message?.[property];
|
|
3626
|
+
if (rawValue === undefined || rawValue === null || rawValue === '') {
|
|
3627
|
+
return undefined;
|
|
3628
|
+
}
|
|
3629
|
+
const value = Number(rawValue);
|
|
3630
|
+
return Number.isFinite(value) && value >= 0
|
|
3631
|
+
? Math.round(value)
|
|
3632
|
+
: undefined;
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
function hasFrameCaptureTiming(message) {
|
|
3636
|
+
if (message?.captureTimingAvailable === false) {
|
|
3637
|
+
return false;
|
|
3638
|
+
}
|
|
3639
|
+
if (message?.captureTimingAvailable === true) {
|
|
3640
|
+
return true;
|
|
3641
|
+
}
|
|
3642
|
+
return ['captureP95Ms', 'captureAverageMs', 'captureStageMs']
|
|
3643
|
+
.some(property => readOptionalFrameStageMs(message, property) !== undefined);
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3612
3646
|
function computeSameContentStreak(previousFrame, contentHash) {
|
|
3613
3647
|
if (!contentHash || !previousFrame?.contentHash || previousFrame.contentHash !== contentHash) {
|
|
3614
3648
|
return 0;
|
|
@@ -3682,7 +3716,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3682
3716
|
byteLength,
|
|
3683
3717
|
transport,
|
|
3684
3718
|
contentHash,
|
|
3685
|
-
captureMs: readFrameCaptureMs(message),
|
|
3719
|
+
captureMs: readFrameCaptureMs(message),
|
|
3686
3720
|
captureStageMs: readFrameStageMs(message, 'captureStageMs'),
|
|
3687
3721
|
convertMs: readFrameStageMs(message, 'convertMs'),
|
|
3688
3722
|
compressMs: readFrameStageMs(message, 'compressMs'),
|
|
@@ -3774,6 +3808,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3774
3808
|
lastFrameAt: '',
|
|
3775
3809
|
lastFrameSeq: 0,
|
|
3776
3810
|
framesReceived: 0,
|
|
3811
|
+
readyFrameReceived: false,
|
|
3777
3812
|
latestFrame: null,
|
|
3778
3813
|
stoppedAt: '',
|
|
3779
3814
|
stopReason: ''
|
|
@@ -3991,6 +4026,8 @@ export function createRemoteHub(options = {}) {
|
|
|
3991
4026
|
&& (activeCaptureGeneration <= 0
|
|
3992
4027
|
|| (frameCaptureGeneration > 0
|
|
3993
4028
|
&& frameCaptureGeneration === activeCaptureGeneration));
|
|
4029
|
+
const readyFrameReceivedBeforeFrame = streamState.readyFrameReceived === true;
|
|
4030
|
+
const captureTimingAvailable = hasFrameCaptureTiming(message);
|
|
3994
4031
|
device.latestLiveFrame = {
|
|
3995
4032
|
streamId,
|
|
3996
4033
|
frameSeq,
|
|
@@ -4037,10 +4074,11 @@ export function createRemoteHub(options = {}) {
|
|
|
4037
4074
|
transferProtocolVersion: transfer.transferProtocolVersion,
|
|
4038
4075
|
handshake: transfer.handshake,
|
|
4039
4076
|
fps: Number.isFinite(Number(message.fps)) ? Number(message.fps) : streamState.fps,
|
|
4040
|
-
requestedFps: Number.isFinite(Number(message.requestedFps)) ? Number(message.requestedFps) : Number(streamState.fps || 0),
|
|
4041
|
-
effectiveFps: Number.isFinite(Number(message.effectiveFps)) ? Number(message.effectiveFps) : Number(message.fps || streamState.fps || 0),
|
|
4042
|
-
|
|
4043
|
-
|
|
4077
|
+
requestedFps: Number.isFinite(Number(message.requestedFps)) ? Number(message.requestedFps) : Number(streamState.fps || 0),
|
|
4078
|
+
effectiveFps: Number.isFinite(Number(message.effectiveFps)) ? Number(message.effectiveFps) : Number(message.fps || streamState.fps || 0),
|
|
4079
|
+
captureTimingAvailable,
|
|
4080
|
+
captureAverageMs: captureTimingAvailable ? readOptionalFrameStageMs(message, 'captureAverageMs') : undefined,
|
|
4081
|
+
captureP95Ms: captureTimingAvailable ? readOptionalFrameStageMs(message, 'captureP95Ms') : undefined,
|
|
4044
4082
|
slowFrameCount: Number.isFinite(Number(message.slowFrameCount)) ? Number(message.slowFrameCount) : 0,
|
|
4045
4083
|
captureHelperRestarts: Number.isFinite(Number(message.captureHelperRestarts)) ? Number(message.captureHelperRestarts) : 0,
|
|
4046
4084
|
capturedAt,
|
|
@@ -4048,8 +4086,8 @@ export function createRemoteHub(options = {}) {
|
|
|
4048
4086
|
byteLength,
|
|
4049
4087
|
transport,
|
|
4050
4088
|
contentHash,
|
|
4051
|
-
captureMs:
|
|
4052
|
-
captureStageMs:
|
|
4089
|
+
captureMs: captureTimingAvailable ? readOptionalFrameStageMs(message, 'captureMs') : undefined,
|
|
4090
|
+
captureStageMs: captureTimingAvailable ? readOptionalFrameStageMs(message, 'captureStageMs') : undefined,
|
|
4053
4091
|
convertMs: readFrameStageMs(message, 'convertMs'),
|
|
4054
4092
|
compressMs: readFrameStageMs(message, 'compressMs'),
|
|
4055
4093
|
captureSourceSerial: Number.isFinite(Number(message.captureSourceSerial)) ? Number(message.captureSourceSerial) : 0,
|
|
@@ -4073,9 +4111,12 @@ export function createRemoteHub(options = {}) {
|
|
|
4073
4111
|
mimeType: device.latestLiveFrame.mimeType,
|
|
4074
4112
|
byteLength: device.latestLiveFrame.byteLength
|
|
4075
4113
|
});
|
|
4076
|
-
streamState.lastFrameAt = device.lastSeenAt;
|
|
4077
|
-
streamState.lastFrameSeq = frameSeq;
|
|
4078
|
-
streamState.framesReceived = (streamState.framesReceived || 0) + 1;
|
|
4114
|
+
streamState.lastFrameAt = device.lastSeenAt;
|
|
4115
|
+
streamState.lastFrameSeq = frameSeq;
|
|
4116
|
+
streamState.framesReceived = (streamState.framesReceived || 0) + 1;
|
|
4117
|
+
streamState.readyFrameReceived = readyFrameReceivedBeforeFrame
|
|
4118
|
+
|| (currentGenerationVerified
|
|
4119
|
+
&& liveFrameSatisfiesReadiness(streamState, device.latestLiveFrame));
|
|
4079
4120
|
streamState.mode = transfer.mode;
|
|
4080
4121
|
streamState.frameMode = transfer.frameMode;
|
|
4081
4122
|
streamState.frameProfile = transfer.frameProfile;
|
|
@@ -4093,7 +4134,9 @@ export function createRemoteHub(options = {}) {
|
|
|
4093
4134
|
streamState.monitorCount = device.latestLiveFrame.monitorCount;
|
|
4094
4135
|
ensureDeviceLiveStreams(device).set(streamId, streamState);
|
|
4095
4136
|
device.counters.liveFramesReceived += 1;
|
|
4096
|
-
if (
|
|
4137
|
+
if (!readyFrameReceivedBeforeFrame
|
|
4138
|
+
&& streamState.readyFrameReceived === true
|
|
4139
|
+
&& liveStreamHasCurrentFrame(streamState)) {
|
|
4097
4140
|
emitRemoteEvent('RemoteLiveStreamReady', device, {
|
|
4098
4141
|
streamId,
|
|
4099
4142
|
commandId: streamState.commandId,
|
|
@@ -5292,6 +5335,15 @@ export function createRemoteHub(options = {}) {
|
|
|
5292
5335
|
activeCaptureGeneration: Number(controlStream.captureGeneration || 0)
|
|
5293
5336
|
};
|
|
5294
5337
|
}
|
|
5338
|
+
const activeMonitorIndex = normalizeMonitorIndex(controlStream.monitorIndex);
|
|
5339
|
+
if (!Number.isInteger(normalized.monitorIndex)
|
|
5340
|
+
|| normalized.monitorIndex !== activeMonitorIndex) {
|
|
5341
|
+
return {
|
|
5342
|
+
ok: false,
|
|
5343
|
+
error: 'STALE_CONTROL_MONITOR',
|
|
5344
|
+
activeMonitorIndex
|
|
5345
|
+
};
|
|
5346
|
+
}
|
|
5295
5347
|
|
|
5296
5348
|
const inputSocket = device.inputSocket;
|
|
5297
5349
|
if (inputSocket && !inputSocket.destroyed) {
|
|
@@ -5311,7 +5363,8 @@ export function createRemoteHub(options = {}) {
|
|
|
5311
5363
|
inputSocket: true,
|
|
5312
5364
|
sessionId: device.sessionId,
|
|
5313
5365
|
commandId: controlStream.commandId,
|
|
5314
|
-
captureGeneration: controlStream.captureGeneration
|
|
5366
|
+
captureGeneration: controlStream.captureGeneration,
|
|
5367
|
+
monitorIndex: activeMonitorIndex
|
|
5315
5368
|
};
|
|
5316
5369
|
}
|
|
5317
5370
|
|
|
@@ -5332,6 +5385,7 @@ export function createRemoteHub(options = {}) {
|
|
|
5332
5385
|
commandId: fallback.commandId,
|
|
5333
5386
|
inputSeq: normalized.inputSeq,
|
|
5334
5387
|
inputType: normalized.type,
|
|
5388
|
+
monitorIndex: normalized.monitorIndex,
|
|
5335
5389
|
issuedAtEpochMs: normalized.issuedAtEpochMs,
|
|
5336
5390
|
hubReceivedAtEpochMs: normalized.hubReceivedAtEpochMs,
|
|
5337
5391
|
hubForwardedAtEpochMs,
|
|
@@ -5348,6 +5402,7 @@ export function createRemoteHub(options = {}) {
|
|
|
5348
5402
|
deliveryCommandId: fallback.commandId,
|
|
5349
5403
|
commandId: controlStream.commandId,
|
|
5350
5404
|
captureGeneration: controlStream.captureGeneration,
|
|
5405
|
+
monitorIndex: activeMonitorIndex,
|
|
5351
5406
|
inputSeq: normalized.inputSeq
|
|
5352
5407
|
}
|
|
5353
5408
|
: {
|
|
@@ -5855,12 +5910,31 @@ export function createRemoteHub(options = {}) {
|
|
|
5855
5910
|
return Number.isFinite(startedAt) && Date.now() - startedAt < LIVE_STREAM_REPLACEMENT_PENDING_MS;
|
|
5856
5911
|
}
|
|
5857
5912
|
|
|
5913
|
+
function liveStreamRequiresReadyKeyFrame(activeLiveStream) {
|
|
5914
|
+
if (safeString(activeLiveStream?.streamPurpose, 24).toLowerCase() !== 'control') {
|
|
5915
|
+
return false;
|
|
5916
|
+
}
|
|
5917
|
+
const codec = safeString(activeLiveStream?.codec, 80).toLowerCase();
|
|
5918
|
+
const mode = safeString(activeLiveStream?.frameMode || activeLiveStream?.mode, 80).toLowerCase();
|
|
5919
|
+
return codec.includes('h264') || mode === 'mode3-h264-hw';
|
|
5920
|
+
}
|
|
5921
|
+
|
|
5922
|
+
function liveFrameSatisfiesReadiness(activeLiveStream, frame) {
|
|
5923
|
+
return !liveStreamRequiresReadyKeyFrame(activeLiveStream)
|
|
5924
|
+
|| frame?.isKeyFrame === true
|
|
5925
|
+
|| safeString(frame?.chunkType, 20).toLowerCase() === 'key';
|
|
5926
|
+
}
|
|
5927
|
+
|
|
5858
5928
|
function liveStreamHasCurrentFrame(activeLiveStream) {
|
|
5859
5929
|
if (!activeLiveStream?.active
|
|
5860
5930
|
|| activeLiveStream.open !== true
|
|
5861
5931
|
|| Number(activeLiveStream.framesReceived || 0) < 1) {
|
|
5862
5932
|
return false;
|
|
5863
5933
|
}
|
|
5934
|
+
if (liveStreamRequiresReadyKeyFrame(activeLiveStream)
|
|
5935
|
+
&& activeLiveStream.readyFrameReceived !== true) {
|
|
5936
|
+
return false;
|
|
5937
|
+
}
|
|
5864
5938
|
const latestFrame = activeLiveStream.latestFrame;
|
|
5865
5939
|
if (!latestFrame || latestFrame.currentGenerationVerified !== true) {
|
|
5866
5940
|
return false;
|
|
@@ -5984,6 +6058,7 @@ export function createRemoteHub(options = {}) {
|
|
|
5984
6058
|
lastFrameAt: '',
|
|
5985
6059
|
lastFrameSeq: 0,
|
|
5986
6060
|
framesReceived: 0,
|
|
6061
|
+
readyFrameReceived: false,
|
|
5987
6062
|
streamPurpose,
|
|
5988
6063
|
captureGeneration
|
|
5989
6064
|
});
|
|
@@ -6201,8 +6276,9 @@ export function createRemoteHub(options = {}) {
|
|
|
6201
6276
|
stoppedAt: '',
|
|
6202
6277
|
stopReason: '',
|
|
6203
6278
|
lastFrameAt: '',
|
|
6204
|
-
lastFrameSeq: 0,
|
|
6279
|
+
lastFrameSeq: 0,
|
|
6205
6280
|
framesReceived: 0,
|
|
6281
|
+
readyFrameReceived: false,
|
|
6206
6282
|
streamPurpose,
|
|
6207
6283
|
captureGeneration,
|
|
6208
6284
|
latestFrame: null,
|
package/hub/src/server.js
CHANGED
|
@@ -2045,8 +2045,13 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
|
|
|
2045
2045
|
fps: Number(frame.fps || 0) || 0,
|
|
2046
2046
|
requestedFps: Number(frame.requestedFps || 0) || 0,
|
|
2047
2047
|
effectiveFps: Number(frame.effectiveFps || 0) || 0,
|
|
2048
|
-
|
|
2049
|
-
|
|
2048
|
+
captureTimingAvailable: frame.captureTimingAvailable === true,
|
|
2049
|
+
captureAverageMs: frame.captureTimingAvailable === true && Number.isFinite(Number(frame.captureAverageMs))
|
|
2050
|
+
? Number(frame.captureAverageMs)
|
|
2051
|
+
: null,
|
|
2052
|
+
captureP95Ms: frame.captureTimingAvailable === true && Number.isFinite(Number(frame.captureP95Ms))
|
|
2053
|
+
? Number(frame.captureP95Ms)
|
|
2054
|
+
: null,
|
|
2050
2055
|
slowFrameCount: Number(frame.slowFrameCount || 0) || 0,
|
|
2051
2056
|
captureHelperRestarts: Number(frame.captureHelperRestarts || 0) || 0,
|
|
2052
2057
|
capturedAt: frame.capturedAt || '',
|
|
@@ -2055,8 +2060,12 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
|
|
|
2055
2060
|
hubPacketEpochMs,
|
|
2056
2061
|
byteLength: Number(frameEvent.byteLength || payload.length) || payload.length,
|
|
2057
2062
|
contentHash: frame.contentHash || '',
|
|
2058
|
-
captureMs: Number(frame.captureMs
|
|
2059
|
-
|
|
2063
|
+
captureMs: frame.captureTimingAvailable === true && Number.isFinite(Number(frame.captureMs))
|
|
2064
|
+
? Number(frame.captureMs)
|
|
2065
|
+
: null,
|
|
2066
|
+
captureStageMs: frame.captureTimingAvailable === true && Number.isFinite(Number(frame.captureStageMs))
|
|
2067
|
+
? Number(frame.captureStageMs)
|
|
2068
|
+
: null,
|
|
2060
2069
|
convertMs: Number(frame.convertMs || 0) || 0,
|
|
2061
2070
|
compressMs: Number(frame.compressMs || 0) || 0,
|
|
2062
2071
|
captureSourceSerial: Number(frame.captureSourceSerial || 0) || 0,
|
|
@@ -2157,7 +2166,8 @@ function broadcastRemoteBinaryFrame(frameEvent) {
|
|
|
2157
2166
|
|| Number(frame.monitorIndex || 0) !== expectedBinding.monitorIndex) {
|
|
2158
2167
|
continue;
|
|
2159
2168
|
}
|
|
2160
|
-
|
|
2169
|
+
const requiresReadyKeyFrame = String(expectedBinding.streamPurpose || '').toLowerCase() === 'control' && isH264;
|
|
2170
|
+
if (!expectedBinding.readySent && (!requiresReadyKeyFrame || isKeyFrame)) {
|
|
2161
2171
|
expectedBinding.readySent = sendJson(client, {
|
|
2162
2172
|
type: 'RemoteFrameStreamReady',
|
|
2163
2173
|
deviceId,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livedesk",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"livedeskClientVersion": "0.1.
|
|
3
|
+
"version": "0.1.432",
|
|
4
|
+
"livedeskClientVersion": "0.1.190",
|
|
5
5
|
"buildFlavor": "production",
|
|
6
6
|
"description": "LiveDesk Hub and client launcher",
|
|
7
7
|
"type": "module",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"ws": "^8.18.3"
|
|
51
51
|
},
|
|
52
52
|
"optionalDependencies": {
|
|
53
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
54
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
55
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
56
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
53
|
+
"@livedesk/fast-linux-x64": "0.1.397",
|
|
54
|
+
"@livedesk/fast-osx-arm64": "0.1.397",
|
|
55
|
+
"@livedesk/fast-osx-x64": "0.1.397",
|
|
56
|
+
"@livedesk/fast-win-x64": "0.1.397"
|
|
57
57
|
},
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|