livedesk 0.1.567 → 0.1.568
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 +86 -15
- package/hub/src/server.js +57 -14
- package/package.json +1 -1
- package/web/dist/livedesk-build-evidence.json +6 -6
- package/web/dist/sw.js +1 -1
package/hub/src/remote-hub.js
CHANGED
|
@@ -9533,7 +9533,7 @@ export function createRemoteHub(options = {}) {
|
|
|
9533
9533
|
return getLiveStreamIdleMs(activeLiveStream) <= getLiveStreamFreshWindowMs(activeLiveStream);
|
|
9534
9534
|
}
|
|
9535
9535
|
|
|
9536
|
-
function liveStreamMatchesOptions(activeLiveStream, normalized) {
|
|
9536
|
+
function liveStreamMatchesOptions(activeLiveStream, normalized) {
|
|
9537
9537
|
if (!activeLiveStream?.active) {
|
|
9538
9538
|
return false;
|
|
9539
9539
|
}
|
|
@@ -9544,8 +9544,49 @@ export function createRemoteHub(options = {}) {
|
|
|
9544
9544
|
&& Number(activeLiveStream.quality || 0) === normalized.quality
|
|
9545
9545
|
&& Number(activeLiveStream.monitorIndex || 0) === normalized.monitorIndex
|
|
9546
9546
|
&& (safeString(activeLiveStream.streamPurpose, 24).toLowerCase() || 'wall')
|
|
9547
|
-
=== normalized.streamPurpose;
|
|
9548
|
-
}
|
|
9547
|
+
=== normalized.streamPurpose;
|
|
9548
|
+
}
|
|
9549
|
+
|
|
9550
|
+
function liveStreamMatchesOwnerIdentity(activeLiveStream, normalized) {
|
|
9551
|
+
if (!activeLiveStream) {
|
|
9552
|
+
return false;
|
|
9553
|
+
}
|
|
9554
|
+
return activeLiveStream.frameMode === normalized.transfer.frameMode
|
|
9555
|
+
&& Number(activeLiveStream.monitorIndex || 0) === normalized.monitorIndex
|
|
9556
|
+
&& (safeString(activeLiveStream.streamPurpose, 24).toLowerCase() || 'wall')
|
|
9557
|
+
=== normalized.streamPurpose;
|
|
9558
|
+
}
|
|
9559
|
+
|
|
9560
|
+
function sharedLiveProfileResult(device, activeLiveStream, normalized, extra = {}) {
|
|
9561
|
+
return {
|
|
9562
|
+
ok: true,
|
|
9563
|
+
commandId: activeLiveStream.commandId,
|
|
9564
|
+
sessionId: device.sessionId,
|
|
9565
|
+
streamId: activeLiveStream.streamId,
|
|
9566
|
+
streamPurpose: safeString(activeLiveStream.streamPurpose, 24) || normalized.streamPurpose,
|
|
9567
|
+
fps: Number(activeLiveStream.fps || normalized.fps),
|
|
9568
|
+
mode: activeLiveStream.mode || normalized.transfer.mode,
|
|
9569
|
+
frameMode: activeLiveStream.frameMode || normalized.transfer.frameMode,
|
|
9570
|
+
monitorIndex: Number(activeLiveStream.monitorIndex ?? normalized.monitorIndex),
|
|
9571
|
+
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
9572
|
+
ready: liveStreamHasCurrentFrame(activeLiveStream),
|
|
9573
|
+
reused: true,
|
|
9574
|
+
sharedProfileReused: true,
|
|
9575
|
+
requestedProfile: {
|
|
9576
|
+
fps: normalized.fps,
|
|
9577
|
+
maxWidth: normalized.maxWidth,
|
|
9578
|
+
maxHeight: normalized.maxHeight,
|
|
9579
|
+
quality: normalized.quality
|
|
9580
|
+
},
|
|
9581
|
+
effectiveProfile: {
|
|
9582
|
+
fps: Number(activeLiveStream.fps || normalized.fps),
|
|
9583
|
+
maxWidth: Number(activeLiveStream.maxWidth || normalized.maxWidth),
|
|
9584
|
+
maxHeight: Number(activeLiveStream.maxHeight || normalized.maxHeight),
|
|
9585
|
+
quality: Number(activeLiveStream.quality || normalized.quality)
|
|
9586
|
+
},
|
|
9587
|
+
...extra
|
|
9588
|
+
};
|
|
9589
|
+
}
|
|
9549
9590
|
|
|
9550
9591
|
function startLiveStream(deviceId, options = {}) {
|
|
9551
9592
|
const device = devices.get(String(deviceId || ''));
|
|
@@ -9701,17 +9742,28 @@ export function createRemoteHub(options = {}) {
|
|
|
9701
9742
|
const captureClaim = claimSingleLiveCapture(deviceId, device, streamId, streamPurpose);
|
|
9702
9743
|
if (!captureClaim.ok) return captureClaim;
|
|
9703
9744
|
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
9704
|
-
const pendingDescriptor = getPendingLiveStreamDescriptor(activeLiveStream);
|
|
9705
|
-
if (pendingDescriptor?.commandId) {
|
|
9706
|
-
const pendingMatchesRequest = liveStreamMatchesOptions(pendingDescriptor, normalized);
|
|
9707
|
-
|
|
9708
|
-
|
|
9745
|
+
const pendingDescriptor = getPendingLiveStreamDescriptor(activeLiveStream);
|
|
9746
|
+
if (pendingDescriptor?.commandId) {
|
|
9747
|
+
const pendingMatchesRequest = liveStreamMatchesOptions(pendingDescriptor, normalized);
|
|
9748
|
+
const pendingMatchesSharedOwner = options.forceRestart !== true
|
|
9749
|
+
&& options.reuseExisting === true
|
|
9750
|
+
&& options.reuseSharedExisting === true
|
|
9751
|
+
&& liveStreamMatchesOwnerIdentity(pendingDescriptor, normalized);
|
|
9752
|
+
if ((pendingMatchesRequest || pendingMatchesSharedOwner)
|
|
9753
|
+
&& liveStreamReplacementStillPending(activeLiveStream)) {
|
|
9754
|
+
emitRemoteEvent('RemoteLiveStreamRestartPending', device, {
|
|
9709
9755
|
streamId,
|
|
9710
9756
|
commandId: pendingDescriptor.commandId,
|
|
9711
9757
|
activeCommandId: activeLiveStream.commandId,
|
|
9712
9758
|
reason: safeString(options.restartReason || 'duplicate-restart', 128)
|
|
9713
9759
|
});
|
|
9714
|
-
|
|
9760
|
+
if (pendingMatchesSharedOwner && !pendingMatchesRequest) {
|
|
9761
|
+
return sharedLiveProfileResult(device, pendingDescriptor, normalized, {
|
|
9762
|
+
ready: false,
|
|
9763
|
+
pending: true
|
|
9764
|
+
});
|
|
9765
|
+
}
|
|
9766
|
+
return {
|
|
9715
9767
|
ok: true,
|
|
9716
9768
|
commandId: pendingDescriptor.commandId,
|
|
9717
9769
|
sessionId: device.sessionId,
|
|
@@ -9764,9 +9816,9 @@ export function createRemoteHub(options = {}) {
|
|
|
9764
9816
|
reused: true
|
|
9765
9817
|
};
|
|
9766
9818
|
}
|
|
9767
|
-
if (activeLiveStream
|
|
9768
|
-
&& options.forceRestart !== true
|
|
9769
|
-
&& options.reuseExisting === true
|
|
9819
|
+
if (activeLiveStream
|
|
9820
|
+
&& options.forceRestart !== true
|
|
9821
|
+
&& options.reuseExisting === true
|
|
9770
9822
|
&& liveStreamMatchesOptions(activeLiveStream, normalized)
|
|
9771
9823
|
&& liveStreamIsReusable(activeLiveStream)) {
|
|
9772
9824
|
return {
|
|
@@ -9781,9 +9833,28 @@ export function createRemoteHub(options = {}) {
|
|
|
9781
9833
|
monitorIndex: Number(activeLiveStream.monitorIndex || monitorIndex),
|
|
9782
9834
|
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
9783
9835
|
ready: liveStreamHasCurrentFrame(activeLiveStream),
|
|
9784
|
-
reused: true
|
|
9785
|
-
};
|
|
9786
|
-
}
|
|
9836
|
+
reused: true
|
|
9837
|
+
};
|
|
9838
|
+
}
|
|
9839
|
+
if (activeLiveStream
|
|
9840
|
+
&& options.forceRestart !== true
|
|
9841
|
+
&& options.reuseExisting === true
|
|
9842
|
+
&& options.reuseSharedExisting === true
|
|
9843
|
+
&& liveStreamMatchesOwnerIdentity(activeLiveStream, normalized)
|
|
9844
|
+
&& liveStreamIsReusable(activeLiveStream)) {
|
|
9845
|
+
emitRemoteEvent('RemoteLiveStreamSharedProfileReused', device, {
|
|
9846
|
+
streamId,
|
|
9847
|
+
commandId: activeLiveStream.commandId,
|
|
9848
|
+
captureGeneration: Number(activeLiveStream.captureGeneration || 0),
|
|
9849
|
+
requestedFps: normalized.fps,
|
|
9850
|
+
effectiveFps: Number(activeLiveStream.fps || normalized.fps),
|
|
9851
|
+
requestedMaxWidth: normalized.maxWidth,
|
|
9852
|
+
requestedMaxHeight: normalized.maxHeight,
|
|
9853
|
+
effectiveMaxWidth: Number(activeLiveStream.maxWidth || normalized.maxWidth),
|
|
9854
|
+
effectiveMaxHeight: Number(activeLiveStream.maxHeight || normalized.maxHeight)
|
|
9855
|
+
});
|
|
9856
|
+
return sharedLiveProfileResult(device, activeLiveStream, normalized);
|
|
9857
|
+
}
|
|
9787
9858
|
if (activeLiveStream
|
|
9788
9859
|
&& options.forceRestart !== true
|
|
9789
9860
|
&& liveStreamMatchesOptions(activeLiveStream, normalized)
|
package/hub/src/server.js
CHANGED
|
@@ -1821,7 +1821,7 @@ function unregisterFrameClient(ws) {
|
|
|
1821
1821
|
retireFrameClientSendLane(ws);
|
|
1822
1822
|
}
|
|
1823
1823
|
|
|
1824
|
-
function hasOtherFrameStreamOwner(ws, deviceId, streamId, streamPurpose = '') {
|
|
1824
|
+
function hasOtherFrameStreamOwner(ws, deviceId, streamId, streamPurpose = '') {
|
|
1825
1825
|
if (!streamId) {
|
|
1826
1826
|
return false;
|
|
1827
1827
|
}
|
|
@@ -1844,7 +1844,27 @@ function hasOtherFrameStreamOwner(ws, deviceId, streamId, streamPurpose = '') {
|
|
|
1844
1844
|
}
|
|
1845
1845
|
}
|
|
1846
1846
|
return false;
|
|
1847
|
-
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
function hasOtherFrameStreamDemand(ws, deviceId, streamPurpose = '') {
|
|
1850
|
+
const normalizedPurpose = String(streamPurpose || '').trim().toLowerCase();
|
|
1851
|
+
if (!deviceId || !normalizedPurpose) {
|
|
1852
|
+
return false;
|
|
1853
|
+
}
|
|
1854
|
+
for (const candidate of frameClients) {
|
|
1855
|
+
if (candidate === ws || candidate.readyState !== candidate.OPEN) {
|
|
1856
|
+
continue;
|
|
1857
|
+
}
|
|
1858
|
+
if (candidate.liveDeskAutoStart === true
|
|
1859
|
+
&& candidate.liveDeskDeviceIds instanceof Set
|
|
1860
|
+
&& candidate.liveDeskDeviceIds.has(deviceId)
|
|
1861
|
+
&& String(candidate.liveDeskLiveOptions?.streamPurpose || '').trim().toLowerCase()
|
|
1862
|
+
=== normalizedPurpose) {
|
|
1863
|
+
return true;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
return false;
|
|
1867
|
+
}
|
|
1848
1868
|
|
|
1849
1869
|
function frameStreamStopKey(deviceId, streamId, streamPurpose) {
|
|
1850
1870
|
return `${deviceId}\u0000${streamId}\u0000${streamPurpose}`;
|
|
@@ -2138,15 +2158,24 @@ function snapshotFrameLaneResourceHealth() {
|
|
|
2138
2158
|
const bindings = ws.liveDeskExpectedStreamBindingsByDeviceId instanceof Map
|
|
2139
2159
|
? [...ws.liveDeskExpectedStreamBindingsByDeviceId.values()]
|
|
2140
2160
|
: [];
|
|
2141
|
-
return {
|
|
2161
|
+
return {
|
|
2142
2162
|
deviceIds: bindings
|
|
2143
2163
|
.map(binding => String(binding?.deviceId || '').trim())
|
|
2144
2164
|
.filter(Boolean)
|
|
2145
2165
|
.slice(0, 16),
|
|
2146
|
-
streamPurposes: [...new Set(bindings
|
|
2166
|
+
streamPurposes: [...new Set(bindings
|
|
2147
2167
|
.map(binding => String(binding?.streamPurpose || '').trim().toLowerCase())
|
|
2148
|
-
.filter(Boolean))]
|
|
2149
|
-
.slice(0, 4),
|
|
2168
|
+
.filter(Boolean))]
|
|
2169
|
+
.slice(0, 4),
|
|
2170
|
+
requestedProfile: ws.liveDeskLiveOptions ? {
|
|
2171
|
+
frameMode: String(ws.liveDeskLiveOptions.frameMode || ws.liveDeskLiveOptions.mode || ''),
|
|
2172
|
+
streamPurpose: String(ws.liveDeskLiveOptions.streamPurpose || ''),
|
|
2173
|
+
fps: Math.max(0, Number(ws.liveDeskLiveOptions.fps || 0)),
|
|
2174
|
+
maxWidth: Math.max(0, Number(ws.liveDeskLiveOptions.maxWidth || 0)),
|
|
2175
|
+
maxHeight: Math.max(0, Number(ws.liveDeskLiveOptions.maxHeight || 0)),
|
|
2176
|
+
quality: Math.max(0, Number(ws.liveDeskLiveOptions.quality || 0))
|
|
2177
|
+
} : null,
|
|
2178
|
+
sharedProfileReuseCount: Math.max(0, Number(ws.liveDeskSharedProfileReuseCount || 0)),
|
|
2150
2179
|
queueDepth: Math.max(0, Number(lane?.queue?.length || 0)),
|
|
2151
2180
|
queueLimit: frameClientQueueLimit(ws),
|
|
2152
2181
|
queueHighWaterPackets: Math.max(0, Number(lane?.queuedPacketsHighWater || 0)),
|
|
@@ -2934,14 +2963,28 @@ function startFrameSubscriptionLive(
|
|
|
2934
2963
|
const monitorIndex = Object.prototype.hasOwnProperty.call(liveOptions.monitorSelections || {}, deviceId)
|
|
2935
2964
|
? liveOptions.monitorSelections[deviceId]
|
|
2936
2965
|
: liveOptions.monitorIndex;
|
|
2937
|
-
const result = remoteHub.startLiveStream(deviceId, {
|
|
2938
|
-
...liveOptions,
|
|
2939
|
-
monitorIndex,
|
|
2940
|
-
reuseExisting: liveOptions.forceRestart !== true
|
|
2941
|
-
&& (liveOptions.reuseExisting === true || reason === 'subscribe' || reason === 'watchdog'),
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2966
|
+
const result = remoteHub.startLiveStream(deviceId, {
|
|
2967
|
+
...liveOptions,
|
|
2968
|
+
monitorIndex,
|
|
2969
|
+
reuseExisting: liveOptions.forceRestart !== true
|
|
2970
|
+
&& (liveOptions.reuseExisting === true || reason === 'subscribe' || reason === 'watchdog'),
|
|
2971
|
+
// Wall capture is one shared native encoder per device. Two open browser
|
|
2972
|
+
// views may ask for different soft profiles (for example mobile 5 fps at
|
|
2973
|
+
// 1080p and desktop 20 fps at 540p). Once a healthy shared owner exists,
|
|
2974
|
+
// those preferences must bind to that owner instead of replacing it back
|
|
2975
|
+
// and forth every time either view refreshes its subscription.
|
|
2976
|
+
reuseSharedExisting: liveOptions.forceRestart !== true
|
|
2977
|
+
&& String(liveOptions.streamPurpose || '').trim().toLowerCase() === 'wall'
|
|
2978
|
+
&& hasOtherFrameStreamDemand(ws, deviceId, 'wall'),
|
|
2979
|
+
silentReuse: reason === 'watchdog' && liveOptions.forceRestart !== true
|
|
2980
|
+
});
|
|
2981
|
+
if (result?.ok) {
|
|
2982
|
+
if (result.sharedProfileReused === true) {
|
|
2983
|
+
ws.liveDeskSharedProfileReuseCount = Math.max(
|
|
2984
|
+
0,
|
|
2985
|
+
Number(ws.liveDeskSharedProfileReuseCount || 0)
|
|
2986
|
+
) + 1;
|
|
2987
|
+
}
|
|
2945
2988
|
frameCaptureTransitionRetries.complete(ws, deviceId, intentGeneration, 'capture-started');
|
|
2946
2989
|
const expectedBinding = {
|
|
2947
2990
|
deviceId,
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"kind": "livedesk-production-web-source-evidence",
|
|
4
|
-
"generatedAt": "2026-08-
|
|
5
|
-
"pwaRelease": "0.1.
|
|
6
|
-
"sourceHash": "
|
|
4
|
+
"generatedAt": "2026-08-15T11:55:50.032Z",
|
|
5
|
+
"pwaRelease": "0.1.568",
|
|
6
|
+
"sourceHash": "b6ddf954042b6c26a3965235894648d5171bdc3e327c5c689e0d91989fd4f019",
|
|
7
7
|
"sourceFileCount": 142,
|
|
8
|
-
"sourceBytes":
|
|
8
|
+
"sourceBytes": 2245018,
|
|
9
9
|
"viteEnvironmentHash": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945",
|
|
10
|
-
"outputHash": "
|
|
10
|
+
"outputHash": "74cc3037596534ef697f26c4313052a213c1f54ad82a3be6b2de74af7633acf1",
|
|
11
11
|
"outputFileCount": 18,
|
|
12
12
|
"outputBytes": 1629754,
|
|
13
13
|
"outputManifest": [
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
{
|
|
100
100
|
"path": "sw.js",
|
|
101
101
|
"bytes": 1309,
|
|
102
|
-
"sha256": "
|
|
102
|
+
"sha256": "c12eb04df48d694da8a380a588343ee2ef242888c4285149b6a4839bff33c2ec"
|
|
103
103
|
}
|
|
104
104
|
]
|
|
105
105
|
}
|
package/web/dist/sw.js
CHANGED