mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix: update Discord voice to libopus-wasm 0.1.0
Updates Discord voice Opus callers to the published libopus-wasm 0.1.0 API, pins the Discord plugin dependency and lockfiles to that release, keeps the package freshness exception version-scoped, treats expected Discord receive-stream premature closes as normal stream ends, and includes routed OpenClaw transcript roots for local PR transcript discovery.\n\nProof: npm view libopus-wasm@0.1.0; pnpm install --lockfile-only --filter @openclaw/discord; Node encode/decode smoke with pkg 0.1.0 decoded=3840; node scripts/run-vitest.mjs extensions/discord/src/voice/audio.test.ts extensions/discord/src/voice/receive-recovery.test.ts; git diff --check; autoreview clean; live tmux gateway on e0fa3e3 joined Discord voice and processed realtime audio without decoder.decode or Premature close warning spam.
This commit is contained in:
@@ -56,10 +56,19 @@ function openClawSessionRoots() {
|
||||
const agentsDir = path.join(stateDir, "agents");
|
||||
if (!fs.existsSync(agentsDir)) return [];
|
||||
try {
|
||||
return fs
|
||||
const roots = fs
|
||||
.readdirSync(agentsDir, { withFileTypes: true })
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => path.join(agentsDir, entry.name, "sessions"));
|
||||
.flatMap((entry) => {
|
||||
const agentDir = path.join(agentsDir, entry.name);
|
||||
return [
|
||||
path.join(agentDir, "sessions"),
|
||||
path.join(agentDir, "agent", "sessions"),
|
||||
path.join(agentDir, "agent", "codex-home", "sessions"),
|
||||
];
|
||||
})
|
||||
.filter((root) => fs.existsSync(root));
|
||||
return [...new Set(roots)];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
||||
Generated
+4
-4
@@ -11,7 +11,7 @@
|
||||
"@discordjs/voice": "0.19.2",
|
||||
"discord-api-types": "0.38.48",
|
||||
"https-proxy-agent": "9.0.0",
|
||||
"libopus-wasm": "0.0.1",
|
||||
"libopus-wasm": "0.1.0",
|
||||
"prism-media": "1.3.5",
|
||||
"typebox": "1.1.38",
|
||||
"undici": "8.3.0",
|
||||
@@ -424,9 +424,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/libopus-wasm": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/libopus-wasm/-/libopus-wasm-0.0.1.tgz",
|
||||
"integrity": "sha512-w//dxORfJfLl4quaA5nEA0xZlbbtS/Gba+NrZyCDPmAQh2THX4KI6aI600f+jpxf6v3p9ApGCx0/DCCe4Xftug==",
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/libopus-wasm/-/libopus-wasm-0.1.0.tgz",
|
||||
"integrity": "sha512-/aurGcAVgy0GcBEUzFaX9pm9qv7zYcy8W5hBXFiK+cyqOXAX4lOS6rlFogkY9CcSIajhjnuXyixsbmziSHCDMQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"@discordjs/voice": "0.19.2",
|
||||
"discord-api-types": "0.38.48",
|
||||
"https-proxy-agent": "9.0.0",
|
||||
"libopus-wasm": "0.0.1",
|
||||
"libopus-wasm": "0.1.0",
|
||||
"prism-media": "1.3.5",
|
||||
"typebox": "1.1.38",
|
||||
"undici": "8.3.0",
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
Application,
|
||||
createDecoder as createLibopusDecoder,
|
||||
createEncoder as createLibopusEncoder,
|
||||
type OpusDecoder as LibopusDecoder,
|
||||
type OpusEncoder as LibopusEncoder,
|
||||
type OpusDecoderHandle as LibopusDecoder,
|
||||
type OpusEncoderHandle as LibopusEncoder,
|
||||
} from "libopus-wasm";
|
||||
import { resamplePcm } from "openclaw/plugin-sdk/realtime-voice";
|
||||
import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
||||
@@ -80,7 +80,12 @@ async function createOpusDecoder(params: {
|
||||
return {
|
||||
name: "libopus-wasm",
|
||||
decoder: {
|
||||
decode: (buffer) => pcmInt16ToBuffer(decoder.decodeFrame(buffer, DISCORD_OPUS_FRAME_SIZE)),
|
||||
decode: (buffer) =>
|
||||
pcmInt16ToBuffer(
|
||||
decoder.decode(buffer, {
|
||||
maxFrameSize: DISCORD_OPUS_FRAME_SIZE,
|
||||
}),
|
||||
),
|
||||
free: () => decoder.free(),
|
||||
},
|
||||
};
|
||||
@@ -141,7 +146,13 @@ class DiscordOpusEncodeStream extends Transform {
|
||||
while (this.#buffer.length >= DISCORD_OPUS_FRAME_BYTES) {
|
||||
const frame = this.#buffer.subarray(0, DISCORD_OPUS_FRAME_BYTES);
|
||||
this.#buffer = this.#buffer.subarray(DISCORD_OPUS_FRAME_BYTES);
|
||||
this.push(Buffer.from(encoder.encodePcm16(frame, DISCORD_OPUS_FRAME_SIZE)));
|
||||
this.push(
|
||||
Buffer.from(
|
||||
encoder.encode(frame, {
|
||||
frameSize: DISCORD_OPUS_FRAME_SIZE,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
done();
|
||||
} catch (err) {
|
||||
@@ -156,7 +167,13 @@ class DiscordOpusEncodeStream extends Transform {
|
||||
const frame = Buffer.alloc(DISCORD_OPUS_FRAME_BYTES);
|
||||
this.#buffer.copy(frame);
|
||||
this.#buffer = Buffer.alloc(0);
|
||||
this.push(Buffer.from(encoder.encodePcm16(frame, DISCORD_OPUS_FRAME_SIZE)));
|
||||
this.push(
|
||||
Buffer.from(
|
||||
encoder.encode(frame, {
|
||||
frameSize: DISCORD_OPUS_FRAME_SIZE,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
this.#freeEncoder();
|
||||
done();
|
||||
|
||||
@@ -29,6 +29,15 @@ describe("voice receive recovery", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("treats premature stream close as an expected receive end", () => {
|
||||
expect(analyzeVoiceReceiveError(new Error("Premature close"))).toEqual({
|
||||
message: "Premature close",
|
||||
isAbortLike: true,
|
||||
shouldAttemptPassthrough: false,
|
||||
countsAsDecryptFailure: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("gates recovery after repeated decrypt failures in the same window", () => {
|
||||
const state = createVoiceReceiveRecoveryState();
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ function isAbortLikeReceiveError(err: unknown): boolean {
|
||||
: "";
|
||||
return (
|
||||
name === "AbortError" ||
|
||||
message === "Premature close" ||
|
||||
message.includes("The operation was aborted") ||
|
||||
message.includes("aborted")
|
||||
);
|
||||
|
||||
Generated
+5
-5
@@ -616,8 +616,8 @@ importers:
|
||||
specifier: 9.0.0
|
||||
version: 9.0.0
|
||||
libopus-wasm:
|
||||
specifier: 0.0.1
|
||||
version: 0.0.1
|
||||
specifier: 0.1.0
|
||||
version: 0.1.0
|
||||
prism-media:
|
||||
specifier: 1.3.5
|
||||
version: 1.3.5
|
||||
@@ -5479,8 +5479,8 @@ packages:
|
||||
resolution: {integrity: sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==}
|
||||
engines: {node: '>=22.0.0'}
|
||||
|
||||
libopus-wasm@0.0.1:
|
||||
resolution: {integrity: sha512-w//dxORfJfLl4quaA5nEA0xZlbbtS/Gba+NrZyCDPmAQh2THX4KI6aI600f+jpxf6v3p9ApGCx0/DCCe4Xftug==}
|
||||
libopus-wasm@0.1.0:
|
||||
resolution: {integrity: sha512-/aurGcAVgy0GcBEUzFaX9pm9qv7zYcy8W5hBXFiK+cyqOXAX4lOS6rlFogkY9CcSIajhjnuXyixsbmziSHCDMQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
libsignal@6.0.0:
|
||||
@@ -11294,7 +11294,7 @@ snapshots:
|
||||
|
||||
kysely@0.29.2: {}
|
||||
|
||||
libopus-wasm@0.0.1: {}
|
||||
libopus-wasm@0.1.0: {}
|
||||
|
||||
libsignal@6.0.0:
|
||||
dependencies:
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ minimumReleaseAgeExclude:
|
||||
- "basic-ftp"
|
||||
- "baileys@7.0.0-rc13"
|
||||
- "hono"
|
||||
- "libopus-wasm@0.0.1"
|
||||
- "libopus-wasm@0.1.0"
|
||||
- "libsignal@6.0.0"
|
||||
- "openclaw"
|
||||
- "protobufjs"
|
||||
|
||||
Reference in New Issue
Block a user