fix(frontend): track playback completion and meaningful inactivity
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { afterEach, beforeEach, expect, it, vi } from "vitest";
|
||||
|
||||
let processor: AudioWorkletProcessor;
|
||||
const port = { onmessage: undefined as ((event: MessageEvent) => void) | undefined, postMessage: vi.fn() };
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
port.postMessage.mockClear();
|
||||
vi.stubGlobal("sampleRate", 48000);
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletProcessor",
|
||||
class {
|
||||
port = port;
|
||||
},
|
||||
);
|
||||
vi.stubGlobal("registerProcessor", (_name: string, Processor: new () => AudioWorkletProcessor) => {
|
||||
processor = new Processor();
|
||||
});
|
||||
await import("./audio-playback.worklet");
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
function send(data: unknown) {
|
||||
port.onmessage?.(new MessageEvent("message", { data }));
|
||||
}
|
||||
function render(blocks: number) {
|
||||
let audible = false;
|
||||
for (let index = 0; index < blocks; index++) {
|
||||
const output = new Float32Array(128);
|
||||
processor.process([], [[output]]);
|
||||
audible ||= output.some((value) => value !== 0);
|
||||
}
|
||||
return audible;
|
||||
}
|
||||
it("flushes a final chunk shorter than the prebuffer and signals after playback finishes", () => {
|
||||
send({ kind: "audio", samples: new Float32Array(160).fill(0.5), sequence: 1 });
|
||||
expect(render(1)).toBe(false);
|
||||
expect(port.postMessage).not.toHaveBeenCalled();
|
||||
send({ kind: "finish", sequence: 1 });
|
||||
expect(render(1)).toBe(true);
|
||||
expect(port.postMessage).not.toHaveBeenCalled();
|
||||
render(12);
|
||||
expect(port.postMessage).toHaveBeenCalledExactlyOnceWith({ kind: "drained", sequence: 1 });
|
||||
});
|
||||
it("discards cleared samples and identifies the latest playback generation", () => {
|
||||
send({ kind: "audio", samples: new Float32Array(16000).fill(0.5), sequence: 1 });
|
||||
expect(render(1)).toBe(true);
|
||||
send({ kind: "clear", sequence: 2 });
|
||||
render(2);
|
||||
expect(port.postMessage).toHaveBeenLastCalledWith({ kind: "drained", sequence: 2 });
|
||||
expect(render(10)).toBe(false);
|
||||
send({ kind: "audio", samples: new Float32Array(160).fill(0.25), sequence: 3 });
|
||||
send({ kind: "finish", sequence: 3 });
|
||||
expect(render(12)).toBe(true);
|
||||
expect(port.postMessage).toHaveBeenLastCalledWith({ kind: "drained", sequence: 3 });
|
||||
});
|
||||
Reference in New Issue
Block a user