mirror of
https://github.com/vector-im/element-call.git
synced 2026-05-10 10:24:44 +00:00
tests for DeepFilterNet Noise reduction
This commit is contained in:
103
src/livekit/NoiseSuppressionTransformer.test.ts
Normal file
103
src/livekit/NoiseSuppressionTransformer.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("deepfilternet3-noise-filter", () => {
|
||||
const setEnabled = vi.fn();
|
||||
const setSuppressionLevel = vi.fn();
|
||||
const destroy = vi.fn();
|
||||
|
||||
function DeepFilterNoiseFilterProcessor(this: any, options: any) {
|
||||
Object.assign(this, options);
|
||||
this.setEnabled = setEnabled;
|
||||
this.setSuppressionLevel = setSuppressionLevel;
|
||||
this.destroy = destroy;
|
||||
}
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
DeepFilterNoiseFilterProcessor: vi.fn().mockImplementation(DeepFilterNoiseFilterProcessor),
|
||||
__setEnabledSpy: setEnabled,
|
||||
__setSuppressionLevelSpy: setSuppressionLevel,
|
||||
__destroySpy: destroy,
|
||||
};
|
||||
});
|
||||
|
||||
import { NoiseSuppressionTransformer } from "./NoiseSuppressionTransformer";
|
||||
import {
|
||||
DeepFilterNoiseFilterProcessor,
|
||||
__setEnabledSpy as mockSetEnabled,
|
||||
__setSuppressionLevelSpy as mockSetSuppressionLevel,
|
||||
__destroySpy as mockDestroy,
|
||||
} from "deepfilternet3-noise-filter";
|
||||
|
||||
const mockDeepFilterNoiseFilterProcessor = vi.mocked(DeepFilterNoiseFilterProcessor);
|
||||
|
||||
describe("NoiseSuppressionTransformer", () => {
|
||||
beforeEach(() => {
|
||||
mockSetEnabled.mockClear();
|
||||
mockSetSuppressionLevel.mockClear();
|
||||
mockDestroy.mockClear();
|
||||
mockDeepFilterNoiseFilterProcessor.mockClear();
|
||||
});
|
||||
|
||||
it("initializes the underlying processor with the expected configuration", () => {
|
||||
const transformer = new NoiseSuppressionTransformer();
|
||||
|
||||
transformer.initialize(0.5, false);
|
||||
|
||||
expect(mockDeepFilterNoiseFilterProcessor).toHaveBeenCalledTimes(1);
|
||||
expect(mockDeepFilterNoiseFilterProcessor).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sampleRate: 48000,
|
||||
noiseReductionLevel: 50,
|
||||
enabled: false,
|
||||
assetConfig: expect.objectContaining({
|
||||
cdnUrl: expect.any(String),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(transformer.getProcessor()).not.toBeNull();
|
||||
});
|
||||
|
||||
it("does not initialize twice", () => {
|
||||
const transformer = new NoiseSuppressionTransformer();
|
||||
|
||||
transformer.initialize(0.3, true);
|
||||
transformer.initialize(0.7, false);
|
||||
|
||||
expect(mockDeepFilterNoiseFilterProcessor).toHaveBeenCalledTimes(1);
|
||||
expect(transformer.getProcessor()).not.toBeNull();
|
||||
});
|
||||
|
||||
it("forwards suppression level changes and clamps out-of-range values", () => {
|
||||
const transformer = new NoiseSuppressionTransformer();
|
||||
transformer.initialize(0.2, true);
|
||||
|
||||
transformer.setSuppressionLevel(1.5);
|
||||
transformer.setSuppressionLevel(-0.2);
|
||||
|
||||
expect(mockSetSuppressionLevel).toHaveBeenNthCalledWith(1, 100);
|
||||
expect(mockSetSuppressionLevel).toHaveBeenNthCalledWith(2, 0);
|
||||
});
|
||||
|
||||
it("forwards enabled state changes to the underlying processor", () => {
|
||||
const transformer = new NoiseSuppressionTransformer();
|
||||
transformer.initialize(0.4, true);
|
||||
|
||||
transformer.setEnabled(false);
|
||||
transformer.setEnabled(true);
|
||||
|
||||
expect(mockSetEnabled).toHaveBeenNthCalledWith(1, false);
|
||||
expect(mockSetEnabled).toHaveBeenNthCalledWith(2, true);
|
||||
});
|
||||
|
||||
it("destroys the processor and resets internal state", () => {
|
||||
const transformer = new NoiseSuppressionTransformer();
|
||||
transformer.initialize(0.6, true);
|
||||
|
||||
transformer.destroy();
|
||||
|
||||
expect(mockDestroy).toHaveBeenCalledTimes(1);
|
||||
expect(transformer.getProcessor()).toBeNull();
|
||||
});
|
||||
});
|
||||
120
src/livekit/audioTrackNoiseSuppressionSync.test.ts
Normal file
120
src/livekit/audioTrackNoiseSuppressionSync.test.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
const localStorageMock = {
|
||||
getItem: vi.fn(() => null),
|
||||
setItem: vi.fn(() => {}),
|
||||
removeItem: vi.fn(() => {}),
|
||||
clear: vi.fn(() => {}),
|
||||
};
|
||||
|
||||
Object.defineProperty(globalThis, "localStorage", {
|
||||
value: localStorageMock,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
|
||||
vi.mock("deepfilternet3-noise-filter", () => {
|
||||
const setEnabled = vi.fn();
|
||||
const setSuppressionLevel = vi.fn();
|
||||
const destroy = vi.fn();
|
||||
|
||||
function DeepFilterNoiseFilterProcessor(this: any, options: any) {
|
||||
Object.assign(this, options);
|
||||
this.setEnabled = setEnabled;
|
||||
this.setSuppressionLevel = setSuppressionLevel;
|
||||
this.destroy = destroy;
|
||||
}
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
DeepFilterNoiseFilterProcessor: vi.fn().mockImplementation(DeepFilterNoiseFilterProcessor),
|
||||
__setEnabledSpy: setEnabled,
|
||||
__setSuppressionLevelSpy: setSuppressionLevel,
|
||||
__destroySpy: destroy,
|
||||
};
|
||||
});
|
||||
|
||||
import { ObservableScope } from "../state/ObservableScope";
|
||||
import type { LocalAudioTrack } from "livekit-client";
|
||||
import type { Behavior } from "../state/Behavior";
|
||||
import {
|
||||
__setEnabledSpy as mockSetEnabled,
|
||||
__setSuppressionLevelSpy as mockSetSuppressionLevel,
|
||||
__destroySpy as mockDestroy,
|
||||
} from "deepfilternet3-noise-filter";
|
||||
|
||||
let audioTrackNoiseSuppressionSync: typeof import("./audioTrackNoiseSuppressionSync").audioTrackNoiseSuppressionSync;
|
||||
let noiseSuppressionEnabled: typeof import("../settings/settings").noiseSuppressionEnabled;
|
||||
let noiseSuppressionLevel: typeof import("../settings/settings").noiseSuppressionLevel;
|
||||
|
||||
class MockLocalAudioTrack {
|
||||
private processor: unknown = undefined;
|
||||
public readonly setProcessor = vi.fn(async (processor: unknown) => {
|
||||
this.processor = processor;
|
||||
});
|
||||
public readonly getProcessor = vi.fn(() => this.processor);
|
||||
public readonly stopProcessor = vi.fn(async () => {
|
||||
this.processor = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
describe("audioTrackNoiseSuppressionSync", () => {
|
||||
let scope: ObservableScope;
|
||||
let audioTrack$: Behavior<LocalAudioTrack | null>;
|
||||
let track: MockLocalAudioTrack;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockSetEnabled.mockClear();
|
||||
mockSetSuppressionLevel.mockClear();
|
||||
mockDestroy.mockClear();
|
||||
track = new MockLocalAudioTrack();
|
||||
audioTrack$ = new BehaviorSubject<LocalAudioTrack | null>(track as unknown as LocalAudioTrack);
|
||||
const settingsModule = await import("../settings/settings");
|
||||
noiseSuppressionEnabled = settingsModule.noiseSuppressionEnabled;
|
||||
noiseSuppressionLevel = settingsModule.noiseSuppressionLevel;
|
||||
const syncModule = await import("./audioTrackNoiseSuppressionSync");
|
||||
audioTrackNoiseSuppressionSync = syncModule.audioTrackNoiseSuppressionSync;
|
||||
noiseSuppressionEnabled.setValue(true);
|
||||
noiseSuppressionLevel.setValue(0.75);
|
||||
scope = new ObservableScope();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
scope.end();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
it("sets the processor on the audio track and updates the processor settings", async () => {
|
||||
audioTrackNoiseSuppressionSync(scope, audioTrack$);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(track.setProcessor).toHaveBeenCalledTimes(1);
|
||||
expect(track.getProcessor()).not.toBeUndefined();
|
||||
expect(mockSetEnabled).toHaveBeenCalledWith(false);
|
||||
expect(mockSetSuppressionLevel).toHaveBeenCalledWith(75);
|
||||
});
|
||||
|
||||
it("reapplies processor when audio track becomes available", async () => {
|
||||
audioTrack$ = new BehaviorSubject<LocalAudioTrack | null>(null);
|
||||
audioTrackNoiseSuppressionSync(scope, audioTrack$);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(track.setProcessor).toHaveBeenCalledTimes(0);
|
||||
|
||||
audioTrack$.next(track as unknown as LocalAudioTrack);
|
||||
await Promise.resolve();
|
||||
|
||||
expect(track.setProcessor).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("destroys the transformer when the scope ends", async () => {
|
||||
audioTrackNoiseSuppressionSync(scope, audioTrack$);
|
||||
await Promise.resolve();
|
||||
|
||||
scope.end();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(mockDestroy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user