SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run

This commit is contained in:
TanTan committed 2026-11-13 09:02:00 +08:00
commit fa9c73363d
1367 files changed
+355735

No files matched your search

@@ -0,0 +1,170 @@
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
import os from 'os';
import path from 'path';
import { fileURLToPath } from 'url';
import { convertAudioBytes, encodeSilk } from '@snowluma/protocol/highway/ffmpeg-addon';
interface NativeAudioAddon {
convertToNTSilkTct(inputFile: string, outputFile: string): Promise<void>;
decodeAudioToFmt(
inputFile: string,
outputFile: string,
format: string,
): Promise<{ result: boolean; sampleRate: number; channels: number; format: string }>;
getDuration(filePath: string): Promise<number>;
}
const __dirname = path.dirname(fileURLToPath(import.meta.url));
function makeMonoWav(sampleRate = 24_000, durationSeconds = 1): Buffer {
const samples = sampleRate * durationSeconds;
const bytes = Buffer.alloc(44 + samples * 2);
bytes.write('RIFF', 0);
bytes.writeUInt32LE(36 + samples * 2, 4);
bytes.write('WAVE', 8);
bytes.write('fmt ', 12);
bytes.writeUInt32LE(16, 16);
bytes.writeUInt16LE(1, 20);
bytes.writeUInt16LE(1, 22);
bytes.writeUInt32LE(sampleRate, 24);
bytes.writeUInt32LE(sampleRate * 2, 28);
bytes.writeUInt16LE(2, 32);
bytes.writeUInt16LE(16, 34);
bytes.write('data', 36);
bytes.writeUInt32LE(samples * 2, 40);
for (let i = 0; i < samples; i += 1) {
bytes.writeInt16LE(
Math.round(Math.sin((2 * Math.PI * 440 * i) / sampleRate) * 12_000),
44 + i * 2,
);
}
return bytes;
}
function loadBundledAddon(): NativeAudioAddon {
const addonPath = path.resolve(
__dirname,
`../../../runtime/native/ffmpeg/ffmpegAddon.${process.platform}.${process.arch}.node`,
);
const mod = { exports: {} as Record<string, unknown> };
process.dlopen(mod, addonPath);
return mod.exports as unknown as NativeAudioAddon;
}
function hasMp3Signature(bytes: Buffer): boolean {
const hasId3Tag = bytes.length >= 3 && bytes.subarray(0, 3).toString('ascii') === 'ID3';
const hasFrameSync = bytes.length >= 2 && bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0;
return hasId3Tag || hasFrameSync;
}
const isReleaseTarget =
(process.platform === 'win32' && process.arch === 'x64') ||
(process.platform === 'linux' && (process.arch === 'x64' || process.arch === 'arm64'));
const describeBundledAddon = isReleaseTarget ? describe : describe.skip;
describeBundledAddon('bundled native ffmpeg addon', () => {
let tmpDir: string;
beforeAll(() => {
tmpDir = mkdtempSync(path.join(os.tmpdir(), 'sl-native-audio-test-'));
});
afterAll(() => rmSync(tmpDir, { recursive: true, force: true }));
describe.each(['silk', 'ntsilk', 'extensionless'] as const)('%s duration', (format) => {
it.each([0.02, 1, 2.5])('measures %s seconds from the encoded frames', async (seconds) => {
const addon = loadBundledAddon();
const wavPath = path.join(tmpDir, `duration-${format}-${seconds}.wav`);
const recordPath = path.join(
tmpDir,
`duration-${format}-${seconds}${format === 'extensionless' ? '' : `.${format}`}`,
);
writeFileSync(wavPath, makeMonoWav(24_000, seconds));
await addon.convertToNTSilkTct(wavPath, recordPath);
if (format === 'silk') {
// Standard SILK has the same packets without the QQ container prefix.
const encoded = readFileSync(recordPath);
expect(encoded.subarray(0, 10)).toEqual(
Buffer.concat([Buffer.from([0x02]), Buffer.from('#!SILK_V3', 'ascii')]),
);
writeFileSync(recordPath, encoded.subarray(1));
}
expect(await addon.getDuration(recordPath)).toBeCloseTo(seconds, 6);
});
it('rejects a truncated packet instead of reporting a duration', async () => {
const addon = loadBundledAddon();
const wavPath = path.join(tmpDir, `truncated-${format}.wav`);
const recordPath = path.join(
tmpDir,
`truncated-${format}${format === 'extensionless' ? '' : `.${format}`}`,
);
writeFileSync(wavPath, makeMonoWav());
await addon.convertToNTSilkTct(wavPath, recordPath);
const encoded = readFileSync(recordPath);
writeFileSync(
recordPath,
encoded.subarray(format === 'silk' ? 1 : 0, encoded.length - 1),
);
await expect(addon.getDuration(recordPath)).rejects.toThrow(/Invalid data/);
await expect(encodeSilk(recordPath, tmpDir)).rejects.toThrow(/Invalid data/);
});
});
it('encodes a WAV with the runtime addon when started from the protocol package', async () => {
const wavPath = path.join(tmpDir, 'runtime-input.wav');
writeFileSync(wavPath, makeMonoWav());
const result = await encodeSilk(wavPath, tmpDir);
expect(result.converted).toBe(true);
expect(result.duration).toBe(1);
expect(readFileSync(result.path).subarray(1, 10).toString('ascii')).toBe('#!SILK_V3');
expect(await loadBundledAddon().getDuration(result.path)).toBeCloseTo(1, 6);
});
it('converts a mono QQ-style SILK record to a decodable MP3 through the public transcode seam', async () => {
const addon = loadBundledAddon();
const wavPath = path.join(tmpDir, 'mono-input.wav');
const silkPath = path.join(tmpDir, 'mono-input.ntsilk');
writeFileSync(wavPath, makeMonoWav());
await addon.convertToNTSilkTct(wavPath, silkPath);
const result = await convertAudioBytes(readFileSync(silkPath), 'mp3', { addon, tmpDir });
const mp3 = Buffer.from(result.base64, 'base64');
const outputPath = path.join(tmpDir, 'mono-output.mp3');
writeFileSync(outputPath, mp3);
expect(result.size).toBe(mp3.length);
expect(hasMp3Signature(mp3)).toBe(true);
const duration = await addon.getDuration(outputPath);
expect(duration).toBeGreaterThan(0.9);
expect(duration).toBeLessThan(1.2);
});
it('converts the QQ AI SILK container variant through the public transcode seam', async () => {
const addon = loadBundledAddon();
const wavPath = path.join(tmpDir, 'ai-input.wav');
const silkPath = path.join(tmpDir, 'ai-input.ntsilk');
writeFileSync(wavPath, makeMonoWav());
await addon.convertToNTSilkTct(wavPath, silkPath);
const aiSilk = readFileSync(silkPath);
expect(aiSilk.subarray(0, 10)).toEqual(
Buffer.concat([Buffer.from([0x02]), Buffer.from('#!SILK_V3', 'ascii')]),
);
aiSilk[0] = 0x03;
const result = await convertAudioBytes(aiSilk, 'mp3', { addon, tmpDir });
const mp3 = Buffer.from(result.base64, 'base64');
const outputPath = path.join(tmpDir, 'ai-output.mp3');
writeFileSync(outputPath, mp3);
expect(hasMp3Signature(mp3)).toBe(true);
const duration = await addon.getDuration(outputPath);
expect(duration).toBeGreaterThan(0.9);
expect(duration).toBeLessThan(1.2);
});
});