livedesk 0.1.225 → 0.1.227
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/mode4-atlas.js +7 -2
- package/hub/src/remote-hub.js +37 -11
- package/hub/src/server.js +124 -37
- package/package.json +2 -2
- package/web/dist/assets/index-BeXhnYq1.js +15 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-DTVXLmHj.js +0 -15
package/hub/src/mode4-atlas.js
CHANGED
|
@@ -10,6 +10,8 @@ export class Mode4AtlasSession {
|
|
|
10
10
|
this.onStatus = typeof options.onStatus === 'function' ? options.onStatus : () => {};
|
|
11
11
|
this.deviceIds = [];
|
|
12
12
|
this.deviceSet = new Set();
|
|
13
|
+
this.inputDeviceIds = [];
|
|
14
|
+
this.inputDeviceSet = new Set();
|
|
13
15
|
this.config = null;
|
|
14
16
|
this.closed = false;
|
|
15
17
|
this.worker = null;
|
|
@@ -65,7 +67,10 @@ export class Mode4AtlasSession {
|
|
|
65
67
|
this.deviceIds = [...new Set((Array.isArray(options.deviceIds) ? options.deviceIds : [])
|
|
66
68
|
.map(value => String(value || '').trim()).filter(Boolean))].slice(0, 100);
|
|
67
69
|
this.deviceSet = new Set(this.deviceIds);
|
|
68
|
-
this.
|
|
70
|
+
this.inputDeviceIds = [...new Set((Array.isArray(options.inputDeviceIds) ? options.inputDeviceIds : this.deviceIds)
|
|
71
|
+
.map(value => String(value || '').trim()).filter(value => this.deviceSet.has(value)))].slice(0, 100);
|
|
72
|
+
this.inputDeviceSet = new Set(this.inputDeviceIds);
|
|
73
|
+
this.pendingFrames = new Map([...this.pendingFrames].filter(([deviceId]) => this.inputDeviceSet.has(deviceId)));
|
|
69
74
|
this.config = {
|
|
70
75
|
deviceIds: this.deviceIds,
|
|
71
76
|
width: Number(options.width || 1920),
|
|
@@ -102,7 +107,7 @@ export class Mode4AtlasSession {
|
|
|
102
107
|
const frame = frameEvent?.frame || {};
|
|
103
108
|
const deviceId = String(frameEvent?.deviceId || frame.deviceId || '').trim();
|
|
104
109
|
const mode = String(frame.frameMode || frame.mode || '').toLowerCase();
|
|
105
|
-
if (!this.
|
|
110
|
+
if (!this.inputDeviceSet.has(deviceId) || mode !== 'mode2-lzo' || !Buffer.isBuffer(frameEvent?.payload)) return;
|
|
106
111
|
this.pendingFrames.set(deviceId, {
|
|
107
112
|
type: 'frame',
|
|
108
113
|
deviceId,
|
package/hub/src/remote-hub.js
CHANGED
|
@@ -3474,6 +3474,12 @@ export function createRemoteHub(options = {}) {
|
|
|
3474
3474
|
transferProtocolVersion: transfer.transferProtocolVersion,
|
|
3475
3475
|
handshake: transfer.handshake,
|
|
3476
3476
|
fps: Number.isFinite(Number(message.fps)) ? Number(message.fps) : streamState.fps,
|
|
3477
|
+
requestedFps: Number.isFinite(Number(message.requestedFps)) ? Number(message.requestedFps) : Number(streamState.fps || 0),
|
|
3478
|
+
effectiveFps: Number.isFinite(Number(message.effectiveFps)) ? Number(message.effectiveFps) : Number(message.fps || streamState.fps || 0),
|
|
3479
|
+
captureAverageMs: readFrameStageMs(message, 'captureAverageMs'),
|
|
3480
|
+
captureP95Ms: readFrameStageMs(message, 'captureP95Ms'),
|
|
3481
|
+
slowFrameCount: Number.isFinite(Number(message.slowFrameCount)) ? Number(message.slowFrameCount) : 0,
|
|
3482
|
+
captureHelperRestarts: Number.isFinite(Number(message.captureHelperRestarts)) ? Number(message.captureHelperRestarts) : 0,
|
|
3477
3483
|
capturedAt,
|
|
3478
3484
|
receivedAt: device.lastSeenAt,
|
|
3479
3485
|
byteLength,
|
|
@@ -4809,16 +4815,27 @@ export function createRemoteHub(options = {}) {
|
|
|
4809
4815
|
return `${role}-${hash}`;
|
|
4810
4816
|
}
|
|
4811
4817
|
|
|
4818
|
+
function normalizeLivePlatform(value) {
|
|
4819
|
+
const normalized = safeString(value, 32).toLowerCase();
|
|
4820
|
+
if (['macos', 'darwin', 'mac', 'macosx'].includes(normalized)) return 'macos';
|
|
4821
|
+
if (['windows', 'win32', 'win32nt'].includes(normalized)) return 'windows';
|
|
4822
|
+
if (['linux', 'unix'].includes(normalized)) return 'linux';
|
|
4823
|
+
return normalized || 'unknown';
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4812
4826
|
function normalizeLiveStreamStartOptions(options = {}) {
|
|
4813
4827
|
const transfer = buildRemoteFrameTransferDescriptor(options.mode || options.frameMode || DEFAULT_REMOTE_FRAME_MODE);
|
|
4814
4828
|
const streamPurpose = safeString(options.streamPurpose || options.purpose || 'wall', 24) || 'wall';
|
|
4815
|
-
const
|
|
4816
|
-
const
|
|
4817
|
-
const
|
|
4818
|
-
const
|
|
4829
|
+
const platform = normalizeLivePlatform(options.platform);
|
|
4830
|
+
const macWallProfile = platform === 'macos' && streamPurpose !== 'control';
|
|
4831
|
+
const maxFps = streamPurpose === 'control' ? 60 : macWallProfile ? 8 : 30;
|
|
4832
|
+
const defaultFps = macWallProfile && options.fps === undefined ? 4 : 8;
|
|
4833
|
+
const maxWidth = clampNumber(options.maxWidth, 320, macWallProfile ? 432 : 3840, macWallProfile ? 432 : 640);
|
|
4834
|
+
const maxHeight = clampNumber(options.maxHeight, 180, macWallProfile ? 243 : 2160, macWallProfile ? 243 : 360);
|
|
4835
|
+
const fps = clampNumber(options.fps, 1, maxFps, defaultFps);
|
|
4819
4836
|
const quality = clampNumber(options.quality, 20, 95, 45);
|
|
4820
4837
|
const monitorIndex = normalizeMonitorIndex(options.monitorIndex ?? options.screenIndex ?? options.displayIndex);
|
|
4821
|
-
return { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose };
|
|
4838
|
+
return { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose, platform, macWallProfile };
|
|
4822
4839
|
}
|
|
4823
4840
|
|
|
4824
4841
|
function liveStreamStartStillPending(activeLiveStream) {
|
|
@@ -4879,7 +4896,7 @@ export function createRemoteHub(options = {}) {
|
|
|
4879
4896
|
}
|
|
4880
4897
|
|
|
4881
4898
|
const now = new Date().toISOString();
|
|
4882
|
-
const normalized = normalizeLiveStreamStartOptions({ fps: 2, ...options });
|
|
4899
|
+
const normalized = normalizeLiveStreamStartOptions({ fps: 2, ...options, platform: device.platform });
|
|
4883
4900
|
const { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose } = normalized;
|
|
4884
4901
|
const streamId = safeString(options.streamId, 128) || makeStableLiveStreamId(deviceId, streamPurpose);
|
|
4885
4902
|
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
@@ -4956,7 +4973,7 @@ export function createRemoteHub(options = {}) {
|
|
|
4956
4973
|
}
|
|
4957
4974
|
|
|
4958
4975
|
const now = new Date().toISOString();
|
|
4959
|
-
const normalized = normalizeLiveStreamStartOptions(options);
|
|
4976
|
+
const normalized = normalizeLiveStreamStartOptions({ ...options, platform: device.platform });
|
|
4960
4977
|
const { fps, maxWidth, maxHeight, quality, monitorIndex, transfer, streamPurpose } = normalized;
|
|
4961
4978
|
const streamId = safeString(options.streamId, 128) || makeStableLiveStreamId(deviceId, streamPurpose);
|
|
4962
4979
|
const activeLiveStream = getDeviceLiveStream(device, streamId);
|
|
@@ -5099,11 +5116,22 @@ export function createRemoteHub(options = {}) {
|
|
|
5099
5116
|
|
|
5100
5117
|
function stopLiveStream(deviceId, options = {}) {
|
|
5101
5118
|
const device = devices.get(String(deviceId || ''));
|
|
5119
|
+
const streamPurpose = safeString(options.streamPurpose || options.purpose, 24);
|
|
5120
|
+
const requestedStreamId = safeString(options.streamId, 128);
|
|
5121
|
+
const purposeStreamId = streamPurpose ? makeStableLiveStreamId(deviceId, streamPurpose) : '';
|
|
5122
|
+
const streamId = requestedStreamId || purposeStreamId || device?.activeLiveStream?.streamId || '';
|
|
5123
|
+
const streamState = getDeviceLiveStream(device, streamId);
|
|
5124
|
+
if (streamState && streamState.active !== true) {
|
|
5125
|
+
return {
|
|
5126
|
+
ok: true,
|
|
5127
|
+
commandId: safeString(options.commandId, 128),
|
|
5128
|
+
streamId,
|
|
5129
|
+
alreadyStopped: true
|
|
5130
|
+
};
|
|
5131
|
+
}
|
|
5102
5132
|
if (device?.synthetic === true && device.connected) {
|
|
5103
|
-
const streamId = safeString(options.streamId, 128) || device.activeLiveStream?.streamId || '';
|
|
5104
5133
|
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
5105
5134
|
device.counters.commandsSent += 1;
|
|
5106
|
-
const streamState = getDeviceLiveStream(device, streamId);
|
|
5107
5135
|
if (streamState) {
|
|
5108
5136
|
streamState.active = false;
|
|
5109
5137
|
streamState.stoppedAt = new Date().toISOString();
|
|
@@ -5122,7 +5150,6 @@ export function createRemoteHub(options = {}) {
|
|
|
5122
5150
|
return { ok: false, error: 'device-not-connected' };
|
|
5123
5151
|
}
|
|
5124
5152
|
|
|
5125
|
-
const streamId = safeString(options.streamId, 128) || device.activeLiveStream?.streamId || '';
|
|
5126
5153
|
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
5127
5154
|
const result = sendCommand(deviceId, {
|
|
5128
5155
|
command: 'stream.stop',
|
|
@@ -5137,7 +5164,6 @@ export function createRemoteHub(options = {}) {
|
|
|
5137
5164
|
return result;
|
|
5138
5165
|
}
|
|
5139
5166
|
|
|
5140
|
-
const streamState = getDeviceLiveStream(device, streamId);
|
|
5141
5167
|
if (streamState) {
|
|
5142
5168
|
streamState.active = false;
|
|
5143
5169
|
streamState.stoppedAt = new Date().toISOString();
|
package/hub/src/server.js
CHANGED
|
@@ -101,11 +101,11 @@ function handleRemoteHubEvent(type, event) {
|
|
|
101
101
|
if (!deviceId) {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
for (const ws of atlasClients.keys()) {
|
|
105
|
-
if (ws.readyState === 1 && ws.
|
|
106
|
-
startMode4AtlasInput(ws, deviceId, 'device-connected');
|
|
107
|
-
}
|
|
108
|
-
}
|
|
104
|
+
for (const ws of atlasClients.keys()) {
|
|
105
|
+
if (ws.readyState === 1 && ws.liveDeskAtlasInputDeviceIds?.has(deviceId)) {
|
|
106
|
+
startMode4AtlasInput(ws, deviceId, 'device-connected');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
109
|
const clients = new Set([
|
|
110
110
|
...(frameClientsByDeviceId.get(deviceId) || []),
|
|
111
111
|
...frameWildcardClients
|
|
@@ -976,11 +976,12 @@ function safeWebSocketSend(ws, payload, options = undefined) {
|
|
|
976
976
|
}
|
|
977
977
|
}
|
|
978
978
|
|
|
979
|
-
function unregisterFrameClient(ws) {
|
|
980
|
-
if (!ws) {
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
|
-
|
|
979
|
+
function unregisterFrameClient(ws) {
|
|
980
|
+
if (!ws) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
stopFrameClientStreams(ws);
|
|
984
|
+
const ids = ws.liveDeskDeviceIds instanceof Set ? ws.liveDeskDeviceIds : new Set();
|
|
984
985
|
for (const deviceId of ids) {
|
|
985
986
|
const clients = frameClientsByDeviceId.get(deviceId);
|
|
986
987
|
if (!clients) {
|
|
@@ -991,9 +992,49 @@ function unregisterFrameClient(ws) {
|
|
|
991
992
|
frameClientsByDeviceId.delete(deviceId);
|
|
992
993
|
}
|
|
993
994
|
}
|
|
994
|
-
frameWildcardClients.delete(ws);
|
|
995
|
-
ws.liveDeskFrameSendLane?.queue?.splice?.(0);
|
|
996
|
-
}
|
|
995
|
+
frameWildcardClients.delete(ws);
|
|
996
|
+
ws.liveDeskFrameSendLane?.queue?.splice?.(0);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
function hasOtherFrameStreamOwner(ws, deviceId, streamId) {
|
|
1000
|
+
if (!streamId) {
|
|
1001
|
+
return false;
|
|
1002
|
+
}
|
|
1003
|
+
for (const candidate of frameClients) {
|
|
1004
|
+
if (candidate === ws || candidate.readyState !== candidate.OPEN) {
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
if (candidate.liveDeskStreamIdsByDeviceId instanceof Map
|
|
1008
|
+
&& candidate.liveDeskStreamIdsByDeviceId.get(deviceId) === streamId) {
|
|
1009
|
+
return true;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return false;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
function stopFrameClientStreams(ws) {
|
|
1016
|
+
const streams = ws.liveDeskStreamIdsByDeviceId instanceof Map
|
|
1017
|
+
? ws.liveDeskStreamIdsByDeviceId
|
|
1018
|
+
: null;
|
|
1019
|
+
if (!streams) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const streamPurpose = String(ws.liveDeskLiveOptions?.streamPurpose || 'wall');
|
|
1023
|
+
for (const [deviceId, streamId] of streams.entries()) {
|
|
1024
|
+
if (!streamId || hasOtherFrameStreamOwner(ws, deviceId, streamId)) {
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
const result = remoteHub.stopLiveStream(deviceId, {
|
|
1028
|
+
streamId,
|
|
1029
|
+
streamPurpose,
|
|
1030
|
+
reason: 'frame-client-closed'
|
|
1031
|
+
});
|
|
1032
|
+
if (result?.ok && !result.alreadyStopped) {
|
|
1033
|
+
console.log(`[LiveDesk Hub] stopped ${streamPurpose} stream after frame client closed device=${deviceId} stream=${streamId}`);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
streams.clear();
|
|
1037
|
+
}
|
|
997
1038
|
|
|
998
1039
|
function registerFrameClient(ws) {
|
|
999
1040
|
if (!ws) {
|
|
@@ -1322,9 +1363,15 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
|
|
|
1322
1363
|
hardwareEncoder: frame.hardwareEncoder || '',
|
|
1323
1364
|
platformProfile: frame.platformProfile || '',
|
|
1324
1365
|
monitorIndex: Number.isFinite(Number(frame.monitorIndex)) ? Number(frame.monitorIndex) : 0,
|
|
1325
|
-
monitorCount: Number.isFinite(Number(frame.monitorCount)) ? Number(frame.monitorCount) : 1,
|
|
1326
|
-
fps: Number(frame.fps || 0) || 0,
|
|
1327
|
-
|
|
1366
|
+
monitorCount: Number.isFinite(Number(frame.monitorCount)) ? Number(frame.monitorCount) : 1,
|
|
1367
|
+
fps: Number(frame.fps || 0) || 0,
|
|
1368
|
+
requestedFps: Number(frame.requestedFps || 0) || 0,
|
|
1369
|
+
effectiveFps: Number(frame.effectiveFps || 0) || 0,
|
|
1370
|
+
captureAverageMs: Number(frame.captureAverageMs || 0) || 0,
|
|
1371
|
+
captureP95Ms: Number(frame.captureP95Ms || 0) || 0,
|
|
1372
|
+
slowFrameCount: Number(frame.slowFrameCount || 0) || 0,
|
|
1373
|
+
captureHelperRestarts: Number(frame.captureHelperRestarts || 0) || 0,
|
|
1374
|
+
capturedAt: frame.capturedAt || '',
|
|
1328
1375
|
receivedAt: frame.receivedAt || '',
|
|
1329
1376
|
hubPacketAt,
|
|
1330
1377
|
hubPacketEpochMs,
|
|
@@ -1537,28 +1584,42 @@ function sendMode4AtlasFrame(ws, output) {
|
|
|
1537
1584
|
}
|
|
1538
1585
|
}
|
|
1539
1586
|
|
|
1540
|
-
function configureMode4Atlas(ws, payload = {}) {
|
|
1541
|
-
const deviceIds = normalizeDeviceIds(payload.deviceIds ?? payload.devices ?? payload.deviceId).slice(0, 100);
|
|
1542
|
-
const
|
|
1587
|
+
function configureMode4Atlas(ws, payload = {}) {
|
|
1588
|
+
const deviceIds = normalizeDeviceIds(payload.deviceIds ?? payload.devices ?? payload.deviceId).slice(0, 100);
|
|
1589
|
+
const captureDeviceIds = normalizeDeviceIds(payload.captureDeviceIds ?? payload.inputDeviceIds ?? deviceIds)
|
|
1590
|
+
.filter(deviceId => deviceIds.includes(deviceId));
|
|
1591
|
+
const monitorSelections = normalizeMonitorSelections(payload.monitorSelections);
|
|
1543
1592
|
const sharpTiles = Number(payload.tileWidth) >= 480 || Number(payload.tileHeight) >= 270;
|
|
1544
1593
|
const tileWidth = sharpTiles ? 480 : 320;
|
|
1545
1594
|
const tileHeight = sharpTiles ? 270 : 180;
|
|
1546
|
-
ws.
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1595
|
+
const previousInputDeviceIds = ws.liveDeskAtlasInputDeviceIds instanceof Set
|
|
1596
|
+
? new Set(ws.liveDeskAtlasInputDeviceIds)
|
|
1597
|
+
: new Set(deviceIds);
|
|
1598
|
+
ws.liveDeskAtlasDeviceIds = new Set(deviceIds);
|
|
1599
|
+
ws.liveDeskAtlasInputDeviceIds = new Set(captureDeviceIds);
|
|
1600
|
+
ws.liveDeskAtlasInputOptions = { tileWidth, tileHeight, monitorSelections };
|
|
1601
|
+
ws.liveDeskAtlasSession.configure({
|
|
1602
|
+
deviceIds,
|
|
1603
|
+
inputDeviceIds: captureDeviceIds,
|
|
1550
1604
|
width: clampNumber(payload.width, 640, 3840, 1920),
|
|
1551
1605
|
height: clampNumber(payload.height, 360, 2160, 1080),
|
|
1552
1606
|
tileWidth,
|
|
1553
1607
|
tileHeight,
|
|
1554
1608
|
fps: clampNumber(payload.fps, 1, 30, 20)
|
|
1555
1609
|
});
|
|
1556
|
-
for (const deviceId of
|
|
1557
|
-
|
|
1558
|
-
|
|
1610
|
+
for (const deviceId of previousInputDeviceIds) {
|
|
1611
|
+
if (ws.liveDeskAtlasInputDeviceIds.has(deviceId)) {
|
|
1612
|
+
continue;
|
|
1613
|
+
}
|
|
1614
|
+
stopMode4AtlasInput(ws, deviceId, 'atlas-input-paused');
|
|
1615
|
+
}
|
|
1616
|
+
for (const deviceId of captureDeviceIds) {
|
|
1617
|
+
startMode4AtlasInput(ws, deviceId, 'atlas-configure');
|
|
1618
|
+
}
|
|
1559
1619
|
sendJson(ws, {
|
|
1560
|
-
type: 'Mode4AtlasSubscription',
|
|
1561
|
-
deviceIds,
|
|
1620
|
+
type: 'Mode4AtlasSubscription',
|
|
1621
|
+
deviceIds,
|
|
1622
|
+
captureDeviceIds,
|
|
1562
1623
|
inputMode: 'mode2-lzo',
|
|
1563
1624
|
outputMode: 'mode4-h264-atlas',
|
|
1564
1625
|
tileWidth,
|
|
@@ -1567,10 +1628,10 @@ function configureMode4Atlas(ws, payload = {}) {
|
|
|
1567
1628
|
});
|
|
1568
1629
|
}
|
|
1569
1630
|
|
|
1570
|
-
function startMode4AtlasInput(ws, deviceId, reason = 'atlas-configure') {
|
|
1571
|
-
const options = ws?.liveDeskAtlasInputOptions;
|
|
1572
|
-
if (!options || !ws.
|
|
1573
|
-
return remoteHub.startLiveStream(deviceId, {
|
|
1631
|
+
function startMode4AtlasInput(ws, deviceId, reason = 'atlas-configure') {
|
|
1632
|
+
const options = ws?.liveDeskAtlasInputOptions;
|
|
1633
|
+
if (!options || !ws.liveDeskAtlasInputDeviceIds?.has(deviceId)) return { ok: false, error: 'atlas-device-not-configured' };
|
|
1634
|
+
return remoteHub.startLiveStream(deviceId, {
|
|
1574
1635
|
fps: 8,
|
|
1575
1636
|
maxWidth: options.tileWidth,
|
|
1576
1637
|
maxHeight: options.tileHeight,
|
|
@@ -1582,8 +1643,30 @@ function startMode4AtlasInput(ws, deviceId, reason = 'atlas-configure') {
|
|
|
1582
1643
|
reuseExisting: false,
|
|
1583
1644
|
silentReuse: true,
|
|
1584
1645
|
restartReason: reason
|
|
1585
|
-
});
|
|
1586
|
-
}
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
function hasOtherAtlasInputOwner(ws, deviceId) {
|
|
1650
|
+
for (const candidate of atlasClients.keys()) {
|
|
1651
|
+
if (candidate === ws || candidate.readyState !== candidate.OPEN) {
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (candidate.liveDeskAtlasInputDeviceIds?.has(deviceId)) {
|
|
1655
|
+
return true;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
return false;
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
function stopMode4AtlasInput(ws, deviceId, reason = 'atlas-input-stopped') {
|
|
1662
|
+
if (!deviceId || hasOtherAtlasInputOwner(ws, deviceId)) {
|
|
1663
|
+
return { ok: true, alreadyOwned: true };
|
|
1664
|
+
}
|
|
1665
|
+
return remoteHub.stopLiveStream(deviceId, {
|
|
1666
|
+
streamPurpose: 'atlas',
|
|
1667
|
+
reason
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1587
1670
|
|
|
1588
1671
|
function wantsBinaryFrame(req) {
|
|
1589
1672
|
return /^(1|true|yes|on|binary|raw)$/i.test(String(req.query?.binary ?? req.query?.raw ?? ''))
|
|
@@ -2457,9 +2540,13 @@ atlasWss.on('connection', ws => {
|
|
|
2457
2540
|
});
|
|
2458
2541
|
ws.liveDeskAtlasSession = session;
|
|
2459
2542
|
atlasClients.set(ws, session);
|
|
2460
|
-
const cleanup = () => {
|
|
2461
|
-
atlasClients.delete(ws);
|
|
2462
|
-
|
|
2543
|
+
const cleanup = () => {
|
|
2544
|
+
atlasClients.delete(ws);
|
|
2545
|
+
for (const deviceId of ws.liveDeskAtlasInputDeviceIds || []) {
|
|
2546
|
+
stopMode4AtlasInput(ws, deviceId, 'atlas-client-closed');
|
|
2547
|
+
}
|
|
2548
|
+
ws.liveDeskAtlasInputDeviceIds = new Set();
|
|
2549
|
+
session.close();
|
|
2463
2550
|
const lane = ws.liveDeskFrameSendLane;
|
|
2464
2551
|
if (lane) {
|
|
2465
2552
|
lane.queue.length = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livedesk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.227",
|
|
4
4
|
"description": "LiveDesk Hub and client launcher",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
34
|
-
"@livedesk/client": "0.1.
|
|
34
|
+
"@livedesk/client": "0.1.130",
|
|
35
35
|
"@openai/codex-sdk": "0.144.5",
|
|
36
36
|
"cors": "^2.8.5",
|
|
37
37
|
"express": "^4.21.2",
|