livedesk 0.1.408 → 0.1.410
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/README.md +1 -1
- package/client/bin/livedesk-client.js +1 -1
- package/client/package.json +5 -5
- package/hub/src/mode4-atlas-sizing.js +32 -0
- package/hub/src/mode4-atlas-worker.js +14 -7
- package/hub/src/server.js +19 -10
- package/package.json +6 -6
- package/web/dist/assets/{index-DGODhq1E.js → index-CmEDMI47.js} +1 -1
- package/web/dist/index.html +1 -1
package/client/README.md
CHANGED
|
@@ -89,7 +89,7 @@ Frame pipeline roadmap:
|
|
|
89
89
|
|
|
90
90
|
- Mode 1: `mode1-jpeg` - current test path using screen capture, resize, and JPEG binary frames.
|
|
91
91
|
- Mode 2: `mode2-lzo` - cross-platform wall path using independent RGB565LE frames capped at 320x180 and compressed as LZO1X blocks. The wall defaults to 8 fps. macOS and Linux keep one persistent local capture helper per client process. Legacy `mode2-lz4` settings migrate to this mode.
|
|
92
|
-
- Mode 3: `mode3-h264-hw` - OS-specific
|
|
92
|
+
- Mode 3: `mode3-h264-hw` - OS-specific H.264 path. Windows tries Media Foundation/NVENC/QSV/AMF, macOS prefers ScreenCaptureKit plus VideoToolbox, and Linux tries NVENC/VAAPI/QSV before falling back to the bundled ffmpeg `libx264` encoder. Linux users do not need to install ffmpeg separately when starting LiveDesk through the published npm package. macOS emits one startup key frame and then an approximately one-second GOP. The launcher uses bundled ffmpeg for fallback paths unless `LIVEDESK_FFMPEG` points to a custom binary. On macOS, set `LIVEDESK_FFMPEG_AVFOUNDATION_INPUT` only when the ScreenCaptureKit helper is unavailable and the AVFoundation fallback input is not `1:none`.
|
|
93
93
|
|
|
94
94
|
Legacy mode names such as `remote-fast` and `remote-quality` are treated as
|
|
95
95
|
Mode 1 aliases.
|
|
@@ -3772,7 +3772,7 @@ function buildFastEnvironment(prepared) {
|
|
|
3772
3772
|
env.LIVEDESK_FFMPEG_PATHS = merged.join(separator);
|
|
3773
3773
|
}
|
|
3774
3774
|
|
|
3775
|
-
if (process.platform === 'darwin' || env.LIVEDESK_DEBUG_FFMPEG === '1') {
|
|
3775
|
+
if (process.platform === 'darwin' || process.platform === 'linux' || env.LIVEDESK_DEBUG_FFMPEG === '1') {
|
|
3776
3776
|
const describe = path => path.includes('ffmpeg-static')
|
|
3777
3777
|
? 'ffmpeg-static'
|
|
3778
3778
|
: path.includes('@ffmpeg-installer')
|
package/client/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livedesk/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.175",
|
|
4
4
|
"description": "LiveDesk local remote client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"ws": "^8.18.3"
|
|
40
40
|
},
|
|
41
41
|
"optionalDependencies": {
|
|
42
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
43
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
44
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
45
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
42
|
+
"@livedesk/fast-linux-x64": "0.1.381",
|
|
43
|
+
"@livedesk/fast-osx-arm64": "0.1.381",
|
|
44
|
+
"@livedesk/fast-osx-x64": "0.1.381",
|
|
45
|
+
"@livedesk/fast-win-x64": "0.1.381"
|
|
46
46
|
},
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const TILE_PRESETS = Object.freeze([
|
|
2
|
+
Object.freeze({ width: 320, height: 180 }),
|
|
3
|
+
Object.freeze({ width: 480, height: 270 }),
|
|
4
|
+
Object.freeze({ width: 640, height: 360 })
|
|
5
|
+
]);
|
|
6
|
+
|
|
7
|
+
export function resolveMode4AtlasTileSize(options = {}) {
|
|
8
|
+
const deviceCount = Math.max(1, Math.floor(Number(options.deviceCount) || 1));
|
|
9
|
+
const atlasWidth = Math.max(640, Math.floor(Number(options.atlasWidth) || 1920));
|
|
10
|
+
const atlasHeight = Math.max(360, Math.floor(Number(options.atlasHeight) || 1080));
|
|
11
|
+
const requestedWidth = Number(options.requestedWidth) || 320;
|
|
12
|
+
const requestedHeight = Number(options.requestedHeight) || 180;
|
|
13
|
+
const columns = Math.max(1, Math.ceil(Math.sqrt(deviceCount)));
|
|
14
|
+
const rows = Math.max(1, Math.ceil(deviceCount / columns));
|
|
15
|
+
const requestedPresetIndex = requestedWidth >= 640 || requestedHeight >= 360
|
|
16
|
+
? 2
|
|
17
|
+
: requestedWidth >= 480 || requestedHeight >= 270
|
|
18
|
+
? 1
|
|
19
|
+
: 0;
|
|
20
|
+
const supportedCandidates = TILE_PRESETS.slice(0, requestedPresetIndex + 1).reverse();
|
|
21
|
+
const selected = supportedCandidates.find(candidate => (
|
|
22
|
+
candidate.width * columns <= atlasWidth
|
|
23
|
+
&& candidate.height * rows <= atlasHeight
|
|
24
|
+
)) || TILE_PRESETS[0];
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
width: selected.width,
|
|
28
|
+
height: selected.height,
|
|
29
|
+
columns,
|
|
30
|
+
rows
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -4,6 +4,7 @@ import { spawn } from 'node:child_process';
|
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { existsSync } from 'node:fs';
|
|
6
6
|
import { decodeLzo1xBlock } from './lzo1x.js';
|
|
7
|
+
import { resolveMode4AtlasTileSize } from './mode4-atlas-sizing.js';
|
|
7
8
|
|
|
8
9
|
const require = createRequire(import.meta.url);
|
|
9
10
|
const DEFAULT_WIDTH = 1920;
|
|
@@ -11,8 +12,8 @@ const DEFAULT_HEIGHT = 1080;
|
|
|
11
12
|
const DEFAULT_FPS = 20;
|
|
12
13
|
const MAX_DEVICES = 100;
|
|
13
14
|
const FRAME_POOL_SIZE = 3;
|
|
14
|
-
const MAX_TILE_WIDTH =
|
|
15
|
-
const MAX_TILE_HEIGHT =
|
|
15
|
+
const MAX_TILE_WIDTH = 640;
|
|
16
|
+
const MAX_TILE_HEIGHT = 360;
|
|
16
17
|
|
|
17
18
|
const rgb565Red = new Uint8Array(65_536);
|
|
18
19
|
const rgb565Green = new Uint8Array(65_536);
|
|
@@ -59,12 +60,18 @@ function normalizeConfig(value) {
|
|
|
59
60
|
.map(item => String(item || '').trim()).filter(Boolean))].slice(0, MAX_DEVICES);
|
|
60
61
|
const maxWidth = clamp(value?.width, 640, 3840, DEFAULT_WIDTH);
|
|
61
62
|
const maxHeight = clamp(value?.height, 360, 2160, DEFAULT_HEIGHT);
|
|
62
|
-
const sharpTiles = Number(value?.tileWidth) >= 480 || Number(value?.tileHeight) >= 270;
|
|
63
|
-
const sourceTileWidth = sharpTiles ? 480 : 320;
|
|
64
|
-
const sourceTileHeight = sharpTiles ? 270 : 180;
|
|
65
63
|
const count = Math.max(1, deviceIds.length);
|
|
66
|
-
const
|
|
67
|
-
|
|
64
|
+
const tileSize = resolveMode4AtlasTileSize({
|
|
65
|
+
requestedWidth: value?.tileWidth,
|
|
66
|
+
requestedHeight: value?.tileHeight,
|
|
67
|
+
deviceCount: count,
|
|
68
|
+
atlasWidth: maxWidth,
|
|
69
|
+
atlasHeight: maxHeight
|
|
70
|
+
});
|
|
71
|
+
const columns = tileSize.columns;
|
|
72
|
+
const rows = tileSize.rows;
|
|
73
|
+
const sourceTileWidth = tileSize.width;
|
|
74
|
+
const sourceTileHeight = tileSize.height;
|
|
68
75
|
const tileWidth = Math.max(2, Math.min(sourceTileWidth, Math.floor(maxWidth / columns))) & ~1;
|
|
69
76
|
const tileHeight = Math.max(2, Math.min(sourceTileHeight, Math.floor(maxHeight / rows))) & ~1;
|
|
70
77
|
return {
|
package/hub/src/server.js
CHANGED
|
@@ -8,8 +8,9 @@ import { dirname, resolve } from 'node:path';
|
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import os from 'node:os';
|
|
10
10
|
import { WebSocketServer } from 'ws';
|
|
11
|
-
import { createRemoteHub } from './remote-hub.js';
|
|
11
|
+
import { createRemoteHub } from './remote-hub.js';
|
|
12
12
|
import { buildMode4AtlasSessionKey, Mode4AtlasPool, planMode4AtlasInputTransitions } from './mode4-atlas-pool.js';
|
|
13
|
+
import { resolveMode4AtlasTileSize } from './mode4-atlas-sizing.js';
|
|
13
14
|
import { createHubFilesystem } from './filesystem/hub-filesystem.js';
|
|
14
15
|
import { createHubTransferJobs } from './filesystem/transfer-jobs.js';
|
|
15
16
|
import { createHubSharedFolders } from './filesystem/shared-folders.js';
|
|
@@ -2287,13 +2288,21 @@ function sendMode4AtlasFrame(ws, output) {
|
|
|
2287
2288
|
}
|
|
2288
2289
|
|
|
2289
2290
|
function configureMode4Atlas(ws, payload = {}) {
|
|
2290
|
-
const deviceIds = normalizeDeviceIds(payload.deviceIds ?? payload.devices ?? payload.deviceId).slice(0, 100);
|
|
2291
|
-
const captureDeviceIds = normalizeDeviceIds(payload.captureDeviceIds ?? payload.inputDeviceIds ?? deviceIds)
|
|
2292
|
-
.filter(deviceId => deviceIds.includes(deviceId));
|
|
2293
|
-
const monitorSelections = normalizeMonitorSelections(payload.monitorSelections);
|
|
2294
|
-
const
|
|
2295
|
-
const
|
|
2296
|
-
const
|
|
2291
|
+
const deviceIds = normalizeDeviceIds(payload.deviceIds ?? payload.devices ?? payload.deviceId).slice(0, 100);
|
|
2292
|
+
const captureDeviceIds = normalizeDeviceIds(payload.captureDeviceIds ?? payload.inputDeviceIds ?? deviceIds)
|
|
2293
|
+
.filter(deviceId => deviceIds.includes(deviceId));
|
|
2294
|
+
const monitorSelections = normalizeMonitorSelections(payload.monitorSelections);
|
|
2295
|
+
const width = clampNumber(payload.width, 640, 3840, 1920);
|
|
2296
|
+
const height = clampNumber(payload.height, 360, 2160, 1080);
|
|
2297
|
+
const tileSize = resolveMode4AtlasTileSize({
|
|
2298
|
+
requestedWidth: payload.tileWidth,
|
|
2299
|
+
requestedHeight: payload.tileHeight,
|
|
2300
|
+
deviceCount: deviceIds.length,
|
|
2301
|
+
atlasWidth: width,
|
|
2302
|
+
atlasHeight: height
|
|
2303
|
+
});
|
|
2304
|
+
const tileWidth = tileSize.width;
|
|
2305
|
+
const tileHeight = tileSize.height;
|
|
2297
2306
|
const previousInputDeviceIds = ws.liveDeskAtlasInputDeviceIds instanceof Set
|
|
2298
2307
|
? new Set(ws.liveDeskAtlasInputDeviceIds)
|
|
2299
2308
|
: new Set();
|
|
@@ -2304,8 +2313,8 @@ function configureMode4Atlas(ws, payload = {}) {
|
|
|
2304
2313
|
// every layout device ingestible lets a paused/reused input retain its
|
|
2305
2314
|
// latest tile while only the changed device restarts capture.
|
|
2306
2315
|
inputDeviceIds: deviceIds,
|
|
2307
|
-
width
|
|
2308
|
-
height
|
|
2316
|
+
width,
|
|
2317
|
+
height,
|
|
2309
2318
|
tileWidth,
|
|
2310
2319
|
tileHeight,
|
|
2311
2320
|
fps: clampNumber(payload.fps, 1, 30, 20),
|
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.410",
|
|
4
|
+
"livedeskClientVersion": "0.1.175",
|
|
5
5
|
"buildFlavor": "production",
|
|
6
6
|
"description": "LiveDesk Hub and client launcher",
|
|
7
7
|
"type": "module",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"ws": "^8.18.3"
|
|
50
50
|
},
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@livedesk/fast-linux-x64": "0.1.
|
|
53
|
-
"@livedesk/fast-osx-arm64": "0.1.
|
|
54
|
-
"@livedesk/fast-osx-x64": "0.1.
|
|
55
|
-
"@livedesk/fast-win-x64": "0.1.
|
|
52
|
+
"@livedesk/fast-linux-x64": "0.1.381",
|
|
53
|
+
"@livedesk/fast-osx-arm64": "0.1.381",
|
|
54
|
+
"@livedesk/fast-osx-x64": "0.1.381",
|
|
55
|
+
"@livedesk/fast-win-x64": "0.1.381"
|
|
56
56
|
},
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|