livedesk 0.1.223 → 0.1.225
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 +69 -1
- package/hub/src/server.js +39 -16
- package/package.json +2 -2
- package/web/dist/assets/index-DTVXLmHj.js +15 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-DKIUzgwS.js +0 -15
package/hub/src/remote-hub.js
CHANGED
|
@@ -672,6 +672,7 @@ function createDeviceCounters(overrides = {}) {
|
|
|
672
672
|
audioStreamsStopped: 0,
|
|
673
673
|
audioFramesReceived: 0,
|
|
674
674
|
audioFramesDropped: 0,
|
|
675
|
+
audioStatusReceived: 0,
|
|
675
676
|
tasksQueued: 0,
|
|
676
677
|
taskResultsReceived: 0,
|
|
677
678
|
taskResultsFailed: 0,
|
|
@@ -958,6 +959,7 @@ function serializeDevice(device, options = {}) {
|
|
|
958
959
|
byteLength: device.latestAudioFrame.byteLength
|
|
959
960
|
}
|
|
960
961
|
: null,
|
|
962
|
+
latestAudioStatus: device.latestAudioStatus ? { ...device.latestAudioStatus } : null,
|
|
961
963
|
latestTask: device.latestTask ? { ...device.latestTask } : null,
|
|
962
964
|
synthetic: device.synthetic === true,
|
|
963
965
|
recentTasks: Array.isArray(device.recentTasks)
|
|
@@ -2456,6 +2458,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2456
2458
|
activeLiveStream: null,
|
|
2457
2459
|
activeAudioStream: null,
|
|
2458
2460
|
latestAudioFrame: null,
|
|
2461
|
+
latestAudioStatus: null,
|
|
2459
2462
|
latestTask,
|
|
2460
2463
|
recentTasks: latestTask ? [latestTask] : [],
|
|
2461
2464
|
pendingTaskCommands: new Map(),
|
|
@@ -2621,6 +2624,7 @@ export function createRemoteHub(options = {}) {
|
|
|
2621
2624
|
activeLiveStream: null,
|
|
2622
2625
|
activeAudioStream: null,
|
|
2623
2626
|
latestAudioFrame: null,
|
|
2627
|
+
latestAudioStatus: null,
|
|
2624
2628
|
latestTask: null,
|
|
2625
2629
|
recentTasks: [],
|
|
2626
2630
|
pendingTaskCommands: new Map(),
|
|
@@ -3590,6 +3594,50 @@ export function createRemoteHub(options = {}) {
|
|
|
3590
3594
|
return true;
|
|
3591
3595
|
}
|
|
3592
3596
|
|
|
3597
|
+
function applyAudioStatus(device, message, framePayload, transport = 'binary') {
|
|
3598
|
+
if (!Buffer.isBuffer(framePayload) || framePayload.length < 1) {
|
|
3599
|
+
device.counters.audioFramesDropped += 1;
|
|
3600
|
+
return false;
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
const streamId = safeString(message.streamId, 128) || device.activeAudioStream?.streamId || 'audio';
|
|
3604
|
+
const status = {
|
|
3605
|
+
streamId,
|
|
3606
|
+
commandId: safeString(message.commandId, 128),
|
|
3607
|
+
captureAlive: message.captureAlive === true,
|
|
3608
|
+
helperAlive: message.helperAlive === true,
|
|
3609
|
+
helperPid: Number(message.helperPid || 0) || 0,
|
|
3610
|
+
captureGeneration: Number(message.captureGeneration || 0) || 0,
|
|
3611
|
+
lastPcmAtEpochMs: Number(message.lastPcmAtEpochMs || 0) || 0,
|
|
3612
|
+
silentForMs: Math.max(0, Number(message.silentForMs || 0) || 0),
|
|
3613
|
+
restartCount: Math.max(0, Number(message.restartCount || 0) || 0),
|
|
3614
|
+
error: safeString(message.error, 500),
|
|
3615
|
+
statusAtEpochMs: Number(message.statusAtEpochMs || 0) || Date.now(),
|
|
3616
|
+
receivedAt: new Date().toISOString(),
|
|
3617
|
+
transport
|
|
3618
|
+
};
|
|
3619
|
+
device.latestAudioStatus = status;
|
|
3620
|
+
if (device.activeAudioStream && device.activeAudioStream.streamId === streamId) {
|
|
3621
|
+
device.activeAudioStream.lastStatusAt = status.receivedAt;
|
|
3622
|
+
device.activeAudioStream.captureAlive = status.captureAlive;
|
|
3623
|
+
device.activeAudioStream.helperAlive = status.helperAlive;
|
|
3624
|
+
device.activeAudioStream.captureGeneration = status.captureGeneration;
|
|
3625
|
+
device.activeAudioStream.lastPcmAtEpochMs = status.lastPcmAtEpochMs;
|
|
3626
|
+
device.activeAudioStream.silentForMs = status.silentForMs;
|
|
3627
|
+
device.activeAudioStream.restartCount = status.restartCount;
|
|
3628
|
+
device.activeAudioStream.audioError = status.error;
|
|
3629
|
+
}
|
|
3630
|
+
device.counters.audioStatusReceived += 1;
|
|
3631
|
+
emitAudio({
|
|
3632
|
+
deviceId: device.deviceId,
|
|
3633
|
+
audioStatus: true,
|
|
3634
|
+
frame: status,
|
|
3635
|
+
payload: framePayload,
|
|
3636
|
+
byteLength: framePayload.length
|
|
3637
|
+
});
|
|
3638
|
+
return true;
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3593
3641
|
function handleAgentBinaryFrame(socket, state, header, framePayload) {
|
|
3594
3642
|
if (!state.authenticated || !state.device) {
|
|
3595
3643
|
writeJsonLine(socket, { type: 'error', error: 'hello-required' });
|
|
@@ -3632,6 +3680,11 @@ export function createRemoteHub(options = {}) {
|
|
|
3632
3680
|
return;
|
|
3633
3681
|
}
|
|
3634
3682
|
|
|
3683
|
+
if (frameKind === 'audio-status' || header.type === 'audio.status.binary') {
|
|
3684
|
+
applyAudioStatus(device, header, framePayload, 'binary');
|
|
3685
|
+
return;
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3635
3688
|
emitRemoteEvent('RemoteAgentMessageIgnored', device, {
|
|
3636
3689
|
messageType: safeString(header.type, 80),
|
|
3637
3690
|
frameKind
|
|
@@ -3650,7 +3703,12 @@ export function createRemoteHub(options = {}) {
|
|
|
3650
3703
|
&& header.isKeyFrame !== true
|
|
3651
3704
|
&& chunkType !== 'key';
|
|
3652
3705
|
});
|
|
3653
|
-
const
|
|
3706
|
+
const nonStatusIndex = state.binaryQueue.findIndex(item => {
|
|
3707
|
+
const header = item?.header || {};
|
|
3708
|
+
const frameKind = safeString(header.frameKind || header.kind || header.frameType || '', 40).toLowerCase();
|
|
3709
|
+
return frameKind !== 'audio-status' && header.type !== 'audio.status.binary';
|
|
3710
|
+
});
|
|
3711
|
+
const index = deltaIndex >= 0 ? deltaIndex : nonStatusIndex >= 0 ? nonStatusIndex : 0;
|
|
3654
3712
|
state.binaryQueue.splice(index, 1);
|
|
3655
3713
|
state.binaryQueueDrops = Number(state.binaryQueueDrops || 0) + 1;
|
|
3656
3714
|
}
|
|
@@ -3829,6 +3887,16 @@ export function createRemoteHub(options = {}) {
|
|
|
3829
3887
|
hubAcknowledgedAtEpochMs: Date.now()
|
|
3830
3888
|
});
|
|
3831
3889
|
}
|
|
3890
|
+
if (message.type === 'input.error') {
|
|
3891
|
+
emitEvent('RemoteInputError', {
|
|
3892
|
+
deviceId: device.deviceId,
|
|
3893
|
+
inputSeq: Number(message.inputSeq || 0) || 0,
|
|
3894
|
+
inputType: safeString(message.inputType, 48),
|
|
3895
|
+
error: safeString(message.error, 600) || 'remote-input-failed',
|
|
3896
|
+
failedAtEpochMs: Number(message.failedAtEpochMs || 0) || 0,
|
|
3897
|
+
hubAcknowledgedAtEpochMs: Date.now()
|
|
3898
|
+
});
|
|
3899
|
+
}
|
|
3832
3900
|
return;
|
|
3833
3901
|
}
|
|
3834
3902
|
if (state.frameOnly) {
|
package/hub/src/server.js
CHANGED
|
@@ -73,15 +73,24 @@ function readPositiveIntegerEnv(name, fallback) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
function handleRemoteHubEvent(type, event) {
|
|
76
|
-
if (type === 'RemoteInputApplied') {
|
|
76
|
+
if (type === 'RemoteInputApplied') {
|
|
77
77
|
for (const ws of inputClients) {
|
|
78
78
|
sendJson(ws, {
|
|
79
79
|
type: 'RemoteInputApplied',
|
|
80
80
|
...event
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (type === 'RemoteInputError') {
|
|
86
|
+
for (const ws of inputClients) {
|
|
87
|
+
sendJson(ws, {
|
|
88
|
+
type: 'RemoteInputError',
|
|
89
|
+
...event
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
85
94
|
if (type === 'RemoteDeviceConnected' || type === 'RemoteDeviceDisconnected') {
|
|
86
95
|
connectedDeviceCount = Number(remoteHub.getStatus({ includeSecrets: false }).connectedDeviceCount || 0);
|
|
87
96
|
}
|
|
@@ -1345,24 +1354,38 @@ function buildRemoteFrameBinaryPacket(frameEvent, diagnostics = {}) {
|
|
|
1345
1354
|
return Buffer.concat([header, metaBuffer, payload], 4 + metaBuffer.length + payload.length);
|
|
1346
1355
|
}
|
|
1347
1356
|
|
|
1348
|
-
function buildRemoteAudioBinaryPacket(audioEvent) {
|
|
1349
|
-
const payload = audioEvent?.payload;
|
|
1350
|
-
if (!Buffer.isBuffer(payload) || payload.length === 0) {
|
|
1351
|
-
return null;
|
|
1352
|
-
}
|
|
1353
|
-
const frame = audioEvent.frame || {};
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1357
|
+
function buildRemoteAudioBinaryPacket(audioEvent) {
|
|
1358
|
+
const payload = audioEvent?.payload;
|
|
1359
|
+
if (!Buffer.isBuffer(payload) || payload.length === 0) {
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
const frame = audioEvent.frame || {};
|
|
1363
|
+
const audioStatus = audioEvent.audioStatus === true;
|
|
1364
|
+
const metadata = {
|
|
1365
|
+
type: audioStatus ? 'remote.audio.status' : 'remote.audio.binary',
|
|
1366
|
+
frameKind: audioStatus ? 'audio-status' : 'audio',
|
|
1367
|
+
deviceId: audioEvent.deviceId || frame.deviceId || '',
|
|
1368
|
+
frameSeq: Number(frame.frameSeq || 0) || 0,
|
|
1369
|
+
streamId: frame.streamId || '',
|
|
1359
1370
|
mimeType: audioEvent.mimeType || frame.mimeType || frame.format || 'audio/webm;codecs=opus',
|
|
1360
1371
|
sampleRate: Number(frame.sampleRate || 0) || 48000,
|
|
1361
1372
|
channels: Number(frame.channels || 0) || 2,
|
|
1362
1373
|
capturedAt: frame.capturedAt || '',
|
|
1363
1374
|
receivedAt: frame.receivedAt || '',
|
|
1364
|
-
byteLength: Number(audioEvent.byteLength || payload.length) || payload.length
|
|
1365
|
-
|
|
1375
|
+
byteLength: Number(audioEvent.byteLength || payload.length) || payload.length,
|
|
1376
|
+
...(audioStatus ? {
|
|
1377
|
+
commandId: frame.commandId || '',
|
|
1378
|
+
captureAlive: frame.captureAlive === true,
|
|
1379
|
+
helperAlive: frame.helperAlive === true,
|
|
1380
|
+
helperPid: Number(frame.helperPid || 0) || 0,
|
|
1381
|
+
captureGeneration: Number(frame.captureGeneration || 0) || 0,
|
|
1382
|
+
lastPcmAtEpochMs: Number(frame.lastPcmAtEpochMs || 0) || 0,
|
|
1383
|
+
silentForMs: Math.max(0, Number(frame.silentForMs || 0) || 0),
|
|
1384
|
+
restartCount: Math.max(0, Number(frame.restartCount || 0) || 0),
|
|
1385
|
+
error: String(frame.error || ''),
|
|
1386
|
+
statusAtEpochMs: Number(frame.statusAtEpochMs || 0) || Date.now()
|
|
1387
|
+
} : {})
|
|
1388
|
+
};
|
|
1366
1389
|
const metaBuffer = Buffer.from(JSON.stringify(metadata), 'utf8');
|
|
1367
1390
|
const header = Buffer.allocUnsafe(4);
|
|
1368
1391
|
header.writeUInt32BE(metaBuffer.length, 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livedesk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.225",
|
|
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.128",
|
|
35
35
|
"@openai/codex-sdk": "0.144.5",
|
|
36
36
|
"cors": "^2.8.5",
|
|
37
37
|
"express": "^4.21.2",
|