@newgameplusinc/alpha-spatial-comms 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1092 -0
- package/dist/index.d.mts +342 -0
- package/dist/index.d.ts +342 -0
- package/dist/index.js +3275 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3252 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/EventManager.ts","../src/core/MediasoupManager.ts","../src/channels/spatial/SpatialAudioTypes.ts","../src/utils/spatial/distance-calc.ts","../src/utils/spatial/gain-calc.ts","../src/utils/spatial/pan-calc.ts","../src/utils/spatial/head-position.ts","../src/utils/position/normalize.ts","../src/utils/position/snap.ts","../src/utils/smoothing/pan-smoothing.ts","../src/utils/smoothing/gain-smoothing.ts","../src/audio/MLNoiseSuppressor.ts","../src/utils/debug.ts","../src/channels/spatial/SpatialAudioChannel.ts","../src/screen-share-live-in-space/screen-share-live-manager.ts","../src/core/room.ts","../src/producers/tracks.ts","../src/events/listeners.ts","../src/chat/ChatManager.ts","../src/index.ts"],"names":["ready","sum","bins","lastGain","io"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Event Bus (factory function)\n *\n * A lightweight in-process event bus for SDK events.\n * No Node.js `events` dependency — runs natively in the browser.\n */\n\nimport {OdysseyEvent} from \"../types/events\";\n\nexport interface EventBus {\n on(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n off(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n emit(event: OdysseyEvent, ...args: any[]): void;\n removeAllListeners(event?: OdysseyEvent): void;\n}\n\nexport function createEventBus(): EventBus {\n const listeners = new Map<string, Set<(...args: any[]) => void>>();\n\n function on(event: OdysseyEvent, listener: (...args: any[]) => void): void {\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(listener);\n }\n\n function off(event: OdysseyEvent, listener: (...args: any[]) => void): void {\n listeners.get(event)?.delete(listener);\n }\n\n function emit(event: OdysseyEvent, ...args: any[]): void {\n listeners.get(event)?.forEach((fn) => fn(...args));\n }\n\n function removeAllListeners(event?: OdysseyEvent): void {\n if (event) {\n listeners.delete(event);\n } else {\n listeners.clear();\n }\n }\n\n return {on, off, emit, removeAllListeners};\n}\n","/**\n * Mediasoup Manager (factory function)\n *\n * Handles WebRTC transport, producer, and consumer management\n * using the mediasoup-client library.\n */\n\nimport * as mediasoupClient from \"mediasoup-client\";\nimport {Device, types} from \"mediasoup-client\";\nimport {Socket} from \"socket.io-client\";\nimport {createEventBus, EventBus} from \"./EventManager\";\nimport {OdysseyEvent} from \"../types/events\";\n\n// ─── Public types ─────────────────────────────────────────────────────────────\n\nexport type TransportEvent =\n | \"transport-connected\"\n | \"transport-disconnected\"\n | \"transport-failed\"\n | \"transport-closed\"\n | \"transport-connecting\";\n\nexport interface ConsumeData {\n consumerId: string;\n producerId: string;\n kind: \"audio\" | \"video\";\n rtpParameters: types.RtpParameters;\n participantId: string;\n}\n\n// ─── Factory handle interface ──────────────────────────────────────────────────\n\nexport interface MediasoupManagerHandle {\n loadDevice(routerRtpCapabilities: types.RtpCapabilities): Promise<void>;\n sendDeviceRtpCapabilities(participantId: string): void;\n createSendTransport(participantId: string): Promise<void>;\n createRecvTransport(participantId: string): Promise<void>;\n produce(\n track: MediaStreamTrack,\n appData?: {isScreenshare?: boolean}\n ): Promise<types.Producer>;\n consume(\n data: ConsumeData\n ): Promise<{consumer: types.Consumer; track: MediaStreamTrack}>;\n resumeConsumer(consumerId: string): Promise<void>;\n getTransportStates(): {send: string; recv: string};\n getConsumers(): Map<string, types.Consumer>;\n close(): void;\n onTransportEvent(\n event: TransportEvent,\n listener: (data: {direction: string; reason?: string}) => void\n ): void;\n}\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport function createMediasoupManager(socket: Socket): MediasoupManagerHandle {\n const device = new Device();\n let sendTransport: types.Transport | null = null;\n let recvTransport: types.Transport | null = null;\n const producers = new Map<string, types.Producer>();\n const consumers = new Map<string, types.Consumer>();\n let participantId = \"\";\n let sendTransportState = \"new\";\n let recvTransportState = \"new\";\n let iceRestartAttempts = 0;\n const MAX_ICE_RESTART_ATTEMPTS = 3;\n\n // Internal event bus for transport events (replaces EventEmitter inheritance)\n const internalBus: EventBus = createEventBus();\n\n function emitTransportEvent(\n event: TransportEvent,\n data: {direction: string; reason?: string}\n ): void {\n internalBus.emit(event as OdysseyEvent, data);\n }\n\n async function loadDevice(\n routerRtpCapabilities: types.RtpCapabilities\n ): Promise<void> {\n if (device.loaded) return;\n await device.load({routerRtpCapabilities});\n }\n\n function sendDeviceRtpCapabilities(pid: string): void {\n participantId = pid;\n socket.emit(\"device-rtp-capabilities\", {\n participantId: pid,\n rtpCapabilities: device.rtpCapabilities,\n });\n }\n\n function createWebRtcTransport(\n direction: \"send\" | \"recv\",\n pid: string\n ): Promise<mediasoupClient.types.TransportOptions> {\n return new Promise((resolve, reject) => {\n const handleTransportCreated = (data: {\n type: string;\n error?: string;\n params: mediasoupClient.types.TransportOptions;\n }) => {\n if (data.type === direction) {\n socket.off(\"transport-created\", handleTransportCreated);\n if (data.error) return reject(new Error(data.error));\n resolve(data.params);\n }\n };\n\n socket.on(\"transport-created\", handleTransportCreated);\n socket.emit(\"create-transport\", {direction, participantId: pid});\n\n setTimeout(() => {\n socket.off(\"transport-created\", handleTransportCreated);\n reject(new Error(`Timeout waiting for ${direction} transport`));\n }, 10000);\n });\n }\n\n function attemptIceRestart(direction: \"send\" | \"recv\"): void {\n if (iceRestartAttempts >= MAX_ICE_RESTART_ATTEMPTS) {\n emitTransportEvent(\"transport-failed\", {\n direction,\n reason: \"max-ice-restarts\",\n });\n return;\n }\n\n iceRestartAttempts++;\n const transport = direction === \"send\" ? sendTransport : recvTransport;\n if (!transport) return;\n\n socket.emit(\n \"request-ice-restart\",\n {participantId, transportId: transport.id, direction},\n async (response: {\n error?: string;\n iceParameters?: types.IceParameters;\n }) => {\n if (response.error) {\n setTimeout(() => attemptIceRestart(direction), 2000);\n return;\n }\n if (response.iceParameters) {\n try {\n await transport.restartIce({iceParameters: response.iceParameters});\n } catch {\n setTimeout(() => attemptIceRestart(direction), 2000);\n }\n }\n }\n );\n }\n\n function connectSendTransport(): void {\n sendTransport?.on(\n \"connect\",\n async (\n {dtlsParameters}: {dtlsParameters: types.DtlsParameters},\n callback: () => void,\n errback: (error: Error) => void\n ) => {\n socket.emit(\n \"connect-transport\",\n {transportId: sendTransport!.id, dtlsParameters},\n (response: {error?: string}) => {\n if (response.error) {\n errback(new Error(response.error));\n } else {\n callback();\n }\n }\n );\n }\n );\n\n sendTransport?.on(\n \"produce\",\n async (\n {\n kind,\n rtpParameters,\n appData,\n }: {\n kind: types.MediaKind;\n rtpParameters: types.RtpParameters;\n appData: Record<string, unknown>;\n },\n callback: ({id}: {id: string}) => void,\n errback: (error: Error) => void\n ) => {\n socket.emit(\n \"produce\",\n {\n transportId: sendTransport!.id,\n kind,\n rtpParameters,\n appData,\n },\n (response: {error?: string; producerId?: string}) => {\n if (response.error) {\n errback(new Error(response.error));\n } else if (response.producerId) {\n callback({id: response.producerId});\n }\n }\n );\n }\n );\n\n sendTransport?.on(\"connectionstatechange\", (state: string) => {\n sendTransportState = state;\n switch (state) {\n case \"connected\":\n iceRestartAttempts = 0;\n emitTransportEvent(\"transport-connected\", {direction: \"send\"});\n break;\n case \"disconnected\":\n emitTransportEvent(\"transport-disconnected\", {direction: \"send\"});\n attemptIceRestart(\"send\");\n break;\n case \"failed\":\n producers.clear();\n emitTransportEvent(\"transport-failed\", {direction: \"send\"});\n socket.emit(\"transport-failed\", {participantId, direction: \"send\"});\n break;\n case \"closed\":\n producers.clear();\n emitTransportEvent(\"transport-closed\", {direction: \"send\"});\n break;\n case \"connecting\":\n emitTransportEvent(\"transport-connecting\", {direction: \"send\"});\n break;\n }\n });\n }\n\n function connectRecvTransport(): void {\n recvTransport?.on(\n \"connect\",\n async (\n {dtlsParameters}: {dtlsParameters: types.DtlsParameters},\n callback: () => void,\n errback: (error: Error) => void\n ) => {\n socket.emit(\n \"connect-transport\",\n {transportId: recvTransport!.id, dtlsParameters},\n (response: {error?: string}) => {\n if (response.error) {\n errback(new Error(response.error));\n } else {\n callback();\n }\n }\n );\n }\n );\n\n recvTransport?.on(\"connectionstatechange\", (state: string) => {\n recvTransportState = state;\n switch (state) {\n case \"connected\":\n iceRestartAttempts = 0;\n emitTransportEvent(\"transport-connected\", {direction: \"recv\"});\n break;\n case \"disconnected\":\n emitTransportEvent(\"transport-disconnected\", {direction: \"recv\"});\n attemptIceRestart(\"recv\");\n break;\n case \"failed\":\n emitTransportEvent(\"transport-failed\", {direction: \"recv\"});\n socket.emit(\"transport-failed\", {participantId, direction: \"recv\"});\n break;\n case \"closed\":\n emitTransportEvent(\"transport-closed\", {direction: \"recv\"});\n break;\n case \"connecting\":\n emitTransportEvent(\"transport-connecting\", {direction: \"recv\"});\n break;\n }\n });\n }\n\n async function createSendTransport(pid: string): Promise<void> {\n const params = await createWebRtcTransport(\"send\", pid);\n const {iceServers, ...transportParams} = params as typeof params & {\n iceServers?: RTCIceServer[];\n };\n sendTransport = device.createSendTransport({\n ...transportParams,\n iceServers: iceServers || [],\n });\n connectSendTransport();\n }\n\n async function createRecvTransport(pid: string): Promise<void> {\n const params = await createWebRtcTransport(\"recv\", pid);\n const {iceServers, ...transportParams} = params as typeof params & {\n iceServers?: RTCIceServer[];\n };\n recvTransport = device.createRecvTransport({\n ...transportParams,\n iceServers: iceServers || [],\n });\n connectRecvTransport();\n }\n\n async function produce(\n track: MediaStreamTrack,\n appData?: {isScreenshare?: boolean}\n ): Promise<types.Producer> {\n if (!sendTransport) throw new Error(\"Send transport not initialized\");\n\n const produceOptions: {\n track: MediaStreamTrack;\n appData?: Record<string, unknown>;\n encodings?: types.RtpEncodingParameters[];\n codecOptions?: {videoGoogleStartBitrate?: number};\n } = {track, appData};\n\n const isScreenshare = appData?.isScreenshare === true;\n\n if (track.kind === \"video\") {\n if (isScreenshare) {\n produceOptions.encodings = [\n {\n rid: \"r0\",\n active: true,\n maxBitrate: 500000,\n maxFramerate: 10,\n scaleResolutionDownBy: 4,\n },\n {\n rid: \"r1\",\n active: true,\n maxBitrate: 1500000,\n maxFramerate: 15,\n scaleResolutionDownBy: 2,\n },\n {\n rid: \"r2\",\n active: true,\n maxBitrate: 3000000,\n maxFramerate: 15,\n scaleResolutionDownBy: 1,\n },\n ];\n produceOptions.codecOptions = {videoGoogleStartBitrate: 1500};\n } else {\n produceOptions.encodings = [\n {\n rid: \"r0\",\n active: true,\n maxBitrate: 100000,\n scaleResolutionDownBy: 4,\n },\n {\n rid: \"r1\",\n active: true,\n maxBitrate: 300000,\n scaleResolutionDownBy: 2,\n },\n {\n rid: \"r2\",\n active: true,\n maxBitrate: 900000,\n scaleResolutionDownBy: 1,\n },\n ];\n produceOptions.codecOptions = {videoGoogleStartBitrate: 1000};\n }\n }\n\n const producer = await sendTransport.produce(produceOptions);\n\n producer.on(\"transportclose\", () => {\n producers.delete(producer.id);\n });\n producer.on(\"trackended\", () => {\n producer.close();\n producers.delete(producer.id);\n });\n\n producers.set(producer.id, producer);\n return producer;\n }\n\n async function consume(\n data: ConsumeData\n ): Promise<{consumer: types.Consumer; track: MediaStreamTrack}> {\n if (!recvTransport) throw new Error(\"Receive transport not set up\");\n\n const consumer = await recvTransport.consume({\n id: data.consumerId,\n producerId: data.producerId,\n kind: data.kind,\n rtpParameters: data.rtpParameters,\n });\n\n consumer.on(\"transportclose\", () => {\n consumers.delete(consumer.id);\n });\n consumer.on(\"trackended\", () => {\n consumer.close();\n consumers.delete(consumer.id);\n });\n\n consumers.set(consumer.id, consumer);\n return {consumer, track: consumer.track};\n }\n\n async function resumeConsumer(consumerId: string): Promise<void> {\n return new Promise((resolve, reject) => {\n socket.emit(\n \"resume-consumer\",\n {consumerId, participantId},\n (response: {error?: string}) => {\n if (response.error) {\n reject(new Error(response.error));\n } else {\n resolve();\n }\n }\n );\n });\n }\n\n function getTransportStates(): {send: string; recv: string} {\n return {send: sendTransportState, recv: recvTransportState};\n }\n\n function getConsumers(): Map<string, types.Consumer> {\n return consumers;\n }\n\n function close(): void {\n producers.forEach((p) => p.close());\n consumers.forEach((c) => c.close());\n if (sendTransport) sendTransport.close();\n if (recvTransport) recvTransport.close();\n producers.clear();\n consumers.clear();\n }\n\n return {\n loadDevice,\n sendDeviceRtpCapabilities,\n createSendTransport,\n createRecvTransport,\n produce,\n consume,\n resumeConsumer,\n getTransportStates,\n getConsumers,\n close,\n onTransportEvent: (\n event: TransportEvent,\n listener: (data: {direction: string; reason?: string}) => void\n ) => internalBus.on(event as OdysseyEvent, listener),\n };\n}\n","/**\n * Spatial Audio Types\n *\n * Type definitions for spatial audio processing\n */\n\n/**\n * Spatial audio distance configuration\n *\n * DISTANCE-BASED GAIN SPECIFICATION (CUBIC FALLOFF):\n * ┌──────────────┬─────────┬────────────────────────────────┐\n * │ Distance │ Gain % │ Description │\n * ├──────────────┼─────────┼────────────────────────────────┤\n * │ 0.0 - 0.5m │ 100% │ Full volume (intimate) │\n * │ 1.0m │ ~90% │ Very close - still loud │\n * │ 2.0m │ ~72% │ Normal talking - NOTICEABLE │\n * │ 3.0m │ ~57% │ Across table - CLEARLY QUIETER │\n * │ 5.0m │ ~33% │ Across room - MUCH QUIETER │\n * │ 7.0m │ ~17% │ Far end of room - very faint │\n * │ 10.0m │ ~4% │ Barely audible │\n * │ ≥15.0m │ 0% │ Silent (COMPLETE CUTOFF) │\n * └──────────────┴─────────┴────────────────────────────────┘\n */\nexport interface SpatialDistanceConfig {\n refDistance?: number; // Full volume at this distance (meters)\n maxDistance?: number; // Silent beyond this distance (meters)\n rolloffFactor?: number; // Unused (kept for compatibility)\n unit?: \"auto\" | \"meters\" | \"centimeters\";\n}\n\n/**\n * Default spatial distance configuration\n * User requirement: 0.5m = 100%, 15m = 0% (audio OFF)\n */\nexport const DEFAULT_SPATIAL_CONFIG: Required<SpatialDistanceConfig> = {\n refDistance: 0.5, // Full volume at 0.5m or closer\n maxDistance: 15, // Silent at 15m (audio cutoff at 15.1m+)\n rolloffFactor: 1, // Unused - we use quadratic falloff\n unit: \"auto\",\n};\n\n/**\n * Denoiser options for noise suppression\n */\nexport interface DenoiserOptions {\n enabled?: boolean;\n threshold?: number;\n noiseFloor?: number;\n release?: number;\n attack?: number;\n holdMs?: number;\n maxReduction?: number;\n hissCut?: number;\n expansionRatio?: number;\n learnRate?: number;\n voiceBoost?: number;\n voiceSensitivity?: number;\n voiceEnhancement?: boolean;\n silenceFloor?: number;\n silenceHoldMs?: number;\n silenceReleaseMs?: number;\n speechBoost?: number;\n highBandGate?: number;\n highBandAttack?: number;\n highBandRelease?: number;\n}\n\n/**\n * Default denoiser configuration\n */\nexport const DEFAULT_DENOISER_OPTIONS: Required<DenoiserOptions> = {\n enabled: false,\n threshold: 0.002,\n noiseFloor: 0.0005,\n release: 0.4,\n attack: 0.1,\n holdMs: 200,\n maxReduction: 0.15,\n hissCut: 0.15,\n expansionRatio: 1.05,\n learnRate: 0.03,\n voiceBoost: 0.35,\n voiceSensitivity: 0.1,\n voiceEnhancement: false,\n silenceFloor: 0.0002,\n silenceHoldMs: 400,\n silenceReleaseMs: 200,\n speechBoost: 0.25,\n highBandGate: 0.15,\n highBandAttack: 0.08,\n highBandRelease: 0.03,\n};\n\n/**\n * Audio nodes for a participant\n */\nexport interface ParticipantAudioNodes {\n source: MediaStreamAudioSourceNode;\n panner: PannerNode;\n stereoPanner: StereoPannerNode;\n monoSplitter: ChannelSplitterNode;\n monoGainL: GainNode;\n monoGainR: GainNode;\n monoMerger: ChannelMergerNode;\n stereoUpmixer: ChannelMergerNode;\n analyser: AnalyserNode;\n gain: GainNode;\n proximityGain: GainNode;\n compressor: DynamicsCompressorNode;\n highpassFilter: BiquadFilterNode;\n lowpassFilter: BiquadFilterNode;\n voiceBandFilter: BiquadFilterNode;\n dynamicLowpass: BiquadFilterNode;\n denoiseNode?: AudioWorkletNode;\n stream: MediaStream;\n}\n\n/**\n * Listener state\n */\nexport interface ListenerState {\n position: {x: number; y: number; z: number};\n right: {x: number; z: number};\n initialized: boolean;\n}\n","/**\n * Distance Calculations\n *\n * Functions for calculating distances between positions in 3D space\n */\n\nimport {Position} from \"../../types/position\";\n\n/**\n * Calculate 3D Euclidean distance between two positions\n * distance = √(Δx² + Δy² + Δz²)\n *\n * @param a First position\n * @param b Second position\n * @returns Distance in the same units as input positions\n */\nexport function getDistanceBetween(a: Position, b: Position): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const dz = b.z - a.z;\n return Math.sqrt(dx * dx + dy * dy + dz * dz);\n}\n\n/**\n * Calculate horizontal distance (XZ plane only, ignoring Y/height)\n * Useful for spatial audio where vertical distance matters less\n *\n * @param a First position\n * @param b Second position\n * @returns Horizontal distance\n */\nexport function getHorizontalDistance(a: Position, b: Position): number {\n const dx = b.x - a.x;\n const dz = b.z - a.z;\n return Math.sqrt(dx * dx + dz * dz);\n}\n\n/**\n * Check if a position is within a certain range of another\n *\n * @param a First position\n * @param b Second position\n * @param maxDistance Maximum allowed distance\n * @returns True if within range\n */\nexport function isWithinRange(\n a: Position,\n b: Position,\n maxDistance: number\n): boolean {\n return getDistanceBetween(a, b) <= maxDistance;\n}\n","/**\n * Gain Calculations\n *\n * Functions for calculating audio gain based on distance\n * Uses CUBIC EXPONENTIAL equation for clearly NOTICEABLE volume changes\n */\n\n/**\n * Gain calculation configuration\n */\nexport interface GainConfig {\n minDistance?: number; // Full volume at this distance (meters)\n maxDistance?: number; // Silent beyond this distance (meters)\n}\n\n/**\n * Default gain configuration\n * CUBIC FALLOFF settings for noticeable volume changes:\n * - 0.5m or closer: 100% volume\n * - 5m: ~33% volume (clearly quieter)\n * - 10m: ~4% volume (barely audible)\n * - 15m or further: 0% volume (SILENT - complete cutoff)\n */\nexport const DEFAULT_GAIN_CONFIG: Required<GainConfig> = {\n minDistance: 0.5, // Full volume at 0.5m or closer\n maxDistance: 15.0, // Silent at 15m\n};\n\n/**\n * Calculate gain based on distance using CUBIC EXPONENTIAL equation\n *\n * Uses CUBIC (cubed) falloff for clearly NOTICEABLE volume drops:\n * Gain = 100 * (1 - normalized)³\n *\n * Distance → Gain mapping (with 0.5m-15m range):\n * ┌──────────────┬─────────┬────────────────────────────────┐\n * │ Distance │ Gain % │ Description │\n * ├──────────────┼─────────┼────────────────────────────────┤\n * │ 0.0 - 0.5m │ 100% │ Full volume (intimate) │\n * │ 1.0m │ ~90% │ Very close - still loud │\n * │ 2.0m │ ~72% │ Normal talking - NOTICEABLE │\n * │ 3.0m │ ~57% │ Across table - CLEARLY QUIETER │\n * │ 5.0m │ ~33% │ Across room - MUCH QUIETER │\n * │ 7.0m │ ~17% │ Far end of room - very faint │\n * │ 10.0m │ ~4% │ Barely audible │\n * │ ≥15.0m │ 0% │ Silent (cutoff) │\n * └──────────────┴─────────┴────────────────────────────────┘\n *\n * @param distance Distance in meters\n * @param config Optional gain configuration\n * @returns Gain as percentage (0-100)\n */\nexport function calculateLogarithmicGain(\n distance: number,\n config: GainConfig = {}\n): number {\n const {minDistance, maxDistance} = {\n ...DEFAULT_GAIN_CONFIG,\n ...config,\n };\n\n // Beyond max distance = SILENT (0%) - HARD CUTOFF\n if (distance >= maxDistance) return 0;\n\n // Full volume within minimum distance\n if (distance <= minDistance) return 100;\n\n // CUBIC EXPONENTIAL FALLOFF for noticeable volume changes\n // Formula: gain = 100 * (1 - normalized)³\n // The cubed term makes volume drop STEEPER than squared\n //\n // Example: At 3m distance, gain ≈ 57% (clearly quieter!)\n // Example: At 5m distance, gain ≈ 33% (MUCH quieter!)\n // Example: At 10m distance, gain ≈ 4% (barely audible)\n // Example: At 15m+ distance, gain = 0% (SILENT)\n\n const range = maxDistance - minDistance;\n const normalizedDistance = (distance - minDistance) / range;\n\n // CUBIC falloff: (1 - x)³ where x is 0 to 1\n const remainingRatio = 1 - normalizedDistance;\n const gain = 100 * remainingRatio * remainingRatio * remainingRatio;\n\n // Ensure we never go negative\n return Math.max(0, gain);\n}\n","/**\n * Pan Calculations\n *\n * Functions for calculating stereo panning based on listener/source positions\n *\n * 360° PANNING SPECIFICATION:\n * ┌──────────────┬─────────────┬────────────────────────────────┐\n * │ Angle │ Pan (L, R) │ Description │\n * ├──────────────┼─────────────┼────────────────────────────────┤\n * │ 0° (front) │ L100, R100 │ Sound in both ears (center) │\n * │ 45° (f-right)│ L50, R100 │ Mostly right, some left │\n * │ 90° (right) │ L0, R100 │ Full RIGHT ear only │\n * │ 135° (b-right)│ L50, R100 │ Mostly right, some left │\n * │ 180° (behind)│ L100, R100 │ Sound in both ears (center) │\n * │ 225° (b-left)│ L100, R50 │ Mostly left, some right │\n * │ 270° (left) │ L100, R0 │ Full LEFT ear only │\n * │ 315° (f-left)│ L100, R50 │ Mostly left, some right │\n * └──────────────┴─────────────┴────────────────────────────────┘\n */\n\nimport {Position, ListenerRight} from \"../../types/position\";\n\n/**\n * Panning values for left/right channels\n */\nexport interface Panning {\n left: number; // 0-100 percentage\n right: number; // 0-100 percentage\n}\n\n/**\n * Calculate listener's right-ear vector from yaw rotation\n *\n * CLOCKWISE ROTATION (Game Engine Standard):\n * 0° → Facing +Z (forward), right ear → +X\n * 90° → Facing +X (right), right ear → -Z\n * 180° → Facing -Z (back), right ear → -X\n * 270° → Facing -X (left), right ear → +Z\n *\n * @param yawDegrees Yaw rotation in degrees (CLOCKWISE from +Z)\n * @returns Unit vector pointing to listener's right ear (X, Z components)\n */\nexport function calculateListenerRight(yawDegrees: number): ListenerRight {\n // CLOCKWISE rotation formula (standard game engine convention)\n const yawRad = (yawDegrees * Math.PI) / 180;\n\n // Right ear vector:\n // cos(yaw) for X component\n // -sin(yaw) for Z component (NEGATIVE sine for CLOCKWISE)\n return {\n x: Math.cos(yawRad),\n z: -Math.sin(yawRad),\n };\n}\n\n/**\n * Calculate pan value from listener and source positions\n *\n * Uses atan2 + sin for TRUE 360° spatial audio:\n * - 0° (front): pan = 0 → center\n * - 90° (right): pan = +1 → full right\n * - 180° (behind): pan = 0 → center\n * - 270° (left): pan = -1 → full left\n *\n * @param listenerPos Listener position\n * @param sourcePos Sound source position\n * @param listenerRight Listener's right-ear unit vector\n * @returns Pan value from -1 (full left) to +1 (full right)\n */\nexport function calculatePanFromPositions(\n listenerPos: Position,\n sourcePos: Position,\n listenerRight: ListenerRight\n): number {\n // Calculate relative vector (speaker relative to listener)\n const vecToSource = {\n x: sourcePos.x - listenerPos.x,\n z: sourcePos.z - listenerPos.z,\n };\n\n // Project onto listener's right-ear axis using dot product\n // Positive = sound is to the RIGHT of listener\n // Negative = sound is to the LEFT of listener\n const dxLocal =\n vecToSource.x * listenerRight.x + vecToSource.z * listenerRight.z;\n\n // Calculate forward component (dzLocal)\n // Forward vector is right vector rotated 90° counter-clockwise: (x,z) -> (-z,x)\n const listenerForward = {x: -listenerRight.z, z: listenerRight.x};\n const dzLocal =\n vecToSource.x * listenerForward.x + vecToSource.z * listenerForward.z;\n\n // TRUE 360° SPATIAL AUDIO PANNING\n // Calculate angle from listener to source using atan2\n // atan2(dxLocal, dzLocal) gives angle from forward direction\n // Range: -π to +π radians (-180° to +180°)\n const angleToSource = Math.atan2(dxLocal, dzLocal);\n\n // Convert to pan value using sine\n // sin(angle) maps:\n // 0° (front) → sin(0) = 0 → CENTER\n // 45° (f-R) → sin(π/4) ≈ 0.71 → PARTIAL RIGHT\n // 90° (right) → sin(π/2) = 1 → FULL RIGHT\n // 135° (b-R) → sin(3π/4) ≈ 0.71→ PARTIAL RIGHT\n // 180° (back) → sin(π) = 0 → CENTER\n // -45° (f-L) → sin(-π/4) ≈-0.71→ PARTIAL LEFT\n // -90° (left) → sin(-π/2) = -1 → FULL LEFT\n // -135° (b-L) → sin(-3π/4)≈-0.71→ PARTIAL LEFT\n const rawPanValue = Math.sin(angleToSource);\n\n return rawPanValue;\n}\n\n/**\n * Convert pan value (-1 to +1) to left/right channel percentages\n *\n * EXACT SPECIFICATION:\n * ┌───────────┬──────────┬───────────┬─────────────────────┐\n * │ Pan Value │ Left Ear │ Right Ear │ Angle (from front) │\n * ├───────────┼──────────┼───────────┼─────────────────────┤\n * │ -1.0 │ 100% │ 0% │ 270° (full left) │\n * │ -0.71 │ 100% │ 50% │ 315° or 225° │\n * │ -0.5 │ 100% │ 50% │ ~330° or ~210° │\n * │ 0.0 │ 100% │ 100% │ 0° or 180° (center) │\n * │ +0.5 │ 50% │ 100% │ ~30° or ~150° │\n * │ +0.71 │ 50% │ 100% │ 45° or 135° │\n * │ +1.0 │ 0% │ 100% │ 90° (full right) │\n * └───────────┴──────────┴───────────┴─────────────────────┘\n *\n * @param pan Pan value from -1 (full left) to +1 (full right)\n * @returns Panning percentages for left and right channels\n */\nexport function panValueToPanning(pan: number): Panning {\n const clamped = Math.max(-1, Math.min(1, pan));\n\n // Convert pan (-1 to +1) to left/right percentages\n // pan = 0 (center): L=100%, R=100%\n // pan = +1 (right): L=0%, R=100%\n // pan = -1 (left): L=100%, R=0%\n //\n // Formula:\n // - Left ear reduces as pan goes positive (right)\n // - Right ear reduces as pan goes negative (left)\n\n let left: number;\n let right: number;\n\n if (clamped >= 0) {\n // Sound is to the RIGHT (or center)\n // Right ear stays at 100%\n // Left ear reduces from 100% to 0% as pan goes 0 → +1\n left = 100 * (1 - clamped);\n right = 100;\n } else {\n // Sound is to the LEFT\n // Left ear stays at 100%\n // Right ear reduces from 100% to 0% as pan goes 0 → -1\n left = 100;\n right = 100 * (1 + clamped); // clamped is negative, so this reduces\n }\n\n return {\n left: Math.round(Math.max(0, Math.min(100, left))),\n right: Math.round(Math.max(0, Math.min(100, right))),\n };\n}\n","/**\n * Head Position Calculations\n *\n * Functions for computing head/mouth position from body position\n */\n\nimport {Position} from \"../../types/position\";\n\n/**\n * Default head height offset in meters\n * Average human head height above body origin\n */\nconst DEFAULT_HEAD_HEIGHT = 1.6;\n\n/**\n * Compute estimated head/mouth position from body position\n * Body position is typically at feet/base - add head height offset\n *\n * @param bodyPosition Body position (typically feet/base)\n * @param headHeight Height offset to add (default: 1.6m)\n * @returns Estimated head position\n */\nexport function computeHeadPosition(\n bodyPosition: Position,\n headHeight: number = DEFAULT_HEAD_HEIGHT\n): Position {\n return {\n x: bodyPosition.x,\n y: bodyPosition.y + headHeight,\n z: bodyPosition.z,\n };\n}\n\n/**\n * Parse body height string to meters\n * Handles various formats: \"170\", \"170cm\", \"1.7m\", etc.\n *\n * @param bodyHeightStr Body height string from participant data\n * @param fallback Fallback height in meters (default: 1.6)\n * @returns Height in meters\n */\nexport function parseBodyHeight(\n bodyHeightStr?: string,\n fallback: number = 1.6\n): number {\n if (!bodyHeightStr) return fallback;\n\n const str = bodyHeightStr.toLowerCase().trim();\n\n // Try parsing as number with optional unit\n const numMatch = str.match(/^([\\d.]+)\\s*(cm|m)?$/);\n if (numMatch) {\n const value = parseFloat(numMatch[1]);\n const unit = numMatch[2];\n\n if (isNaN(value)) return fallback;\n\n if (unit === \"m\") {\n return value;\n } else if (unit === \"cm\" || value > 10) {\n // Assume centimeters if > 10 or explicitly cm\n return value / 100;\n } else {\n return value;\n }\n }\n\n return fallback;\n}\n\n/**\n * Get vector from listener to target position\n *\n * @param listenerPosition Listener position\n * @param targetPosition Target position\n * @returns Vector from listener to target\n */\nexport function getVectorFromListener(\n listenerPosition: Position,\n targetPosition: Position\n): Position {\n return {\n x: targetPosition.x - listenerPosition.x,\n y: targetPosition.y - listenerPosition.y,\n z: targetPosition.z - listenerPosition.z,\n };\n}\n","/**\n * Position Normalization\n *\n * Functions for normalizing position units (cm to meters, etc.)\n */\n\nimport {Position} from \"../../types/position\";\n\n/**\n * Normalize position units to meters\n * Detects if values are likely in centimeters and converts\n *\n * @param position Position to normalize\n * @param unit Force unit interpretation: 'auto' | 'meters' | 'centimeters'\n * @returns Position in meters\n */\nexport function normalizePositionUnits(\n position: Position,\n unit: \"auto\" | \"meters\" | \"centimeters\" = \"auto\"\n): Position {\n if (unit === \"meters\") {\n return {...position};\n }\n\n if (unit === \"centimeters\") {\n return {\n x: position.x / 100,\n y: position.y / 100,\n z: position.z / 100,\n };\n }\n\n // Auto-detect: if any axis > 50, likely centimeters\n const maxAxis = Math.max(\n Math.abs(position.x),\n Math.abs(position.y),\n Math.abs(position.z)\n );\n\n if (maxAxis > 50) {\n return {\n x: position.x / 100,\n y: position.y / 100,\n z: position.z / 100,\n };\n }\n\n return {...position};\n}\n\n/**\n * Convert meters to centimeters\n *\n * @param position Position in meters\n * @returns Position in centimeters\n */\nexport function metersToCentimeters(position: Position): Position {\n return {\n x: position.x * 100,\n y: position.y * 100,\n z: position.z * 100,\n };\n}\n\n/**\n * Convert centimeters to meters\n *\n * @param position Position in centimeters\n * @returns Position in meters\n */\nexport function centimetersToMeters(position: Position): Position {\n return {\n x: position.x / 100,\n y: position.y / 100,\n z: position.z / 100,\n };\n}\n\n/**\n * Check if position values are likely in centimeters\n *\n * @param position Position to check\n * @param threshold Threshold for detection (default: 50)\n * @returns True if likely centimeters\n */\nexport function isLikelyCentimeters(\n position: Position,\n threshold: number = 50\n): boolean {\n const maxAxis = Math.max(\n Math.abs(position.x),\n Math.abs(position.y),\n Math.abs(position.z)\n );\n return maxAxis > threshold;\n}\n","/**\n * Position Snapping\n *\n * Factory function for reducing position jitter by snapping to a grid.\n */\n\nimport {Position} from \"../../types/position\";\n\nexport interface SnapConfig {\n threshold: number;\n}\n\nexport const SNAP_CONFIG: SnapConfig = {\n threshold: 0.3,\n};\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport interface PositionSnapCacheHandle {\n snap(position: Position, id: string): Position;\n clear(id: string): void;\n clearAll(): void;\n}\n\nexport function createPositionSnapCache(\n threshold = SNAP_CONFIG.threshold\n): PositionSnapCacheHandle {\n const cache = new Map<string, Position>();\n\n function snap(position: Position, id: string): Position {\n const cached = cache.get(id);\n\n if (!cached || (cached.x === 0 && cached.y === 0 && cached.z === 0)) {\n cache.set(id, {...position});\n return position;\n }\n\n const dx = position.x - cached.x;\n const dy = position.y - cached.y;\n const dz = position.z - cached.z;\n const movedDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);\n\n if (movedDistance > threshold) {\n cache.set(id, {...position});\n return position;\n }\n\n return cached;\n }\n\n return {\n snap,\n clear: (id) => {\n cache.delete(id);\n },\n clearAll: () => {\n cache.clear();\n },\n };\n}\n\n// ─── Standalone helper ───────────────────────────────────────────────────────\n\nexport function snapPositionSimple(\n position: Position,\n gridSize: number = 0.1\n): Position {\n return {\n x: Math.round(position.x / gridSize) * gridSize,\n y: Math.round(position.y / gridSize) * gridSize,\n z: Math.round(position.z / gridSize) * gridSize,\n };\n}\n","/**\n * Pan Smoothing\n *\n * Factory function for smoothing stereo panning values to prevent audio jitter.\n */\n\nexport interface PanSmootherOptions {\n smoothingFactor?: number;\n changeThreshold?: number;\n centerDeadZone?: number;\n}\n\nexport const DEFAULT_PAN_SMOOTHER_OPTIONS: Required<PanSmootherOptions> = {\n smoothingFactor: 0.3,\n changeThreshold: 0.02,\n centerDeadZone: 0.03,\n};\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport interface PanSmootherHandle {\n smooth(participantId: string, newPanValue: number): number;\n clear(participantId: string): void;\n clearAll(): void;\n}\n\nexport function createPanSmoother(\n options: PanSmootherOptions = {}\n): PanSmootherHandle {\n const opts = {...DEFAULT_PAN_SMOOTHER_OPTIONS, ...options};\n const smoothedValues = new Map<string, number>();\n const lastUpdateTime = new Map<string, number>();\n\n function smooth(participantId: string, newPanValue: number): number {\n const previousPan = smoothedValues.get(participantId);\n const now = Date.now();\n const lastTime = lastUpdateTime.get(participantId) || 0;\n const timeSinceLastUpdate = now - lastTime;\n\n let targetPan = newPanValue;\n if (Math.abs(newPanValue) < opts.centerDeadZone) {\n targetPan = 0;\n }\n\n if (previousPan === undefined) {\n smoothedValues.set(participantId, targetPan);\n lastUpdateTime.set(participantId, now);\n return targetPan;\n }\n\n const panChange = Math.abs(targetPan - previousPan);\n\n if (panChange < opts.changeThreshold) {\n return previousPan;\n }\n\n let effectiveSmoothingFactor = opts.smoothingFactor;\n\n const signFlipped =\n (previousPan > 0 && targetPan < 0) || (previousPan < 0 && targetPan > 0);\n const bothNearCenter =\n Math.abs(previousPan) < 0.15 && Math.abs(targetPan) < 0.15;\n\n const isLikelyJitter =\n signFlipped && panChange > 1.0 && timeSinceLastUpdate < 60;\n\n if (isLikelyJitter) {\n effectiveSmoothingFactor = 0.7;\n } else if (bothNearCenter) {\n effectiveSmoothingFactor = Math.min(opts.smoothingFactor + 0.1, 0.5);\n }\n\n const smoothedPan =\n previousPan * effectiveSmoothingFactor +\n targetPan * (1 - effectiveSmoothingFactor);\n\n const finalPan =\n Math.abs(smoothedPan) < opts.centerDeadZone ? 0 : smoothedPan;\n\n smoothedValues.set(participantId, finalPan);\n lastUpdateTime.set(participantId, now);\n\n return finalPan;\n }\n\n function clear(participantId: string): void {\n smoothedValues.delete(participantId);\n lastUpdateTime.delete(participantId);\n }\n\n function clearAll(): void {\n smoothedValues.clear();\n lastUpdateTime.clear();\n }\n\n return {smooth, clear, clearAll};\n}\n","/**\n * Gain Smoothing\n *\n * Functions for smoothing audio gain changes to prevent clicks/pops\n */\n\n/**\n * Apply smooth gain transition using Web Audio API's setTargetAtTime\n *\n * @param gainNode The GainNode to modify\n * @param targetGain Target gain value (0-1)\n * @param audioContext AudioContext for timing\n * @param timeConstant Time constant for transition (default: 0.1 = ~300ms to settle)\n */\nexport function applyGainSmooth(\n gainNode: GainNode,\n targetGain: number,\n audioContext: AudioContext,\n timeConstant: number = 0.1\n): void {\n try {\n gainNode.gain.setTargetAtTime(\n targetGain,\n audioContext.currentTime,\n timeConstant\n );\n } catch (err) {\n // Fallback: set value directly\n gainNode.gain.value = targetGain;\n }\n}\n\n/**\n * Apply smooth stereo pan transition\n *\n * @param stereoPanner The StereoPannerNode to modify\n * @param panValue Target pan value (-1 to +1)\n * @param audioContext AudioContext for timing\n * @param timeConstant Time constant for transition (default: 0.05 = ~150ms)\n */\nexport function applyStereoPanSmooth(\n stereoPanner: StereoPannerNode,\n panValue: number,\n audioContext: AudioContext,\n timeConstant: number = 0.05\n): void {\n try {\n stereoPanner.pan.setTargetAtTime(\n panValue,\n audioContext.currentTime,\n timeConstant\n );\n } catch (err) {\n // Fallback: set value directly\n stereoPanner.pan.value = panValue;\n }\n}\n","/**\n * ML Noise Suppressor - TensorFlow.js-based Real-Time Audio Enhancement\n *\n * Integrates trained ML model for noise suppression\n * Falls back to traditional DSP if ML is unavailable\n */\n\nimport * as tf from \"@tensorflow/tfjs\";\n\n// =============================================================================\n// L2 regularizer compatibility\n//\n// Some exported Keras model.json files include:\n// \"kernel_regularizer\": {\"class_name\": \"L2\", ...}\n// TF.js deserialization can fail if \"L2\" is not registered in this runtime.\n// For inference-only usage, this regularizer has no behavioral impact.\n// =============================================================================\nclass L2RegularizerCompat {\n static className = \"L2\";\n\n private readonly l2: number;\n\n constructor(config?: {l2?: number}) {\n this.l2 = config?.l2 ?? 0;\n }\n\n apply(x: tf.Tensor): tf.Scalar {\n // Keep mathematically correct implementation for compatibility.\n return tf.tidy(\n () => tf.sum(tf.square(x)).mul(tf.scalar(this.l2)) as tf.Scalar\n );\n }\n\n getConfig(): tf.serialization.ConfigDict {\n return {l2: this.l2};\n }\n}\ntf.serialization.registerClass(L2RegularizerCompat as any);\n\n// =============================================================================\n// Custom GRUCell — supports reset_after=True (Keras 2.x default)\n//\n// TF.js 4.x throws ValueError for reset_after=True in its built-in GRUCell.\n// We register a replacement class BEFORE loadLayersModel is called.\n// It implements both paths so reset_after=false models also work correctly.\n// =============================================================================\nclass GRUCellResetAfterSupport extends tf.layers.Layer {\n // Must match TF.js serialization class name\n static className = \"GRUCell\";\n\n private readonly units: number;\n private readonly resetAfter: boolean;\n private readonly useBiasFlag: boolean;\n private readonly activationFn: (x: tf.Tensor) => tf.Tensor;\n private readonly recurrentActivationFn: (x: tf.Tensor) => tf.Tensor;\n\n // Weight variables — assigned in build()\n private kernelW!: tf.LayerVariable;\n private recurrentKernelW!: tf.LayerVariable;\n private biasW?: tf.LayerVariable;\n\n // Required by TF.js RNN infra\n public stateSize: number;\n public dropoutMask: tf.Tensor | tf.Tensor[] | null = null;\n public recurrentDropoutMask: tf.Tensor | tf.Tensor[] | null = null;\n\n constructor(config: any) {\n super(config);\n this.units = config.units as number;\n // Accept BOTH camelCase (TF.js internal) and snake_case (Keras JSON export)\n this.resetAfter = (config.resetAfter ?? config.reset_after) !== false; // Keras default = true\n this.useBiasFlag = (config.useBias ?? config.use_bias) !== false;\n this.stateSize = this.units;\n this.activationFn = GRUCellResetAfterSupport.makeActivation(\n config.activation || \"tanh\"\n );\n this.recurrentActivationFn = GRUCellResetAfterSupport.makeActivation(\n config.recurrentActivation ?? config.recurrent_activation ?? \"sigmoid\" // Keras default (model.json uses 'sigmoid', NOT 'hardSigmoid')\n );\n }\n\n override build(inputShape: tf.Shape | tf.Shape[]): void {\n // TF.js may pass inputShape in two forms depending on version:\n // (a) [[null, features], [null, units], …] — array of shapes (one per input+state)\n // (b) [null, features] — flat step-input shape directly\n // We need the LAST element of the step-input shape as inputDim.\n // Detect form by checking whether the first element is itself an array.\n let shape: tf.Shape;\n if (Array.isArray((inputShape as tf.Shape[])[0])) {\n // Form (a): first element is the step-input shape, e.g. [null, 40]\n shape = (inputShape as tf.Shape[])[0] as tf.Shape;\n } else {\n // Form (b): inputShape IS the step-input shape, e.g. [null, 40]\n shape = inputShape as tf.Shape;\n }\n const inputDim = (shape as number[])[shape.length - 1] as number;\n\n this.kernelW = this.addWeight(\n \"kernel\",\n [inputDim, this.units * 3],\n \"float32\",\n tf.initializers.glorotUniform({})\n );\n this.recurrentKernelW = this.addWeight(\n \"recurrent_kernel\",\n [this.units, this.units * 3],\n \"float32\",\n tf.initializers.orthogonal({})\n );\n if (this.useBiasFlag) {\n // reset_after=True → bias shape [2, 3*units] (kernel row + recurrent row)\n // reset_after=False → bias shape [3*units]\n const biasShape = this.resetAfter\n ? [2, this.units * 3]\n : [this.units * 3];\n this.biasW = this.addWeight(\n \"bias\",\n biasShape as number[],\n \"float32\",\n tf.initializers.zeros()\n );\n }\n this.built = true;\n }\n\n override call(\n inputs: tf.Tensor[],\n _kwargs: Record<string, unknown>\n ): tf.Tensor[] {\n return tf.tidy(() => {\n const input = inputs[0];\n const hPrev = inputs[1];\n let matrixX = input.matMul(this.kernelW.read());\n\n if (this.resetAfter) {\n // ── reset_after=True (Keras default) ──────────────────────────────────\n // Bias is [2, 3*units]: row 0 = kernel bias, row 1 = recurrent bias\n let bKernel: tf.Tensor | null = null;\n let bRecurrent: tf.Tensor | null = null;\n if (this.useBiasFlag && this.biasW) {\n const b = this.biasW.read(); // [2, 3*units]\n bKernel = b.slice([0, 0], [1, -1]).squeeze([0]); // [3*units]\n bRecurrent = b.slice([1, 0], [1, -1]).squeeze([0]); // [3*units]\n }\n if (bKernel) matrixX = matrixX.add(bKernel);\n\n // Full recurrent multiply for all gates\n const matrixInner = hPrev.matMul(this.recurrentKernelW.read()); // [B, 3u]\n const [xZ, xR, xH] = tf.split(matrixX, 3, matrixX.rank - 1);\n const [iZ, iR, iH] = tf.split(matrixInner, 3, matrixInner.rank - 1);\n\n let rZ = iZ,\n rR = iR,\n rH = iH;\n if (bRecurrent) {\n const [rbZ, rbR, rbH] = tf.split(bRecurrent, 3, 0);\n rZ = iZ.add(rbZ);\n rR = iR.add(rbR);\n rH = iH.add(rbH); // recurrent bias applied before r gate\n }\n\n const z = this.recurrentActivationFn(xZ.add(rZ));\n const r = this.recurrentActivationFn(xR.add(rR));\n // Key difference: r gates the recurrent part AFTER kernel multiply\n const hh = this.activationFn(xH.add(r.mul(rH)));\n const h = tf.add(tf.mul(z, hPrev), tf.mul(tf.sub(tf.scalar(1), z), hh));\n return [h, h];\n } else {\n // ── reset_after=False (TF.js default) ────────────────────────────────\n if (this.useBiasFlag && this.biasW) {\n matrixX = matrixX.add(this.biasW.read());\n }\n const rk = this.recurrentKernelW.read();\n const [rk1, rk2] = tf.split(\n rk,\n [2 * this.units, this.units],\n rk.rank - 1\n );\n const matrixInner = hPrev.matMul(rk1);\n const [xZ, xR, xH] = tf.split(matrixX, 3, matrixX.rank - 1);\n const [recZ, recR] = tf.split(matrixInner, 2, matrixInner.rank - 1);\n const z = this.recurrentActivationFn(xZ.add(recZ));\n const r = this.recurrentActivationFn(xR.add(recR));\n const recH = tf.mul(r, hPrev).matMul(rk2);\n const hh = this.activationFn(xH.add(recH));\n const h = tf.add(tf.mul(z, hPrev), tf.mul(tf.sub(tf.scalar(1), z), hh));\n return [h, h];\n }\n });\n }\n\n private static makeActivation(name: string): (x: tf.Tensor) => tf.Tensor {\n switch (name.toLowerCase()) {\n case \"tanh\":\n return (x) => x.tanh();\n case \"sigmoid\":\n return (x) => x.sigmoid();\n case \"hardsigmoid\":\n case \"hard_sigmoid\":\n return (x) =>\n tf.clipByValue(x.mul(tf.scalar(0.2)).add(tf.scalar(0.5)), 0, 1);\n case \"relu\":\n return (x) => x.relu();\n case \"linear\":\n return (x) => x;\n default:\n return (x) => x.sigmoid();\n }\n }\n\n override getConfig(): tf.serialization.ConfigDict {\n return {\n ...super.getConfig(),\n units: this.units,\n useBias: this.useBiasFlag,\n resetAfter: this.resetAfter,\n };\n }\n}\n// Override TF.js built-in GRUCell — must happen before loadLayersModel\n// (Kept as a safety net for any direct GRUCell deserialization paths.)\ntf.serialization.registerClass(GRUCellResetAfterSupport);\n\n// =============================================================================\n// GRULayerWithResetAfter — intercepts GRU LAYER deserialization\n//\n// WHY registerClass('GRUCell') alone is NOT enough:\n// TF.js built-in GRU layer constructor does `new GRUCell(args)` DIRECTLY —\n// it never goes through the serialization registry. So our custom GRUCell\n// never gets instantiated. We must register a replacement for the GRU LAYER\n// itself so that when model.json contains \"class_name\": \"GRU\", TF.js calls\n// GRULayerWithResetAfter.fromConfig() instead of the built-in GRU constructor.\n//\n// WEIGHT NAMING:\n// model.json weightsManifest uses paths like \"gru_96/gru_cell/kernel\".\n// TF.js builds variable names as `${layer.name}/${varName}`.\n// So the cell MUST be named `${layerName}/gru_cell` (e.g. \"gru_96/gru_cell\")\n// so that addWeight('kernel') → \"gru_96/gru_cell/kernel\" ← matches manifest.\n// =============================================================================\nclass GRULayerWithResetAfter {\n static className = \"GRU\";\n\n static fromConfig(_cls: unknown, config: any): tf.layers.Layer {\n const layerName: string = config.name as string;\n\n // Create our cell — named so its weights match the manifest paths.\n // IMPORTANT: name must be just \"gru_cell\" (no layer prefix).\n // The RNN wrapper layer is already named `layerName` (e.g. \"gru_96\").\n // TF.js scopes cell weights under the RNN layer scope, so the final path\n // becomes \"gru_96/gru_cell/kernel\" ✅ (matches the weightsManifest).\n // Using `${layerName}/gru_cell` would double-prefix → \"gru_96/gru_96/gru_cell/kernel\" ❌\n const cell = new GRUCellResetAfterSupport({\n ...config,\n name: `gru_cell`, // → weights: \"gru_96/gru_cell/kernel\" ✅\n // Normalise keys: Keras JSON is snake_case; TF.js internals are camelCase\n useBias: config.useBias ?? config.use_bias ?? true,\n recurrentActivation:\n config.recurrentActivation ?? config.recurrent_activation ?? \"sigmoid\",\n resetAfter: (config.resetAfter ?? config.reset_after) !== false,\n returnSequences:\n config.returnSequences ?? config.return_sequences ?? false,\n });\n\n // Wrap in a standard RNN layer — it exposes cell.trainableWeights correctly\n return tf.layers.rnn({\n cell: cell as any,\n returnSequences:\n ((config.returnSequences ?? config.return_sequences) as boolean) ??\n false,\n returnState:\n ((config.returnState ?? config.return_state) as boolean) ?? false,\n goBackwards:\n ((config.goBackwards ?? config.go_backwards) as boolean) ?? false,\n stateful: (config.stateful as boolean) ?? false,\n unroll: (config.unroll as boolean) ?? false,\n // Always use float32 — model.json exports dtype as a Keras Policy object\n // (e.g. {class_name:\"Policy\", config:{name:\"mixed_float16\"}}) which TF.js\n // cannot use as a DataType string. Weights are float32 anyway (UINT8 quantized\n // with original_dtype=float32), so float32 is always correct here.\n dtype: \"float32\" as tf.DataType,\n name: layerName, // e.g. \"gru_96\" — RNN layer keeps this name\n }) as tf.layers.Layer;\n }\n}\ntf.serialization.registerClass(GRULayerWithResetAfter as any);\n\nexport interface ModelConfig {\n model_name: string;\n sample_rate: number;\n frame_size: number;\n hop_length: number;\n n_fft?: number; // FFT size for mel spectrogram (default 2048)\n sequence_length: number;\n n_mels: number;\n quantized: boolean;\n voice_frequency_ranges?: {\n fundamental: number[];\n core_pitch: number[];\n warmth: number[];\n };\n}\n\ninterface NormalizationStats {\n mean: number;\n std: number;\n}\n\n// WebRTC standard sample rate (browser audio always comes in at this rate)\nconst WEBRTC_SAMPLE_RATE = 48000;\n\n// ─── Public handle interface ──────────────────────────────────────────────────\n\nexport interface MLNoiseSuppressorHandle {\n initialize(modelUrl: string): Promise<void>;\n isReady(): boolean;\n getModelConfig(): ModelConfig | null;\n getInfo(): {initialized: boolean; backend: string; modelLoaded: boolean};\n computeGainsFromFeatures(\n features: Float32Array,\n seqLen: number,\n nMels: number,\n participantId?: string\n ): Promise<Float32Array>;\n clearParticipantSmoothingState(participantId: string): void;\n processAudioSync(inputBuffer: Float32Array): Float32Array;\n reset(): void;\n dispose(): void;\n}\n\nexport function createMLNoiseSuppressor(): MLNoiseSuppressorHandle {\n const instance = new MLNoiseSuppressor();\n return {\n initialize: (url) => instance.initialize(url),\n isReady: () => instance.isReady(),\n getModelConfig: () => instance.getModelConfig(),\n getInfo: () => instance.getInfo(),\n computeGainsFromFeatures: (f, s, n, p) =>\n instance.computeGainsFromFeatures(f, s, n, p),\n clearParticipantSmoothingState: (id) =>\n instance.clearParticipantSmoothingState(id),\n processAudioSync: (buf) => instance.processAudioSync(buf),\n reset: () => instance.reset(),\n dispose: () => instance.dispose(),\n };\n}\n\n/** @internal — keep as class; TF.js serialization cannot use plain objects */\nexport class MLNoiseSuppressor {\n private model: tf.LayersModel | null = null;\n private config: ModelConfig | null = null;\n private normStats: NormalizationStats | null = null;\n private isInitialized = false;\n\n // Temporal smoothing state — per-participant to avoid cross-participant corruption\n // when multiple async computeGainsFromFeatures() calls run concurrently.\n private prevMaskMap: Map<string, Float32Array> = new Map();\n // Faster smoothing: 0.70 means 30% of new value per frame (~3 frames to stabilise).\n // Old 0.92 was too slow — first speech frame had smoothed max≈0.08 which fell below\n // the isSpeechFrame threshold and silenced the first ~200ms of every utterance.\n private readonly SMOOTHING_ALPHA = 0.7;\n\n // Mel filterbank cache (built once, reused every frame)\n private melFilterbank: Float32Array[] | null = null;\n\n // ── Google Meet-style ring buffer architecture ─────────────────────────────\n // Process audio in exact hop_length (80 sample) steps at 16kHz.\n // Each hop: STFT → apply cached FFT gains → ISTFT → OLA.\n // Model runs async, updates cachedFftGains after each inference.\n // Audio thread cost: ~2ms. Model inference: async, never blocks.\n\n // Persistent input ring buffer (16kHz) — accumulates samples across callbacks.\n private inRing: Float32Array = new Float32Array(8192);\n private inRingLen: number = 0;\n\n // OLA accumulator (16kHz) — each hop's ISTFT output is overlap-added here.\n private outAccum: Float32Array = new Float32Array(16384);\n private outNorm: Float32Array = new Float32Array(16384); // sum of hann² for normalisation\n\n // Per-FFT-bin gains from last completed async inference.\n // All-ones until first inference completes → transparent passthrough.\n private cachedFftGains: Float32Array | null = null;\n private inferenceInFlight = false;\n\n // Hann window cache (allocated once per N_FFT)\n private hannWinCache: Float32Array | null = null;\n\n // Rolling mel frame history — seq_len frames of mel features for model input.\n private melFrameHistory: number[][] = [];\n\n // Resampling state (for 16kHz models)\n private needsResampling = false;\n private resampleRatio = 1; // WEBRTC_SAMPLE_RATE / model.sample_rate\n\n // Legacy fields (kept for isReady / reset API compatibility)\n private lastComplexFrames: {real: Float32Array; imag: Float32Array}[] = [];\n private readonly VOICE_FUNDAMENTAL_MIN = 80;\n private readonly VOICE_FUNDAMENTAL_MAX = 500;\n private frameCounter = 0;\n private skipFrames = 0;\n private lastProcessedOutput: Float32Array | null = null;\n private processingTimes: number[] = [];\n private readonly MAX_PROCESSING_TIME_MS = 42;\n\n /**\n * Initialize ML model for noise suppression\n * @param modelUrl Path to model.json file\n */\n async initialize(modelUrl: string): Promise<void> {\n try {\n // Use CPU backend — for small 73K-param GRU models, CPU is faster than WebGL.\n // WebGL has shader compilation + GPU↔CPU transfer overhead (~25-30ms) that dwarfs\n // actual compute time (~2-5ms). CPU backend runs inference in <5ms consistently.\n try {\n await tf.setBackend(\"cpu\");\n } catch {\n await tf.setBackend(\"webgl\");\n }\n await tf.ready();\n console.log(\n `[MLNoiseSuppressor] TF.js backend ready: ${tf.getBackend()}`\n );\n\n // ── Weight remapping fix ─────────────────────────────────────────────────\n // model.json manifest uses \"gru_96/gru_cell/kernel\" (Keras scoping).\n // TF.js 4.x variables are named \"gru_96/kernel\" (no gru_cell/ scope).\n // loadLayersModel(url) fails to match → GRU stays at glorot_uniform → rawMax≈0.\n //\n // Fix: fetch topology + binary ourselves, strip \"/gru_cell/\" from weightSpecs,\n // then load via tf.io.fromMemory so TF.js uses correct names with correct byte offsets.\n const baseUrlForWeights = modelUrl\n .split(\"?\")[0]\n .replace(/model\\.json$/, \"\");\n const [modelJsonResp, binResp] = await Promise.all([\n fetch(modelUrl),\n fetch(`${baseUrlForWeights}group1-shard1of1.bin`),\n ]);\n const modelJsonData = (await modelJsonResp.json()) as {\n modelTopology: unknown;\n weightsManifest: Array<{\n paths: string[];\n weights: Array<{\n name: string;\n shape: number[];\n dtype: string;\n quantization?: unknown;\n }>;\n }>;\n format?: string;\n generatedBy?: string;\n convertedBy?: string;\n };\n const weightData = await binResp.arrayBuffer();\n\n // Strip \"/gru_cell/\" from each weight name — keeps byte offsets intact\n const remappedWeightSpecs = modelJsonData.weightsManifest[0].weights.map(\n (w) => ({...w, name: w.name.replace(\"/gru_cell/\", \"/\")})\n );\n\n this.model = await tf.loadLayersModel(\n tf.io.fromMemory({\n modelTopology: modelJsonData.modelTopology,\n weightSpecs: remappedWeightSpecs,\n weightData: weightData,\n format: modelJsonData.format,\n generatedBy: modelJsonData.generatedBy,\n convertedBy: modelJsonData.convertedBy,\n } as tf.io.ModelArtifacts)\n );\n console.log(\n `[MLNoiseSuppressor] Model loaded — ${this.model.countParams().toLocaleString()} params | backend: ${tf.getBackend()} | url: ${modelUrl}`\n );\n\n // Load config\n const baseUrl = modelUrl.substring(0, modelUrl.lastIndexOf(\"/\"));\n const configResponse = await fetch(`${baseUrl}/model_config.json`);\n this.config = await configResponse.json();\n\n // Load normalization stats\n try {\n const normResponse = await fetch(`${baseUrl}/normalization_stats.json`);\n this.normStats = await normResponse.json();\n console.log(\n `[MLNoiseSuppressor] Normalization stats loaded — mean: ${this.normStats!.mean.toFixed(4)}, std: ${this.normStats!.std.toFixed(4)}`\n );\n } catch (e) {\n console.warn(\n `[MLNoiseSuppressor] normalization_stats.json not found, using defaults (mean=0, std=1)`\n );\n this.normStats = {mean: 0, std: 1};\n }\n\n // Check if resampling is needed (model trained at different sample rate than WebRTC)\n const modelSampleRate = this.config!.sample_rate || 48000;\n if (modelSampleRate !== WEBRTC_SAMPLE_RATE) {\n this.needsResampling = true;\n this.resampleRatio = WEBRTC_SAMPLE_RATE / modelSampleRate;\n console.log(\n `[MLNoiseSuppressor] Resampling enabled: ${WEBRTC_SAMPLE_RATE}Hz → ${modelSampleRate}Hz (ratio: ${this.resampleRatio})`\n );\n } else {\n this.needsResampling = false;\n this.resampleRatio = 1;\n }\n\n // Warmup: run 3 dummy inferences to JIT-compile GRU + dense paths.\n // Without warmup, TF.js compiles lazily on the audio thread → first ~20 frames are slow.\n const seqLen = this.config!.sequence_length || 8;\n const nMels = this.config!.n_mels || 40;\n console.log(\n `[MLNoiseSuppressor] Warming up model (${seqLen} × ${nMels})...`\n );\n const warmupInput = tf.zeros([1, seqLen, nMels]);\n for (let w = 0; w < 3; w++) {\n const warmupOut = this.model!.predict(warmupInput) as tf.Tensor;\n warmupOut.dataSync(); // force full synchronous execution\n warmupOut.dispose();\n }\n warmupInput.dispose();\n\n // Weight-load diagnostic: run model on constant 0.5 input to verify GRU weights loaded.\n // If weights loaded correctly, output should be non-trivial (max > 0.01).\n // If max ≈ 0.0000 the GRU weights failed to load (cell naming mismatch).\n const diagInput = tf.fill([1, seqLen, nMels], 0.5);\n const diagOut = this.model!.predict(diagInput) as tf.Tensor;\n const diagData = new Float32Array(await diagOut.dataSync());\n const diagMax = Math.max(...Array.from(diagData));\n const diagMin = Math.min(...Array.from(diagData));\n diagOut.dispose();\n diagInput.dispose();\n console.log(\n `[MLNoiseSuppressor] ⚠️ Weight check (input=0.5): output max=${diagMax.toFixed(4)} min=${diagMin.toFixed(4)} — ${diagMax > 0.01 ? \"✅ weights LOADED\" : \"❌ weights NOT loaded (all-zero output)\"}`\n );\n\n // Dump all TF.js weight variable names so we can compare against the weightsManifest.\n // The manifest has paths like \"gru_96/gru_cell/kernel\".\n // If TF.js names the variable differently, the weight won't load (model outputs ~0).\n console.log(\n `[MLNoiseSuppressor] 📋 TF.js weight variable names (${this.model!.weights.length} total):`\n );\n this.model!.weights.forEach((w, i) => {\n const vals = w.read().dataSync();\n const wMax = Math.max(...Array.from(vals).slice(0, 20)); // first 20 values\n const wMin = Math.min(...Array.from(vals).slice(0, 20));\n console.log(\n ` [${i}] ${w.name} shape=${JSON.stringify(w.shape)} val_range=[${wMin.toFixed(4)}, ${wMax.toFixed(4)}]${Math.abs(wMax) < 1e-6 && Math.abs(wMin) < 1e-6 ? \" ← ❌ ALL ZEROS (not loaded!)\" : \"\"}`\n );\n });\n\n console.log(`[MLNoiseSuppressor] Warmup done`);\n\n this.isInitialized = true;\n console.log(`[MLNoiseSuppressor] ✅ Ready — noise suppression is ACTIVE`);\n console.log(\n `[MLNoiseSuppressor] Config: ${modelSampleRate}Hz, ${this.config!.n_mels} mels, n_fft=${this.config!.n_fft || 2048}`\n );\n } catch (error) {\n console.error(`[MLNoiseSuppressor] ❌ Initialization failed:`, error);\n throw error;\n }\n }\n\n /**\n * Google Meet-style ring buffer noise suppression.\n *\n * Trains / Google Meet process audio in exact hop_length steps (80 samples = 5ms @ 16kHz).\n * Each step:\n * 1. Extract one STFT frame (n_fft=512) with Hann window — zero-pad if near end\n * 2. Apply cached per-FFT-bin gains (from last async inference) → ISTFT\n * 3. Overlap-add into persistent output ring buffer\n * 4. Fire async inference (non-blocking) to update gains for next steps\n *\n * Audio thread cost: ~2ms (pure JS STFT + OLA).\n * Model cost: async, never blocks audio thread.\n * Mask staleness: ≤1 hop (5ms) — imperceptible for noise suppression.\n */\n processAudioSync(inputBuffer: Float32Array): Float32Array {\n if (!this.isInitialized || !this.model || !this.config) {\n return inputBuffer;\n }\n\n const N_FFT = this.config.n_fft || 512;\n const HOP = this.config.hop_length || 80;\n const N_MELS = this.config.n_mels || 40;\n const SEQ_LEN = this.config.sequence_length || 8;\n const bins = N_FFT / 2 + 1;\n\n // Hann window — allocated once\n if (!this.hannWinCache || this.hannWinCache.length !== N_FFT) {\n this.hannWinCache = new Float32Array(N_FFT);\n for (let i = 0; i < N_FFT; i++)\n this.hannWinCache[i] =\n 0.5 * (1 - Math.cos((2 * Math.PI * i) / (N_FFT - 1)));\n }\n const hann = this.hannWinCache;\n\n try {\n // ── 1. Downsample 48kHz → 16kHz ─────────────────────────────────────────\n const in16 = this.needsResampling\n ? this.downsample(inputBuffer, this.resampleRatio)\n : inputBuffer;\n\n // ── 2. Append to input ring buffer ──────────────────────────────────────\n if (this.inRingLen + in16.length > this.inRing.length) {\n const grown = new Float32Array(\n Math.max((this.inRingLen + in16.length) * 2, 8192)\n );\n grown.set(this.inRing.subarray(0, this.inRingLen));\n this.inRing = grown;\n }\n this.inRing.set(in16, this.inRingLen);\n this.inRingLen += in16.length;\n\n // Grow output buffers if needed (each hop can write up to offset + N_FFT)\n const maxOut = this.inRingLen + N_FFT;\n if (maxOut > this.outAccum.length) {\n const g1 = new Float32Array(maxOut * 2);\n g1.set(this.outAccum);\n this.outAccum = g1;\n const g2 = new Float32Array(maxOut * 2);\n g2.set(this.outNorm);\n this.outNorm = g2;\n }\n\n // ── 3. Process one hop at a time ────────────────────────────────────────\n // Each hop advances by HOP samples. We need ≥1 new sample at `offset`\n // to constitute new audio; the rest of the N_FFT window is zero-padded.\n let offset = 0;\n while (offset + HOP <= this.inRingLen) {\n // Build one windowed N_FFT frame (zero-pad beyond ring buffer)\n const frame = new Float32Array(N_FFT);\n for (let i = 0; i < N_FFT; i++) {\n const idx = offset + i;\n frame[i] = (idx < this.inRingLen ? this.inRing[idx] : 0) * hann[i];\n }\n\n // FFT\n const {real: fR, imag: fI} = MLNoiseSuppressor.fftForward(frame);\n\n // Mel features for this hop — push to rolling history\n const power = new Float32Array(bins);\n for (let k = 0; k < bins; k++) power[k] = fR[k] * fR[k] + fI[k] * fI[k];\n const melFrame = this.computeMelFrame(power, N_MELS);\n this.melFrameHistory.push(melFrame);\n if (this.melFrameHistory.length > SEQ_LEN)\n this.melFrameHistory = this.melFrameHistory.slice(-SEQ_LEN);\n\n // Apply per-bin gains (all-ones = transparent until first inference)\n const gains = this.cachedFftGains ?? new Float32Array(bins).fill(1.0);\n const mR = new Float32Array(N_FFT);\n const mI = new Float32Array(N_FFT);\n for (let k = 0; k < bins; k++) {\n mR[k] = fR[k] * gains[k];\n mI[k] = fI[k] * gains[k];\n if (k > 0 && k < N_FFT / 2) {\n // mirror conjugate symmetry\n mR[N_FFT - k] = mR[k];\n mI[N_FFT - k] = -mI[k];\n }\n }\n\n // ISTFT → time domain frame\n const recon = MLNoiseSuppressor.ifftFromComplex(mR, mI);\n\n // Overlap-add into output accumulator at this hop's position\n for (let i = 0; i < N_FFT; i++) {\n const pos = offset + i;\n this.outAccum[pos] += recon[i] * hann[i]; // synthesis Hann window\n this.outNorm[pos] += hann[i] * hann[i]; // OLA normalisation envelope\n }\n\n // Fire async inference every hop (non-blocking; inferenceInFlight prevents overlap)\n if (!this.inferenceInFlight) {\n this.runInferenceAsync(this.melFrameHistory.slice(), SEQ_LEN, N_MELS);\n }\n\n offset += HOP;\n }\n\n // After the loop, positions 0..offset-1 are fully covered by all overlapping hops\n // that will ever write to them. Read those samples, normalise, and output them.\n\n // ── 4. Read `in16.length` output samples ────────────────────────────────\n const out16 = new Float32Array(in16.length);\n const ready = Math.min(in16.length, offset); // offset = # samples fully processed\n for (let i = 0; i < ready; i++) {\n out16[i] =\n this.outNorm[i] > 1e-10\n ? this.outAccum[i] / this.outNorm[i]\n : in16[i]; // no coverage → raw passthrough\n }\n // Any samples beyond `ready` (rare, only first few callbacks) → raw passthrough\n for (let i = ready; i < in16.length; i++) out16[i] = in16[i];\n\n // ── 5. Advance ring buffers ──────────────────────────────────────────────\n // Discard the `offset` processed input samples; shift output accumulators so\n // any partial OLA contributions from the last N_FFT window carry over correctly.\n this.inRing.copyWithin(0, offset);\n this.inRingLen -= offset;\n this.outAccum.copyWithin(0, offset);\n this.outNorm.copyWithin(0, offset);\n // Zero-fill the freed tail (so stale values don't corrupt future hops)\n this.outAccum.fill(0, this.inRingLen + N_FFT);\n this.outNorm.fill(0, this.inRingLen + N_FFT);\n\n // ── 6. Upsample 16kHz → 48kHz ───────────────────────────────────────────\n return this.needsResampling\n ? this.upsample(out16, this.resampleRatio, inputBuffer.length)\n : out16;\n } catch {\n return inputBuffer;\n }\n }\n\n /**\n * Compute mel-spectrogram features for one STFT frame.\n * Matches training pipeline: power_to_db(ref=max) → (db+80)/80 clipped [0,1].\n */\n private computeMelFrame(powerSpec: Float32Array, N_MELS: number): number[] {\n if (!this.config) return Array(N_MELS).fill(0);\n const N_FFT = this.config.n_fft || 512;\n const SR = this.config.sample_rate || 16000;\n if (!this.melFilterbank)\n this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n N_MELS,\n N_FFT,\n SR\n );\n\n const melPow = new Float32Array(N_MELS);\n for (let m = 0; m < N_MELS; m++) {\n let s = 0;\n const filt = this.melFilterbank![m];\n for (let k = 0; k < filt.length && k < powerSpec.length; k++)\n s += filt[k] * powerSpec[k];\n melPow[m] = s;\n }\n let maxP = 1e-10;\n for (let m = 0; m < N_MELS; m++) if (melPow[m] > maxP) maxP = melPow[m];\n const refDb = 10 * Math.log10(maxP);\n const out = new Array<number>(N_MELS);\n for (let m = 0; m < N_MELS; m++) {\n const db = 10 * Math.log10(melPow[m] + 1e-10) - refDb;\n out[m] = Math.max(0, Math.min(1, (db + 80) / 80));\n }\n return out;\n }\n\n /**\n * Run model inference asynchronously.\n * Updates cachedFftGains (per-FFT-bin gains) — audio thread applies them each hop.\n * Never awaited from processAudioSync; inferenceInFlight prevents overlapping calls.\n */\n private async runInferenceAsync(\n historySnapshot: number[][],\n SEQ_LEN: number,\n N_MELS: number\n ): Promise<void> {\n this.inferenceInFlight = true;\n try {\n // Build [1, SEQ_LEN, N_MELS] input tensor, zero-padded at start\n const histLen = historySnapshot.length;\n const padCount = SEQ_LEN - histLen;\n const flat = new Array(SEQ_LEN * N_MELS).fill(0);\n for (let f = 0; f < histLen; f++)\n for (let m = 0; m < N_MELS; m++)\n flat[(padCount + f) * N_MELS + m] = historySnapshot[f][m];\n\n const N_FFT = this.config!.n_fft || 512;\n const SR = this.config!.sample_rate || 16000;\n const bins = N_FFT / 2 + 1;\n\n const inp = tf.tensor(flat, [1, SEQ_LEN, N_MELS]) as tf.Tensor3D;\n const out = this.model!.predict(inp) as tf.Tensor;\n\n // .data() is async — NEVER blocks the audio thread\n const maskFlat = new Float32Array(await out.data());\n inp.dispose();\n out.dispose();\n\n // Use the LAST row of [SEQ_LEN, N_MELS] output = mask for the most recent frame\n const mask40 = new Float32Array(N_MELS);\n for (let m = 0; m < N_MELS; m++)\n mask40[m] = maskFlat[(SEQ_LEN - 1) * N_MELS + m];\n\n // Temporal smoothing\n const smoothed = this.applyTemporalSmoothing(mask40);\n\n // Map mel-band mask → per-FFT-bin gains via transpose filterbank\n if (!this.melFilterbank)\n this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n N_MELS,\n N_FFT,\n SR\n );\n\n const gains = new Float32Array(bins);\n const filtTotal = new Float32Array(bins);\n for (let m = 0; m < N_MELS; m++) {\n const filt = this.melFilterbank![m];\n for (let k = 0; k < filt.length && k < bins; k++) {\n gains[k] += filt[k] * smoothed[m];\n filtTotal[k] += filt[k];\n }\n }\n for (let k = 0; k < bins; k++) {\n // No mel coverage → preserve (DC, Nyquist)\n gains[k] = filtTotal[k] > 1e-8 ? gains[k] / filtTotal[k] : 1.0;\n // Floor: 0.0 → let model fully suppress noise. Voice protected by model itself.\n gains[k] = Math.max(0.0, Math.min(1.0, gains[k]));\n }\n\n this.cachedFftGains = gains;\n } catch {\n // Keep last good gains\n } finally {\n this.inferenceInFlight = false;\n }\n }\n\n /**\n * Downsample audio buffer (e.g., 48kHz → 16kHz)\n * Simple linear interpolation for speed\n */\n private downsample(input: Float32Array, ratio: number): Float32Array {\n const outputLength = Math.floor(input.length / ratio);\n const output = new Float32Array(outputLength);\n\n for (let i = 0; i < outputLength; i++) {\n const srcIndex = i * ratio;\n const srcIndexFloor = Math.floor(srcIndex);\n const frac = srcIndex - srcIndexFloor;\n\n if (srcIndexFloor + 1 < input.length) {\n // Linear interpolation between samples\n output[i] =\n input[srcIndexFloor] * (1 - frac) + input[srcIndexFloor + 1] * frac;\n } else {\n output[i] = input[srcIndexFloor];\n }\n }\n\n return output;\n }\n\n /**\n * Upsample audio buffer (e.g., 16kHz → 48kHz)\n * Linear interpolation to match original length\n */\n private upsample(\n input: Float32Array,\n ratio: number,\n targetLength: number\n ): Float32Array {\n const output = new Float32Array(targetLength);\n\n for (let i = 0; i < targetLength; i++) {\n const srcIndex = i / ratio;\n const srcIndexFloor = Math.floor(srcIndex);\n const frac = srcIndex - srcIndexFloor;\n\n if (srcIndexFloor + 1 < input.length) {\n // Linear interpolation between samples\n output[i] =\n input[srcIndexFloor] * (1 - frac) + input[srcIndexFloor + 1] * frac;\n } else if (srcIndexFloor < input.length) {\n output[i] = input[srcIndexFloor];\n } else {\n output[i] = input[input.length - 1];\n }\n }\n\n return output;\n }\n\n /**\n * Extract mel-spectrogram features matching the training pipeline exactly:\n * librosa.feature.melspectrogram(n_fft, hop_length, n_mels) — values from config\n * → power_to_db(ref=np.max)\n * → (mel_db + 80) / 80 clipped to [0, 1]\n * No z-score normalisation applied (model trained on raw [0,1] values).\n *\n * Config driven: works with 16kHz/40mels or 48kHz/128mels depending on model_config.json\n */\n private extractFeatures(audio: Float32Array): number[][] {\n if (!this.config) return [[Array(128).fill(0)][0]];\n\n const N_FFT = this.config?.n_fft || 2048;\n const HOP = this.config.hop_length || 256;\n const N_MELS = this.config.n_mels || 128;\n const SR = this.config.sample_rate || 48000;\n\n // Build (and cache) the mel filterbank once\n if (!this.melFilterbank) {\n this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n N_MELS,\n N_FFT,\n SR\n );\n }\n\n // Pre-compute Hann window\n const hannWindow = new Float32Array(N_FFT);\n for (let i = 0; i < N_FFT; i++) {\n hannWindow[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (N_FFT - 1)));\n }\n\n const numFrames = Math.max(1, Math.floor((audio.length - N_FFT) / HOP) + 1);\n const features: number[][] = [];\n this.lastComplexFrames = []; // reset for this buffer\n\n for (let fi = 0; fi < numFrames; fi++) {\n const start = fi * HOP;\n\n // Apply Hann window to this frame (zero-pad if near end)\n const frame = new Float32Array(N_FFT);\n for (let i = 0; i < N_FFT; i++) {\n frame[i] =\n (start + i < audio.length ? audio[start + i] : 0) * hannWindow[i];\n }\n\n // FFT → complex spectrum (saved for OLA reconstruction) + power spectrum\n const {real: fftReal, imag: fftImag} =\n MLNoiseSuppressor.fftForward(frame);\n const bins = N_FFT / 2 + 1;\n this.lastComplexFrames.push({\n real: fftReal.slice(0, bins),\n imag: fftImag.slice(0, bins),\n });\n const powerSpec = new Float32Array(bins);\n for (let k = 0; k < bins; k++) {\n powerSpec[k] = fftReal[k] * fftReal[k] + fftImag[k] * fftImag[k];\n }\n\n // Apply mel filterbank → mel power per band\n const melPower = new Float32Array(N_MELS);\n for (let m = 0; m < N_MELS; m++) {\n let sum = 0;\n const filt = this.melFilterbank![m];\n for (let k = 0; k < filt.length; k++) sum += filt[k] * powerSpec[k];\n melPower[m] = sum;\n }\n\n // power_to_db(ref=np.max): 10*log10(S/max(S)) — matches librosa default\n let maxPow = 1e-10;\n for (let m = 0; m < N_MELS; m++)\n if (melPower[m] > maxPow) maxPow = melPower[m];\n const refDb = 10 * Math.log10(maxPow);\n\n // (mel_db + 80) / 80, clipped to [0, 1] — matches training normalisation\n const melNorm = new Array<number>(N_MELS);\n for (let m = 0; m < N_MELS; m++) {\n const db = 10 * Math.log10(melPower[m] + 1e-10) - refDb;\n melNorm[m] = Math.max(0, Math.min(1, (db + 80) / 80));\n }\n\n features.push(melNorm);\n }\n\n return features;\n }\n\n /**\n * Cooley-Tukey radix-2 FFT — returns full complex spectrum.\n * Accepts optional imaginary input for use as IFFT building block.\n * frameReal.length must be a power of 2.\n */\n private static fftForward(\n frameReal: Float32Array,\n frameImag?: Float32Array\n ): {real: Float32Array; imag: Float32Array} {\n const N = frameReal.length;\n const real = new Float32Array(frameReal);\n const imag = frameImag ? new Float32Array(frameImag) : new Float32Array(N);\n\n // Bit-reversal permutation\n let j = 0;\n for (let i = 1; i < N; i++) {\n let bit = N >> 1;\n while (j & bit) {\n j ^= bit;\n bit >>= 1;\n }\n j ^= bit;\n if (i < j) {\n let tmp = real[i];\n real[i] = real[j];\n real[j] = tmp;\n tmp = imag[i];\n imag[i] = imag[j];\n imag[j] = tmp;\n }\n }\n\n // Butterfly passes\n for (let len = 2; len <= N; len <<= 1) {\n const halfLen = len >> 1;\n const ang = (-2 * Math.PI) / len;\n const wRe = Math.cos(ang);\n const wIm = Math.sin(ang);\n for (let i = 0; i < N; i += len) {\n let curRe = 1,\n curIm = 0;\n for (let k = 0; k < halfLen; k++) {\n const uRe = real[i + k],\n uIm = imag[i + k];\n const vRe =\n real[i + k + halfLen] * curRe - imag[i + k + halfLen] * curIm;\n const vIm =\n real[i + k + halfLen] * curIm + imag[i + k + halfLen] * curRe;\n real[i + k] = uRe + vRe;\n imag[i + k] = uIm + vIm;\n real[i + k + halfLen] = uRe - vRe;\n imag[i + k + halfLen] = uIm - vIm;\n const newRe = curRe * wRe - curIm * wIm;\n curIm = curRe * wIm + curIm * wRe;\n curRe = newRe;\n }\n }\n }\n return {real, imag};\n }\n\n /**\n * IFFT via conjugate trick: ifft(X) = conj(fft(conj(X))) / N\n * Returns the real part of the time-domain signal.\n */\n private static ifftFromComplex(\n real: Float32Array,\n imag: Float32Array\n ): Float32Array {\n const N = real.length;\n // Conjugate input: negate imaginary part\n const conjImag = new Float32Array(N);\n for (let i = 0; i < N; i++) conjImag[i] = -imag[i];\n // FFT of conjugate\n const {real: outReal, imag: outImag} = MLNoiseSuppressor.fftForward(\n real,\n conjImag\n );\n // Conjugate result and scale by 1/N — take real part (output is real-valued)\n const output = new Float32Array(N);\n for (let i = 0; i < N; i++) {\n output[i] = outReal[i] / N; // conj(outReal+j*outImag)/N → real part = outReal/N\n }\n return output;\n }\n\n /**\n * Build an N-band triangular mel filterbank matching librosa's defaults.\n * Uses Slaney mel scale (htk=False, librosa default): linear below 1 kHz,\n * logarithmic above. This matches librosa.feature.melspectrogram used in\n * Colab training — HTK formula would produce different band-frequency\n * assignments and degrade suppression quality.\n */\n static buildMelFilterbank(\n nMels: number,\n nFft: number,\n sr: number\n ): Float32Array[] {\n const bins = nFft / 2 + 1;\n // Slaney mel scale — matches librosa htk=False default\n const F_SP = 200.0 / 3; // Hz per linear mel (~66.67)\n const MIN_LOG_HZ = 1000.0; // breakpoint\n const MIN_LOG_MEL = MIN_LOG_HZ / F_SP; // ≈15.0\n const LOGSTEP = Math.log(6.4) / 27.0; // log step above breakpoint\n const hzToMel = (hz: number) =>\n hz < MIN_LOG_HZ\n ? hz / F_SP\n : MIN_LOG_MEL + Math.log(hz / MIN_LOG_HZ) / LOGSTEP;\n const melToHz = (mel: number) =>\n mel < MIN_LOG_MEL\n ? mel * F_SP\n : MIN_LOG_HZ * Math.exp(LOGSTEP * (mel - MIN_LOG_MEL));\n\n const melMin = hzToMel(0);\n const melMax = hzToMel(sr / 2);\n\n // nMels + 2 equally-spaced mel points covering [0, sr/2]\n const melPts = new Float32Array(nMels + 2);\n for (let i = 0; i < nMels + 2; i++) {\n melPts[i] = melToHz(melMin + (i / (nMels + 1)) * (melMax - melMin));\n }\n\n // FFT bin centre frequencies\n const fftFreqs = new Float32Array(bins);\n for (let k = 0; k < bins; k++) fftFreqs[k] = (k * sr) / nFft;\n\n const filters: Float32Array[] = [];\n for (let m = 0; m < nMels; m++) {\n const filt = new Float32Array(bins);\n const left = melPts[m];\n const center = melPts[m + 1];\n const right = melPts[m + 2];\n for (let k = 0; k < bins; k++) {\n const f = fftFreqs[k];\n if (f >= left && f <= center) {\n filt[k] = (f - left) / (center - left + 1e-10);\n } else if (f > center && f <= right) {\n filt[k] = (right - f) / (right - center + 1e-10);\n }\n }\n filters.push(filt);\n }\n return filters;\n }\n\n /**\n * Apply temporal smoothing to the 40-band mel mask.\n *\n * Standard IRM smoothing: alpha weighted toward the PREVIOUS mask (heavy weight)\n * to prevent \"musical noise\" — rapid per-band gain changes that create tonal\n * artifacts. SMOOTHING_ALPHA=0.85 means 85% previous + 15% new each frame.\n *\n * BUG FIX: the old code had `alpha * current + (1-alpha) * prev` which was\n * effectively 85% tracking the current mask — almost no smoothing, causing chirps.\n */\n private applyTemporalSmoothing(\n currentMask: Float32Array,\n participantId: string = \"__default__\"\n ): Float32Array {\n const smoothed = new Float32Array(currentMask.length);\n const prev = this.prevMaskMap.get(participantId);\n\n if (!prev || prev.length !== currentMask.length) {\n const init = new Float32Array(currentMask);\n this.prevMaskMap.set(participantId, init);\n return init;\n }\n\n for (let i = 0; i < currentMask.length; i++) {\n // Heavy weight on PREVIOUS mask for smooth transitions — no pumping artefacts\n smoothed[i] =\n this.SMOOTHING_ALPHA * prev[i] +\n (1 - this.SMOOTHING_ALPHA) * currentMask[i];\n // NO floor — let the model fully suppress noise bins (IRM ≈ 0).\n // A 0.3 floor forced ALL bins (including pure noise) to 30% gain,\n // causing residual noise bleed-through and overall quiet/muffled audio.\n // Voice protection comes from the model itself (trained IRM ≈ 1.0 for voice bands).\n smoothed[i] = Math.max(0.0, Math.min(1.0, smoothed[i]));\n }\n\n this.prevMaskMap.set(participantId, smoothed);\n return smoothed;\n }\n\n /**\n * Apply the 40-band spectral mask via STFT → gain → ISTFT (overlap-add).\n *\n * Replaces the old applyMaskToAudio which incorrectly used frequency-domain mask\n * values as time-domain sample gains — producing distortion rather than clean\n * suppression. Correct approach:\n * 1. Map 40-band mel mask → per-FFT-bin gain via transpose mel filterbank\n * 2. Apply gains to the saved complex STFT frames\n * 3. Reconstruct via synthesis Hann window + overlap-add\n */\n private applyMaskViaOLA(\n audio: Float32Array,\n mask40: Float32Array,\n N_FFT: number,\n HOP: number,\n N_MELS: number\n ): Float32Array {\n // Fallback: if STFT frames weren't saved, pass audio through unchanged\n if (!this.melFilterbank || this.lastComplexFrames.length === 0) {\n return audio;\n }\n\n const bins = N_FFT / 2 + 1;\n\n // ── Map 40-mel mask → per-FFT-bin gain via transpose filterbank ──────────\n // For each STFT bin k: gain[k] = (∑m filters[m][k] × mask[m]) / (∑m filters[m][k])\n // Bins with no mel coverage keep gain=1.0 (DC, Nyquist — don't suppress).\n const fftGains = new Float32Array(bins);\n const filtTotals = new Float32Array(bins);\n for (let m = 0; m < N_MELS; m++) {\n const filt = this.melFilterbank[m];\n for (let k = 0; k < filt.length && k < bins; k++) {\n fftGains[k] += filt[k] * mask40[m];\n filtTotals[k] += filt[k];\n }\n }\n for (let k = 0; k < bins; k++) {\n fftGains[k] = filtTotals[k] > 1e-8 ? fftGains[k] / filtTotals[k] : 1.0; // no mel coverage → preserve\n fftGains[k] = Math.max(0.3, Math.min(1.0, fftGains[k])); // floor 0.3 — voice never suppressed below 30%\n }\n\n // Synthesis Hann window (= analysis window; guarantees perfect reconstruction at 50% overlap)\n const hannWindow = new Float32Array(N_FFT);\n for (let i = 0; i < N_FFT; i++) {\n hannWindow[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / (N_FFT - 1)));\n }\n\n const output = new Float32Array(audio.length);\n const normFactor = new Float32Array(audio.length);\n\n for (let fi = 0; fi < this.lastComplexFrames.length; fi++) {\n const start = fi * HOP;\n const {real: origReal, imag: origImag} = this.lastComplexFrames[fi];\n\n // Build full N_FFT complex arrays with conjugate symmetry applied\n const maskedReal = new Float32Array(N_FFT);\n const maskedImag = new Float32Array(N_FFT);\n for (let k = 0; k < bins; k++) {\n maskedReal[k] = origReal[k] * fftGains[k];\n maskedImag[k] = origImag[k] * fftGains[k];\n // Mirror conjugate for negative frequencies (skip DC k=0 and Nyquist k=N_FFT/2)\n if (k > 0 && k < N_FFT / 2) {\n maskedReal[N_FFT - k] = maskedReal[k];\n maskedImag[N_FFT - k] = -maskedImag[k]; // conjugate: negate imag\n }\n }\n\n // IFFT → time-domain frame\n const reconstructed = MLNoiseSuppressor.ifftFromComplex(\n maskedReal,\n maskedImag\n );\n\n // Overlap-add with synthesis window\n for (let i = 0; i < N_FFT; i++) {\n const pos = start + i;\n if (pos < audio.length) {\n output[pos] += reconstructed[i] * hannWindow[i];\n normFactor[pos] += hannWindow[i] * hannWindow[i];\n }\n }\n }\n\n // Normalise by OLA envelope; fall back to original sample where no coverage\n for (let i = 0; i < output.length; i++) {\n output[i] = normFactor[i] > 1e-10 ? output[i] / normFactor[i] : audio[i];\n }\n\n return output;\n }\n\n /**\n * Reset processing state (call when participant reconnects or audio track resets)\n */\n reset(): void {\n this.prevMaskMap.clear();\n this.melFrameHistory = [];\n this.lastComplexFrames = [];\n // Ring buffer state\n this.inRing = new Float32Array(8192);\n this.inRingLen = 0;\n this.outAccum = new Float32Array(16384);\n this.outNorm = new Float32Array(16384);\n this.cachedFftGains = null;\n this.inferenceInFlight = false;\n }\n\n /**\n * Check if ML processor is ready\n */\n isReady(): boolean {\n return this.isInitialized && this.model !== null;\n }\n\n /**\n * Return the loaded model config so callers (e.g. AudioWorkletNode setup)\n * can read n_fft, hop_length, n_mels, sample_rate, sequence_length.\n */\n getModelConfig(): ModelConfig | null {\n return this.config;\n }\n\n /**\n * Run one inference pass from pre-computed mel features and return per-FFT-bin\n * gains. Called by SpatialAudioChannel for each AudioWorkletNode message.\n *\n * @param features Flat Float32Array of shape [SEQ_LEN × N_MELS] (row-major).\n * Produced by the AudioWorklet processor and transferred via postMessage.\n * @param seqLen Sequence length (default from config).\n * @param nMels Number of mel bands (default from config).\n * @returns Float32Array of length N_FFT/2+1 with per-bin gains in [0,1].\n */\n async computeGainsFromFeatures(\n features: Float32Array,\n seqLen: number,\n nMels: number,\n participantId: string = \"__default__\"\n ): Promise<Float32Array> {\n if (!this.model || !this.config) {\n const bins = (this.config?.n_fft || 512) / 2 + 1;\n return new Float32Array(bins).fill(1.0);\n }\n\n const N_FFT = this.config.n_fft || 512;\n const SR = this.config.sample_rate || 16000;\n const bins = N_FFT / 2 + 1;\n\n try {\n // Features arrive from the AudioWorklet already in [0, 1] range via:\n // (power_to_db(ref=max) + 80) / 80 — identical to the training pipeline.\n // The model was trained on raw [0, 1] features WITHOUT z-score normalization.\n // (normalization_stats.json describes the data distribution but was NOT\n // applied to X before training in Colab.) Applying z-score here would\n // shift inputs to [-3, +3] and produce garbage gains.\n const inp = tf.tensor(Array.from(features), [\n 1,\n seqLen,\n nMels,\n ]) as tf.Tensor3D;\n const out = this.model.predict(inp) as tf.Tensor;\n const maskFlat = new Float32Array(await out.data());\n inp.dispose();\n out.dispose();\n\n // ── Step 1: Extract last frame's raw mel IRM (sigmoid output, [0,1]) ───\n const rawMask = new Float32Array(nMels);\n for (let m = 0; m < nMels; m++) {\n rawMask[m] = Math.max(\n 0,\n Math.min(1, maskFlat[(seqLen - 1) * nMels + m])\n );\n }\n\n // ── Step 2: Detect speech from RAW model output — BEFORE smoothing ──────\n //\n // CRITICAL FIX: isSpeechFrame must use the raw model output, NOT the\n // temporally-smoothed gains. With SMOOTHING_ALPHA=0.92 (old value), the\n // first speech frame produced smoothed max ≈ 0.08, which fell below the\n // 0.10 threshold → isSpeechFrame=false → gains=0 → first ~200ms of every\n // utterance was SILENCED. Using raw output (typically max=1.0 for speech)\n // ensures the gate opens on the very first speech frame.\n let rawMax = 0;\n for (let m = 0; m < nMels; m++) {\n if (rawMask[m] > rawMax) rawMax = rawMask[m];\n }\n\n // Safety: if model outputs near-zero (weight loading failure, warmup,\n // or feature mismatch), return full passthrough so the worklet gate stays\n // open and audio is heard. rawMax=0.000 in logs usually means the model\n // is outputting ~0.0001-0.003 (rounds to 0.000 at 3dp) — caught here.\n if (rawMax < 0.005) {\n // ⚠️ LOG THIS — silent passthrough was the root cause of \"fan noise always heard\".\n // If you see this frequently, weights are not loaded (GRU cell naming mismatch).\n const passthroughCount =\n (MLNoiseSuppressor as any)._passthroughCount || 0;\n (MLNoiseSuppressor as any)._passthroughCount = passthroughCount + 1;\n const lastPassthroughLog =\n (MLNoiseSuppressor as any)._lastPassthroughLog || 0;\n if (Date.now() - lastPassthroughLog > 2000) {\n (MLNoiseSuppressor as any)._lastPassthroughLog = Date.now();\n console.warn(\n `[ML] ❌ PASSTHROUGH (rawMax=${rawMax.toFixed(5)}) — model output near-zero. ` +\n `Count since last log: ${passthroughCount}. ` +\n `Weights likely NOT loaded. Check [MLNoiseSuppressor] weight name dump above.`\n );\n (MLNoiseSuppressor as any)._passthroughCount = 0;\n }\n const passthrough = new Float32Array(bins).fill(1.0);\n return passthrough;\n }\n\n // Threshold 0.108: fan/AC noise consistently scores rawMax=0.094-0.100.\n // Speech consistently scores rawMax≥0.111. Gap between 0.100 and 0.111 gives\n // 8% margin. Previously 0.10 caused fan frames scoring exactly 0.100 to\n // be classified as speech → fan noise leaked through during silence.\n let isSpeechFrame = rawMax >= 0.108;\n\n // ── Speech holdover: bridge within-word noise frames ─────────────────\n // The model scores fricatives (\"s\",\"f\"), plosives (\"t\",\"k\",\"p\") and\n // vowel transitions below threshold even mid-utterance, causing rapid\n // speech/noise alternation in the gains signal. A short holdover of\n // SF_HOLDOVER frames (~40ms) keeps isSpeechFrame=true for a few frames\n // after the last detected speech frame, smoothing out the chatter.\n const SF_HOLDOVER = 8; // 8 hops × ~5ms = ~40ms\n const sfMap: Map<string, number> =\n (MLNoiseSuppressor as any)._sfHoldoverMap ||\n ((MLNoiseSuppressor as any)._sfHoldoverMap = new Map());\n const sfHold = sfMap.get(participantId) || 0;\n if (isSpeechFrame) {\n sfMap.set(participantId, SF_HOLDOVER);\n } else if (sfHold > 0) {\n isSpeechFrame = true; // bridge: still within holdover window\n sfMap.set(participantId, sfHold - 1);\n } else {\n sfMap.set(participantId, 0);\n }\n\n // ── Step 3: Temporal smoothing on mel mask ────────────────────────────\n // Smoothing happens AFTER speech detection so it only affects gain\n // magnitude (fade-in/out), not the binary speech/noise decision.\n const smoothed = this.applyTemporalSmoothing(rawMask, participantId);\n\n // ── Step 4: Map 40 mel IRM → 257 FFT bins via transpose filterbank ────\n if (!this.melFilterbank) {\n this.melFilterbank = MLNoiseSuppressor.buildMelFilterbank(\n nMels,\n N_FFT,\n SR\n );\n }\n const gains = new Float32Array(bins);\n const filtTotal = new Float32Array(bins);\n for (let m = 0; m < nMels; m++) {\n const filt = this.melFilterbank[m];\n for (let k = 0; k < filt.length && k < bins; k++) {\n gains[k] += filt[k] * smoothed[m];\n filtTotal[k] += filt[k];\n }\n }\n for (let k = 0; k < bins; k++) {\n gains[k] = filtTotal[k] > 1e-8 ? gains[k] / filtTotal[k] : 1.0;\n gains[k] = Math.max(0.0, Math.min(1.0, gains[k]));\n }\n\n // ── Step 5: Speech-band protection floor ──────────────────────────────\n // Logs showed removed=7–9dB with floor=0.20: fan bins (model IRM≈0.05)\n // were being held at 0.20 = −14dB passthrough. Suppressed level was still\n // -47dBFS → still audible. Need -60dBFS+.\n //\n // Lower floor to 0.05: fan bins go 0.20→0.05 = −26dB on those bins.\n // Voice bins (model IRM≈0.85) are unaffected — well above either floor.\n // Effect:\n // Speech fundamental (raw IRM≈0.86) → 0.86 (unchanged, full voice)\n // Speech formants (raw IRM≈0.65) → 0.65 (unchanged, full voice)\n // Mixed fan+speech (raw IRM≈0.25) → 0.25 (−12dB, acceptable)\n // Pure fan bins (raw IRM≈0.05) → 0.05 (−26dB, near-inaudible)\n // Expected: removed increases from ~8dB → ~18dB.\n // During noise frames: no floor — model suppresses to full silence.\n const IRM_SPEECH_FLOOR = 0.05;\n if (isSpeechFrame) {\n for (let k = 1; k < bins; k++) {\n gains[k] = Math.max(IRM_SPEECH_FLOOR, gains[k]);\n }\n }\n\n // ── Step 6: Override gains[0] as explicit gate signal ────────────────\n // The DC bin (k=0) has no mel filter coverage → filtTotal[0] ≤ 1e-8 →\n // gains[0] defaults to 1.0 regardless of the model's output. The worklet\n // reads gains[0] as its ML gate: if it's always 1.0, ML never closes the\n // gate and background noise leaks through during speech. Override it to\n // the binary speech decision so the worklet gate properly tracks ML output.\n gains[0] = isSpeechFrame ? 1.0 : 0.0;\n\n // ── Diagnostic log ────────────────────────────────────────────────────\n const now = Date.now();\n const lastLog = (MLNoiseSuppressor as any)._lastGainLog || new Map();\n const lastT = lastLog.get(participantId) || 0;\n if (!isSpeechFrame || now - lastT > 1000) {\n lastLog.set(participantId, now);\n (MLNoiseSuppressor as any)._lastGainLog = lastLog;\n // suppression% = how much energy the ML removed (0%=passthrough, 100%=silence)\n let gainSum = 0;\n for (let k = 1; k < bins; k++) gainSum += gains[k];\n const meanIRM = gainSum / (bins - 1);\n const suppPct = ((1 - meanIRM) * 100).toFixed(0);\n console.log(\n `[ML] ${isSpeechFrame ? \"🎙️ SPEECH\" : \"🔇 NOISE \"} p=${participantId.substring(0, 8)} rawMax=${rawMax.toFixed(3)} suppression=${suppPct}% gate=${gains[0].toFixed(0)}`\n );\n }\n\n return gains;\n } catch {\n return new Float32Array(bins).fill(1.0);\n }\n }\n\n /**\n * Get model info\n */\n getInfo(): {initialized: boolean; backend: string; modelLoaded: boolean} {\n return {\n initialized: this.isInitialized,\n backend: tf.getBackend(),\n modelLoaded: this.model !== null,\n };\n }\n\n /**\n * Remove per-participant smoothing state when a participant disconnects.\n * Keeps prevMaskMap from growing unboundedly in long sessions.\n */\n clearParticipantSmoothingState(participantId: string): void {\n this.prevMaskMap.delete(participantId);\n }\n\n /**\n * Cleanup resources\n */\n dispose(): void {\n if (this.model) {\n this.model.dispose();\n this.model = null;\n }\n this.prevMaskMap.clear();\n this.isInitialized = false;\n }\n}\n","/**\n * Centralised debug logging utility.\n *\n * Enable in the browser console: window.ODYSSEY_DEBUG = true\n */\n\ndeclare global {\n interface Window {\n ODYSSEY_DEBUG?: boolean;\n }\n}\n\nexport const isDebugEnabled = (): boolean =>\n typeof window !== \"undefined\" && window.ODYSSEY_DEBUG === true;\n\nexport const debugLog = (\n category: string,\n message: string,\n data?: unknown\n): void => {\n if (!isDebugEnabled()) return;\n const timestamp = new Date().toISOString().slice(11, 23);\n if (data !== undefined) {\n console.log(`[${timestamp}][SDK:${category}] ${message}`, data);\n } else {\n console.log(`[${timestamp}][SDK:${category}] ${message}`);\n }\n};\n","/**\n * Spatial Audio Channel\n *\n * Processes audio for spatial positioning using Web Audio API\n */\n\nimport {Position} from \"../../types/position\";\nimport {\n SpatialDistanceConfig,\n DenoiserOptions,\n ParticipantAudioNodes,\n ListenerState,\n DEFAULT_SPATIAL_CONFIG,\n DEFAULT_DENOISER_OPTIONS,\n} from \"./SpatialAudioTypes\";\nimport {getDistanceBetween} from \"../../utils/spatial/distance-calc\";\nimport {calculateLogarithmicGain} from \"../../utils/spatial/gain-calc\";\nimport {\n calculateListenerRight,\n calculatePanFromPositions,\n} from \"../../utils/spatial/pan-calc\";\nimport {computeHeadPosition} from \"../../utils/spatial/head-position\";\nimport {normalizePositionUnits} from \"../../utils/position/normalize\";\nimport {\n createPositionSnapCache,\n PositionSnapCacheHandle,\n} from \"../../utils/position/snap\";\nimport {\n createPanSmoother,\n PanSmootherHandle,\n} from \"../../utils/smoothing/pan-smoothing\";\nimport {\n applyGainSmooth,\n applyStereoPanSmooth,\n} from \"../../utils/smoothing/gain-smoothing\";\nimport {\n createMLNoiseSuppressor,\n MLNoiseSuppressorHandle,\n} from \"../../audio/MLNoiseSuppressor\";\nimport {debugLog} from \"../../utils/debug\";\n\n/**\n * Spatial audio configuration\n */\nexport interface SpatialAudioConfig {\n distance?: SpatialDistanceConfig;\n denoiser?: DenoiserOptions;\n}\n// ─── Factory handle interface ──────────────────────────────────────────────────\n\nexport interface SpatialAudioManagerHandle {\n getAudioContext(): AudioContext;\n setupParticipant(\n participantId: string,\n track: MediaStreamTrack,\n bypassSpatialization?: boolean\n ): Promise<void>;\n setupSpatialAudioForParticipant(\n participantId: string,\n track: MediaStreamTrack,\n bypassSpatialization?: boolean\n ): Promise<void>;\n updateSpatialAudio(\n participantId: string,\n position: Position,\n direction?: {x: number; y: number; z: number}\n ): void;\n setListenerFromLSD(\n listenerPos: Position,\n cameraPos: Position,\n lookAtPos: Position,\n rot?: {x: number; y: number; z: number}\n ): void;\n setListenerPosition(\n position: Position,\n orientation?: {\n forwardX: number;\n forwardY: number;\n forwardZ: number;\n upX: number;\n upY: number;\n upZ: number;\n }\n ): void;\n setParticipantSpatialization(\n participantId: string,\n enableSpatialization: boolean\n ): void;\n setParticipantMuted(participantId: string, muted: boolean): void;\n setMasterMuted(muted: boolean): void;\n getMasterMuted(): boolean;\n initializeMLNoiseSuppression(\n modelPath: string,\n workletUrl?: string\n ): Promise<void>;\n enhanceOutgoingAudioTrack(track: MediaStreamTrack): Promise<MediaStreamTrack>;\n getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\";\n isMLModelLoaded(): boolean;\n removeParticipant(participantId: string): void;\n resumeAudioContext(): Promise<void>;\n getAudioContextState(): AudioContextState;\n getParticipantAudioLevel(participantId: string): number;\n isParticipantSpeaking(participantId: string, threshold?: number): boolean;\n getActiveParticipants(): string[];\n hasParticipant(participantId: string): boolean;\n getParticipantCount(): number;\n}\n\n// ─── Factory function ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Create a spatial audio manager.\n * All state is held in closure variables — no class instantiation needed.\n */\nexport function createSpatialAudioManager(\n config?: SpatialAudioConfig\n): SpatialAudioManagerHandle {\n // ── Configuration ─────────────────────────────────────────────────────────\n const distanceConfig: Required<SpatialDistanceConfig> = {\n ...DEFAULT_SPATIAL_CONFIG,\n ...config?.distance,\n };\n const denoiserConfig: Required<DenoiserOptions> = {\n ...DEFAULT_DENOISER_OPTIONS,\n ...config?.denoiser,\n };\n\n // ── AudioContext + master chain ───────────────────────────────────────────\n const audioContext = new AudioContext({sampleRate: 48000});\n\n // Chrome suspends AudioContext created outside a user-gesture frame.\n const resumeOnGesture = () => {\n if (audioContext.state === \"suspended\") {\n audioContext.resume().catch(() => {\n /* ignore */\n });\n }\n document.removeEventListener(\"click\", resumeOnGesture);\n document.removeEventListener(\"keydown\", resumeOnGesture);\n document.removeEventListener(\"touchstart\", resumeOnGesture);\n };\n document.addEventListener(\"click\", resumeOnGesture);\n document.addEventListener(\"keydown\", resumeOnGesture);\n document.addEventListener(\"touchstart\", resumeOnGesture);\n\n // Master gain raised to 2.5 to compensate for ML IRM attenuation.\n const masterGainNode = audioContext.createGain();\n masterGainNode.gain.value = 2.5;\n\n // Master compressor — DISABLED for spatial audio (ratio 1:1 = pass-through)\n const masterCompressor = audioContext.createDynamicsCompressor();\n masterCompressor.threshold.value = 0;\n masterCompressor.knee.value = 0;\n masterCompressor.ratio.value = 1;\n masterCompressor.attack.value = 0.003;\n masterCompressor.release.value = 0.25;\n\n masterGainNode.connect(masterCompressor);\n masterCompressor.connect(audioContext.destination);\n\n // ── Per-participant state ──────────────────────────────────────────────────\n const participantNodes = new Map<string, ParticipantAudioNodes>();\n\n const listenerState: ListenerState = {\n position: {x: 0, y: 0, z: 0},\n right: {x: 1, z: 0},\n initialized: false,\n };\n\n const positionCache = createPositionSnapCache(0.3);\n const panSmoother = createPanSmoother();\n let isMasterMuted = false;\n\n const lastGainValues = new Map<string, number>();\n const lastPanValues = new Map<string, number>();\n const GAIN_CHANGE_THRESHOLD = 0.02;\n const PAN_CHANGE_THRESHOLD = 0.03;\n const lastUpdateTime = new Map<string, number>();\n const MIN_UPDATE_INTERVAL_MS = 50;\n\n // ── ML / AudioWorklet state ───────────────────────────────────────────────\n let mlNoiseSuppressor: MLNoiseSuppressorHandle | null = null;\n let noiseSuppressionMode: \"ml\" | \"audioworklet\" | \"none\" = \"none\";\n const inferenceInFlight = new Set<string>();\n let workletRegistered = false;\n let workletUrl: string | null = null;\n\n type OutgoingChain = {\n inputTrack: MediaStreamTrack;\n outputTrack: MediaStreamTrack;\n source: MediaStreamAudioSourceNode;\n denoiseNode: AudioWorkletNode;\n destination: MediaStreamAudioDestinationNode;\n };\n let outgoingDenoiseChain: OutgoingChain | null = null;\n\n // ── Private helpers ────────────────────────────────────────────────────────\n function createPanner(): PannerNode {\n const panner = audioContext.createPanner();\n panner.panningModel = \"HRTF\";\n panner.distanceModel = \"inverse\";\n panner.refDistance = distanceConfig.refDistance;\n panner.maxDistance = distanceConfig.maxDistance;\n panner.rolloffFactor = distanceConfig.rolloffFactor;\n panner.coneInnerAngle = 360;\n panner.coneOuterAngle = 360;\n panner.coneOuterGain = 0.3;\n return panner;\n }\n\n function createMonoChain() {\n const monoSplitter = audioContext.createChannelSplitter(2);\n const monoGainL = audioContext.createGain();\n const monoGainR = audioContext.createGain();\n const monoMerger = audioContext.createChannelMerger(1);\n const stereoUpmixer = audioContext.createChannelMerger(2);\n monoGainL.gain.value = 0.5;\n monoGainR.gain.value = 0.5;\n return {monoSplitter, monoGainL, monoGainR, monoMerger, stereoUpmixer};\n }\n\n function createParticipantCompressor(): DynamicsCompressorNode {\n const comp = audioContext.createDynamicsCompressor();\n comp.threshold.value = -30;\n comp.knee.value = 12;\n comp.ratio.value = 3;\n comp.attack.value = 0.003;\n comp.release.value = 0.15;\n return comp;\n }\n\n function createFilters() {\n const highpassFilter = audioContext.createBiquadFilter();\n highpassFilter.type = \"highpass\";\n highpassFilter.frequency.value = 100;\n highpassFilter.Q.value = 0.5;\n\n const lowpassFilter = audioContext.createBiquadFilter();\n lowpassFilter.type = \"lowpass\";\n lowpassFilter.frequency.value = 10000;\n lowpassFilter.Q.value = 0.5;\n\n const voiceBandFilter = audioContext.createBiquadFilter();\n voiceBandFilter.type = \"peaking\";\n voiceBandFilter.frequency.value = 180;\n voiceBandFilter.Q.value = 0.5;\n voiceBandFilter.gain.value = 0;\n\n const dynamicLowpass = audioContext.createBiquadFilter();\n dynamicLowpass.type = \"lowpass\";\n dynamicLowpass.frequency.value = 12000;\n dynamicLowpass.Q.value = 0.5;\n\n return {highpassFilter, lowpassFilter, voiceBandFilter, dynamicLowpass};\n }\n\n function teardownOutgoingDenoiseChain(\n chain: OutgoingChain | null = outgoingDenoiseChain\n ): void {\n const localPid = \"__local_outgoing__\";\n inferenceInFlight.delete(localPid);\n if (mlNoiseSuppressor) {\n mlNoiseSuppressor.clearParticipantSmoothingState(localPid);\n }\n if (!chain) return;\n try {\n chain.denoiseNode.port.close();\n } catch {\n /* ignore */\n }\n try {\n chain.source.disconnect();\n } catch {\n /* ignore */\n }\n try {\n chain.denoiseNode.disconnect();\n } catch {\n /* ignore */\n }\n if (outgoingDenoiseChain === chain) {\n outgoingDenoiseChain = null;\n }\n }\n\n // ── Public methods ─────────────────────────────────────────────────────────\n\n function getAudioContext(): AudioContext {\n return audioContext;\n }\n\n async function setupParticipant(\n participantId: string,\n track: MediaStreamTrack,\n bypassSpatialization: boolean = false\n ): Promise<void> {\n if (audioContext.state === \"suspended\") {\n await audioContext.resume();\n }\n\n const stream = new MediaStream([track]);\n const source = audioContext.createMediaStreamSource(stream);\n const panner = createPanner();\n const stereoPanner = audioContext.createStereoPanner();\n const {monoSplitter, monoGainL, monoGainR, monoMerger, stereoUpmixer} =\n createMonoChain();\n const analyser = audioContext.createAnalyser();\n const gain = audioContext.createGain();\n const proximityGain = audioContext.createGain();\n const comp = createParticipantCompressor();\n const {highpassFilter, lowpassFilter, voiceBandFilter, dynamicLowpass} =\n createFilters();\n\n gain.gain.value = 1.0;\n proximityGain.gain.value = 1.0;\n\n let noiseNode: AudioWorkletNode | null = null;\n\n if (workletRegistered && mlNoiseSuppressor) {\n const cfg = mlNoiseSuppressor.getModelConfig();\n noiseNode = new AudioWorkletNode(audioContext, \"noise-suppressor\", {\n numberOfInputs: 1,\n numberOfOutputs: 1,\n outputChannelCount: [1],\n });\n\n noiseNode.port.postMessage({\n type: \"config\",\n n_fft: cfg?.n_fft ?? 512,\n hop_length: cfg?.hop_length ?? 80,\n n_mels: cfg?.n_mels ?? 40,\n sample_rate: cfg?.sample_rate ?? 16000,\n sequence_length: cfg?.sequence_length ?? 8,\n });\n\n const workletRef = noiseNode;\n const seqLen = cfg?.sequence_length ?? 8;\n const nMels = cfg?.n_mels ?? 40;\n const _pid = participantId;\n noiseNode.port.onmessage = async (e: MessageEvent) => {\n if (e.data.type === \"mel_features\" && mlNoiseSuppressor?.isReady()) {\n if (inferenceInFlight.has(_pid)) return;\n inferenceInFlight.add(_pid);\n try {\n const gains = await mlNoiseSuppressor.computeGainsFromFeatures(\n new Float32Array(e.data.features),\n seqLen,\n nMels,\n _pid\n );\n try {\n workletRef.port.postMessage({type: \"gains\", gains}, [\n gains.buffer,\n ]);\n } catch {\n /* worklet disconnected */\n }\n } finally {\n inferenceInFlight.delete(_pid);\n }\n }\n };\n }\n\n if (noiseNode) {\n source.connect(noiseNode);\n noiseNode.connect(comp);\n } else {\n source.connect(comp);\n }\n\n comp.connect(highpassFilter);\n highpassFilter.connect(voiceBandFilter);\n voiceBandFilter.connect(lowpassFilter);\n lowpassFilter.connect(dynamicLowpass);\n dynamicLowpass.connect(proximityGain);\n\n proximityGain.connect(monoSplitter);\n monoSplitter.connect(monoGainL, 0);\n monoSplitter.connect(monoGainR, 1);\n monoGainL.connect(monoMerger, 0, 0);\n monoGainR.connect(monoMerger, 0, 0);\n monoMerger.connect(stereoUpmixer, 0, 0);\n monoMerger.connect(stereoUpmixer, 0, 1);\n stereoUpmixer.connect(analyser);\n\n if (bypassSpatialization) {\n analyser.connect(gain);\n } else {\n analyser.connect(stereoPanner);\n stereoPanner.connect(gain);\n }\n gain.connect(masterGainNode);\n\n participantNodes.set(participantId, {\n source,\n panner,\n stereoPanner,\n monoSplitter,\n monoGainL,\n monoGainR,\n monoMerger,\n stereoUpmixer,\n analyser,\n gain,\n proximityGain,\n compressor: comp,\n highpassFilter,\n lowpassFilter,\n voiceBandFilter,\n dynamicLowpass,\n denoiseNode: noiseNode ?? undefined,\n stream,\n });\n\n lastGainValues.set(participantId, 1.0);\n lastPanValues.set(participantId, 0);\n }\n\n function updateSpatialAudio(\n participantId: string,\n position: Position,\n direction?: {x: number; y: number; z: number}\n ): void {\n const nodes = participantNodes.get(participantId);\n if (!nodes?.panner) return;\n\n if (!listenerState.initialized) return;\n\n const now = performance.now();\n const lastTime = lastUpdateTime.get(participantId) || 0;\n if (now - lastTime < MIN_UPDATE_INTERVAL_MS) return;\n lastUpdateTime.set(participantId, now);\n\n const normalizedPos = normalizePositionUnits(position, distanceConfig.unit);\n const snappedPos = positionCache.snap(normalizedPos, participantId);\n const speakerHead = computeHeadPosition(snappedPos);\n\n const listenerPos = listenerState.position;\n const distance = getDistanceBetween(listenerPos, speakerHead);\n\n if (distance >= distanceConfig.maxDistance) {\n const lastGain = lastGainValues.get(participantId) ?? 1.0;\n if (lastGain > 0.01) {\n applyGainSmooth(nodes.gain, 0, audioContext, 0.1);\n lastGainValues.set(participantId, 0);\n }\n return;\n }\n\n const rawPan = calculatePanFromPositions(\n listenerPos,\n speakerHead,\n listenerState.right\n );\n const smoothedPan = panSmoother.smooth(participantId, rawPan);\n\n const gainPercent = calculateLogarithmicGain(distance, {\n minDistance: distanceConfig.refDistance,\n maxDistance: distanceConfig.maxDistance,\n });\n const gainValue = gainPercent / 100;\n const panValue = smoothedPan;\n\n const lastPan = lastPanValues.get(participantId) ?? 0;\n const lastGain = lastGainValues.get(participantId) ?? 1.0;\n const panChanged = Math.abs(panValue - lastPan) > PAN_CHANGE_THRESHOLD;\n const gainChanged = Math.abs(gainValue - lastGain) > GAIN_CHANGE_THRESHOLD;\n\n if (panChanged || gainChanged) {\n const panDirection =\n panValue > 0.3 ? \"RIGHT\" : panValue < -0.3 ? \"LEFT\" : \"CENTER\";\n const panPercent = Math.abs(panValue * 100).toFixed(0);\n\n debugLog(\"SPATIAL\", `${participantId.slice(0, 8)}`, {\n dist: distance.toFixed(1) + \"m\",\n gain: (gainValue * 100).toFixed(0) + \"%\",\n pan: `${panPercent}% ${panDirection}`,\n rawPan: rawPan.toFixed(2),\n listenerRight: `(${listenerState.right.x.toFixed(2)}, ${listenerState.right.z.toFixed(2)})`,\n });\n }\n\n if (panChanged) {\n applyStereoPanSmooth(nodes.stereoPanner, panValue, audioContext, 0.08);\n lastPanValues.set(participantId, panValue);\n }\n\n const GAIN_THRESHOLD = 0.025;\n const isFirstCalculation = !lastGainValues.has(participantId);\n const significantChange = Math.abs(gainValue - lastGain) > GAIN_THRESHOLD;\n\n if (isFirstCalculation || significantChange) {\n applyGainSmooth(nodes.gain, gainValue, audioContext, 0.15);\n lastGainValues.set(participantId, gainValue);\n }\n }\n\n function setListenerFromLSD(\n listenerPos: Position,\n cameraPos: Position,\n lookAtPos: Position,\n rot?: {x: number; y: number; z: number}\n ): void {\n const normalizedListener = normalizePositionUnits(\n cameraPos,\n distanceConfig.unit\n );\n const snappedListener = positionCache.snap(normalizedListener, \"listener\");\n\n listenerState.position = snappedListener;\n listenerState.initialized = true;\n\n if (rot && typeof rot.y === \"number\") {\n listenerState.right = calculateListenerRight(rot.y);\n } else if (lookAtPos && cameraPos) {\n const dx = lookAtPos.x - cameraPos.x;\n const dz = lookAtPos.z - cameraPos.z;\n const yawRadians = Math.atan2(dx, dz);\n const yawDegrees = (yawRadians * 180) / Math.PI;\n listenerState.right = calculateListenerRight(yawDegrees);\n }\n }\n\n function setParticipantSpatialization(\n participantId: string,\n enableSpatialization: boolean\n ): void {\n const nodes = participantNodes.get(participantId);\n if (!nodes) {\n console.warn(\n `[SpatialAudioChannel] Cannot set spatialization - no nodes for participant: ${participantId}`\n );\n return;\n }\n\n try {\n const currentTime = audioContext.currentTime;\n const fadeTime = 0.03;\n\n if (enableSpatialization) {\n nodes.analyser.connect(nodes.stereoPanner);\n nodes.stereoPanner.connect(nodes.gain);\n setTimeout(() => {\n try {\n /* already routed */\n } catch (e) {\n /* ignore */\n }\n }, fadeTime * 1000);\n } else {\n nodes.analyser.connect(nodes.gain);\n nodes.gain.gain.setTargetAtTime(1.0, currentTime, fadeTime);\n nodes.stereoPanner.pan.setTargetAtTime(0, currentTime, fadeTime);\n setTimeout(() => {\n try {\n nodes.stereoPanner.disconnect();\n } catch (e) {\n /* already disconnected */\n }\n }, fadeTime * 1000);\n }\n } catch (error) {\n console.error(\n `[SpatialAudioChannel] Error setting spatialization for ${participantId}:`,\n error\n );\n }\n }\n\n function setParticipantMuted(participantId: string, muted: boolean): void {\n const nodes = participantNodes.get(participantId);\n if (!nodes?.gain) return;\n applyGainSmooth(nodes.gain, muted ? 0 : 1, audioContext, 0.05);\n }\n\n function setMasterMuted(muted: boolean): void {\n isMasterMuted = muted;\n applyGainSmooth(masterGainNode, muted ? 0 : 1, audioContext, 0.05);\n }\n\n function getMasterMuted(): boolean {\n return isMasterMuted;\n }\n\n function setListenerPosition(\n position: Position,\n orientation?: {\n forwardX: number;\n forwardY: number;\n forwardZ: number;\n upX: number;\n upY: number;\n upZ: number;\n }\n ): void {\n const normalizedPosition = normalizePositionUnits(position);\n positionCache.snap(normalizedPosition, \"listener\");\n listenerState.position = normalizedPosition;\n\n if (orientation) {\n const yawRadians = Math.atan2(orientation.forwardX, orientation.forwardZ);\n const yawDegrees = (yawRadians * 180) / Math.PI;\n listenerState.right = calculateListenerRight(yawDegrees);\n }\n\n listenerState.initialized = true;\n }\n\n async function setupSpatialAudioForParticipant(\n participantId: string,\n track: MediaStreamTrack,\n bypassSpatialization?: boolean\n ): Promise<void> {\n return setupParticipant(\n participantId,\n track,\n bypassSpatialization || false\n );\n }\n\n async function initializeMLNoiseSuppression(\n modelPath: string,\n workletUrlParam?: string\n ): Promise<void> {\n if (workletUrlParam && !workletRegistered) {\n try {\n await audioContext.audioWorklet.addModule(workletUrlParam);\n workletRegistered = true;\n workletUrl = workletUrlParam;\n console.log(\n `[SpatialAudioChannel] AudioWorklet registered: ${workletUrlParam}`\n );\n } catch (e) {\n console.warn(\n \"[SpatialAudioChannel] AudioWorklet registration failed — falling back to passthrough:\",\n e\n );\n }\n }\n\n mlNoiseSuppressor = createMLNoiseSuppressor();\n await mlNoiseSuppressor.initialize(modelPath);\n\n if (!mlNoiseSuppressor.isReady()) {\n mlNoiseSuppressor = null;\n throw new Error(\n `[SpatialAudioChannel] ML model loaded from ${modelPath} but isReady() returned false`\n );\n }\n\n noiseSuppressionMode = \"ml\";\n console.log(\n `[SpatialAudioChannel] ML noise suppression ACTIVE — model loaded from ${modelPath}`\n );\n }\n\n async function enhanceOutgoingAudioTrack(\n track: MediaStreamTrack\n ): Promise<MediaStreamTrack> {\n if (track.kind !== \"audio\") return track;\n if (!workletRegistered || !mlNoiseSuppressor?.isReady()) return track;\n\n if (\n outgoingDenoiseChain &&\n outgoingDenoiseChain.outputTrack.id === track.id &&\n outgoingDenoiseChain.outputTrack.readyState === \"live\"\n ) {\n return outgoingDenoiseChain.outputTrack;\n }\n\n if (\n outgoingDenoiseChain &&\n outgoingDenoiseChain.inputTrack.id === track.id &&\n outgoingDenoiseChain.outputTrack.readyState === \"live\"\n ) {\n return outgoingDenoiseChain.outputTrack;\n }\n\n const cfg = mlNoiseSuppressor.getModelConfig();\n if (!cfg) return track;\n\n try {\n if (audioContext.state === \"suspended\") {\n await audioContext.resume();\n }\n\n const previousChain = outgoingDenoiseChain;\n const stream = new MediaStream([track]);\n const source = audioContext.createMediaStreamSource(stream);\n const denoiseNode = new AudioWorkletNode(\n audioContext,\n \"noise-suppressor\",\n {\n numberOfInputs: 1,\n numberOfOutputs: 1,\n outputChannelCount: [1],\n }\n );\n const destination = audioContext.createMediaStreamDestination();\n\n denoiseNode.port.postMessage({\n type: \"config\",\n n_fft: cfg.n_fft ?? 512,\n hop_length: cfg.hop_length ?? 80,\n n_mels: cfg.n_mels ?? 40,\n sample_rate: cfg.sample_rate ?? 16000,\n sequence_length: cfg.sequence_length ?? 8,\n });\n\n const seqLen = cfg.sequence_length ?? 8;\n const nMels = cfg.n_mels ?? 40;\n const localPid = \"__local_outgoing__\";\n const workletRef = denoiseNode;\n\n denoiseNode.port.onmessage = async (e: MessageEvent) => {\n if (e.data.type === \"mel_features\" && mlNoiseSuppressor?.isReady()) {\n if (inferenceInFlight.has(localPid)) return;\n inferenceInFlight.add(localPid);\n try {\n const gains = await mlNoiseSuppressor.computeGainsFromFeatures(\n new Float32Array(e.data.features),\n seqLen,\n nMels,\n localPid\n );\n workletRef.port.postMessage({type: \"gains\", gains}, [gains.buffer]);\n } catch {\n // Keep last known gains when inference fails for one frame.\n } finally {\n inferenceInFlight.delete(localPid);\n }\n }\n };\n\n source.connect(denoiseNode);\n denoiseNode.connect(destination);\n\n const enhancedTrack = destination.stream.getAudioTracks()[0];\n if (!enhancedTrack) {\n try {\n source.disconnect();\n } catch {\n /* ignore */\n }\n try {\n denoiseNode.disconnect();\n } catch {\n /* ignore */\n }\n return track;\n }\n\n enhancedTrack.enabled = track.enabled;\n\n track.addEventListener(\"ended\", () => teardownOutgoingDenoiseChain(), {\n once: true,\n });\n enhancedTrack.addEventListener(\n \"ended\",\n () => teardownOutgoingDenoiseChain(),\n {once: true}\n );\n\n outgoingDenoiseChain = {\n inputTrack: track,\n outputTrack: enhancedTrack,\n source,\n denoiseNode,\n destination,\n };\n\n if (previousChain) {\n teardownOutgoingDenoiseChain(previousChain);\n }\n\n console.log(\n \"[SpatialAudioChannel] Local outgoing ML denoise ACTIVE (AudioWorklet)\"\n );\n return enhancedTrack;\n } catch (e) {\n console.warn(\n \"[SpatialAudioChannel] Failed to enhance outgoing track, using original track:\",\n e\n );\n return track;\n }\n }\n\n function getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\" {\n return noiseSuppressionMode;\n }\n\n function isMLModelLoaded(): boolean {\n return mlNoiseSuppressor?.isReady() ?? false;\n }\n\n function removeParticipant(participantId: string): void {\n const nodes = participantNodes.get(participantId);\n if (nodes) {\n debugLog(\"AUDIO\", `Removing participant: ${participantId.slice(0, 8)}`, {\n totalBefore: participantNodes.size,\n totalAfter: participantNodes.size - 1,\n });\n\n nodes.denoiseNode?.port.close();\n nodes.denoiseNode?.disconnect();\n nodes.source.disconnect();\n nodes.panner.disconnect();\n nodes.stereoPanner.disconnect();\n nodes.analyser.disconnect();\n nodes.gain.disconnect();\n participantNodes.delete(participantId);\n panSmoother.clear(participantId);\n positionCache.clear(participantId);\n lastGainValues.delete(participantId);\n lastPanValues.delete(participantId);\n lastUpdateTime.delete(participantId);\n inferenceInFlight.delete(participantId);\n if (mlNoiseSuppressor) {\n mlNoiseSuppressor.clearParticipantSmoothingState(participantId);\n }\n } else {\n debugLog(\n \"AUDIO\",\n `Remove called but participant not found: ${participantId.slice(0, 8)}`\n );\n }\n }\n\n async function resumeAudioContext(): Promise<void> {\n if (audioContext.state === \"suspended\") {\n await audioContext.resume();\n }\n }\n\n function getAudioContextState(): AudioContextState {\n return audioContext.state;\n }\n\n function getParticipantAudioLevel(participantId: string): number {\n const nodes = participantNodes.get(participantId);\n if (!nodes?.analyser) return 0;\n\n const dataArray = new Uint8Array(nodes.analyser.frequencyBinCount);\n nodes.analyser.getByteFrequencyData(dataArray);\n\n let sum = 0;\n for (let i = 0; i < dataArray.length; i++) {\n sum += dataArray[i] * dataArray[i];\n }\n const rms = Math.sqrt(sum / dataArray.length);\n return Math.min(100, Math.round((rms / 255) * 100));\n }\n\n function isParticipantSpeaking(\n participantId: string,\n threshold: number = 5\n ): boolean {\n return getParticipantAudioLevel(participantId) > threshold;\n }\n\n function getActiveParticipants(): string[] {\n return Array.from(participantNodes.keys());\n }\n\n function hasParticipant(participantId: string): boolean {\n return participantNodes.has(participantId);\n }\n\n function getParticipantCount(): number {\n return participantNodes.size;\n }\n\n // ── Return handle ──────────────────────────────────────────────────────────\n return {\n getAudioContext,\n setupParticipant,\n setupSpatialAudioForParticipant,\n updateSpatialAudio,\n setListenerFromLSD,\n setListenerPosition,\n setParticipantSpatialization,\n setParticipantMuted,\n setMasterMuted,\n getMasterMuted,\n initializeMLNoiseSuppression,\n enhanceOutgoingAudioTrack,\n getNoiseSuppressionMode,\n isMLModelLoaded,\n removeParticipant,\n resumeAudioContext,\n getAudioContextState,\n getParticipantAudioLevel,\n isParticipantSpeaking,\n getActiveParticipants,\n hasParticipant,\n getParticipantCount,\n };\n}\n\nexport type {SpatialAudioConfig as SpatialAudioOptions};\n","/**\n * Screen Share Live In Space Manager (factory function)\n *\n * Manages broadcasting screen share to space for Unreal Engine consumption.\n */\n\nimport {Socket} from \"socket.io-client\";\nimport {\n SpaceLiveBroadcastResult,\n SpaceLiveBroadcastStatus,\n StartSpaceLiveBroadcastRequest,\n StopSpaceLiveBroadcastRequest,\n BroadcastResponse,\n ParticipantInfo,\n RoomInfo,\n} from \"./types\";\nimport {debugLog} from \"../utils/debug\";\n\n// ─── Public handle interface ──────────────────────────────────────────────────\n\nexport interface ScreenShareLiveManagerHandle {\n readonly isActive: boolean;\n readonly broadcastProducerId: string | null;\n startBroadcast(\n room: RoomInfo,\n participant: ParticipantInfo,\n serverUrl: string\n ): Promise<SpaceLiveBroadcastResult>;\n stopBroadcast(room: RoomInfo | null, participantId?: string): Promise<void>;\n getStatus(\n roomId: string | null,\n callback: (status: SpaceLiveBroadcastStatus) => void\n ): void;\n onBroadcastAvailable(\n callback: (data: {\n roomId: string;\n producerId: string;\n producerUserId: string;\n userName: string;\n }) => void\n ): void;\n onBroadcastStopped(callback: (data: {roomId: string}) => void): void;\n removeListeners(): void;\n cleanup(): void;\n}\n\n// ─── Factory function (preferred) ────────────────────────────────────────────\n\nexport function createScreenShareLiveManager(\n socket: Socket\n): ScreenShareLiveManagerHandle {\n let isBroadcasting = false;\n let currentProducerId: string | null = null;\n\n function findScreenshareProducerId(\n participant: ParticipantInfo\n ): string | null {\n for (const [producerId, producer] of participant.producers) {\n if (\n (producer as unknown as {appData?: {isScreenshare?: boolean}}).appData\n ?.isScreenshare\n ) {\n return producerId;\n }\n }\n return null;\n }\n\n async function startBroadcast(\n room: RoomInfo,\n participant: ParticipantInfo,\n serverUrl: string\n ): Promise<SpaceLiveBroadcastResult> {\n if (!room || !participant) {\n throw new Error(\"Must be in a room to start space live broadcast\");\n }\n\n const screenshareProducerId = findScreenshareProducerId(participant);\n if (!screenshareProducerId) {\n throw new Error(\"No active screen share to broadcast to space\");\n }\n\n return new Promise((resolve, reject) => {\n const request: StartSpaceLiveBroadcastRequest = {\n roomId: room.id,\n producerId: screenshareProducerId,\n participantId: participant.participantId,\n userName: participant.userName || \"Unknown\",\n };\n\n const timestamp = Date.now();\n\n socket.emit(\n \"start-space-live-broadcast\",\n request,\n (response: BroadcastResponse) => {\n if (response.error) {\n reject(new Error(response.error));\n } else {\n isBroadcasting = true;\n currentProducerId = screenshareProducerId;\n debugLog(\"SPACE-LIVE\", \"Started space live broadcast\", {\n producerId: screenshareProducerId,\n });\n resolve({\n producerId: screenshareProducerId,\n roomId: room.id,\n serverUrl,\n timestamp,\n });\n }\n }\n );\n });\n }\n\n async function stopBroadcast(\n room: RoomInfo | null,\n participantId?: string\n ): Promise<void> {\n if (!room) {\n isBroadcasting = false;\n currentProducerId = null;\n return;\n }\n\n return new Promise((resolve) => {\n const request: StopSpaceLiveBroadcastRequest = {\n roomId: room.id,\n participantId,\n };\n\n socket.emit(\"stop-space-live-broadcast\", request, () => {\n isBroadcasting = false;\n currentProducerId = null;\n debugLog(\"SPACE-LIVE\", \"Stopped space live broadcast\");\n resolve();\n });\n });\n }\n\n function getStatus(\n roomId: string | null,\n callback: (status: SpaceLiveBroadcastStatus) => void\n ): void {\n if (!roomId) {\n callback({isActive: false});\n return;\n }\n socket.emit(\"get-space-live-broadcast-status\", {roomId}, callback);\n }\n\n function onBroadcastAvailable(\n callback: (data: {\n roomId: string;\n producerId: string;\n producerUserId: string;\n userName: string;\n }) => void\n ): void {\n socket.on(\"space-live-broadcast-available\", callback);\n }\n\n function onBroadcastStopped(\n callback: (data: {roomId: string}) => void\n ): void {\n socket.on(\"space-live-broadcast-stopped\", callback);\n }\n\n function removeListeners(): void {\n socket.off(\"space-live-broadcast-available\");\n socket.off(\"space-live-broadcast-stopped\");\n }\n\n function cleanup(): void {\n isBroadcasting = false;\n currentProducerId = null;\n removeListeners();\n }\n\n return {\n get isActive() {\n return isBroadcasting;\n },\n get broadcastProducerId() {\n return currentProducerId;\n },\n startBroadcast,\n stopBroadcast,\n getStatus,\n onBroadcastAvailable,\n onBroadcastStopped,\n removeListeners,\n cleanup,\n };\n}\n","import {Socket} from \"socket.io-client\";\nimport {EventBus} from \"./EventManager\";\nimport {MediasoupManagerHandle} from \"./MediasoupManager\";\nimport {\n Direction,\n MediaState,\n OdysseyEvent,\n Participant,\n Position,\n RoomJoinedData,\n} from \"../types\";\n\nexport interface RoomState {\n room: {id: string; participants: Map<string, Participant>} | null;\n localParticipant: Participant | null;\n}\n\nexport interface RoomContext {\n socket: Socket;\n bus: EventBus;\n mediasoupManager: MediasoupManagerHandle;\n state: RoomState;\n emitEvent(event: OdysseyEvent, ...args: any[]): void;\n}\n\nexport function createRoomActions(ctx: RoomContext) {\n const {socket, mediasoupManager, state, emitEvent} = ctx;\n\n async function joinRoom(data: {\n roomId: string;\n userId: string;\n deviceId: string;\n participantId?: string;\n position: Position;\n direction: Direction;\n bodyHeight?: string;\n bodyShape?: string;\n userName?: string;\n userEmail?: string;\n }): Promise<Participant> {\n // Wait for socket connection before joining — fail fast if auth is rejected\n if (!socket.connected) {\n await new Promise<void>((resolve, reject) => {\n const CONNECT_TIMEOUT_MS = 10_000;\n const timer = setTimeout(() => {\n socket.off(\"connect\", onConnect);\n socket.off(\"connect_error\", onError);\n reject(\n new Error(\n \"[OdysseySDK] Connection timed out. Verify the server is reachable and your apiKey/userToken are valid.\"\n )\n );\n }, CONNECT_TIMEOUT_MS);\n\n const onConnect = () => {\n clearTimeout(timer);\n socket.off(\"connect_error\", onError);\n resolve();\n };\n\n const onError = (err: Error) => {\n clearTimeout(timer);\n socket.off(\"connect\", onConnect);\n reject(new Error(`[OdysseySDK] Connection failed: ${err.message}`));\n };\n\n socket.once(\"connect\", onConnect);\n socket.once(\"connect_error\", onError);\n });\n }\n\n return new Promise((resolve, reject) => {\n const handleRoomJoined = async (roomData: RoomJoinedData) => {\n try {\n socket.off(\"room-joined\", handleRoomJoined);\n\n await mediasoupManager.loadDevice(roomData.routerRtpCapabilities);\n await mediasoupManager.createSendTransport(roomData.participantId);\n await mediasoupManager.createRecvTransport(roomData.participantId);\n mediasoupManager.sendDeviceRtpCapabilities(roomData.participantId);\n\n const localParticipantData = roomData.participants.find(\n (p) => p.participantId === roomData.participantId\n );\n if (!localParticipantData) {\n throw new Error(\"Could not find local participant in room data\");\n }\n\n state.localParticipant = {\n ...localParticipantData,\n isLocal: true,\n producers: new Map(),\n consumers: new Map(),\n currentChannel: \"spatial\",\n } as Participant;\n\n state.room = {id: roomData.roomId, participants: new Map()};\n\n for (const pData of roomData.participants) {\n const participant: Participant = {\n ...pData,\n isLocal:\n pData.participantId === state.localParticipant.participantId,\n producers: new Map(),\n consumers: new Map(),\n };\n state.room.participants.set(pData.participantId, participant);\n }\n\n emitEvent(\"room-joined\", roomData);\n resolve(state.localParticipant);\n } catch (error) {\n socket.off(\"room-joined\", handleRoomJoined);\n reject(error);\n }\n };\n\n socket.on(\"room-joined\", handleRoomJoined);\n socket.emit(\"join-room\", data);\n });\n }\n\n function leaveRoom(): void {\n if (!socket.connected) return;\n socket.emit(\"leave-room\");\n mediasoupManager.close();\n socket.disconnect();\n state.room = null;\n state.localParticipant = null;\n ctx.bus.removeAllListeners();\n }\n\n function updatePosition(\n position: Position,\n direction: Direction,\n spatialData?: {\n cameraDistance?: number;\n screenPos?: {x: number; y: number} | null;\n rot?: {x: number; y: number; z: number};\n pan?: number;\n dxLocal?: number;\n }\n ): void {\n if (state.localParticipant && state.room) {\n state.localParticipant.position = position;\n state.localParticipant.direction = direction;\n socket.emit(\"update-position\", {\n participantId: state.localParticipant.participantId,\n conferenceId: state.room.id,\n roomId: state.room.id,\n position,\n direction,\n rot: spatialData?.rot,\n cameraDistance: spatialData?.cameraDistance,\n screenPos: spatialData?.screenPos,\n pan: spatialData?.pan,\n dxLocal: spatialData?.dxLocal,\n });\n }\n }\n\n function updateMediaState(mediaState: MediaState): void {\n if (state.localParticipant && state.room) {\n state.localParticipant.mediaState = mediaState;\n socket.emit(\"update-media-state\", {\n participantId: state.localParticipant.participantId,\n conferenceId: state.room.id,\n roomId: state.room.id,\n mediaState,\n });\n }\n }\n\n return {joinRoom, leaveRoom, updatePosition, updateMediaState};\n}\n","import {Socket} from \"socket.io-client\";\nimport {MediasoupManagerHandle} from \"../core/MediasoupManager\";\nimport {RoomState} from \"../core/room\";\n\nexport interface TrackContext {\n socket: Socket;\n state: RoomState;\n mediasoupManager: MediasoupManagerHandle;\n updateMediaState(mediaState: any): void;\n}\n\nexport function createTrackActions(ctx: TrackContext) {\n const {socket, state, mediasoupManager, updateMediaState} = ctx;\n\n async function produceTrack(\n track: MediaStreamTrack,\n appData?: {isScreenshare?: boolean}\n ): Promise<any> {\n const producer = await mediasoupManager.produce(track, appData);\n\n if (state.localParticipant) {\n state.localParticipant.producers.set(producer.id, producer);\n if (track.kind === \"audio\") {\n state.localParticipant.audioTrack = track;\n state.localParticipant.mediaState.audio = true;\n } else if (track.kind === \"video\") {\n if (appData?.isScreenshare) {\n (state.localParticipant as any).screenshareTrack = track;\n state.localParticipant.mediaState.sharescreen = true;\n } else {\n state.localParticipant.videoTrack = track;\n state.localParticipant.mediaState.video = true;\n }\n }\n updateMediaState(state.localParticipant.mediaState);\n }\n return producer;\n }\n\n async function recreateProducers(): Promise<void> {\n if (!state.localParticipant) return;\n\n state.localParticipant.producers.clear();\n const tracksToReproduce: Array<{track: MediaStreamTrack; appData?: any}> =\n [];\n\n if (\n state.localParticipant.audioTrack &&\n state.localParticipant.audioTrack.readyState === \"live\"\n ) {\n tracksToReproduce.push({track: state.localParticipant.audioTrack});\n }\n if (\n state.localParticipant.videoTrack &&\n state.localParticipant.videoTrack.readyState === \"live\"\n ) {\n tracksToReproduce.push({track: state.localParticipant.videoTrack});\n }\n const screenshareTrack = (state.localParticipant as any).screenshareTrack;\n if (screenshareTrack && screenshareTrack.readyState === \"live\") {\n tracksToReproduce.push({\n track: screenshareTrack,\n appData: {isScreenshare: true},\n });\n }\n\n for (const {track, appData} of tracksToReproduce) {\n try {\n await produceTrack(track, appData);\n } catch (error) {\n // Failed to recreate producer - track may need manual restart\n }\n }\n }\n\n async function stopScreenShare(): Promise<void> {\n if (!state.localParticipant || !state.room) return;\n\n const screenshareTrack = (state.localParticipant as any).screenshareTrack;\n if (screenshareTrack) {\n screenshareTrack.stop();\n (state.localParticipant as any).screenshareTrack = null;\n }\n\n for (const [producerId, producer] of state.localParticipant.producers) {\n if ((producer as any).appData?.isScreenshare) {\n producer.close();\n state.localParticipant.producers.delete(producerId);\n break;\n }\n }\n\n return new Promise((resolve) => {\n socket.emit(\n \"stop-screenshare\",\n {participantId: state.localParticipant!.participantId},\n () => {\n state.localParticipant!.mediaState.sharescreen = false;\n resolve();\n }\n );\n });\n }\n\n async function stopVideoProducer(): Promise<void> {\n if (!state.localParticipant || !state.room) return;\n\n const videoTrack = state.localParticipant.videoTrack;\n if (videoTrack) {\n videoTrack.stop();\n state.localParticipant.videoTrack = undefined;\n }\n\n for (const [producerId, producer] of state.localParticipant.producers) {\n if (\n producer.kind === \"video\" &&\n !(producer as any).appData?.isScreenshare\n ) {\n producer.close();\n state.localParticipant.producers.delete(producerId);\n break;\n }\n }\n\n return new Promise((resolve) => {\n socket.emit(\n \"stop-video\",\n {participantId: state.localParticipant!.participantId},\n () => {\n state.localParticipant!.mediaState.video = false;\n resolve();\n }\n );\n });\n }\n\n return {produceTrack, recreateProducers, stopScreenShare, stopVideoProducer};\n}\n","import {Socket} from \"socket.io-client\";\nimport {MediasoupManagerHandle} from \"../core/MediasoupManager\";\nimport {SpatialAudioManagerHandle} from \"../channels/spatial/SpatialAudioChannel\";\nimport {RoomState} from \"../core/room\";\nimport {\n Direction,\n MediaState,\n OdysseyEvent,\n Participant,\n ParticipantsSnapshotEvent,\n Position,\n} from \"../types\";\nimport {debugLog} from \"../utils/debug\";\n\nexport interface ListenerContext {\n socket: Socket;\n state: RoomState;\n mediasoupManager: MediasoupManagerHandle;\n spatialAudioManager: SpatialAudioManagerHandle;\n emitEvent(event: OdysseyEvent, ...args: any[]): void;\n}\n\nexport function registerSocketListeners(ctx: ListenerContext): void {\n const {socket, state, mediasoupManager, spatialAudioManager, emitEvent} = ctx;\n\n // ── Participants snapshot ─────────────────────────────────────────────────\n socket.on(\"all-participants-update\", (payload: ParticipantsSnapshotEvent) => {\n if (!state.room) {\n state.room = {id: payload.roomId, participants: new Map()};\n }\n\n const activeParticipantIds = new Set<string>();\n\n for (const snapshot of payload.participants) {\n activeParticipantIds.add(snapshot.participantId);\n\n let participant = state.room?.participants.get(snapshot.participantId);\n\n const normalizedPosition = {\n x: snapshot.position?.x ?? 0,\n y: snapshot.position?.y ?? 0,\n z: snapshot.position?.z ?? 0,\n };\n const normalizedDirection = {\n x: snapshot.direction?.x ?? 0,\n y: snapshot.direction?.y ?? 0,\n z: snapshot.direction?.z ?? 1,\n };\n const normalizedMediaState: MediaState = {\n audio: snapshot.mediaState?.audio ?? false,\n video: snapshot.mediaState?.video ?? false,\n sharescreen: snapshot.mediaState?.sharescreen ?? false,\n };\n\n if (!participant) {\n participant = {\n participantId: snapshot.participantId,\n userId: snapshot.userId,\n deviceId: snapshot.deviceId,\n isLocal:\n state.localParticipant?.participantId === snapshot.participantId,\n audioTrack: undefined,\n videoTrack: undefined,\n producers: new Map(),\n consumers: new Map(),\n position: normalizedPosition,\n direction: normalizedDirection,\n mediaState: normalizedMediaState,\n } as Participant;\n } else {\n participant.userId = snapshot.userId;\n participant.deviceId = snapshot.deviceId;\n participant.position = normalizedPosition;\n participant.direction = normalizedDirection;\n participant.mediaState = normalizedMediaState;\n }\n\n participant.bodyHeight = snapshot.bodyHeight;\n participant.bodyShape = snapshot.bodyShape;\n participant.userName = snapshot.userName;\n participant.userEmail = snapshot.userEmail;\n participant.isLocal =\n state.localParticipant?.participantId === snapshot.participantId;\n\n // CRITICAL: Store channel data for huddle detection\n (participant as any).currentChannel =\n (snapshot as any).currentChannel || \"spatial\";\n\n state.room?.participants.set(snapshot.participantId, participant);\n\n if (participant.isLocal) {\n state.localParticipant = participant;\n }\n }\n\n if (state.room) {\n for (const existingId of Array.from(state.room.participants.keys())) {\n if (!activeParticipantIds.has(existingId)) {\n state.room.participants.delete(existingId);\n }\n }\n }\n\n const normalizedParticipants = state.room\n ? Array.from(state.room.participants.values())\n : [];\n\n emitEvent(\"all-participants-update\", normalizedParticipants);\n });\n\n // ── New participant joined ────────────────────────────────────────────────\n socket.on(\"new-participant\", (participantData: any) => {\n if (state.room) {\n const newParticipant: Participant = {\n participantId: participantData.participantId,\n userId: participantData.userId,\n deviceId: participantData.deviceId,\n position: participantData.position,\n direction: participantData.direction,\n mediaState: participantData.mediaState,\n isLocal: false,\n producers: new Map(),\n consumers: new Map(),\n bodyHeight: participantData.bodyHeight,\n bodyShape: participantData.bodyShape,\n userName: participantData.userName,\n userEmail: participantData.userEmail,\n };\n // Include currentChannel from server if provided\n (newParticipant as any).currentChannel =\n participantData.currentChannel || \"spatial\";\n state.room.participants.set(\n participantData.participantId,\n newParticipant\n );\n emitEvent(\"new-participant\", newParticipant);\n }\n });\n\n // ── Participant left ──────────────────────────────────────────────────────\n socket.on(\"participant-left\", (data: {participantId: string}) => {\n if (state.room) {\n state.room.participants.delete(data.participantId);\n spatialAudioManager.removeParticipant(data.participantId);\n emitEvent(\"participant-left\", data.participantId);\n }\n });\n\n // ── Consumer created (incoming media track) ───────────────────────────────\n socket.on(\n \"consumer-created\",\n async (data: {\n consumerId: string;\n producerId: string;\n kind: \"audio\" | \"video\";\n rtpParameters: any;\n participantId: string;\n conferenceId: string;\n roomId: string;\n position: Position;\n direction: Direction;\n mediaState: MediaState;\n timestamp: number;\n bodyHeight?: string;\n bodyShape?: string;\n userName?: string;\n userEmail?: string;\n currentChannel?: string;\n }) => {\n debugLog(\"CONSUMER\", `Full data for ${data.userName}`, {\n participantId: data.participantId,\n position: data.position,\n channel: data.currentChannel,\n mediaState: data.mediaState,\n });\n\n let consumer: any;\n let track: MediaStreamTrack;\n try {\n const result = await mediasoupManager.consume(data);\n consumer = result.consumer;\n track = result.track;\n } catch (err: any) {\n console.warn(\n `[SDK] consume() skipped for ${data.participantId?.substring(0, 8)} — transport not ready (${err?.message}).`\n );\n return;\n }\n\n let participant = state.room?.participants.get(data.participantId);\n\n if (!participant && state.room) {\n participant = {\n participantId: data.participantId,\n userId: data.participantId.split(\":\")[0] || data.participantId,\n deviceId: data.participantId.split(\":\")[1] || data.participantId,\n isLocal: false,\n position: data.position,\n direction: data.direction,\n mediaState: data.mediaState,\n producers: new Map(),\n consumers: new Map(),\n bodyHeight: data.bodyHeight,\n bodyShape: data.bodyShape,\n userName: data.userName,\n userEmail: data.userEmail,\n };\n (participant as any).currentChannel = data.currentChannel || \"spatial\";\n state.room.participants.set(data.participantId, participant);\n }\n\n if (participant) {\n participant.position = data.position;\n participant.direction = data.direction;\n participant.mediaState = data.mediaState;\n (participant as any).currentChannel =\n data.currentChannel ||\n (participant as any).currentChannel ||\n \"spatial\";\n\n if (data.bodyHeight !== undefined)\n participant.bodyHeight = data.bodyHeight;\n if (data.bodyShape !== undefined)\n participant.bodyShape = data.bodyShape;\n if (data.userName !== undefined) participant.userName = data.userName;\n if (data.userEmail !== undefined)\n participant.userEmail = data.userEmail;\n\n participant.consumers.set(consumer.id, consumer);\n\n if (track.kind === \"audio\") {\n participant.audioTrack = track;\n\n const isLocalParticipant =\n participant.participantId === state.localParticipant?.participantId;\n\n if (isLocalParticipant) {\n return; // Never connect own audio — prevents loopback\n }\n\n const participantChannel =\n (participant as any).currentChannel || \"spatial\";\n const isInHuddle = participantChannel !== \"spatial\";\n\n await spatialAudioManager.setupSpatialAudioForParticipant(\n participant.participantId,\n track,\n isInHuddle\n );\n\n mediasoupManager\n .resumeConsumer(consumer.id)\n .then(() => {})\n .catch((err) => {\n console.error(`[SDK] Failed to resume consumer:`, err);\n });\n } else if (track.kind === \"video\") {\n const isScreenshare = (data as any).appData?.isScreenshare;\n\n if (isScreenshare) {\n (participant as any).screenshareTrack = track;\n } else {\n participant.videoTrack = track;\n }\n\n const resumeWithRetry = async (retries = 3) => {\n for (let i = 0; i < retries; i++) {\n try {\n await mediasoupManager.resumeConsumer(consumer.id);\n return;\n } catch (err) {\n if (i < retries - 1) {\n await new Promise((resolve) => setTimeout(resolve, 200));\n } else {\n console.error(\n `[SDK] Failed to resume video consumer after ${retries} attempts:`,\n err\n );\n }\n }\n }\n };\n resumeWithRetry();\n }\n\n emitEvent(\"consumer-created\", {\n participant,\n track,\n consumer,\n isScreenshare: (data as any).appData?.isScreenshare,\n appData: (data as any).appData,\n });\n }\n }\n );\n\n // ── Position updated ──────────────────────────────────────────────────────\n socket.on(\n \"participant-position-updated\",\n (data: {\n participantId: string;\n conferenceId: string;\n roomId: string;\n position: Position;\n direction: Direction;\n mediaState: MediaState;\n consumerIds: string[];\n timestamp: number;\n bodyHeight?: string;\n bodyShape?: string;\n userName?: string;\n userEmail?: string;\n currentChannel?: string;\n rot?: {x: number; y: number; z: number};\n pan?: number;\n dxLocal?: number;\n }) => {\n const participant = state.room?.participants.get(data.participantId);\n if (participant) {\n debugLog(\n \"POSITION\",\n `${data.userName || data.participantId.slice(0, 8)}`,\n {\n pos: {\n x: data.position?.x?.toFixed(1),\n y: data.position?.y?.toFixed(1),\n },\n channel: data.currentChannel,\n }\n );\n\n participant.position = data.position;\n participant.direction = data.direction;\n participant.mediaState = data.mediaState;\n if (data.bodyHeight !== undefined)\n participant.bodyHeight = data.bodyHeight;\n if (data.bodyShape !== undefined)\n participant.bodyShape = data.bodyShape;\n if (data.userName !== undefined) participant.userName = data.userName;\n if (data.userEmail !== undefined)\n participant.userEmail = data.userEmail;\n if (data.currentChannel !== undefined)\n participant.currentChannel = data.currentChannel;\n if (data.pan !== undefined) (participant as any).pan = data.pan;\n if (data.dxLocal !== undefined)\n (participant as any).dxLocal = data.dxLocal;\n if (data.rot !== undefined) (participant as any).rot = data.rot;\n\n const participantChannel = (participant as any).currentChannel;\n const isInHuddle = participantChannel !== \"spatial\";\n\n if (!isInHuddle) {\n spatialAudioManager.updateSpatialAudio(\n data.participantId,\n data.position,\n (data as any).rot || data.direction\n );\n }\n\n emitEvent(\"participant-position-updated\", participant);\n }\n }\n );\n\n // ── Media state updated ───────────────────────────────────────────────────\n socket.on(\n \"participant-media-state-updated\",\n (data: {\n participantId: string;\n conferenceId: string;\n roomId: string;\n mediaState: MediaState;\n position: Position;\n direction: Direction;\n timestamp: number;\n }) => {\n const participant = state.room?.participants.get(data.participantId);\n if (participant) {\n participant.mediaState = data.mediaState;\n participant.position = data.position;\n participant.direction = data.direction;\n emitEvent(\"participant-media-state-updated\", participant);\n }\n }\n );\n\n // ── Connection events ─────────────────────────────────────────────────────\n socket.on(\"error\", (error: any) => {\n emitEvent(\"error\", error);\n });\n\n socket.on(\"disconnect\", () => {\n emitEvent(\"disconnected\");\n });\n\n // ── Huddle events ─────────────────────────────────────────────────────────\n socket.on(\"huddle-invite-received\", (data) => {\n emitEvent(\"huddle-invite-received\", data);\n });\n\n socket.on(\"private-huddle-started\", (data) => {\n if (state.localParticipant) {\n state.localParticipant.currentChannel = data.channelId;\n }\n emitEvent(\"private-huddle-started\", data);\n });\n\n socket.on(\"huddle-updated\", (data) => {\n emitEvent(\"huddle-updated\", data);\n });\n\n socket.on(\"huddle-invite-rejected\", (data) => {\n emitEvent(\"huddle-invite-rejected\", data);\n });\n\n socket.on(\"huddle-ended\", (data) => {\n if (state.localParticipant) {\n state.localParticipant.currentChannel = \"spatial\";\n }\n emitEvent(\"huddle-ended\", data);\n });\n\n socket.on(\"participant-channel-changed\", (data) => {\n const participant = state.room?.participants.get(data.participantId);\n if (participant) {\n participant.currentChannel = data.channelId;\n\n const isInSpatialChannel = data.channelId === \"spatial\";\n if (participant.audioTrack) {\n spatialAudioManager.setParticipantSpatialization(\n data.participantId,\n isInSpatialChannel\n );\n }\n\n const myChannel = state.localParticipant?.currentChannel || \"spatial\";\n const theirChannel = data.channelId || \"spatial\";\n if (myChannel !== theirChannel) {\n (participant as any).screenshareTrack = null;\n }\n }\n if (state.localParticipant?.participantId === data.participantId) {\n state.localParticipant!.currentChannel = data.channelId;\n }\n emitEvent(\"participant-channel-changed\", data);\n });\n\n socket.on(\n \"consumer-closed\",\n (data: {\n consumerId: string;\n participantId: string;\n kind: string;\n isScreenshare?: boolean;\n }) => {\n emitEvent(\"consumer-closed\", data);\n }\n );\n\n socket.on(\"mute-requested\", (data) => {\n emitEvent(\"mute-requested\", data);\n });\n\n // ── Space live broadcast events ───────────────────────────────────────────\n socket.on(\n \"space-live-broadcast-available\",\n (data: {\n roomId: string;\n producerId: string;\n producerUserId: string;\n userName: string;\n }) => {\n debugLog(\"SPACE-LIVE-BROADCAST\", \"Broadcast available\", data);\n emitEvent(\"space-live-broadcast-available\", data);\n }\n );\n\n socket.on(\"space-live-broadcast-stopped\", (data: {roomId: string}) => {\n debugLog(\"SPACE-LIVE-BROADCAST\", \"Broadcast stopped\", data);\n emitEvent(\"space-live-broadcast-stopped\", data);\n });\n}\n","import {StreamChat, Channel, Event as StreamEvent} from \"stream-chat\";\nimport {debugLog} from \"../utils/debug\";\n\nexport interface ChatMessage {\n text?: string;\n notification?: any;\n [key: string]: any;\n}\n\nexport interface ChatOptions {\n serverUrl: string;\n}\n\nexport interface ChatHandle {\n init(data: {\n userId: string;\n userName?: string;\n channelId: string;\n channelName?: string;\n }): Promise<void>;\n sendMessage(message: ChatMessage): Promise<any>;\n sendNotification(data: {\n text: string;\n participants: string[];\n sender: {deviceId: string; name?: string; img?: string};\n }): Promise<any>;\n leave(): Promise<void>;\n getChannel(): Channel | null;\n}\n\nexport function createChatManager(options: ChatOptions): ChatHandle {\n const {serverUrl} = options;\n let client: StreamChat | null = null;\n let activeChannel: Channel | null = null;\n let onMessageCallback: ((message: any) => void) | null = null;\n\n function setOnMessage(cb: (message: any) => void) {\n onMessageCallback = cb;\n }\n\n function handleNewMessage(event: StreamEvent) {\n const message = event.message;\n if (message && onMessageCallback) {\n onMessageCallback(message);\n }\n }\n\n async function fetchStreamKey(userId: string): Promise<string> {\n const response = await fetch(\n `${serverUrl}/api/chat/stream-key?userId=${userId}`,\n {\n method: \"GET\",\n headers: {\"Content-Type\": \"application/json\"},\n }\n );\n if (!response.ok) {\n throw new Error(`Failed to get stream key: HTTP ${response.status}`);\n }\n const data = await response.json();\n if (!data.success || !data.consumerKey) {\n throw new Error(\"Stream key not available\");\n }\n return data.consumerKey;\n }\n\n async function fetchStreamToken(userId: string): Promise<string> {\n const response = await fetch(`${serverUrl}/api/chat/stream-token`, {\n method: \"POST\",\n headers: {\"Content-Type\": \"application/json\"},\n body: JSON.stringify({userId}),\n });\n if (!response.ok) {\n throw new Error(`Failed to get stream token: HTTP ${response.status}`);\n }\n const data = await response.json();\n if (!data.success || !data.token) {\n throw new Error(\"Stream token not available\");\n }\n return data.token;\n }\n\n async function init(data: {\n userId: string;\n userName?: string;\n channelId: string;\n channelName?: string;\n }): Promise<void> {\n const {userId, userName, channelId, channelName} = data;\n const key = await fetchStreamKey(userId);\n client = StreamChat.getInstance(key);\n\n const token = await fetchStreamToken(userId);\n\n debugLog(\"Chat\", `Connecting user ${userId}...`);\n const user = await client.connectUser(\n {id: userId, name: userName || userId},\n token\n );\n if (!user) throw new Error(\"Could not connect chat user\");\n debugLog(\"Chat\", \"Connected successfully\");\n\n const channel = client.channel(\"livestream\", channelId, {\n name: channelName || channelId,\n });\n await channel.watch();\n channel.on(\"message.new\", handleNewMessage);\n activeChannel = channel;\n }\n\n async function sendMessage(message: ChatMessage): Promise<any> {\n if (!activeChannel) throw new Error(\"Chat not initialized\");\n return activeChannel.sendMessage(message);\n }\n\n async function sendNotification(data: {\n text: string;\n participants: string[];\n sender: {deviceId: string; name?: string; img?: string};\n }): Promise<any> {\n return sendMessage({\n notification: {\n isNotification: true,\n text: data.text,\n participants: data.participants,\n sender: data.sender,\n },\n });\n }\n\n async function leave(): Promise<void> {\n if (activeChannel) {\n activeChannel.off(\"message.new\", handleNewMessage);\n await activeChannel.stopWatching();\n }\n if (client) {\n await client.disconnectUser();\n }\n activeChannel = null;\n client = null;\n }\n\n function getChannel(): Channel | null {\n return activeChannel;\n }\n\n return {\n init,\n sendMessage,\n sendNotification,\n leave,\n getChannel,\n // Expose for SDK event wiring\n set onMessage(cb: (message: any) => void) {\n onMessageCallback = cb;\n },\n } as ChatHandle & {onMessage: (message: any) => void};\n}\n","import {io, Socket} from \"socket.io-client\";\nimport {createEventBus, EventBus} from \"./core/EventManager\";\nimport {\n createMediasoupManager,\n MediasoupManagerHandle,\n} from \"./core/MediasoupManager\";\nimport {\n createSpatialAudioManager,\n SpatialAudioManagerHandle,\n SpatialAudioOptions,\n} from \"./channels/spatial/SpatialAudioChannel\";\nimport {\n createScreenShareLiveManager,\n ScreenShareLiveManagerHandle,\n} from \"./screen-share-live-in-space\";\nimport {\n SpaceLiveBroadcastAvailableEvent,\n SpaceLiveBroadcastStatusResponse,\n SpaceLiveBroadcastStoppedEvent,\n SpaceLiveBroadcastResult,\n Direction,\n MediaState,\n OdysseyEvent,\n Participant,\n ParticipantsSnapshotEvent,\n Position,\n RoomJoinedData,\n} from \"./types\";\nimport {debugLog} from \"./utils/debug\";\nimport {createRoomActions, RoomState} from \"./core/room\";\nimport {createTrackActions} from \"./producers/tracks\";\nimport {registerSocketListeners} from \"./events/listeners\";\nimport {createChatManager, ChatHandle, ChatMessage} from \"./chat\";\n\n// Re-export space live broadcast types for consumers\nexport type {\n SpaceLiveBroadcastAvailableEvent,\n SpaceLiveBroadcastStatusResponse,\n SpaceLiveBroadcastStoppedEvent,\n SpaceLiveBroadcastResult,\n};\n\n// ─── Public handle interface ─────────────────────────────────────────────────────────\n\nexport interface OdysseySpatialCommsHandle {\n room: {id: string; participants: Map<string, Participant>} | null;\n on(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n off(event: OdysseyEvent, listener: (...args: any[]) => void): void;\n initializeMLNoiseSuppression(\n modelPath: string,\n workletUrl?: string\n ): Promise<void>;\n joinRoom(data: {\n roomId: string;\n userId: string;\n deviceId: string;\n participantId?: string;\n position: Position;\n direction: Direction;\n bodyHeight?: string;\n bodyShape?: string;\n userName?: string;\n userEmail?: string;\n }): Promise<Participant>;\n leaveRoom(): void;\n resumeAudio(): Promise<void>;\n getAudioContextState(): AudioContextState;\n enhanceOutgoingAudioTrack(track: MediaStreamTrack): Promise<MediaStreamTrack>;\n isMLNoiseSuppressionActive(): boolean;\n getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\";\n setMasterMuted(muted: boolean): void;\n getMasterMuted(): boolean;\n produceTrack(\n track: MediaStreamTrack,\n appData?: {isScreenshare?: boolean}\n ): Promise<any>;\n recreateProducers(): Promise<void>;\n updatePosition(\n position: Position,\n direction: Direction,\n spatialData?: {\n cameraDistance?: number;\n screenPos?: {x: number; y: number} | null;\n rot?: {x: number; y: number; z: number};\n pan?: number;\n dxLocal?: number;\n }\n ): void;\n updateMediaState(mediaState: MediaState): void;\n stopScreenShare(): Promise<void>;\n stopVideoProducer(): Promise<void>;\n startSpaceLiveBroadcast(): Promise<SpaceLiveBroadcastResult>;\n stopSpaceLiveBroadcast(): Promise<void>;\n getSpaceLiveBroadcastStatus(\n callback: (info: {\n isActive: boolean;\n producerId?: string;\n producerUserId?: string;\n userName?: string;\n }) => void\n ): void;\n readonly isSpaceLiveBroadcasting: boolean;\n setListenerPosition(\n position: Position,\n orientation: {\n forwardX: number;\n forwardY: number;\n forwardZ: number;\n upX: number;\n upY: number;\n upZ: number;\n }\n ): void;\n setListenerFromLSD(\n listenerPos: Position,\n cameraPos: Position,\n lookAtPos: Position,\n rot?: {x: number; y: number; z: number}\n ): void;\n chat: {\n init(data: {\n userId: string;\n userName?: string;\n channelId: string;\n channelName?: string;\n }): Promise<void>;\n sendMessage(message: ChatMessage): Promise<any>;\n sendNotification(data: {\n text: string;\n participants: string[];\n sender: {deviceId: string; name?: string; img?: string};\n }): Promise<any>;\n leave(): Promise<void>;\n onMessage(callback: (message: any) => void): void;\n };\n sendHuddleInvite(toParticipantId: string): Promise<{\n success?: boolean;\n inviteId?: string;\n huddleId?: string;\n error?: string;\n }>;\n acceptHuddleInvite(inviteId: string): Promise<{\n success?: boolean;\n huddleId?: string;\n participants?: string[];\n error?: string;\n }>;\n rejectHuddleInvite(\n inviteId: string\n ): Promise<{success?: boolean; error?: string}>;\n joinHuddle(): Promise<{\n success?: boolean;\n channelId?: string;\n error?: string;\n }>;\n leaveHuddle(): Promise<{\n success?: boolean;\n channelId?: string;\n error?: string;\n }>;\n getParticipantChannel(participantId: string): Promise<string>;\n muteParticipant(\n participantId: string\n ): Promise<{success?: boolean; error?: string}>;\n getCurrentChannel(): string;\n}\n\n// ─── Server URL (baked in at build time via ODYSSEY_SERVER_URL env var) ────────\ndeclare const process: {env: {ODYSSEY_SERVER_URL: string}};\nconst ODYSSEY_SERVER_URL: string = process.env.ODYSSEY_SERVER_URL;\n\n// ─── Factory function ─────────────────────────────────────────────────────────\n\n/**\n * Create an Odyssey Spatial Comms instance (browser-only SDK).\n * @param apiKey SDK API key issued by Odyssey (from payment service)\n * @param userToken JWT access token for the authenticated user (from SSO)\n * @param spatialOptions Optional spatial audio configuration\n */\nexport function createOdysseySpatialComms(\n apiKey: string,\n userToken: string,\n spatialOptions?: SpatialAudioOptions\n): OdysseySpatialCommsHandle {\n console.log(\n `[OdysseySDK] 🔗 Server URL: ${ODYSSEY_SERVER_URL || \"(empty — URL not baked in!)\"}`\n );\n if (!ODYSSEY_SERVER_URL) {\n throw new Error(\n \"[OdysseySDK] Server URL not configured. This SDK build is missing ODYSSEY_SERVER_URL.\"\n );\n }\n if (!apiKey || typeof apiKey !== \"string\" || !apiKey.trim()) {\n throw new Error(\"[OdysseySDK] A valid apiKey is required.\");\n }\n // if (!userToken || typeof userToken !== \"string\" || !userToken.trim()) {\n // throw new Error(\"[OdysseySDK] A valid userToken is required.\");\n // }\n // ── Closure state ────────────────────────────────────────────────────────\n const bus = createEventBus();\n // Pass apiKey + userToken in handshake.auth — validated on every connect/reconnect.\n const socket: Socket = io(ODYSSEY_SERVER_URL, {\n transports: [\"websocket\"],\n auth: {apiKey, token: userToken},\n });\n\n let sessionStart: number | null = null;\n\n socket.on(\"connect\", () => {\n sessionStart = Date.now();\n debugLog(\"Connection\", `✅ Connected to server socketId=${socket.id}`);\n });\n socket.on(\"connect_error\", (err) =>\n debugLog(\"Connection\", `❌ Connection error: ${err.message}`)\n );\n socket.on(\"disconnect\", (reason) => {\n if (sessionStart !== null) {\n const secs = Math.floor((Date.now() - sessionStart) / 1000);\n const mins = Math.floor(secs / 60);\n const remainSecs = secs % 60;\n const duration = mins > 0 ? `${mins}m ${remainSecs}s` : `${remainSecs}s`;\n console.log(\n `[OdysseySDK] 📊 Session ended — duration: ${duration} (${secs}s raw)`\n );\n sessionStart = null;\n }\n debugLog(\"Connection\", `🔌 Disconnected reason=${reason}`);\n });\n const mediasoupManager = createMediasoupManager(socket);\n const spatialAudioManager = createSpatialAudioManager(spatialOptions);\n const screenShareLiveManager = createScreenShareLiveManager(socket);\n\n // Shared mutable state — passed by reference to all sub-modules\n const state: RoomState = {room: null, localParticipant: null};\n\n function emitEvent(event: OdysseyEvent, ...args: any[]): void {\n bus.emit(event, ...args);\n }\n\n bus.emit(\"connected\" as OdysseyEvent);\n\n // ── Wire logic modules ─────────────────────────────────────────────────\n const chatManager = createChatManager({\n serverUrl: ODYSSEY_SERVER_URL,\n });\n\n const {\n joinRoom: _joinRoom,\n leaveRoom: _leaveRoom,\n updatePosition,\n updateMediaState,\n } = createRoomActions({socket, bus, mediasoupManager, state, emitEvent});\n\n const {produceTrack, recreateProducers, stopScreenShare, stopVideoProducer} =\n createTrackActions({socket, state, mediasoupManager, updateMediaState});\n\n registerSocketListeners({\n socket,\n state,\n mediasoupManager,\n spatialAudioManager,\n emitEvent,\n });\n\n // ── Chat-aware room wrappers ─────────────────────────────────────────────\n\n async function joinRoom(data: Parameters<typeof _joinRoom>[0]) {\n return _joinRoom(data);\n }\n\n function leaveRoom() {\n chatManager.leave().catch(() => {});\n _leaveRoom();\n }\n\n // ── Public methods ───────────────────────────────────────────────────────\n\n async function initializeMLNoiseSuppression(\n modelPath: string,\n workletUrl?: string\n ): Promise<void> {\n try {\n await spatialAudioManager.initializeMLNoiseSuppression(\n modelPath,\n workletUrl\n );\n } catch (error) {\n // Graceful degradation - AudioWorklet will be used as fallback\n }\n }\n\n async function resumeAudio(): Promise<void> {\n await spatialAudioManager.resumeAudioContext();\n }\n\n function getAudioContextState(): AudioContextState {\n return spatialAudioManager.getAudioContextState();\n }\n\n async function enhanceOutgoingAudioTrack(\n track: MediaStreamTrack\n ): Promise<MediaStreamTrack> {\n return spatialAudioManager.enhanceOutgoingAudioTrack(track);\n }\n\n function isMLNoiseSuppressionActive(): boolean {\n return spatialAudioManager.getNoiseSuppressionMode() === \"ml\";\n }\n\n function getNoiseSuppressionMode(): \"ml\" | \"audioworklet\" | \"none\" {\n return spatialAudioManager.getNoiseSuppressionMode();\n }\n\n function setMasterMuted(muted: boolean): void {\n spatialAudioManager.setMasterMuted(muted);\n }\n\n function getMasterMuted(): boolean {\n return spatialAudioManager.getMasterMuted();\n }\n\n async function startSpaceLiveBroadcast(): Promise<SpaceLiveBroadcastResult> {\n if (!state.localParticipant || !state.room) {\n throw new Error(\"Must be in a room to start space live broadcast\");\n }\n return screenShareLiveManager.startBroadcast(\n state.room,\n state.localParticipant,\n ODYSSEY_SERVER_URL\n );\n }\n\n async function stopSpaceLiveBroadcast(): Promise<void> {\n return screenShareLiveManager.stopBroadcast(\n state.room,\n state.localParticipant?.participantId\n );\n }\n\n function getSpaceLiveBroadcastStatus(\n callback: (info: {\n isActive: boolean;\n producerId?: string;\n producerUserId?: string;\n userName?: string;\n }) => void\n ): void {\n screenShareLiveManager.getStatus(state.room?.id || null, callback);\n }\n\n function setListenerPosition(\n position: Position,\n orientation: {\n forwardX: number;\n forwardY: number;\n forwardZ: number;\n upX: number;\n upY: number;\n upZ: number;\n }\n ): void {\n spatialAudioManager.setListenerPosition(position, orientation);\n }\n\n function setListenerFromLSD(\n listenerPos: Position,\n cameraPos: Position,\n lookAtPos: Position,\n rot?: {x: number; y: number; z: number}\n ): void {\n spatialAudioManager.setListenerFromLSD(\n listenerPos,\n cameraPos,\n lookAtPos,\n rot\n );\n }\n\n async function sendHuddleInvite(toParticipantId: string): Promise<{\n success?: boolean;\n inviteId?: string;\n huddleId?: string;\n error?: string;\n }> {\n if (!state.localParticipant || !state.room)\n return {success: false, error: \"Not in a room\"};\n return new Promise((resolve) => {\n socket.emit(\n \"send-huddle-invite\",\n {\n fromParticipantId: state.localParticipant!.participantId,\n toParticipantId,\n roomId: state.room!.id,\n },\n (response: {\n success?: boolean;\n inviteId?: string;\n huddleId?: string;\n error?: string;\n }) => resolve(response)\n );\n });\n }\n\n async function acceptHuddleInvite(inviteId: string): Promise<{\n success?: boolean;\n huddleId?: string;\n participants?: string[];\n error?: string;\n }> {\n if (!state.localParticipant)\n return {success: false, error: \"Not in a room\"};\n return new Promise((resolve) => {\n socket.emit(\n \"accept-huddle-invite\",\n {inviteId, participantId: state.localParticipant!.participantId},\n (response: {\n success?: boolean;\n huddleId?: string;\n participants?: string[];\n error?: string;\n }) => resolve(response)\n );\n });\n }\n\n async function rejectHuddleInvite(\n inviteId: string\n ): Promise<{success?: boolean; error?: string}> {\n if (!state.localParticipant)\n return {success: false, error: \"Not in a room\"};\n return new Promise((resolve) => {\n socket.emit(\n \"reject-huddle-invite\",\n {inviteId, participantId: state.localParticipant!.participantId},\n (response: {success?: boolean; error?: string}) => resolve(response)\n );\n });\n }\n\n async function joinHuddle(): Promise<{\n success?: boolean;\n channelId?: string;\n error?: string;\n }> {\n if (!state.localParticipant || !state.room)\n return {success: false, error: \"Not in a room\"};\n return new Promise((resolve) => {\n socket.emit(\n \"join-huddle\",\n {\n participantId: state.localParticipant!.participantId,\n roomId: state.room!.id,\n },\n (response: {success?: boolean; channelId?: string; error?: string}) => {\n if (response.success && state.localParticipant) {\n state.localParticipant!.currentChannel = response.channelId;\n }\n resolve(response);\n }\n );\n });\n }\n\n async function leaveHuddle(): Promise<{\n success?: boolean;\n channelId?: string;\n error?: string;\n }> {\n if (!state.localParticipant || !state.room)\n return {success: false, error: \"Not in a room\"};\n return new Promise((resolve) => {\n socket.emit(\n \"leave-huddle\",\n {\n participantId: state.localParticipant!.participantId,\n roomId: state.room!.id,\n },\n (response: {success?: boolean; channelId?: string; error?: string}) => {\n if (response.success && state.localParticipant) {\n state.localParticipant!.currentChannel = response.channelId;\n }\n resolve(response);\n }\n );\n });\n }\n\n async function getParticipantChannel(participantId: string): Promise<string> {\n return new Promise((resolve) => {\n socket.emit(\n \"get-participant-channel\",\n {participantId},\n (response: {success?: boolean; channelId?: string; error?: string}) => {\n resolve(response.channelId || \"spatial\");\n }\n );\n });\n }\n\n async function muteParticipant(\n participantId: string\n ): Promise<{success?: boolean; error?: string}> {\n if (!state.localParticipant || !state.room)\n return {success: false, error: \"Not in a room\"};\n return new Promise((resolve) => {\n socket.emit(\n \"mute-participant\",\n {\n targetParticipantId: participantId,\n roomId: state.room!.id,\n requesterId: state.localParticipant!.participantId,\n },\n (response: {success?: boolean; error?: string}) => resolve(response)\n );\n });\n }\n\n function getCurrentChannel(): string {\n return state.localParticipant?.currentChannel || \"spatial\";\n }\n\n // ── Return handle ─────────────────────────────────────────────────────────\n return {\n get room() {\n return state.room;\n },\n on: (event, listener) => {\n bus.on(event, listener);\n },\n off: (event, listener) => {\n bus.off(event, listener);\n },\n initializeMLNoiseSuppression,\n joinRoom,\n leaveRoom,\n resumeAudio,\n getAudioContextState,\n enhanceOutgoingAudioTrack,\n isMLNoiseSuppressionActive,\n getNoiseSuppressionMode,\n setMasterMuted,\n getMasterMuted,\n produceTrack,\n recreateProducers,\n updatePosition,\n updateMediaState,\n stopScreenShare,\n stopVideoProducer,\n startSpaceLiveBroadcast,\n stopSpaceLiveBroadcast,\n getSpaceLiveBroadcastStatus,\n get isSpaceLiveBroadcasting() {\n return screenShareLiveManager.isActive;\n },\n setListenerPosition,\n setListenerFromLSD,\n sendHuddleInvite,\n acceptHuddleInvite,\n rejectHuddleInvite,\n joinHuddle,\n leaveHuddle,\n getParticipantChannel,\n muteParticipant,\n getCurrentChannel,\n chat: {\n init: (data: {\n userId: string;\n userName?: string;\n channelId: string;\n channelName?: string;\n }) => chatManager.init(data),\n sendMessage: (message: ChatMessage) => chatManager.sendMessage(message),\n sendNotification: (data: {\n text: string;\n participants: string[];\n sender: {deviceId: string; name?: string; img?: string};\n }) => chatManager.sendNotification(data),\n leave: () => chatManager.leave(),\n onMessage: (callback: (message: any) => void) => {\n (chatManager as any).onMessage = callback;\n },\n },\n };\n}\n\nexport type {\n ChatMessage,\n Direction,\n MediaState,\n OdysseyEvent,\n Participant,\n Position,\n RoomJoinedData,\n SpatialAudioOptions,\n};\nexport type {OdysseyEvent as OdysseySDKEvent};\n\n// ─── Namespace singleton — the standard public API ───────────────────────────\n//\n// import SpatialCommsSDK from 'odyssey-spatial-comms';\n// const client = SpatialCommsSDK.create('https://your-server.com');\n// client.on('room-joined', handler);\n// await client.joinRoom({ ... });\n//\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SpatialCommsSDK = {\n /**\n * Create a new SDK client instance.\n * @param apiKey SDK API key issued by Odyssey (from payment service)\n * @param userToken JWT access token for the authenticated user (from SSO)\n * @param spatialOptions Optional spatial audio configuration\n */\n create(\n apiKey: string,\n userToken: string,\n spatialOptions?: SpatialAudioOptions\n ): OdysseySpatialCommsHandle {\n return createOdysseySpatialComms(apiKey, userToken, spatialOptions);\n },\n} as const;\n\nexport {SpatialCommsSDK};\n"]}
|