/* Copyright 2024 New Vector Ltd. SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ import { DeepFilterNoiseFilterProcessor } from "deepfilternet3-noise-filter"; import { logger } from "matrix-js-sdk/lib/logger"; /** * Wrapper for DeepFilterNet3 Noise Suppression Processor. * Integrates with LiveKit audio track processing. */ export class NoiseSuppressionTransformer { private processor: DeepFilterNoiseFilterProcessor | null = null; private initialized = false; private readonly sampleRate: number = 48000; /** * Initialize the noise suppression processor * @param level - Noise reduction level (0-1) * @param enabled - Whether noise suppression is enabled */ public async initialize( level: number = 0.75, enabled: boolean = true, ): Promise { if (this.initialized) { return; } try { // Clamp level between 0-1 const clampedLevel = Math.max(0, Math.min(1, level)); // Determine asset URL based on environment // In development, use local proxy to avoid CORS issues // In production, use direct CDN or custom assetConfig const isProduction = import.meta.env.PROD; const assetUrl = isProduction ? process.env.VITE_NOISE_SUPPRESSION_CDN_URL || "https://cdn.mezon.ai/AI/models/datas/noise_suppression/deepfilternet3" : `${window.location.origin}/assets/deepfilternet3`; this.processor = new DeepFilterNoiseFilterProcessor({ sampleRate: this.sampleRate, noiseReductionLevel: clampedLevel * 100, enabled, assetConfig: { cdnUrl: assetUrl, }, }); this.initialized = true; logger.log( `[NoiseSuppressionTransformer] Initialized with level=${clampedLevel}, enabled=${enabled}, assetUrl=${assetUrl}`, ); } catch (error) { logger.error( "[NoiseSuppressionTransformer] Initialization failed:", error, ); throw error; } } /** * Get the underlying processor instance */ public getProcessor(): DeepFilterNoiseFilterProcessor | null { return this.processor; } /** * Set the noise reduction level (0-1) */ public setSuppressionLevel(level: number): void { if (!this.processor) { logger.warn( "[NoiseSuppressionTransformer] Processor not initialized, cannot set suppression level", ); return; } const clampedLevel = Math.max(0, Math.min(1, level)); try { this.processor.setSuppressionLevel(clampedLevel * 100); logger.log( `[NoiseSuppressionTransformer] Suppression level set to ${clampedLevel}`, ); } catch (error) { logger.error( "[NoiseSuppressionTransformer] Failed to set suppression level:", error, ); } } /** * Enable or disable noise suppression */ public setEnabled(enabled: boolean): void { if (!this.processor) { logger.warn( "[NoiseSuppressionTransformer] Processor not initialized, cannot set enabled state", ); return; } try { this.processor.setEnabled(enabled); logger.log( `[NoiseSuppressionTransformer] Noise suppression ${enabled ? "enabled" : "disabled"}`, ); // Log processor state for debugging const processorState = (this.processor as any).enabled; logger.debug( `[NoiseSuppressionTransformer] Processor internal state: enabled=${processorState}`, ); } catch (error) { logger.error( "[NoiseSuppressionTransformer] Failed to set enabled state:", error, ); } } /** * Clean up resources */ public destroy(): void { if (this.processor) { try { // Note: DeepFilterNoiseFilterProcessor may have a destroy method // Call it if available if (typeof (this.processor as any).destroy === "function") { (this.processor as any).destroy(); } } catch (error) { logger.error("[NoiseSuppressionTransformer] Cleanup failed:", error); } this.processor = null; this.initialized = false; } } }