@mindexec/cli 0.2.440 → 0.2.442
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/package.json +1 -1
- package/remote-fast/osx-arm64/MacScreenCaptureKitH264.swift +339 -0
- package/remote-fast/osx-arm64/MacSystemAudioCapture.swift +214 -0
- package/remote-fast/osx-arm64/UnixRawCaptureHelper.mjs +80 -0
- package/remote-fast/osx-arm64/livedesk-raw-capture-resampler.mjs +73 -0
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/MacScreenCaptureKitH264.swift +339 -0
- package/remote-fast/osx-x64/MacSystemAudioCapture.swift +214 -0
- package/remote-fast/osx-x64/UnixRawCaptureHelper.mjs +80 -0
- package/remote-fast/osx-x64/livedesk-raw-capture-resampler.mjs +73 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/NAudio.Asio.dll +0 -0
- package/remote-fast/win-x64/NAudio.Core.dll +0 -0
- package/remote-fast/win-x64/NAudio.Midi.dll +0 -0
- package/remote-fast/win-x64/NAudio.Wasapi.dll +0 -0
- package/remote-fast/win-x64/NAudio.WinForms.dll +0 -0
- package/remote-fast/win-x64/NAudio.WinMM.dll +0 -0
- package/remote-fast/win-x64/NAudio.dll +0 -0
- package/remote-fast/win-x64/SharpGen.Runtime.COM.dll +0 -0
- package/remote-fast/win-x64/SharpGen.Runtime.dll +0 -0
- package/remote-fast/win-x64/Vortice.DXGI.dll +0 -0
- package/remote-fast/win-x64/Vortice.Direct3D11.dll +0 -0
- package/remote-fast/win-x64/Vortice.DirectX.dll +0 -0
- package/remote-fast/win-x64/Vortice.Mathematics.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.deps.json +238 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.exe +0 -0
- package/remote-hub.js +42 -3
- package/server.js +22 -6
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +49 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +6 -2
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +70 -60
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +32 -6
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-remote-codecs.js +126 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-video-playback-controls.js +95 -0
- package/wwwroot/_framework/{MindExecution.Core.808jj176e1.dll → MindExecution.Core.nxjlewduna.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.75hxk08tt0.dll → MindExecution.Kernel.vrfi63yg9f.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.0zkmk8wahq.dll → MindExecution.Plugins.Admin.1rcwhdxl0r.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.vyw3769hrw.dll → MindExecution.Plugins.Business.rx0eieg51y.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.cvmglrxsjb.dll → MindExecution.Plugins.Concept.zzczjzhvk1.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.jtw9q1dm9n.dll → MindExecution.Plugins.Directory.bsorcntiwp.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.8hmc6ps1ux.dll → MindExecution.Plugins.PlanMaster.i5j9t4f1jf.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.xb9sou9ox0.dll → MindExecution.Plugins.YouTube.1mpn9satft.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.pqab76cjb6.dll → MindExecution.Shared.mpi1gzau9b.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.mc24u4bzol.dll → MindExecution.Web.nxykcyxd02.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +21 -21
- package/wwwroot/index.html +3 -1
- package/wwwroot/service-worker-assets.js +35 -27
- package/wwwroot/service-worker.js +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import readline from 'node:readline';
|
|
4
|
+
import { convertRgbaToRgb565 } from './livedesk-raw-capture-resampler.mjs';
|
|
5
|
+
|
|
6
|
+
const screenshotModule = await import('node-screenshots');
|
|
7
|
+
const Monitor = screenshotModule.Monitor || screenshotModule.default?.Monitor;
|
|
8
|
+
if (!Monitor?.all) {
|
|
9
|
+
throw new Error('node-screenshots Monitor API is unavailable.');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function clampInteger(value, min, max, fallback) {
|
|
13
|
+
const number = Number(value);
|
|
14
|
+
if (!Number.isFinite(number)) return fallback;
|
|
15
|
+
return Math.max(min, Math.min(max, Math.round(number)));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function pickMonitor(index) {
|
|
19
|
+
const monitors = Monitor.all();
|
|
20
|
+
if (!monitors.length) {
|
|
21
|
+
throw new Error('No capturable desktop monitor was found.');
|
|
22
|
+
}
|
|
23
|
+
const selectedIndex = clampInteger(index, 0, monitors.length - 1, 0);
|
|
24
|
+
const monitor = monitors[selectedIndex]
|
|
25
|
+
|| monitors.find(item => item?.isPrimary?.() === true)
|
|
26
|
+
|| monitors[0];
|
|
27
|
+
return { monitor, selectedIndex, monitorCount: monitors.length };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function writeResponse(metadata, payload = Buffer.alloc(0)) {
|
|
31
|
+
const header = Buffer.from(JSON.stringify(metadata), 'utf8');
|
|
32
|
+
const prefix = Buffer.allocUnsafe(8);
|
|
33
|
+
prefix.writeUInt32BE(header.length, 0);
|
|
34
|
+
prefix.writeUInt32BE(payload.length, 4);
|
|
35
|
+
process.stdout.write(prefix);
|
|
36
|
+
process.stdout.write(header);
|
|
37
|
+
if (payload.length > 0) process.stdout.write(payload);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const input = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
41
|
+
for await (const line of input) {
|
|
42
|
+
if (!line.trim()) continue;
|
|
43
|
+
let request;
|
|
44
|
+
try {
|
|
45
|
+
request = JSON.parse(line);
|
|
46
|
+
const id = Number.isSafeInteger(Number(request.id)) ? Number(request.id) : 0;
|
|
47
|
+
const maxWidth = clampInteger(request.maxWidth, 1, 480, 320);
|
|
48
|
+
const maxHeight = clampInteger(request.maxHeight, 1, 270, 180);
|
|
49
|
+
const { monitor, selectedIndex, monitorCount } = pickMonitor(request.monitorIndex);
|
|
50
|
+
const captureStartedAt = performance.now();
|
|
51
|
+
const image = await monitor.captureImage();
|
|
52
|
+
const raw = await image.toRaw(false);
|
|
53
|
+
const captureMs = Math.max(0, performance.now() - captureStartedAt);
|
|
54
|
+
const sourceWidth = Number(image.width || monitor.width?.() || 0);
|
|
55
|
+
const sourceHeight = Number(image.height || monitor.height?.() || 0);
|
|
56
|
+
const convertStartedAt = performance.now();
|
|
57
|
+
const converted = convertRgbaToRgb565(raw, sourceWidth, sourceHeight, maxWidth, maxHeight);
|
|
58
|
+
const convertMs = Math.max(0, performance.now() - convertStartedAt);
|
|
59
|
+
writeResponse({
|
|
60
|
+
ok: true,
|
|
61
|
+
id,
|
|
62
|
+
width: converted.width,
|
|
63
|
+
height: converted.height,
|
|
64
|
+
sourceWidth,
|
|
65
|
+
sourceHeight,
|
|
66
|
+
monitorIndex: selectedIndex,
|
|
67
|
+
monitorCount,
|
|
68
|
+
captureMs: Math.round(captureMs),
|
|
69
|
+
convertMs: Math.round(convertMs),
|
|
70
|
+
resizeFilter: converted.filter
|
|
71
|
+
}, converted.output);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
writeResponse({
|
|
74
|
+
ok: false,
|
|
75
|
+
id: Number.isSafeInteger(Number(request?.id)) ? Number(request.id) : 0,
|
|
76
|
+
error: String(error?.message || error || 'capture failed').slice(0, 1000)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function clampInteger(value, min, max, fallback) {
|
|
2
|
+
const number = Number(value);
|
|
3
|
+
if (!Number.isFinite(number)) return fallback;
|
|
4
|
+
return Math.max(min, Math.min(max, Math.round(number)));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function writeRgb565(output, target, red, green, blue) {
|
|
8
|
+
const pixel = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
|
|
9
|
+
output[target] = pixel & 0xff;
|
|
10
|
+
output[target + 1] = pixel >> 8;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function convertRgbaToRgb565(raw, sourceWidthValue, sourceHeightValue, maxWidthValue, maxHeightValue) {
|
|
14
|
+
const sourceWidth = clampInteger(sourceWidthValue, 1, 32_768, 1);
|
|
15
|
+
const sourceHeight = clampInteger(sourceHeightValue, 1, 32_768, 1);
|
|
16
|
+
const maxWidth = clampInteger(maxWidthValue, 1, sourceWidth, sourceWidth);
|
|
17
|
+
const maxHeight = clampInteger(maxHeightValue, 1, sourceHeight, sourceHeight);
|
|
18
|
+
if (raw.length < sourceWidth * sourceHeight * 4) {
|
|
19
|
+
throw new Error(`Raw capture is incomplete: ${raw.length} bytes for ${sourceWidth}x${sourceHeight}.`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const scale = Math.min(1, maxWidth / sourceWidth, maxHeight / sourceHeight);
|
|
23
|
+
const width = Math.max(1, Math.round(sourceWidth * scale));
|
|
24
|
+
const height = Math.max(1, Math.round(sourceHeight * scale));
|
|
25
|
+
const output = Buffer.allocUnsafe(width * height * 2);
|
|
26
|
+
|
|
27
|
+
if (width === sourceWidth && height === sourceHeight) {
|
|
28
|
+
for (let source = 0, target = 0; target < output.length; source += 4, target += 2) {
|
|
29
|
+
writeRgb565(output, target, raw[source], raw[source + 1], raw[source + 2]);
|
|
30
|
+
}
|
|
31
|
+
return { output, width, height, filter: 'none' };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const xStarts = new Int32Array(width);
|
|
35
|
+
const xEnds = new Int32Array(width);
|
|
36
|
+
for (let x = 0; x < width; x += 1) {
|
|
37
|
+
xStarts[x] = Math.min(sourceWidth - 1, Math.floor(x * sourceWidth / width));
|
|
38
|
+
xEnds[x] = Math.max(xStarts[x] + 1, Math.min(sourceWidth, Math.floor((x + 1) * sourceWidth / width)));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let target = 0;
|
|
42
|
+
for (let y = 0; y < height; y += 1) {
|
|
43
|
+
const sourceY0 = Math.min(sourceHeight - 1, Math.floor(y * sourceHeight / height));
|
|
44
|
+
const sourceY1 = Math.max(sourceY0 + 1, Math.min(sourceHeight, Math.floor((y + 1) * sourceHeight / height)));
|
|
45
|
+
for (let x = 0; x < width; x += 1) {
|
|
46
|
+
let red = 0;
|
|
47
|
+
let green = 0;
|
|
48
|
+
let blue = 0;
|
|
49
|
+
let samples = 0;
|
|
50
|
+
for (let sourceY = sourceY0; sourceY < sourceY1; sourceY += 1) {
|
|
51
|
+
let source = (sourceY * sourceWidth + xStarts[x]) * 4;
|
|
52
|
+
for (let sourceX = xStarts[x]; sourceX < xEnds[x]; sourceX += 1) {
|
|
53
|
+
red += raw[source];
|
|
54
|
+
green += raw[source + 1];
|
|
55
|
+
blue += raw[source + 2];
|
|
56
|
+
samples += 1;
|
|
57
|
+
source += 4;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
writeRgb565(
|
|
61
|
+
output,
|
|
62
|
+
target,
|
|
63
|
+
Math.round(red / samples),
|
|
64
|
+
Math.round(green / samples),
|
|
65
|
+
Math.round(blue / samples)
|
|
66
|
+
);
|
|
67
|
+
target += 2;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { output, width, height, filter: 'box' };
|
|
72
|
+
}
|
|
73
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -8,9 +8,156 @@
|
|
|
8
8
|
".NETCoreApp,Version=v9.0": {},
|
|
9
9
|
".NETCoreApp,Version=v9.0/win-x64": {
|
|
10
10
|
"mindexec-remote-fast/1.0.0": {
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"NAudio": "2.2.1",
|
|
13
|
+
"Vortice.Direct3D11": "3.8.3"
|
|
14
|
+
},
|
|
11
15
|
"runtime": {
|
|
12
16
|
"mindexec-remote-fast.dll": {}
|
|
13
17
|
}
|
|
18
|
+
},
|
|
19
|
+
"NAudio/2.2.1": {
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"NAudio.Asio": "2.2.1",
|
|
22
|
+
"NAudio.Core": "2.2.1",
|
|
23
|
+
"NAudio.Midi": "2.2.1",
|
|
24
|
+
"NAudio.Wasapi": "2.2.1",
|
|
25
|
+
"NAudio.WinForms": "2.2.1",
|
|
26
|
+
"NAudio.WinMM": "2.2.1"
|
|
27
|
+
},
|
|
28
|
+
"runtime": {
|
|
29
|
+
"lib/net6.0-windows7.0/NAudio.dll": {
|
|
30
|
+
"assemblyVersion": "2.2.1.0",
|
|
31
|
+
"fileVersion": "2.2.1.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"NAudio.Asio/2.2.1": {
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"NAudio.Core": "2.2.1"
|
|
38
|
+
},
|
|
39
|
+
"runtime": {
|
|
40
|
+
"lib/netstandard2.0/NAudio.Asio.dll": {
|
|
41
|
+
"assemblyVersion": "2.2.1.0",
|
|
42
|
+
"fileVersion": "2.2.1.0"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"NAudio.Core/2.2.1": {
|
|
47
|
+
"runtime": {
|
|
48
|
+
"lib/netstandard2.0/NAudio.Core.dll": {
|
|
49
|
+
"assemblyVersion": "2.2.1.0",
|
|
50
|
+
"fileVersion": "2.2.1.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"NAudio.Midi/2.2.1": {
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"NAudio.Core": "2.2.1"
|
|
57
|
+
},
|
|
58
|
+
"runtime": {
|
|
59
|
+
"lib/netstandard2.0/NAudio.Midi.dll": {
|
|
60
|
+
"assemblyVersion": "2.2.1.0",
|
|
61
|
+
"fileVersion": "2.2.1.0"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"NAudio.Wasapi/2.2.1": {
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"NAudio.Core": "2.2.1"
|
|
68
|
+
},
|
|
69
|
+
"runtime": {
|
|
70
|
+
"lib/netstandard2.0/NAudio.Wasapi.dll": {
|
|
71
|
+
"assemblyVersion": "2.2.1.0",
|
|
72
|
+
"fileVersion": "2.2.1.0"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"NAudio.WinForms/2.2.1": {
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"NAudio.WinMM": "2.2.1"
|
|
79
|
+
},
|
|
80
|
+
"runtime": {
|
|
81
|
+
"lib/netcoreapp3.1/NAudio.WinForms.dll": {
|
|
82
|
+
"assemblyVersion": "2.2.1.0",
|
|
83
|
+
"fileVersion": "2.2.1.0"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"NAudio.WinMM/2.2.1": {
|
|
88
|
+
"dependencies": {
|
|
89
|
+
"NAudio.Core": "2.2.1"
|
|
90
|
+
},
|
|
91
|
+
"runtime": {
|
|
92
|
+
"lib/netstandard2.0/NAudio.WinMM.dll": {
|
|
93
|
+
"assemblyVersion": "2.2.1.0",
|
|
94
|
+
"fileVersion": "2.2.1.0"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"SharpGen.Runtime/2.4.2-beta": {
|
|
99
|
+
"runtime": {
|
|
100
|
+
"lib/net9.0/SharpGen.Runtime.dll": {
|
|
101
|
+
"assemblyVersion": "2.4.2.0",
|
|
102
|
+
"fileVersion": "2.4.2.0"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"SharpGen.Runtime.COM/2.4.2-beta": {
|
|
107
|
+
"dependencies": {
|
|
108
|
+
"SharpGen.Runtime": "2.4.2-beta"
|
|
109
|
+
},
|
|
110
|
+
"runtime": {
|
|
111
|
+
"lib/net9.0/SharpGen.Runtime.COM.dll": {
|
|
112
|
+
"assemblyVersion": "2.4.2.0",
|
|
113
|
+
"fileVersion": "2.4.2.0"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"Vortice.Direct3D11/3.8.3": {
|
|
118
|
+
"dependencies": {
|
|
119
|
+
"SharpGen.Runtime": "2.4.2-beta",
|
|
120
|
+
"Vortice.DXGI": "3.8.3"
|
|
121
|
+
},
|
|
122
|
+
"runtime": {
|
|
123
|
+
"lib/net9.0/Vortice.Direct3D11.dll": {
|
|
124
|
+
"assemblyVersion": "3.8.3.0",
|
|
125
|
+
"fileVersion": "3.8.3.0"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"Vortice.DirectX/3.8.3": {
|
|
130
|
+
"dependencies": {
|
|
131
|
+
"SharpGen.Runtime": "2.4.2-beta",
|
|
132
|
+
"SharpGen.Runtime.COM": "2.4.2-beta",
|
|
133
|
+
"Vortice.Mathematics": "2.1.0"
|
|
134
|
+
},
|
|
135
|
+
"runtime": {
|
|
136
|
+
"lib/net9.0/Vortice.DirectX.dll": {
|
|
137
|
+
"assemblyVersion": "3.8.3.0",
|
|
138
|
+
"fileVersion": "3.8.3.0"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"Vortice.DXGI/3.8.3": {
|
|
143
|
+
"dependencies": {
|
|
144
|
+
"SharpGen.Runtime": "2.4.2-beta",
|
|
145
|
+
"Vortice.DirectX": "3.8.3"
|
|
146
|
+
},
|
|
147
|
+
"runtime": {
|
|
148
|
+
"lib/net9.0/Vortice.DXGI.dll": {
|
|
149
|
+
"assemblyVersion": "3.8.3.0",
|
|
150
|
+
"fileVersion": "3.8.3.0"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"Vortice.Mathematics/2.1.0": {
|
|
155
|
+
"runtime": {
|
|
156
|
+
"lib/net9.0/Vortice.Mathematics.dll": {
|
|
157
|
+
"assemblyVersion": "2.1.0.0",
|
|
158
|
+
"fileVersion": "2.1.0.0"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
14
161
|
}
|
|
15
162
|
}
|
|
16
163
|
},
|
|
@@ -19,6 +166,97 @@
|
|
|
19
166
|
"type": "project",
|
|
20
167
|
"serviceable": false,
|
|
21
168
|
"sha512": ""
|
|
169
|
+
},
|
|
170
|
+
"NAudio/2.2.1": {
|
|
171
|
+
"type": "package",
|
|
172
|
+
"serviceable": true,
|
|
173
|
+
"sha512": "sha512-c0DzwiyyklM0TP39Y7RObwO3QkWecgM6H60ikiEnsV/aEAJPbj5MFCLaD8BSfKuZe0HGuh9GRGWWlJmSxDc9MA==",
|
|
174
|
+
"path": "naudio/2.2.1",
|
|
175
|
+
"hashPath": "naudio.2.2.1.nupkg.sha512"
|
|
176
|
+
},
|
|
177
|
+
"NAudio.Asio/2.2.1": {
|
|
178
|
+
"type": "package",
|
|
179
|
+
"serviceable": true,
|
|
180
|
+
"sha512": "sha512-hQglyOT5iT3XuGpBP8ZG0+aoqwRfidHjTNehpoWwX0g6KJEgtH2VaqM2nuJ2mheKZa/IBqB4YQTZVvrIapzfOA==",
|
|
181
|
+
"path": "naudio.asio/2.2.1",
|
|
182
|
+
"hashPath": "naudio.asio.2.2.1.nupkg.sha512"
|
|
183
|
+
},
|
|
184
|
+
"NAudio.Core/2.2.1": {
|
|
185
|
+
"type": "package",
|
|
186
|
+
"serviceable": true,
|
|
187
|
+
"sha512": "sha512-GgkdP6K/7FqXFo7uHvoqGZTJvW4z8g2IffhOO4JHaLzKCdDOUEzVKtveoZkCuUX8eV2HAINqi7VFqlFndrnz/g==",
|
|
188
|
+
"path": "naudio.core/2.2.1",
|
|
189
|
+
"hashPath": "naudio.core.2.2.1.nupkg.sha512"
|
|
190
|
+
},
|
|
191
|
+
"NAudio.Midi/2.2.1": {
|
|
192
|
+
"type": "package",
|
|
193
|
+
"serviceable": true,
|
|
194
|
+
"sha512": "sha512-6r23ylGo5aeP02WFXsPquz0T0hFJWyh+7t++tz19tc3Kr38NHm+Z9j+FiAv+xkH8tZqXJqus9Q8p6u7bidIgbw==",
|
|
195
|
+
"path": "naudio.midi/2.2.1",
|
|
196
|
+
"hashPath": "naudio.midi.2.2.1.nupkg.sha512"
|
|
197
|
+
},
|
|
198
|
+
"NAudio.Wasapi/2.2.1": {
|
|
199
|
+
"type": "package",
|
|
200
|
+
"serviceable": true,
|
|
201
|
+
"sha512": "sha512-lFfXoqacZZe0WqNChJgGYI+XV/n/61LzPHT3C1CJp4khoxeo2sziyX5wzNYWeCMNbsWxFvT3b3iXeY1UYjBhZw==",
|
|
202
|
+
"path": "naudio.wasapi/2.2.1",
|
|
203
|
+
"hashPath": "naudio.wasapi.2.2.1.nupkg.sha512"
|
|
204
|
+
},
|
|
205
|
+
"NAudio.WinForms/2.2.1": {
|
|
206
|
+
"type": "package",
|
|
207
|
+
"serviceable": true,
|
|
208
|
+
"sha512": "sha512-DlDkewY1myY0A+3NrYRJD+MZhZV0yy1mNF6dckB27IQ9XCs/My5Ip8BZcoSHOsaPSe2GAjvoaDnk6N9w8xTv7w==",
|
|
209
|
+
"path": "naudio.winforms/2.2.1",
|
|
210
|
+
"hashPath": "naudio.winforms.2.2.1.nupkg.sha512"
|
|
211
|
+
},
|
|
212
|
+
"NAudio.WinMM/2.2.1": {
|
|
213
|
+
"type": "package",
|
|
214
|
+
"serviceable": true,
|
|
215
|
+
"sha512": "sha512-xFHRFwH4x6aq3IxRbewvO33ugJRvZFEOfO62i7uQJRUNW2cnu6BeBTHUS0JD5KBucZbHZaYqxQG8dwZ47ezQuQ==",
|
|
216
|
+
"path": "naudio.winmm/2.2.1",
|
|
217
|
+
"hashPath": "naudio.winmm.2.2.1.nupkg.sha512"
|
|
218
|
+
},
|
|
219
|
+
"SharpGen.Runtime/2.4.2-beta": {
|
|
220
|
+
"type": "package",
|
|
221
|
+
"serviceable": true,
|
|
222
|
+
"sha512": "sha512-niTtWAUov1F7wZGAlVeEvW+Tnqvg5yTmhI7rxmYu2Utoyu2TbC9tWWpUpMs0PQg5lu5svoYpCAztNjxCqMFP/w==",
|
|
223
|
+
"path": "sharpgen.runtime/2.4.2-beta",
|
|
224
|
+
"hashPath": "sharpgen.runtime.2.4.2-beta.nupkg.sha512"
|
|
225
|
+
},
|
|
226
|
+
"SharpGen.Runtime.COM/2.4.2-beta": {
|
|
227
|
+
"type": "package",
|
|
228
|
+
"serviceable": true,
|
|
229
|
+
"sha512": "sha512-9lxDFMiepqo3lJQzMSjECCIONeCc2f3Drokgj6HtrTLZcJSftNgcLbD6/iXYj2iphkwgrZb1oLsDOZxoFZkawQ==",
|
|
230
|
+
"path": "sharpgen.runtime.com/2.4.2-beta",
|
|
231
|
+
"hashPath": "sharpgen.runtime.com.2.4.2-beta.nupkg.sha512"
|
|
232
|
+
},
|
|
233
|
+
"Vortice.Direct3D11/3.8.3": {
|
|
234
|
+
"type": "package",
|
|
235
|
+
"serviceable": true,
|
|
236
|
+
"sha512": "sha512-JgFUswu2mgrSwcd0KRF2AnfeE5VbMEgcicmxPD1g2yXyomPIHbnX3wldBNHPOzzD0URC1WJ/pO1ymfi3imZwvg==",
|
|
237
|
+
"path": "vortice.direct3d11/3.8.3",
|
|
238
|
+
"hashPath": "vortice.direct3d11.3.8.3.nupkg.sha512"
|
|
239
|
+
},
|
|
240
|
+
"Vortice.DirectX/3.8.3": {
|
|
241
|
+
"type": "package",
|
|
242
|
+
"serviceable": true,
|
|
243
|
+
"sha512": "sha512-nKwSavv0w5rDF7prSefqAVPDcTyqrfZxKFMVfttiXPfm62VdA/1d+b3PhCZpW4xO7jXczXDwjQdWgD1zGsvM8w==",
|
|
244
|
+
"path": "vortice.directx/3.8.3",
|
|
245
|
+
"hashPath": "vortice.directx.3.8.3.nupkg.sha512"
|
|
246
|
+
},
|
|
247
|
+
"Vortice.DXGI/3.8.3": {
|
|
248
|
+
"type": "package",
|
|
249
|
+
"serviceable": true,
|
|
250
|
+
"sha512": "sha512-MbAUnTeQ6WD99ctAdrj5CQO2I7oaax0Kt2eVdWSUj0bYP9Ed0726+s7dIHe4+tqhpmINW/dcPt0mNtc72o+E0w==",
|
|
251
|
+
"path": "vortice.dxgi/3.8.3",
|
|
252
|
+
"hashPath": "vortice.dxgi.3.8.3.nupkg.sha512"
|
|
253
|
+
},
|
|
254
|
+
"Vortice.Mathematics/2.1.0": {
|
|
255
|
+
"type": "package",
|
|
256
|
+
"serviceable": true,
|
|
257
|
+
"sha512": "sha512-KK+SjNSuKdP+zbavekubi+vaeb1Jo4k87ZF6CMkVWjr6RjJwc8peVtmgzXXDIMy4ZC3ZISyk3llY3q65ISOkBQ==",
|
|
258
|
+
"path": "vortice.mathematics/2.1.0",
|
|
259
|
+
"hashPath": "vortice.mathematics.2.1.0.nupkg.sha512"
|
|
22
260
|
}
|
|
23
261
|
}
|
|
24
262
|
}
|
|
Binary file
|
|
Binary file
|
package/remote-hub.js
CHANGED
|
@@ -60,6 +60,28 @@ const REMOTE_FRAME_MODE_PROFILES = Object.freeze({
|
|
|
60
60
|
modeVersion: 1,
|
|
61
61
|
implemented: true
|
|
62
62
|
}),
|
|
63
|
+
'mode3-h264-hw': Object.freeze({
|
|
64
|
+
mode: 'mode3-h264-hw',
|
|
65
|
+
label: 'Mode 3 H.264 Control',
|
|
66
|
+
transport: 'ws-binary',
|
|
67
|
+
encoding: 'video',
|
|
68
|
+
codec: 'h264',
|
|
69
|
+
compression: 'video/h264',
|
|
70
|
+
profile: 'mode3-h264-hardware-v1',
|
|
71
|
+
modeVersion: 3,
|
|
72
|
+
implemented: true
|
|
73
|
+
}),
|
|
74
|
+
'mode4-h264-atlas': Object.freeze({
|
|
75
|
+
mode: 'mode4-h264-atlas',
|
|
76
|
+
label: 'Mode 4 H.264 Atlas Wall',
|
|
77
|
+
transport: 'ws-binary',
|
|
78
|
+
encoding: 'video',
|
|
79
|
+
codec: 'h264',
|
|
80
|
+
compression: 'video/h264',
|
|
81
|
+
profile: 'mode4-h264-atlas-v1',
|
|
82
|
+
modeVersion: 4,
|
|
83
|
+
implemented: true
|
|
84
|
+
}),
|
|
63
85
|
'video-codec': Object.freeze({
|
|
64
86
|
mode: 'video-codec',
|
|
65
87
|
label: 'Video Codec Stream',
|
|
@@ -81,6 +103,12 @@ const REMOTE_FRAME_MODE_ALIASES = new Map([
|
|
|
81
103
|
['remotequality', 'remote-quality'],
|
|
82
104
|
['remote_quality', 'remote-quality'],
|
|
83
105
|
['remote-quality', 'remote-quality'],
|
|
106
|
+
['mode3-h264', 'mode3-h264-hw'],
|
|
107
|
+
['mode3-h264-hw', 'mode3-h264-hw'],
|
|
108
|
+
['h264', 'mode3-h264-hw'],
|
|
109
|
+
['mode4', 'mode4-h264-atlas'],
|
|
110
|
+
['mode4-h264-atlas', 'mode4-h264-atlas'],
|
|
111
|
+
['atlas', 'mode4-h264-atlas'],
|
|
84
112
|
['thumb', 'thumbnail'],
|
|
85
113
|
['thumbnail', 'thumbnail'],
|
|
86
114
|
['video', 'video-codec'],
|
|
@@ -443,6 +471,9 @@ function normalizeRemoteInputEvent(value = {}) {
|
|
|
443
471
|
code: safeString(input.code || input.Code, 80),
|
|
444
472
|
text: safeText(input.text || input.Text, 256),
|
|
445
473
|
repeat: input.repeat === true || input.Repeat === true,
|
|
474
|
+
inputSeq: Number.isFinite(Number(input.inputSeq ?? input.InputSeq)) ? Math.max(0, Math.floor(Number(input.inputSeq ?? input.InputSeq))) : 0,
|
|
475
|
+
requestAck: input.requestAck === true || input.RequestAck === true,
|
|
476
|
+
fireAndForget: input.fireAndForget === true || input.FireAndForget === true,
|
|
446
477
|
controlLeaseId: safeString(input.controlLeaseId || input.ControlLeaseId, 128),
|
|
447
478
|
issuedAt: safeString(input.issuedAt || input.IssuedAt, 80)
|
|
448
479
|
};
|
|
@@ -1399,7 +1430,7 @@ export function createRemoteHub(options = {}) {
|
|
|
1399
1430
|
transferProtocol: descriptor.transferProtocol,
|
|
1400
1431
|
transferProtocolVersion: descriptor.transferProtocolVersion,
|
|
1401
1432
|
handshake: descriptor.handshake,
|
|
1402
|
-
fps: clampNumber(options.fps, 1,
|
|
1433
|
+
fps: clampNumber(options.fps, 1, 30, mode === 'remote-fast' ? 20 : 1),
|
|
1403
1434
|
capturedAt: now,
|
|
1404
1435
|
receivedAt: now,
|
|
1405
1436
|
byteLength: 68,
|
|
@@ -2416,6 +2447,14 @@ export function createRemoteHub(options = {}) {
|
|
|
2416
2447
|
transferProtocolVersion: transfer.transferProtocolVersion,
|
|
2417
2448
|
handshake: transfer.handshake,
|
|
2418
2449
|
fps: Number.isFinite(Number(message.fps)) ? Number(message.fps) : device.activeLiveStream.fps,
|
|
2450
|
+
streamPurpose: safeString(message.streamPurpose, 32),
|
|
2451
|
+
monitorIndex: Number.isFinite(Number(message.monitorIndex)) ? Number(message.monitorIndex) : 0,
|
|
2452
|
+
h264Format: safeString(message.h264Format, 24),
|
|
2453
|
+
isKeyFrame: message.isKeyFrame === true,
|
|
2454
|
+
chunkType: safeString(message.chunkType, 24),
|
|
2455
|
+
timestampUs: Number.isFinite(Number(message.timestampUs)) ? Number(message.timestampUs) : 0,
|
|
2456
|
+
durationUs: Number.isFinite(Number(message.durationUs)) ? Number(message.durationUs) : 0,
|
|
2457
|
+
streamFrameSeq: Number.isFinite(Number(message.streamFrameSeq)) ? Number(message.streamFrameSeq) : frameSeq,
|
|
2419
2458
|
capturedAt,
|
|
2420
2459
|
receivedAt: device.lastSeenAt,
|
|
2421
2460
|
byteLength,
|
|
@@ -3221,7 +3260,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3221
3260
|
|
|
3222
3261
|
const now = new Date().toISOString();
|
|
3223
3262
|
const streamId = safeString(options.streamId, 128) || `live-${Date.now()}`;
|
|
3224
|
-
const fps = clampNumber(options.fps, 1,
|
|
3263
|
+
const fps = clampNumber(options.fps, 1, 30, 20);
|
|
3225
3264
|
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
3226
3265
|
const transfer = buildRemoteFrameTransferDescriptor(options.mode || DEFAULT_REMOTE_FRAME_MODE);
|
|
3227
3266
|
device.counters.commandsSent += 1;
|
|
@@ -3275,7 +3314,7 @@ export function createRemoteHub(options = {}) {
|
|
|
3275
3314
|
|
|
3276
3315
|
const now = new Date().toISOString();
|
|
3277
3316
|
const streamId = safeString(options.streamId, 128) || `live-${Date.now()}`;
|
|
3278
|
-
const fps = clampNumber(options.fps, 1,
|
|
3317
|
+
const fps = clampNumber(options.fps, 1, 30, 20);
|
|
3279
3318
|
const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
|
|
3280
3319
|
const transfer = buildRemoteFrameTransferDescriptor(options.mode || DEFAULT_REMOTE_FRAME_MODE);
|
|
3281
3320
|
const result = sendCommand(deviceId, {
|
package/server.js
CHANGED
|
@@ -2454,7 +2454,7 @@ const remoteInputWsDiagnostics = {
|
|
|
2454
2454
|
lastError: ''
|
|
2455
2455
|
};
|
|
2456
2456
|
const REMOTE_FRAME_WS_AUTO_START_LIMIT = 120;
|
|
2457
|
-
const REMOTE_FRAME_WS_DEFAULT_FPS =
|
|
2457
|
+
const REMOTE_FRAME_WS_DEFAULT_FPS = 20;
|
|
2458
2458
|
const REMOTE_FRAME_WS_DEFAULT_MAX_WIDTH = 960;
|
|
2459
2459
|
const REMOTE_FRAME_WS_DEFAULT_MAX_HEIGHT = 540;
|
|
2460
2460
|
const REMOTE_FRAME_WS_DEFAULT_QUALITY = 60;
|
|
@@ -2563,7 +2563,10 @@ function updateRemoteFrameClientSubscription(ws, payload = {}) {
|
|
|
2563
2563
|
timestamp: ws.remoteFrameSubscriptionUpdatedAt,
|
|
2564
2564
|
deviceIds,
|
|
2565
2565
|
mode: deviceIds.length > 0 ? 'selected-devices' : 'all-devices',
|
|
2566
|
-
autoStartLive: ws.remoteFrameAutoStartLive === true
|
|
2566
|
+
autoStartLive: ws.remoteFrameAutoStartLive === true,
|
|
2567
|
+
streamPurpose: ws.remoteFrameAutoStartOptions.streamPurpose,
|
|
2568
|
+
fps: ws.remoteFrameAutoStartOptions.fps,
|
|
2569
|
+
frameMode: ws.remoteFrameAutoStartOptions.frameMode
|
|
2567
2570
|
});
|
|
2568
2571
|
maybeAutoStartRemoteFrameLiveStreams(ws, deviceIds);
|
|
2569
2572
|
}
|
|
@@ -2579,13 +2582,16 @@ function clampRemoteFrameWsNumber(value, min, max, fallback) {
|
|
|
2579
2582
|
|
|
2580
2583
|
function normalizeRemoteFrameWsLiveOptions(payload = {}) {
|
|
2581
2584
|
const mode = String(payload.frameMode || payload.mode || 'remote-fast').trim() || 'remote-fast';
|
|
2585
|
+
const streamPurpose = String(payload.streamPurpose || '').trim().toLowerCase();
|
|
2586
|
+
const defaultFps = streamPurpose === 'control' || mode === 'mode3-h264-hw' ? 30 : REMOTE_FRAME_WS_DEFAULT_FPS;
|
|
2582
2587
|
return {
|
|
2583
|
-
fps: clampRemoteFrameWsNumber(payload.fps, 1,
|
|
2588
|
+
fps: clampRemoteFrameWsNumber(payload.fps, 1, 30, defaultFps),
|
|
2584
2589
|
maxWidth: clampRemoteFrameWsNumber(payload.maxWidth, 320, 2560, REMOTE_FRAME_WS_DEFAULT_MAX_WIDTH),
|
|
2585
2590
|
maxHeight: clampRemoteFrameWsNumber(payload.maxHeight, 180, 1440, REMOTE_FRAME_WS_DEFAULT_MAX_HEIGHT),
|
|
2586
2591
|
quality: clampRemoteFrameWsNumber(payload.quality, 20, 95, REMOTE_FRAME_WS_DEFAULT_QUALITY),
|
|
2587
2592
|
mode,
|
|
2588
|
-
frameMode: mode
|
|
2593
|
+
frameMode: mode,
|
|
2594
|
+
streamPurpose: streamPurpose || (mode === 'mode3-h264-hw' ? 'control' : 'wall')
|
|
2589
2595
|
};
|
|
2590
2596
|
}
|
|
2591
2597
|
|
|
@@ -2716,7 +2722,17 @@ function buildRemoteFrameBinaryPacket(frameEvent) {
|
|
|
2716
2722
|
transport: frame.transport || '',
|
|
2717
2723
|
contentHash: frame.contentHash || '',
|
|
2718
2724
|
captureMs: Number(frame.captureMs || 0) || 0,
|
|
2719
|
-
sameContentStreak: Number(frame.sameContentStreak || 0) || 0
|
|
2725
|
+
sameContentStreak: Number(frame.sameContentStreak || 0) || 0,
|
|
2726
|
+
streamPurpose: frame.streamPurpose || '',
|
|
2727
|
+
monitorIndex: Number.isFinite(Number(frame.monitorIndex)) ? Number(frame.monitorIndex) : 0,
|
|
2728
|
+
codec: frame.codec || '',
|
|
2729
|
+
h264Format: frame.h264Format || '',
|
|
2730
|
+
isKeyFrame: frame.isKeyFrame === true,
|
|
2731
|
+
chunkType: frame.chunkType || '',
|
|
2732
|
+
timestampUs: Number.isFinite(Number(frame.timestampUs)) ? Number(frame.timestampUs) : 0,
|
|
2733
|
+
durationUs: Number.isFinite(Number(frame.durationUs)) ? Number(frame.durationUs) : 0,
|
|
2734
|
+
streamFrameSeq: Number.isFinite(Number(frame.streamFrameSeq)) ? Number(frame.streamFrameSeq) : 0,
|
|
2735
|
+
commandId: frame.commandId || ''
|
|
2720
2736
|
};
|
|
2721
2737
|
const metaBuffer = Buffer.from(JSON.stringify(metadata), 'utf8');
|
|
2722
2738
|
const header = Buffer.allocUnsafe(4);
|
|
@@ -12805,7 +12821,7 @@ app.get('/api/remote/devices/:deviceId/live/frame', (req, res) => {
|
|
|
12805
12821
|
app.post('/api/remote/devices/:deviceId/live/start', (req, res) => {
|
|
12806
12822
|
res.json(remoteHub.startLiveStream(req.params.deviceId, {
|
|
12807
12823
|
streamId: req.body?.streamId,
|
|
12808
|
-
mode: req.body?.mode,
|
|
12824
|
+
mode: req.body?.frameMode || req.body?.mode || 'mode3-h264-hw',
|
|
12809
12825
|
fps: req.body?.fps,
|
|
12810
12826
|
maxWidth: req.body?.maxWidth,
|
|
12811
12827
|
maxHeight: req.body?.maxHeight,
|
|
@@ -3697,6 +3697,55 @@ html body .css3d-resolution-wrapper:not(.lod-low).node-type-embed.selected-media
|
|
|
3697
3697
|
0 0 0 1px rgba(var(--node-selection-glow-rgb-soft), 0.12) !important;
|
|
3698
3698
|
}
|
|
3699
3699
|
|
|
3700
|
+
/* Selected video playback is an explicit compact action; native controls stay off. */
|
|
3701
|
+
.mind-map-video-playback-control {
|
|
3702
|
+
position: absolute;
|
|
3703
|
+
left: 50%;
|
|
3704
|
+
bottom: 10px;
|
|
3705
|
+
z-index: 8;
|
|
3706
|
+
display: none;
|
|
3707
|
+
align-items: center;
|
|
3708
|
+
gap: 6px;
|
|
3709
|
+
min-height: 28px;
|
|
3710
|
+
padding: 5px 10px;
|
|
3711
|
+
border: 1px solid rgba(255, 255, 255, 0.34);
|
|
3712
|
+
border-radius: 999px;
|
|
3713
|
+
background: rgba(15, 23, 42, 0.82);
|
|
3714
|
+
color: #f8fafc;
|
|
3715
|
+
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.24);
|
|
3716
|
+
font: 600 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
3717
|
+
letter-spacing: 0.01em;
|
|
3718
|
+
pointer-events: auto;
|
|
3719
|
+
cursor: pointer;
|
|
3720
|
+
transform: translateX(-50%);
|
|
3721
|
+
backdrop-filter: blur(8px);
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3724
|
+
.mind-map-video-playback-control__icon {
|
|
3725
|
+
display: inline-flex;
|
|
3726
|
+
min-width: 10px;
|
|
3727
|
+
align-items: center;
|
|
3728
|
+
justify-content: center;
|
|
3729
|
+
font-size: 10px;
|
|
3730
|
+
}
|
|
3731
|
+
|
|
3732
|
+
.css3d-resolution-wrapper.node-type-video.selected .mind-map-video-playback-control,
|
|
3733
|
+
.css3d-resolution-wrapper.node-type-video.selected-media-safe .mind-map-video-playback-control {
|
|
3734
|
+
display: inline-flex;
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
.css3d-resolution-wrapper.node-type-video.lod-low:not(.selected):not(.selected-media-safe) .mind-map-video-playback-control {
|
|
3738
|
+
display: none !important;
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
.mind-map-video-playback-control:hover,
|
|
3742
|
+
.mind-map-video-playback-control:focus-visible {
|
|
3743
|
+
background: rgba(15, 23, 42, 0.94);
|
|
3744
|
+
border-color: rgba(255, 255, 255, 0.62);
|
|
3745
|
+
outline: 2px solid rgba(96, 165, 250, 0.85);
|
|
3746
|
+
outline-offset: 2px;
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3700
3749
|
html body .css3d-resolution-wrapper:not(.lod-low) > .map-node-bubble.selected,
|
|
3701
3750
|
html body .css3d-resolution-wrapper:not(.lod-low) > .map-node-note.selected,
|
|
3702
3751
|
html body .css3d-resolution-wrapper:not(.lod-low) > .map-node-note:focus-within,
|