@tensamin/audio 0.1.2 → 0.1.4

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/dist/types.d.mts CHANGED
@@ -35,46 +35,154 @@ interface AudioProcessingConfig {
35
35
  vad?: {
36
36
  enabled: boolean;
37
37
  /**
38
- * Plugin name to use. Defaults to 'rnnoise-vad' or 'energy-vad'.
38
+ * Plugin name to use. Defaults to 'energy-vad'.
39
39
  */
40
40
  pluginName?: string;
41
41
  /**
42
42
  * Probability threshold for speech onset (0-1).
43
- * Default: 0.5
43
+ * When VAD probability rises above this, audio is unmuted.
44
+ * Lower = more sensitive (catches quiet speech, may include noise)
45
+ * Higher = less sensitive (only confident speech, may clip quiet parts)
46
+ * Default: 0.6 (optimized for voice-only)
44
47
  */
45
48
  startThreshold?: number;
46
49
  /**
47
50
  * Probability threshold for speech offset (0-1).
48
- * Default: 0.4
51
+ * When VAD probability drops below this (after hangover), audio is muted.
52
+ * Lower = keeps audio on longer (less aggressive gating)
53
+ * Higher = mutes faster (more aggressive noise suppression)
54
+ * Default: 0.45 (balanced voice detection)
49
55
  */
50
56
  stopThreshold?: number;
51
57
  /**
52
- * Time in ms to wait after speech stops before considering it silent.
53
- * Default: 300ms
58
+ * Time in ms to wait after speech stops before muting.
59
+ * Prevents rapid on/off toggling during pauses.
60
+ * Lower = more aggressive gating, may clip between words
61
+ * Higher = smoother but may let trailing noise through
62
+ * Default: 400ms (optimized for natural speech)
54
63
  */
55
64
  hangoverMs?: number;
56
65
  /**
57
- * Time in ms of audio to buffer before speech onset to avoid cutting the start.
58
- * Default: 200ms
66
+ * Time in ms of audio to buffer before speech onset.
67
+ * Prevents cutting off the beginning of speech.
68
+ * Default: 250ms (generous pre-roll for voice)
59
69
  */
60
70
  preRollMs?: number;
71
+ /**
72
+ * Minimum speech duration in ms to consider it valid speech.
73
+ * Filters out very brief noise spikes.
74
+ * Default: 100ms
75
+ */
76
+ minSpeechDurationMs?: number;
77
+ /**
78
+ * Minimum silence duration in ms before allowing another speech segment.
79
+ * Prevents false positives from quick noise bursts.
80
+ * Default: 150ms
81
+ */
82
+ minSilenceDurationMs?: number;
83
+ /**
84
+ * Advanced: Energy VAD specific parameters
85
+ */
86
+ energyVad?: {
87
+ /**
88
+ * Smoothing factor for energy calculation (0-1).
89
+ * Higher = more smoothing, slower to react
90
+ * Default: 0.95
91
+ */
92
+ smoothing?: number;
93
+ /**
94
+ * Initial noise floor estimate.
95
+ * Default: 0.001
96
+ */
97
+ initialNoiseFloor?: number;
98
+ /**
99
+ * Rate at which noise floor adapts to quiet signals (0-1).
100
+ * Default: 0.01
101
+ */
102
+ noiseFloorAdaptRateQuiet?: number;
103
+ /**
104
+ * Rate at which noise floor adapts to loud signals (0-1).
105
+ * Default: 0.001 (slower adaptation for speech)
106
+ */
107
+ noiseFloorAdaptRateLoud?: number;
108
+ /**
109
+ * Minimum SNR (Signal-to-Noise Ratio) for speech detection.
110
+ * Default: 2.0 (voice is 2x louder than noise floor)
111
+ */
112
+ minSNR?: number;
113
+ /**
114
+ * SNR range for probability scaling.
115
+ * Default: 8.0 (probability scales from minSNR to minSNR+snrRange)
116
+ */
117
+ snrRange?: number;
118
+ };
61
119
  };
62
120
  /**
63
121
  * Output gain and muting configuration.
64
122
  */
65
123
  output?: {
66
124
  /**
67
- * Gain to apply when speaking (0-1+). Default: 1.0
125
+ * Gain to apply when speaking (0-infinity).
126
+ * Values > 1.0 will amplify the voice.
127
+ * Default: 1.0 (unity gain)
68
128
  */
69
129
  speechGain?: number;
70
130
  /**
71
- * Gain to apply when silent (0-1). Default: 0.0 (mute)
131
+ * Gain to apply when silent (0-1).
132
+ * 0.0 = complete mute (recommended for voice-only)
133
+ * 0.1-0.3 = allow some background ambience
134
+ * Default: 0.0 (full mute for voice-only)
72
135
  */
73
136
  silenceGain?: number;
74
137
  /**
75
- * Time in seconds to ramp gain changes. Default: 0.02
138
+ * Time in seconds to ramp gain changes.
139
+ * Lower = faster transitions (may cause clicks)
140
+ * Higher = smoother transitions (may sound sluggish)
141
+ * Default: 0.015 (fast but smooth for voice)
76
142
  */
77
143
  gainRampTime?: number;
144
+ /**
145
+ * Apply additional gain reduction during the transition to silence.
146
+ * Helps create cleaner cutoffs without abrupt clicks.
147
+ * Default: true
148
+ */
149
+ smoothTransitions?: boolean;
150
+ /**
151
+ * Maximum gain in dB to apply (prevents clipping).
152
+ * Default: 6.0 dB (roughly 2x amplitude)
153
+ */
154
+ maxGainDb?: number;
155
+ /**
156
+ * Apply dynamic range compression when speaking.
157
+ * Makes quiet parts louder and loud parts quieter.
158
+ * Default: false (transparent audio)
159
+ */
160
+ enableCompression?: boolean;
161
+ /**
162
+ * Compression settings (when enabled)
163
+ */
164
+ compression?: {
165
+ /**
166
+ * Threshold in dB above which compression starts.
167
+ * Default: -24.0 dB
168
+ */
169
+ threshold?: number;
170
+ /**
171
+ * Compression ratio (1:N).
172
+ * Default: 3.0 (3:1 ratio)
173
+ */
174
+ ratio?: number;
175
+ /**
176
+ * Attack time in seconds.
177
+ * Default: 0.003 (3ms)
178
+ */
179
+ attack?: number;
180
+ /**
181
+ * Release time in seconds.
182
+ * Default: 0.05 (50ms)
183
+ */
184
+ release?: number;
185
+ };
78
186
  };
79
187
  /**
80
188
  * LiveKit integration configuration.
package/dist/types.d.ts CHANGED
@@ -35,46 +35,154 @@ interface AudioProcessingConfig {
35
35
  vad?: {
36
36
  enabled: boolean;
37
37
  /**
38
- * Plugin name to use. Defaults to 'rnnoise-vad' or 'energy-vad'.
38
+ * Plugin name to use. Defaults to 'energy-vad'.
39
39
  */
40
40
  pluginName?: string;
41
41
  /**
42
42
  * Probability threshold for speech onset (0-1).
43
- * Default: 0.5
43
+ * When VAD probability rises above this, audio is unmuted.
44
+ * Lower = more sensitive (catches quiet speech, may include noise)
45
+ * Higher = less sensitive (only confident speech, may clip quiet parts)
46
+ * Default: 0.6 (optimized for voice-only)
44
47
  */
45
48
  startThreshold?: number;
46
49
  /**
47
50
  * Probability threshold for speech offset (0-1).
48
- * Default: 0.4
51
+ * When VAD probability drops below this (after hangover), audio is muted.
52
+ * Lower = keeps audio on longer (less aggressive gating)
53
+ * Higher = mutes faster (more aggressive noise suppression)
54
+ * Default: 0.45 (balanced voice detection)
49
55
  */
50
56
  stopThreshold?: number;
51
57
  /**
52
- * Time in ms to wait after speech stops before considering it silent.
53
- * Default: 300ms
58
+ * Time in ms to wait after speech stops before muting.
59
+ * Prevents rapid on/off toggling during pauses.
60
+ * Lower = more aggressive gating, may clip between words
61
+ * Higher = smoother but may let trailing noise through
62
+ * Default: 400ms (optimized for natural speech)
54
63
  */
55
64
  hangoverMs?: number;
56
65
  /**
57
- * Time in ms of audio to buffer before speech onset to avoid cutting the start.
58
- * Default: 200ms
66
+ * Time in ms of audio to buffer before speech onset.
67
+ * Prevents cutting off the beginning of speech.
68
+ * Default: 250ms (generous pre-roll for voice)
59
69
  */
60
70
  preRollMs?: number;
71
+ /**
72
+ * Minimum speech duration in ms to consider it valid speech.
73
+ * Filters out very brief noise spikes.
74
+ * Default: 100ms
75
+ */
76
+ minSpeechDurationMs?: number;
77
+ /**
78
+ * Minimum silence duration in ms before allowing another speech segment.
79
+ * Prevents false positives from quick noise bursts.
80
+ * Default: 150ms
81
+ */
82
+ minSilenceDurationMs?: number;
83
+ /**
84
+ * Advanced: Energy VAD specific parameters
85
+ */
86
+ energyVad?: {
87
+ /**
88
+ * Smoothing factor for energy calculation (0-1).
89
+ * Higher = more smoothing, slower to react
90
+ * Default: 0.95
91
+ */
92
+ smoothing?: number;
93
+ /**
94
+ * Initial noise floor estimate.
95
+ * Default: 0.001
96
+ */
97
+ initialNoiseFloor?: number;
98
+ /**
99
+ * Rate at which noise floor adapts to quiet signals (0-1).
100
+ * Default: 0.01
101
+ */
102
+ noiseFloorAdaptRateQuiet?: number;
103
+ /**
104
+ * Rate at which noise floor adapts to loud signals (0-1).
105
+ * Default: 0.001 (slower adaptation for speech)
106
+ */
107
+ noiseFloorAdaptRateLoud?: number;
108
+ /**
109
+ * Minimum SNR (Signal-to-Noise Ratio) for speech detection.
110
+ * Default: 2.0 (voice is 2x louder than noise floor)
111
+ */
112
+ minSNR?: number;
113
+ /**
114
+ * SNR range for probability scaling.
115
+ * Default: 8.0 (probability scales from minSNR to minSNR+snrRange)
116
+ */
117
+ snrRange?: number;
118
+ };
61
119
  };
62
120
  /**
63
121
  * Output gain and muting configuration.
64
122
  */
65
123
  output?: {
66
124
  /**
67
- * Gain to apply when speaking (0-1+). Default: 1.0
125
+ * Gain to apply when speaking (0-infinity).
126
+ * Values > 1.0 will amplify the voice.
127
+ * Default: 1.0 (unity gain)
68
128
  */
69
129
  speechGain?: number;
70
130
  /**
71
- * Gain to apply when silent (0-1). Default: 0.0 (mute)
131
+ * Gain to apply when silent (0-1).
132
+ * 0.0 = complete mute (recommended for voice-only)
133
+ * 0.1-0.3 = allow some background ambience
134
+ * Default: 0.0 (full mute for voice-only)
72
135
  */
73
136
  silenceGain?: number;
74
137
  /**
75
- * Time in seconds to ramp gain changes. Default: 0.02
138
+ * Time in seconds to ramp gain changes.
139
+ * Lower = faster transitions (may cause clicks)
140
+ * Higher = smoother transitions (may sound sluggish)
141
+ * Default: 0.015 (fast but smooth for voice)
76
142
  */
77
143
  gainRampTime?: number;
144
+ /**
145
+ * Apply additional gain reduction during the transition to silence.
146
+ * Helps create cleaner cutoffs without abrupt clicks.
147
+ * Default: true
148
+ */
149
+ smoothTransitions?: boolean;
150
+ /**
151
+ * Maximum gain in dB to apply (prevents clipping).
152
+ * Default: 6.0 dB (roughly 2x amplitude)
153
+ */
154
+ maxGainDb?: number;
155
+ /**
156
+ * Apply dynamic range compression when speaking.
157
+ * Makes quiet parts louder and loud parts quieter.
158
+ * Default: false (transparent audio)
159
+ */
160
+ enableCompression?: boolean;
161
+ /**
162
+ * Compression settings (when enabled)
163
+ */
164
+ compression?: {
165
+ /**
166
+ * Threshold in dB above which compression starts.
167
+ * Default: -24.0 dB
168
+ */
169
+ threshold?: number;
170
+ /**
171
+ * Compression ratio (1:N).
172
+ * Default: 3.0 (3:1 ratio)
173
+ */
174
+ ratio?: number;
175
+ /**
176
+ * Attack time in seconds.
177
+ * Default: 0.003 (3ms)
178
+ */
179
+ attack?: number;
180
+ /**
181
+ * Release time in seconds.
182
+ * Default: 0.05 (50ms)
183
+ */
184
+ release?: number;
185
+ };
78
186
  };
79
187
  /**
80
188
  * LiveKit integration configuration.
@@ -23,13 +23,25 @@ __export(vad_node_exports, {
23
23
  EnergyVADPlugin: () => EnergyVADPlugin
24
24
  });
25
25
  module.exports = __toCommonJS(vad_node_exports);
26
- var energyVadWorkletCode = `
26
+ var createEnergyVadWorkletCode = (vadConfig) => {
27
+ const energyParams = vadConfig?.energyVad || {};
28
+ const smoothing = energyParams.smoothing ?? 0.95;
29
+ const initialNoiseFloor = energyParams.initialNoiseFloor ?? 1e-3;
30
+ const noiseFloorAdaptRateQuiet = energyParams.noiseFloorAdaptRateQuiet ?? 0.01;
31
+ const noiseFloorAdaptRateLoud = energyParams.noiseFloorAdaptRateLoud ?? 1e-3;
32
+ const minSNR = energyParams.minSNR ?? 2;
33
+ const snrRange = energyParams.snrRange ?? 8;
34
+ return `
27
35
  class EnergyVadProcessor extends AudioWorkletProcessor {
28
36
  constructor() {
29
37
  super();
30
- this.smoothing = 0.95;
38
+ this.smoothing = ${smoothing};
31
39
  this.energy = 0;
32
- this.noiseFloor = 0.001;
40
+ this.noiseFloor = ${initialNoiseFloor};
41
+ this.noiseFloorAdaptRateQuiet = ${noiseFloorAdaptRateQuiet};
42
+ this.noiseFloorAdaptRateLoud = ${noiseFloorAdaptRateLoud};
43
+ this.minSNR = ${minSNR};
44
+ this.snrRange = ${snrRange};
33
45
  }
34
46
 
35
47
  process(inputs, outputs, parameters) {
@@ -37,51 +49,89 @@ class EnergyVadProcessor extends AudioWorkletProcessor {
37
49
  if (!input || !input.length) return true;
38
50
  const channel = input[0];
39
51
 
40
- // Calculate RMS
52
+ // Calculate RMS (Root Mean Square) energy
41
53
  let sum = 0;
42
54
  for (let i = 0; i < channel.length; i++) {
43
55
  sum += channel[i] * channel[i];
44
56
  }
45
57
  const rms = Math.sqrt(sum / channel.length);
46
58
 
47
- // Simple adaptive noise floor (very basic)
59
+ // Adaptive noise floor estimation
60
+ // When signal is quiet, adapt quickly to find new noise floor
61
+ // When signal is loud (speech), adapt slowly to avoid raising noise floor
48
62
  if (rms < this.noiseFloor) {
49
- this.noiseFloor = this.noiseFloor * 0.99 + rms * 0.01;
63
+ this.noiseFloor = this.noiseFloor * (1 - this.noiseFloorAdaptRateQuiet) + rms * this.noiseFloorAdaptRateQuiet;
50
64
  } else {
51
- this.noiseFloor = this.noiseFloor * 0.999 + rms * 0.001;
65
+ this.noiseFloor = this.noiseFloor * (1 - this.noiseFloorAdaptRateLoud) + rms * this.noiseFloorAdaptRateLoud;
52
66
  }
53
67
 
54
- // Calculate "probability" based on SNR
55
- // This is a heuristic mapping from energy to 0-1
68
+ // Calculate Signal-to-Noise Ratio (SNR)
56
69
  const snr = rms / (this.noiseFloor + 1e-6);
57
- const probability = Math.min(1, Math.max(0, (snr - 1.5) / 10)); // Arbitrary scaling
70
+
71
+ // Map SNR to probability (0-1)
72
+ // Probability is 0 when SNR <= minSNR
73
+ // Probability scales linearly from 0 to 1 between minSNR and (minSNR + snrRange)
74
+ // Probability is 1 when SNR >= (minSNR + snrRange)
75
+ const probability = Math.min(1, Math.max(0, (snr - this.minSNR) / this.snrRange));
58
76
 
59
- this.port.postMessage({ probability });
77
+ this.port.postMessage({ probability, snr, noiseFloor: this.noiseFloor, rms });
60
78
 
61
79
  return true;
62
80
  }
63
81
  }
64
82
  registerProcessor('energy-vad-processor', EnergyVadProcessor);
65
83
  `;
84
+ };
66
85
  var EnergyVADPlugin = class {
67
86
  name = "energy-vad";
68
87
  async createNode(context, config, onDecision) {
69
- const blob = new Blob([energyVadWorkletCode], {
88
+ if (!config?.enabled) {
89
+ console.log("VAD disabled, using passthrough node");
90
+ const pass = context.createGain();
91
+ return pass;
92
+ }
93
+ const workletCode = createEnergyVadWorkletCode(config);
94
+ const blob = new Blob([workletCode], {
70
95
  type: "application/javascript"
71
96
  });
72
97
  const url = URL.createObjectURL(blob);
73
98
  try {
74
99
  await context.audioWorklet.addModule(url);
100
+ console.log("Energy VAD worklet loaded successfully");
75
101
  } catch (e) {
76
- console.warn("Failed to add Energy VAD worklet:", e);
77
- throw e;
78
- } finally {
102
+ const error = new Error(
103
+ `Failed to load Energy VAD worklet: ${e instanceof Error ? e.message : String(e)}`
104
+ );
105
+ console.error(error.message);
79
106
  URL.revokeObjectURL(url);
107
+ throw error;
108
+ }
109
+ URL.revokeObjectURL(url);
110
+ let node;
111
+ try {
112
+ node = new AudioWorkletNode(context, "energy-vad-processor");
113
+ console.log("Energy VAD node created successfully");
114
+ } catch (e) {
115
+ const error = new Error(
116
+ `Failed to create Energy VAD node: ${e instanceof Error ? e.message : String(e)}`
117
+ );
118
+ console.error(error.message);
119
+ throw error;
80
120
  }
81
- const node = new AudioWorkletNode(context, "energy-vad-processor");
82
121
  node.port.onmessage = (event) => {
83
- const { probability } = event.data;
84
- onDecision(probability);
122
+ try {
123
+ const { probability } = event.data;
124
+ if (typeof probability === "number" && !isNaN(probability)) {
125
+ onDecision(probability);
126
+ } else {
127
+ console.warn("Invalid VAD probability received:", event.data);
128
+ }
129
+ } catch (error) {
130
+ console.error("Error in VAD message handler:", error);
131
+ }
132
+ };
133
+ node.port.onmessageerror = (event) => {
134
+ console.error("VAD port message error:", event);
85
135
  };
86
136
  return node;
87
137
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  EnergyVADPlugin
3
- } from "../chunk-UMU2KIB6.mjs";
3
+ } from "../chunk-NMHKX64G.mjs";
4
4
  export {
5
5
  EnergyVADPlugin
6
6
  };
@@ -6,6 +6,7 @@ declare class VADStateMachine {
6
6
  private currentState;
7
7
  private lastSpeechTime;
8
8
  private speechStartTime;
9
+ private lastSilenceTime;
9
10
  private frameDurationMs;
10
11
  constructor(config: AudioProcessingConfig["vad"]);
11
12
  updateConfig(config: Partial<AudioProcessingConfig["vad"]>): void;
@@ -6,6 +6,7 @@ declare class VADStateMachine {
6
6
  private currentState;
7
7
  private lastSpeechTime;
8
8
  private speechStartTime;
9
+ private lastSilenceTime;
9
10
  private frameDurationMs;
10
11
  constructor(config: AudioProcessingConfig["vad"]);
11
12
  updateConfig(config: Partial<AudioProcessingConfig["vad"]>): void;
@@ -28,31 +28,60 @@ var VADStateMachine = class {
28
28
  currentState = "silent";
29
29
  lastSpeechTime = 0;
30
30
  speechStartTime = 0;
31
+ lastSilenceTime = 0;
31
32
  frameDurationMs = 20;
32
33
  // Assumed frame duration, updated by calls
33
34
  constructor(config) {
34
35
  this.config = {
35
36
  enabled: config?.enabled ?? true,
36
37
  pluginName: config?.pluginName ?? "energy-vad",
37
- startThreshold: config?.startThreshold ?? 0.5,
38
- stopThreshold: config?.stopThreshold ?? 0.4,
39
- hangoverMs: config?.hangoverMs ?? 300,
40
- preRollMs: config?.preRollMs ?? 200
38
+ // Voice-optimized defaults
39
+ startThreshold: config?.startThreshold ?? 0.6,
40
+ // Higher threshold to avoid noise
41
+ stopThreshold: config?.stopThreshold ?? 0.45,
42
+ // Balanced for voice
43
+ hangoverMs: config?.hangoverMs ?? 400,
44
+ // Smooth for natural speech
45
+ preRollMs: config?.preRollMs ?? 250,
46
+ // Generous pre-roll
47
+ minSpeechDurationMs: config?.minSpeechDurationMs ?? 100,
48
+ minSilenceDurationMs: config?.minSilenceDurationMs ?? 150,
49
+ energyVad: {
50
+ smoothing: config?.energyVad?.smoothing ?? 0.95,
51
+ initialNoiseFloor: config?.energyVad?.initialNoiseFloor ?? 1e-3,
52
+ noiseFloorAdaptRateQuiet: config?.energyVad?.noiseFloorAdaptRateQuiet ?? 0.01,
53
+ noiseFloorAdaptRateLoud: config?.energyVad?.noiseFloorAdaptRateLoud ?? 1e-3,
54
+ minSNR: config?.energyVad?.minSNR ?? 2,
55
+ snrRange: config?.energyVad?.snrRange ?? 8
56
+ }
41
57
  };
58
+ this.lastSilenceTime = Date.now();
42
59
  }
43
60
  updateConfig(config) {
44
61
  this.config = { ...this.config, ...config };
45
62
  }
46
63
  processFrame(probability, timestamp) {
47
- const { startThreshold, stopThreshold, hangoverMs } = this.config;
64
+ const {
65
+ startThreshold,
66
+ stopThreshold,
67
+ hangoverMs,
68
+ minSpeechDurationMs,
69
+ minSilenceDurationMs
70
+ } = this.config;
48
71
  let newState = this.currentState;
49
72
  if (this.currentState === "silent" || this.currentState === "speech_ending") {
50
73
  if (probability >= startThreshold) {
51
- newState = "speech_starting";
52
- this.speechStartTime = timestamp;
53
- this.lastSpeechTime = timestamp;
74
+ const silenceDuration = timestamp - this.lastSilenceTime;
75
+ if (silenceDuration >= minSilenceDurationMs) {
76
+ newState = "speech_starting";
77
+ this.speechStartTime = timestamp;
78
+ this.lastSpeechTime = timestamp;
79
+ } else {
80
+ newState = "silent";
81
+ }
54
82
  } else {
55
83
  newState = "silent";
84
+ this.lastSilenceTime = timestamp;
56
85
  }
57
86
  } else if (this.currentState === "speech_starting" || this.currentState === "speaking") {
58
87
  if (probability >= stopThreshold) {
@@ -60,10 +89,15 @@ var VADStateMachine = class {
60
89
  this.lastSpeechTime = timestamp;
61
90
  } else {
62
91
  const timeSinceSpeech = timestamp - this.lastSpeechTime;
92
+ const speechDuration = timestamp - this.speechStartTime;
63
93
  if (timeSinceSpeech < hangoverMs) {
64
94
  newState = "speaking";
95
+ } else if (speechDuration < minSpeechDurationMs) {
96
+ newState = "silent";
97
+ this.lastSilenceTime = timestamp;
65
98
  } else {
66
99
  newState = "speech_ending";
100
+ this.lastSilenceTime = timestamp;
67
101
  }
68
102
  }
69
103
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VADStateMachine
3
- } from "../chunk-JJASCVEW.mjs";
3
+ } from "../chunk-N553RHTI.mjs";
4
4
  export {
5
5
  VADStateMachine
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensamin/audio",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -1,38 +0,0 @@
1
- import {
2
- createAudioPipeline
3
- } from "./chunk-QU7E5HBA.mjs";
4
-
5
- // src/livekit/integration.ts
6
- async function attachProcessingToTrack(track, config = {}) {
7
- const originalTrack = track.mediaStreamTrack;
8
- const pipeline = await createAudioPipeline(originalTrack, config);
9
- await track.replaceTrack(pipeline.processedTrack);
10
- if (config.livekit?.manageTrackMute) {
11
- let isVadMuted = false;
12
- pipeline.events.on("vadChange", async (state) => {
13
- if (state.isSpeaking) {
14
- if (isVadMuted) {
15
- await track.unmute();
16
- isVadMuted = false;
17
- }
18
- } else {
19
- if (!track.isMuted) {
20
- await track.mute();
21
- isVadMuted = true;
22
- }
23
- }
24
- });
25
- }
26
- const originalDispose = pipeline.dispose;
27
- pipeline.dispose = () => {
28
- if (originalTrack.readyState === "live") {
29
- track.replaceTrack(originalTrack).catch(console.error);
30
- }
31
- originalDispose();
32
- };
33
- return pipeline;
34
- }
35
-
36
- export {
37
- attachProcessingToTrack
38
- };