@agentdeck/bridge 1.0.2 → 1.0.4
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/assets/fm-helper/agentdeck-fm-helper +0 -0
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +5 -2
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/runner.d.ts +11 -0
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +60 -4
- package/dist/apme/runner.js.map +1 -1
- package/dist/apme/settings.d.ts +10 -0
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +14 -0
- package/dist/apme/settings.js.map +1 -1
- package/dist/awaiting-overlay.d.ts +44 -10
- package/dist/awaiting-overlay.d.ts.map +1 -1
- package/dist/awaiting-overlay.js +96 -28
- package/dist/awaiting-overlay.js.map +1 -1
- package/dist/bridge-core.d.ts +10 -0
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +47 -12
- package/dist/bridge-core.js.map +1 -1
- package/dist/card-feed.d.ts +107 -0
- package/dist/card-feed.d.ts.map +1 -0
- package/dist/card-feed.js +277 -0
- package/dist/card-feed.js.map +1 -0
- package/dist/card-modules.d.ts +87 -0
- package/dist/card-modules.d.ts.map +1 -0
- package/dist/card-modules.js +179 -0
- package/dist/card-modules.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +232 -69
- package/dist/cli.js.map +1 -1
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +1008 -47
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon-ws-client.d.ts +2 -1
- package/dist/daemon-ws-client.d.ts.map +1 -1
- package/dist/daemon-ws-client.js +2 -1
- package/dist/daemon-ws-client.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/device-photo.d.ts +86 -0
- package/dist/device-photo.d.ts.map +1 -0
- package/dist/device-photo.js +200 -0
- package/dist/device-photo.js.map +1 -0
- package/dist/device-voice-reply.d.ts +124 -0
- package/dist/device-voice-reply.d.ts.map +1 -0
- package/dist/device-voice-reply.js +236 -0
- package/dist/device-voice-reply.js.map +1 -0
- package/dist/device-voice.d.ts +56 -0
- package/dist/device-voice.d.ts.map +1 -0
- package/dist/device-voice.js +134 -0
- package/dist/device-voice.js.map +1 -0
- package/dist/esp32-serial.d.ts +40 -0
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +109 -13
- package/dist/esp32-serial.js.map +1 -1
- package/dist/foundation-models-helper.d.ts +30 -0
- package/dist/foundation-models-helper.d.ts.map +1 -1
- package/dist/foundation-models-helper.js +45 -0
- package/dist/foundation-models-helper.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.js +5 -18
- package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-discover.d.ts.map +1 -1
- package/dist/idotmatrix/idotmatrix-discover.js +6 -14
- package/dist/idotmatrix/idotmatrix-discover.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mdns.d.ts +11 -0
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +13 -0
- package/dist/mdns.js.map +1 -1
- package/dist/observed-inject.d.ts +119 -0
- package/dist/observed-inject.d.ts.map +1 -0
- package/dist/observed-inject.js +405 -0
- package/dist/observed-inject.js.map +1 -0
- package/dist/passive-observer.d.ts +14 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +35 -5
- package/dist/passive-observer.js.map +1 -1
- package/dist/peripheral-mapping.d.ts +65 -0
- package/dist/peripheral-mapping.d.ts.map +1 -0
- package/dist/peripheral-mapping.js +115 -0
- package/dist/peripheral-mapping.js.map +1 -0
- package/dist/python-ble-runtime.d.ts +62 -0
- package/dist/python-ble-runtime.d.ts.map +1 -0
- package/dist/python-ble-runtime.js +215 -0
- package/dist/python-ble-runtime.js.map +1 -0
- package/dist/session-aggregator.d.ts +4 -1
- package/dist/session-aggregator.d.ts.map +1 -1
- package/dist/session-aggregator.js +5 -5
- package/dist/session-aggregator.js.map +1 -1
- package/dist/session-id-resolve.d.ts +17 -0
- package/dist/session-id-resolve.d.ts.map +1 -0
- package/dist/session-id-resolve.js +35 -0
- package/dist/session-id-resolve.js.map +1 -0
- package/dist/session-transcript-timeline.d.ts +7 -0
- package/dist/session-transcript-timeline.d.ts.map +1 -1
- package/dist/session-transcript-timeline.js +16 -6
- package/dist/session-transcript-timeline.js.map +1 -1
- package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -1
- package/dist/timebox/timebox-daemon-sync.js +5 -20
- package/dist/timebox/timebox-daemon-sync.js.map +1 -1
- package/dist/timebox/timebox-discover.d.ts.map +1 -1
- package/dist/timebox/timebox-discover.js +6 -15
- package/dist/timebox/timebox-discover.js.map +1 -1
- package/dist/timeline-store.js +2 -2
- package/dist/timeline-store.js.map +1 -1
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +14 -7
- package/dist/usage-event.js.map +1 -1
- package/dist/voice.d.ts +13 -10
- package/dist/voice.d.ts.map +1 -1
- package/dist/voice.js +26 -272
- package/dist/voice.js.map +1 -1
- package/dist/ws-server.d.ts +14 -0
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +66 -1
- package/dist/ws-server.js.map +1 -1
- package/fm-helper/AgentDeckFMHelper.swift +303 -0
- package/package.json +8 -4
- package/python/requirements-ble.txt +5 -0
- package/src/idotmatrix/brightness.py +40 -0
- package/src/idotmatrix/scan.py +35 -0
- package/src/idotmatrix/sync.py +400 -0
- package/src/pysync/matrix_sync_common.py +89 -0
- package/src/timebox/scan_ble.py +52 -0
- package/src/timebox/sync_ble.py +394 -0
- package/dist/d200h/hid-protocol.d.ts +0 -62
- package/dist/d200h/hid-protocol.d.ts.map +0 -1
- package/dist/d200h/hid-protocol.js +0 -124
- package/dist/d200h/hid-protocol.js.map +0 -1
- package/dist/d200h/image-renderer.d.ts +0 -24
- package/dist/d200h/image-renderer.d.ts.map +0 -1
- package/dist/d200h/image-renderer.js +0 -321
- package/dist/d200h/image-renderer.js.map +0 -1
- package/dist/hook-migration.d.ts +0 -2
- package/dist/hook-migration.d.ts.map +0 -1
- package/dist/hook-migration.js +0 -104
- package/dist/hook-migration.js.map +0 -1
- package/dist/modules/d200h-module.d.ts +0 -65
- package/dist/modules/d200h-module.d.ts.map +0 -1
- package/dist/modules/d200h-module.js +0 -495
- package/dist/modules/d200h-module.js.map +0 -1
- package/dist/modules/d200h-renderer.d.ts +0 -7
- package/dist/modules/d200h-renderer.d.ts.map +0 -1
- package/dist/modules/d200h-renderer.js +0 -321
- package/dist/modules/d200h-renderer.js.map +0 -1
- package/dist/modules/trmnl-module.d.ts +0 -38
- package/dist/modules/trmnl-module.d.ts.map +0 -1
- package/dist/modules/trmnl-module.js +0 -111
- package/dist/modules/trmnl-module.js.map +0 -1
- package/dist/trmnl/byos-server.d.ts +0 -39
- package/dist/trmnl/byos-server.d.ts.map +0 -1
- package/dist/trmnl/byos-server.js +0 -301
- package/dist/trmnl/byos-server.js.map +0 -1
- package/dist/trmnl/frame-cache.d.ts +0 -37
- package/dist/trmnl/frame-cache.d.ts.map +0 -1
- package/dist/trmnl/frame-cache.js +0 -157
- package/dist/trmnl/frame-cache.js.map +0 -1
- package/dist/trmnl/image-renderer.d.ts +0 -27
- package/dist/trmnl/image-renderer.d.ts.map +0 -1
- package/dist/trmnl/image-renderer.js +0 -235
- package/dist/trmnl/image-renderer.js.map +0 -1
- package/dist/trmnl/trmnl-settings.d.ts +0 -96
- package/dist/trmnl/trmnl-settings.d.ts.map +0 -1
- package/dist/trmnl/trmnl-settings.js +0 -177
- package/dist/trmnl/trmnl-settings.js.map +0 -1
- package/dist/trmnl/trmnl-telemetry.d.ts +0 -47
- package/dist/trmnl/trmnl-telemetry.d.ts.map +0 -1
- package/dist/trmnl/trmnl-telemetry.js +0 -56
- package/dist/trmnl/trmnl-telemetry.js.map +0 -1
- package/dist/whisper-server-manager.d.ts +0 -19
- package/dist/whisper-server-manager.d.ts.map +0 -1
- package/dist/whisper-server-manager.js +0 -171
- package/dist/whisper-server-manager.js.map +0 -1
package/dist/voice.d.ts
CHANGED
|
@@ -3,15 +3,12 @@ export declare class VoiceManager extends EventEmitter {
|
|
|
3
3
|
private recording;
|
|
4
4
|
private audioProcess;
|
|
5
5
|
private audioFile;
|
|
6
|
-
private whisperBin;
|
|
7
|
-
private whisperModel;
|
|
8
6
|
private recBin;
|
|
9
7
|
private soxBin;
|
|
10
|
-
private hasMetal;
|
|
11
|
-
private whisperServerBin;
|
|
12
|
-
private serverPort;
|
|
13
|
-
private useServer;
|
|
14
8
|
constructor();
|
|
9
|
+
/** No-op kept so callers written for the whisper-server era keep compiling.
|
|
10
|
+
* Transcription now goes through the bundled Swift helper, which the
|
|
11
|
+
* Foundation Models client already manages as a long-lived process. */
|
|
15
12
|
connectToServer(): Promise<void>;
|
|
16
13
|
disconnectFromServer(): void;
|
|
17
14
|
startRecording(): void;
|
|
@@ -20,10 +17,16 @@ export declare class VoiceManager extends EventEmitter {
|
|
|
20
17
|
isRecording(): boolean;
|
|
21
18
|
/** Transcribe a WAV file (used by /voice/transcribe endpoint) */
|
|
22
19
|
transcribeFile(filePath: string): Promise<string>;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Transcribe with Apple's on-device recognizer via the bundled Swift helper
|
|
22
|
+
* (the same binary the APME judge uses for Foundation Models). whisper.cpp
|
|
23
|
+
* was retired here: it required arm64 Homebrew, `brew install whisper-cpp`,
|
|
24
|
+
* a ~1.5 GB model download and a second long-lived server process, which is
|
|
25
|
+
* exactly the install surface docs/voice-setup.md removed from the Apple
|
|
26
|
+
* side. Both daemons now transcribe with the same engine and nothing to
|
|
27
|
+
* install.
|
|
28
|
+
*/
|
|
29
|
+
private transcribeViaHelper;
|
|
27
30
|
private cleanup;
|
|
28
31
|
}
|
|
29
32
|
//# sourceMappingURL=voice.d.ts.map
|
package/dist/voice.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AA+BtC,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;;IASvB;;4EAEwE;IAClE,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC,oBAAoB,IAAI,IAAI;IAI5B,cAAc,IAAI,IAAI;IA0ChB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAyDtC,MAAM,IAAI,IAAI;IAUd,WAAW,IAAI,OAAO;IAItB,iEAAiE;IAC3D,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWvD;;;;;;;;OAQG;YACW,mBAAmB;IAOjC,OAAO,CAAC,OAAO;CAMhB"}
|
package/dist/voice.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { spawn
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
3
|
import { tmpdir } from 'os';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { unlinkSync, existsSync, statSync, readFileSync } from 'fs';
|
|
6
6
|
import { debug } from './logger.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
// Dynamic timeout: base + multiplier × audio duration
|
|
10
|
-
// Metal GPU: fast inference; Rosetta/CPU: ~3-4x slower
|
|
11
|
-
const TIMEOUT_BASE_MS = 15_000;
|
|
12
|
-
const TIMEOUT_MULTIPLIER_METAL = 1; // 15s + 1× audio duration
|
|
13
|
-
const TIMEOUT_MULTIPLIER_ROSETTA = 4; // 15s + 4× audio duration
|
|
7
|
+
import { transcribeWithHelper, probeFoundationModelsHelper } from './foundation-models-helper.js';
|
|
8
|
+
import { REC_CANDIDATES, SOX_CANDIDATES } from '@agentdeck/shared';
|
|
14
9
|
function findBinary(candidates, fallback) {
|
|
15
10
|
for (const path of candidates) {
|
|
16
11
|
if (existsSync(path))
|
|
@@ -19,52 +14,6 @@ function findBinary(candidates, fallback) {
|
|
|
19
14
|
return fallback;
|
|
20
15
|
}
|
|
21
16
|
/** Check if a whisper-cli binary has Metal GPU support (native arm64 + libggml-metal). */
|
|
22
|
-
function detectMetal(whisperPath) {
|
|
23
|
-
// Skip if whisper-cli doesn't exist (just a fallback name, not installed)
|
|
24
|
-
if (!existsSync(whisperPath)) {
|
|
25
|
-
debug('Voice', `whisper-cli not found, skipping Metal detection`);
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const otoolOut = execSync(`otool -L "${whisperPath}"`, { encoding: 'utf8' });
|
|
30
|
-
const hasMetal = otoolOut.includes('libggml-metal');
|
|
31
|
-
const fileOut = execSync(`file "${whisperPath}"`, { encoding: 'utf8' });
|
|
32
|
-
const isArm64 = fileOut.includes('arm64');
|
|
33
|
-
debug('Voice', `whisper-cli: arm64=${isArm64}, metal=${hasMetal} (${whisperPath})`);
|
|
34
|
-
return hasMetal && isArm64;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
debug('Voice', `Could not detect capabilities: ${whisperPath}`);
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function findWhisperModel(preference) {
|
|
42
|
-
for (const model of preference) {
|
|
43
|
-
for (const dir of MODEL_SEARCH_DIRS) {
|
|
44
|
-
const path = join(dir, model);
|
|
45
|
-
if (existsSync(path)) {
|
|
46
|
-
debug('Voice', `Selected whisper model: ${path}`);
|
|
47
|
-
return path;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
debug('Voice', `No whisper model found in: ${MODEL_SEARCH_DIRS.join(', ')}`);
|
|
52
|
-
return join(MODEL_SEARCH_DIRS[0], preference[0]);
|
|
53
|
-
}
|
|
54
|
-
function findFallbackModel(currentModel) {
|
|
55
|
-
const all = [...MODELS_WITH_METAL];
|
|
56
|
-
const currentName = currentModel.split('/').pop() ?? '';
|
|
57
|
-
const idx = all.indexOf(currentName);
|
|
58
|
-
// Find a smaller model than current
|
|
59
|
-
for (let i = idx + 1; i < all.length; i++) {
|
|
60
|
-
for (const dir of MODEL_SEARCH_DIRS) {
|
|
61
|
-
const path = join(dir, all[i]);
|
|
62
|
-
if (existsSync(path))
|
|
63
|
-
return path;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
17
|
/** Compute RMS energy of a 16-bit PCM WAV file (skip 44-byte header). */
|
|
69
18
|
function computeRms(wavFile) {
|
|
70
19
|
const buf = readFileSync(wavFile);
|
|
@@ -83,39 +32,25 @@ export class VoiceManager extends EventEmitter {
|
|
|
83
32
|
recording = false;
|
|
84
33
|
audioProcess = null;
|
|
85
34
|
audioFile = '';
|
|
86
|
-
whisperBin;
|
|
87
|
-
whisperModel;
|
|
88
35
|
recBin;
|
|
89
36
|
soxBin;
|
|
90
|
-
hasMetal;
|
|
91
|
-
whisperServerBin;
|
|
92
|
-
serverPort = null;
|
|
93
|
-
useServer = false;
|
|
94
37
|
constructor() {
|
|
95
38
|
super();
|
|
96
|
-
this.whisperBin = findBinary(WHISPER_CANDIDATES, 'whisper-cli');
|
|
97
39
|
this.recBin = findBinary(REC_CANDIDATES, 'rec');
|
|
98
40
|
this.soxBin = findBinary(SOX_CANDIDATES, 'sox');
|
|
99
|
-
this.
|
|
100
|
-
this.hasMetal = detectMetal(this.whisperBin);
|
|
101
|
-
const preference = this.hasMetal ? MODELS_WITH_METAL : MODELS_WITHOUT_METAL;
|
|
102
|
-
this.whisperModel = findWhisperModel(preference);
|
|
103
|
-
if (!this.hasMetal) {
|
|
104
|
-
debug('Voice', 'WARNING: whisper-cli has no Metal GPU support (x86/Rosetta). Using smaller model for speed. Install arm64 Homebrew for best quality.');
|
|
105
|
-
}
|
|
106
|
-
debug('Voice', `Binaries: whisper=${this.whisperBin}, rec=${this.recBin}, sox=${this.soxBin}, server=${this.whisperServerBin}`);
|
|
41
|
+
debug('Voice', `Binaries: rec=${this.recBin}, sox=${this.soxBin} (transcription: Apple Speech via bundled helper)`);
|
|
107
42
|
}
|
|
43
|
+
/** No-op kept so callers written for the whisper-server era keep compiling.
|
|
44
|
+
* Transcription now goes through the bundled Swift helper, which the
|
|
45
|
+
* Foundation Models client already manages as a long-lived process. */
|
|
108
46
|
async connectToServer() {
|
|
109
|
-
const
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
this.useServer = true;
|
|
47
|
+
const status = await probeFoundationModelsHelper();
|
|
48
|
+
if (!status.available) {
|
|
49
|
+
debug('Voice', `Speech helper unavailable: ${status.reason ?? 'unknown'}`);
|
|
113
50
|
}
|
|
114
51
|
}
|
|
115
52
|
disconnectFromServer() {
|
|
116
|
-
|
|
117
|
-
this.serverPort = null;
|
|
118
|
-
releaseWhisperServer();
|
|
53
|
+
// Helper lifetime is owned by foundation-models-helper.ts.
|
|
119
54
|
}
|
|
120
55
|
startRecording() {
|
|
121
56
|
if (this.recording)
|
|
@@ -193,22 +128,7 @@ export class VoiceManager extends EventEmitter {
|
|
|
193
128
|
}
|
|
194
129
|
// --- Transcription: prefer whisper-server, fallback to whisper-cli ---
|
|
195
130
|
try {
|
|
196
|
-
|
|
197
|
-
if (this.useServer && this.serverPort) {
|
|
198
|
-
// Server mode: skip resample, whisper-server handles format conversion (--convert)
|
|
199
|
-
debug('Voice', 'Server mode: skipping sox resample');
|
|
200
|
-
try {
|
|
201
|
-
text = await this.transcribeViaServer(this.audioFile);
|
|
202
|
-
}
|
|
203
|
-
catch (serverErr) {
|
|
204
|
-
debug('Voice', `Server transcription failed, falling back to whisper-cli: ${serverErr}`);
|
|
205
|
-
this.useServer = false;
|
|
206
|
-
text = await this.transcribeWithCli(this.audioFile);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
text = await this.transcribeWithCli(this.audioFile);
|
|
211
|
-
}
|
|
131
|
+
const text = await this.transcribeViaHelper(this.audioFile);
|
|
212
132
|
debug('Voice', `Transcription result: "${text.slice(0, 80)}"`);
|
|
213
133
|
this.emit('transcription', text);
|
|
214
134
|
this.cleanup();
|
|
@@ -242,188 +162,22 @@ export class VoiceManager extends EventEmitter {
|
|
|
242
162
|
if (rms < 0.001) {
|
|
243
163
|
throw new Error('No audio detected — silent recording');
|
|
244
164
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const boundary = `----whisper${Date.now()}`;
|
|
260
|
-
const filename = audioFile.split('/').pop() || 'audio.wav';
|
|
261
|
-
// Build multipart form-data manually (no external deps)
|
|
262
|
-
const header = Buffer.from(`--${boundary}\r\n` +
|
|
263
|
-
`Content-Disposition: form-data; name="file"; filename="${filename}"\r\n` +
|
|
264
|
-
`Content-Type: audio/wav\r\n\r\n`);
|
|
265
|
-
const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
|
|
266
|
-
const body = Buffer.concat([header, fileData, footer]);
|
|
267
|
-
const url = `http://127.0.0.1:${this.serverPort}/inference`;
|
|
268
|
-
debug('Voice', `POST ${url} (${fileData.length} bytes audio)`);
|
|
269
|
-
const res = await fetch(url, {
|
|
270
|
-
method: 'POST',
|
|
271
|
-
headers: { 'Content-Type': `multipart/form-data; boundary=${boundary}` },
|
|
272
|
-
body,
|
|
273
|
-
signal: AbortSignal.timeout(15_000),
|
|
274
|
-
});
|
|
275
|
-
if (!res.ok) {
|
|
276
|
-
throw new Error(`whisper-server returned ${res.status}: ${await res.text()}`);
|
|
277
|
-
}
|
|
278
|
-
const json = await res.json();
|
|
279
|
-
const text = (json.text ?? '').trim();
|
|
280
|
-
debug('Voice', `whisper-server response: "${text.slice(0, 80)}"`);
|
|
165
|
+
return await this.transcribeViaHelper(filePath);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Transcribe with Apple's on-device recognizer via the bundled Swift helper
|
|
169
|
+
* (the same binary the APME judge uses for Foundation Models). whisper.cpp
|
|
170
|
+
* was retired here: it required arm64 Homebrew, `brew install whisper-cpp`,
|
|
171
|
+
* a ~1.5 GB model download and a second long-lived server process, which is
|
|
172
|
+
* exactly the install surface docs/voice-setup.md removed from the Apple
|
|
173
|
+
* side. Both daemons now transcribe with the same engine and nothing to
|
|
174
|
+
* install.
|
|
175
|
+
*/
|
|
176
|
+
async transcribeViaHelper(audioFile) {
|
|
177
|
+
const text = await transcribeWithHelper(audioFile);
|
|
178
|
+
debug('Voice', `Helper transcription: "${text.slice(0, 80)}"`);
|
|
281
179
|
return text;
|
|
282
180
|
}
|
|
283
|
-
async transcribeWithCli(audioFile) {
|
|
284
|
-
// Resample to 16kHz/16-bit mono WAV (macOS coreaudio may record at 48kHz/32-bit)
|
|
285
|
-
const resampledFile = audioFile.replace('.wav', '_16k.wav');
|
|
286
|
-
debug('Voice', `Resampling ${audioFile} → ${resampledFile}`);
|
|
287
|
-
try {
|
|
288
|
-
await this.resample(audioFile, resampledFile);
|
|
289
|
-
}
|
|
290
|
-
catch (err) {
|
|
291
|
-
debug('Voice', `Resample failed, using original: ${err}`);
|
|
292
|
-
}
|
|
293
|
-
const whisperInput = existsSync(resampledFile) ? resampledFile : audioFile;
|
|
294
|
-
debug('Voice', `Whisper input: ${whisperInput}`);
|
|
295
|
-
// Calculate dynamic timeout based on audio duration and Metal support
|
|
296
|
-
const audioDurationSec = (statSync(whisperInput).size - 44) / 32000; // 16kHz × 16-bit
|
|
297
|
-
const multiplier = this.hasMetal ? TIMEOUT_MULTIPLIER_METAL : TIMEOUT_MULTIPLIER_ROSETTA;
|
|
298
|
-
const timeoutMs = TIMEOUT_BASE_MS + Math.ceil(audioDurationSec * 1000 * multiplier);
|
|
299
|
-
debug('Voice', `Starting whisper-cli transcription (${audioDurationSec.toFixed(1)}s audio, timeout ${(timeoutMs / 1000).toFixed(0)}s, metal=${this.hasMetal})...`);
|
|
300
|
-
try {
|
|
301
|
-
let text;
|
|
302
|
-
try {
|
|
303
|
-
text = await this.transcribe(whisperInput, this.whisperModel, timeoutMs);
|
|
304
|
-
}
|
|
305
|
-
catch (err) {
|
|
306
|
-
const isTimeout = err instanceof Error && err.message.includes('timed out');
|
|
307
|
-
const fallback = isTimeout ? findFallbackModel(this.whisperModel) : null;
|
|
308
|
-
if (fallback) {
|
|
309
|
-
debug('Voice', `Timeout with current model, retrying with fallback: ${fallback}`);
|
|
310
|
-
this.whisperModel = fallback; // persist for future calls
|
|
311
|
-
text = await this.transcribe(whisperInput, fallback, timeoutMs);
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
throw err;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
if (existsSync(resampledFile))
|
|
318
|
-
try {
|
|
319
|
-
unlinkSync(resampledFile);
|
|
320
|
-
}
|
|
321
|
-
catch { /* */ }
|
|
322
|
-
return text;
|
|
323
|
-
}
|
|
324
|
-
catch (err) {
|
|
325
|
-
if (existsSync(resampledFile))
|
|
326
|
-
try {
|
|
327
|
-
unlinkSync(resampledFile);
|
|
328
|
-
}
|
|
329
|
-
catch { /* */ }
|
|
330
|
-
throw err;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
resample(inputFile, outputFile) {
|
|
334
|
-
return new Promise((resolve, reject) => {
|
|
335
|
-
// Resample to 16kHz/16-bit mono + gentle highpass (80Hz removes rumble, preserves voice)
|
|
336
|
-
// + normalize volume for consistent whisper input
|
|
337
|
-
const sox = spawn(this.soxBin, [
|
|
338
|
-
inputFile,
|
|
339
|
-
'-r', '16000',
|
|
340
|
-
'-c', '1',
|
|
341
|
-
'-b', '16',
|
|
342
|
-
outputFile,
|
|
343
|
-
'highpass', '80',
|
|
344
|
-
'norm',
|
|
345
|
-
]);
|
|
346
|
-
let stderr = '';
|
|
347
|
-
sox.stderr?.on('data', (data) => { stderr += data.toString(); });
|
|
348
|
-
sox.on('error', (err) => reject(new Error(`sox spawn error: ${err.message}`)));
|
|
349
|
-
sox.on('close', (code) => {
|
|
350
|
-
if (code !== 0) {
|
|
351
|
-
reject(new Error(`sox exited with code ${code}: ${stderr.slice(-200)}`));
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
debug('Voice', `Resampled OK (${statSync(outputFile).size} bytes)`);
|
|
355
|
-
resolve();
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
transcribe(audioFile, modelPath, timeoutMs) {
|
|
361
|
-
return new Promise((resolve, reject) => {
|
|
362
|
-
const args = [
|
|
363
|
-
'-m', modelPath,
|
|
364
|
-
'-l', 'auto', // auto-detect language (supports Korean, English, etc.)
|
|
365
|
-
'-f', audioFile,
|
|
366
|
-
'--no-timestamps',
|
|
367
|
-
'-np', // suppress whisper's own progress output
|
|
368
|
-
'--prompt', 'coding, programming, Claude, terminal, git, function, component, API',
|
|
369
|
-
];
|
|
370
|
-
debug('Voice', `${this.whisperBin} ${args.join(' ')}`);
|
|
371
|
-
const whisper = spawn(this.whisperBin, args);
|
|
372
|
-
let stdout = '';
|
|
373
|
-
let stderr = '';
|
|
374
|
-
let settled = false;
|
|
375
|
-
// Timeout guard (dynamic based on audio length + Metal support)
|
|
376
|
-
const timer = setTimeout(() => {
|
|
377
|
-
if (!settled) {
|
|
378
|
-
settled = true;
|
|
379
|
-
debug('Voice', `whisper-cli timed out after ${(timeoutMs / 1000).toFixed(0)}s, killing`);
|
|
380
|
-
whisper.kill('SIGKILL');
|
|
381
|
-
reject(new Error(`whisper-cli timed out after ${(timeoutMs / 1000).toFixed(0)}s`));
|
|
382
|
-
}
|
|
383
|
-
}, timeoutMs);
|
|
384
|
-
whisper.stdout.on('data', (data) => {
|
|
385
|
-
stdout += data.toString();
|
|
386
|
-
});
|
|
387
|
-
whisper.stderr.on('data', (data) => {
|
|
388
|
-
stderr += data.toString();
|
|
389
|
-
});
|
|
390
|
-
whisper.on('error', (err) => {
|
|
391
|
-
if (!settled) {
|
|
392
|
-
settled = true;
|
|
393
|
-
clearTimeout(timer);
|
|
394
|
-
debug('Voice', `whisper-cli spawn error: ${err.message}`);
|
|
395
|
-
reject(new Error(`Failed to run whisper-cli: ${err.message}`));
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
whisper.on('close', (code) => {
|
|
399
|
-
if (settled)
|
|
400
|
-
return;
|
|
401
|
-
settled = true;
|
|
402
|
-
clearTimeout(timer);
|
|
403
|
-
debug('Voice', `whisper-cli exited with code ${code}`);
|
|
404
|
-
if (stderr.length > 0) {
|
|
405
|
-
debug('Voice', `whisper stderr (last 200): ${stderr.slice(-200)}`);
|
|
406
|
-
}
|
|
407
|
-
if (code !== 0) {
|
|
408
|
-
reject(new Error(`whisper-cli exited with code ${code}: ${stderr.slice(-300)}`));
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
const text = stdout
|
|
412
|
-
.split('\n')
|
|
413
|
-
.map((line) => line.trim())
|
|
414
|
-
.filter((line) => line.length > 0 &&
|
|
415
|
-
!line.startsWith('[') && // skip timestamp lines
|
|
416
|
-
line !== '(blank audio)' && // skip blank audio markers
|
|
417
|
-
!line.startsWith('(') && // skip other whisper annotations
|
|
418
|
-
!/^\[BLANK_AUDIO\]$/i.test(line) // skip blank audio tags
|
|
419
|
-
)
|
|
420
|
-
.join(' ')
|
|
421
|
-
.trim();
|
|
422
|
-
debug('Voice', `whisper stdout raw (${stdout.length} chars): "${stdout.slice(0, 100)}"`);
|
|
423
|
-
resolve(text);
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
181
|
cleanup() {
|
|
428
182
|
if (this.audioFile && existsSync(this.audioFile)) {
|
|
429
183
|
try {
|
package/dist/voice.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice.js","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"voice.js","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"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"}
|
package/dist/ws-server.d.ts
CHANGED
|
@@ -5,10 +5,16 @@ export declare class WsServer {
|
|
|
5
5
|
private wss;
|
|
6
6
|
private commandCallback;
|
|
7
7
|
private rawMessageCallback;
|
|
8
|
+
private binaryCallback;
|
|
9
|
+
private onPongCallback;
|
|
8
10
|
private onConnectCallback;
|
|
9
11
|
private onDisconnectCallback;
|
|
10
12
|
private clientAlive;
|
|
11
13
|
private esp32Clients;
|
|
14
|
+
private recentConnectsByIp;
|
|
15
|
+
private flappingClients;
|
|
16
|
+
private knownBoardIps;
|
|
17
|
+
private socketRemoteIp;
|
|
12
18
|
private eventTransformer;
|
|
13
19
|
private ulanziClients;
|
|
14
20
|
private tuiClients;
|
|
@@ -19,10 +25,18 @@ export declare class WsServer {
|
|
|
19
25
|
onBroadcast(hook: (event: BridgeEvent) => void): void;
|
|
20
26
|
setEventTransformer(transformer: ((event: BridgeEvent, client: WebSocket) => BridgeEvent | null) | null): void;
|
|
21
27
|
isEsp32Client(ws: WebSocket): boolean;
|
|
28
|
+
/** True when this socket's remote IP has been reconnecting fast enough to
|
|
29
|
+
* count as flapping (see the connection handler). Callers use it to skip
|
|
30
|
+
* the heavy parts of the initial burst so a marginal client can't resonate
|
|
31
|
+
* the daemon into saturation. */
|
|
32
|
+
isFlappingClient(ws: WebSocket): boolean;
|
|
22
33
|
markEsp32Client(ws: WebSocket): void;
|
|
23
34
|
private payloadFor;
|
|
24
35
|
broadcast(event: BridgeEvent): void;
|
|
25
36
|
onCommand(callback: (cmd: PluginCommand) => void): void;
|
|
37
|
+
/** Register a callback for binary frames (device audio). */
|
|
38
|
+
onPong(callback: (ws: WebSocket) => void): void;
|
|
39
|
+
onBinary(callback: (data: Buffer, sender: WebSocket) => void): void;
|
|
26
40
|
/** Register a callback for raw messages before PluginCommand dispatch. Return true to consume. */
|
|
27
41
|
onRawMessage(callback: (msg: Record<string, unknown>, sender: WebSocket) => boolean): void;
|
|
28
42
|
/** Broadcast to all clients except the sender */
|
package/dist/ws-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-server.d.ts","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAK7D,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,kBAAkB,CAA+E;IACzG,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,oBAAoB,CAA0C;IACtE,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,YAAY,CAAwB;
|
|
1
|
+
{"version":3,"file":"ws-server.d.ts","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAK7D,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,kBAAkB,CAA+E;IACzG,OAAO,CAAC,cAAc,CAA4D;IAClF,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,oBAAoB,CAA0C;IACtE,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,YAAY,CAAwB;IAE5C,OAAO,CAAC,kBAAkB,CAA+B;IACzD,OAAO,CAAC,eAAe,CAAwB;IAO/C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,gBAAgB,CAAgF;IAGxG,OAAO,CAAC,aAAa,CAAwB;IAK7C,OAAO,CAAC,UAAU,CAAsD;IACxE,OAAO,CAAC,SAAS,CAAiC;gBAEtC,MAAM,EAAE,MAAM;IAoJ1B,OAAO,CAAC,cAAc,CAA2C;IAEjE,sFAAsF;IACtF,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAIrD,mBAAmB,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,KAAK,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAI9G,aAAa,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO;IAIrC;;;sCAGkC;IAClC,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO;IAIxC,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAMpC,OAAO,CAAC,UAAU;IAOlB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAiBnC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAIvD,4DAA4D;IAC5D,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,IAAI;IAI/C,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,IAAI,GAAG,IAAI;IAInE,kGAAkG;IAClG,YAAY,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,GAAG,IAAI;IAI1F,iDAAiD;IACjD,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI;IAW5D,eAAe,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,IAAI;IAIxD,kBAAkB,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,IAAI;IAI3D,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAQ/C,cAAc,IAAI,MAAM;IAIxB,oBAAoB,IAAI,MAAM;IAI9B;;oDAEgD;IAChD,aAAa,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAMpD,KAAK,IAAI,IAAI;CASd"}
|
package/dist/ws-server.js
CHANGED
|
@@ -6,10 +6,23 @@ export class WsServer {
|
|
|
6
6
|
wss;
|
|
7
7
|
commandCallback = null;
|
|
8
8
|
rawMessageCallback = null;
|
|
9
|
+
binaryCallback = null;
|
|
10
|
+
onPongCallback = null;
|
|
9
11
|
onConnectCallback = null;
|
|
10
12
|
onDisconnectCallback = null;
|
|
11
13
|
clientAlive = new Map();
|
|
12
14
|
esp32Clients = new Set();
|
|
15
|
+
// Per-IP connect timestamps for the flap guard (window: 30s, threshold: >6).
|
|
16
|
+
recentConnectsByIp = new Map();
|
|
17
|
+
flappingClients = new Set();
|
|
18
|
+
// IPs that have ever sent device_info this daemon lifetime. A board that
|
|
19
|
+
// predates the `?clientType=esp32` tag (XTeink 6ccbe140) is only recognized
|
|
20
|
+
// AFTER its first device_info — one connect too late, because the initial
|
|
21
|
+
// burst already went out untagged. Remembering the IP makes every subsequent
|
|
22
|
+
// connect board-class from byte one, so the ≤4096B invariant holds and a
|
|
23
|
+
// heap-tight board can't be killed by its own welcome payload.
|
|
24
|
+
knownBoardIps = new Set();
|
|
25
|
+
socketRemoteIp = new Map();
|
|
13
26
|
eventTransformer = null;
|
|
14
27
|
// Clients that registered as the Ulanzi Studio plugin. Their WebSocket
|
|
15
28
|
// presence is the daemon's D200H connectivity signal.
|
|
@@ -60,10 +73,31 @@ export class WsServer {
|
|
|
60
73
|
debug('WS', `Remote client authenticated from ${remoteIp}`);
|
|
61
74
|
}
|
|
62
75
|
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
76
|
+
this.socketRemoteIp.set(ws, remoteIp);
|
|
63
77
|
if (url.searchParams.get('clientType') === 'esp32' || url.searchParams.get('esp32') === '1') {
|
|
64
78
|
this.esp32Clients.add(ws);
|
|
65
79
|
debug('WS', 'ESP32 WiFi client tagged from query');
|
|
66
80
|
}
|
|
81
|
+
else if (this.knownBoardIps.has(remoteIp)) {
|
|
82
|
+
this.esp32Clients.add(ws);
|
|
83
|
+
debug('WS', `ESP32 WiFi client tagged from known board IP ${remoteIp}`);
|
|
84
|
+
}
|
|
85
|
+
// Flap guard: a client whose IP reconnected >6 times in the last 30s is
|
|
86
|
+
// marked flapping. It is still served (rejecting outright would blind a
|
|
87
|
+
// recovering board forever), but sendInitialState skips the expensive
|
|
88
|
+
// burst for it — a marginal-RF board must not be able to resonate the
|
|
89
|
+
// daemon into event-loop saturation (connect → heavy serialize → client
|
|
90
|
+
// dies on the burst → immediate reconnect → repeat).
|
|
91
|
+
{
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const recent = (this.recentConnectsByIp.get(remoteIp) ?? []).filter((t) => now - t < 30_000);
|
|
94
|
+
recent.push(now);
|
|
95
|
+
this.recentConnectsByIp.set(remoteIp, recent);
|
|
96
|
+
if (recent.length > 6) {
|
|
97
|
+
this.flappingClients.add(ws);
|
|
98
|
+
debug('WS', `Flapping client ${remoteIp}: ${recent.length} connects/30s — initial burst reduced`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
67
101
|
debug('WS', 'Plugin connected');
|
|
68
102
|
this.clientAlive.set(ws, true);
|
|
69
103
|
// Send current state to newly connected client
|
|
@@ -72,8 +106,20 @@ export class WsServer {
|
|
|
72
106
|
}
|
|
73
107
|
ws.on('pong', () => {
|
|
74
108
|
this.clientAlive.set(ws, true);
|
|
109
|
+
// A display-only board sends no application messages while idle, so a
|
|
110
|
+
// message-based lastSeen brands every healthy quiet board "stale". Its
|
|
111
|
+
// pong every WS_PING_INTERVAL_MS is real liveness — surface it.
|
|
112
|
+
this.onPongCallback?.(ws);
|
|
75
113
|
});
|
|
76
|
-
ws.on('message', (data) => {
|
|
114
|
+
ws.on('message', (data, isBinary) => {
|
|
115
|
+
// Binary frames are device audio (voice capture), not JSON — route
|
|
116
|
+
// them out before the parser, which would otherwise log a parse error
|
|
117
|
+
// per 1 KB PCM frame.
|
|
118
|
+
if (isBinary) {
|
|
119
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
120
|
+
this.binaryCallback?.(buf, ws);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
77
123
|
try {
|
|
78
124
|
const msg = JSON.parse(data.toString());
|
|
79
125
|
debug('WS', `recv cmd: ${msg.type}`);
|
|
@@ -109,6 +155,8 @@ export class WsServer {
|
|
|
109
155
|
debug('WS', 'Plugin disconnected');
|
|
110
156
|
this.clientAlive.delete(ws);
|
|
111
157
|
this.esp32Clients.delete(ws);
|
|
158
|
+
this.flappingClients.delete(ws);
|
|
159
|
+
this.socketRemoteIp.delete(ws);
|
|
112
160
|
this.tuiClients.delete(ws);
|
|
113
161
|
if (this.ulanziClients.delete(ws) && this.ulanziClients.size === 0) {
|
|
114
162
|
debug('WS', 'Ulanzi plugin gone — D200H disconnected');
|
|
@@ -133,8 +181,18 @@ export class WsServer {
|
|
|
133
181
|
isEsp32Client(ws) {
|
|
134
182
|
return this.esp32Clients.has(ws);
|
|
135
183
|
}
|
|
184
|
+
/** True when this socket's remote IP has been reconnecting fast enough to
|
|
185
|
+
* count as flapping (see the connection handler). Callers use it to skip
|
|
186
|
+
* the heavy parts of the initial burst so a marginal client can't resonate
|
|
187
|
+
* the daemon into saturation. */
|
|
188
|
+
isFlappingClient(ws) {
|
|
189
|
+
return this.flappingClients.has(ws);
|
|
190
|
+
}
|
|
136
191
|
markEsp32Client(ws) {
|
|
137
192
|
this.esp32Clients.add(ws);
|
|
193
|
+
const ip = this.socketRemoteIp.get(ws);
|
|
194
|
+
if (ip)
|
|
195
|
+
this.knownBoardIps.add(ip);
|
|
138
196
|
}
|
|
139
197
|
payloadFor(event, client, cachedPayload) {
|
|
140
198
|
if (!this.eventTransformer)
|
|
@@ -170,6 +228,13 @@ export class WsServer {
|
|
|
170
228
|
onCommand(callback) {
|
|
171
229
|
this.commandCallback = callback;
|
|
172
230
|
}
|
|
231
|
+
/** Register a callback for binary frames (device audio). */
|
|
232
|
+
onPong(callback) {
|
|
233
|
+
this.onPongCallback = callback;
|
|
234
|
+
}
|
|
235
|
+
onBinary(callback) {
|
|
236
|
+
this.binaryCallback = callback;
|
|
237
|
+
}
|
|
173
238
|
/** Register a callback for raw messages before PluginCommand dispatch. Return true to consume. */
|
|
174
239
|
onRawMessage(callback) {
|
|
175
240
|
this.rawMessageCallback = callback;
|