@tensamin/audio 0.2.6 → 0.2.7

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 CHANGED
@@ -87,12 +87,4 @@ output: {
87
87
  maxGainDb?: number; // default: 6.0
88
88
  smoothTransitions?: boolean;// default: true
89
89
  }
90
- ``+
91
-
92
- ### LiveKit mute handling
93
-
94
- ```ts
95
- muteWhenSilent?: boolean; // default: false
96
- ````
97
-
98
- When `muteWhenSilent` is `true`, the library automatically calls `track.mute()` when silence is detected and `track.unmute()` when speech resumes (only if it muted the track itself).
90
+ ```
@@ -21,16 +21,30 @@ async function attachSpeakingDetectionToTrack(track, options = {}) {
21
21
  const listeners = /* @__PURE__ */ new Set();
22
22
  let mutedByController = false;
23
23
  let currentState = pipeline.state;
24
+ let gainNode = null;
25
+ if (options.muteWhenSilent) {
26
+ try {
27
+ const audioContext = new AudioContext();
28
+ const source = audioContext.createMediaStreamSource(
29
+ new MediaStream([pipeline.processedTrack])
30
+ );
31
+ gainNode = audioContext.createGain();
32
+ source.connect(gainNode);
33
+ gainNode.connect(audioContext.destination);
34
+ } catch (error) {
35
+ console.error("Failed to create gain node for volume control", error);
36
+ }
37
+ }
24
38
  const speakingHandler = (state) => {
25
39
  currentState = state;
26
40
  listeners.forEach((listener) => listener(state));
27
- if (options.muteWhenSilent) {
28
- if (!state.speaking && !track.isMuted) {
29
- track.mute().catch((error) => console.error("mute failed", error));
41
+ if (options.muteWhenSilent && gainNode) {
42
+ if (!state.speaking && gainNode.gain.value > 0) {
43
+ gainNode.gain.value = 0;
30
44
  mutedByController = true;
31
45
  }
32
46
  if (state.speaking && mutedByController) {
33
- track.unmute().catch((error) => console.error("unmute failed", error));
47
+ gainNode.gain.value = 1;
34
48
  mutedByController = false;
35
49
  }
36
50
  }
@@ -62,9 +76,15 @@ async function attachSpeakingDetectionToTrack(track, options = {}) {
62
76
  pipeline.events.off("speakingChange", speakingHandler);
63
77
  pipeline.events.off("error", errorHandler);
64
78
  listeners.clear();
65
- if (mutedByController && !track.isMuted) {
66
- track.unmute().catch((error) => console.error("unmute failed", error));
67
- mutedByController = false;
79
+ if (gainNode) {
80
+ if (mutedByController && gainNode.gain.value === 0) {
81
+ gainNode.gain.value = 1;
82
+ mutedByController = false;
83
+ }
84
+ try {
85
+ gainNode.disconnect();
86
+ } catch (error) {
87
+ }
68
88
  }
69
89
  pipeline.dispose();
70
90
  if (originalTrack.readyState === "live") {
package/dist/index.js CHANGED
@@ -503,16 +503,30 @@ async function attachSpeakingDetectionToTrack(track, options = {}) {
503
503
  const listeners = /* @__PURE__ */ new Set();
504
504
  let mutedByController = false;
505
505
  let currentState = pipeline.state;
506
+ let gainNode = null;
507
+ if (options.muteWhenSilent) {
508
+ try {
509
+ const audioContext = new AudioContext();
510
+ const source = audioContext.createMediaStreamSource(
511
+ new MediaStream([pipeline.processedTrack])
512
+ );
513
+ gainNode = audioContext.createGain();
514
+ source.connect(gainNode);
515
+ gainNode.connect(audioContext.destination);
516
+ } catch (error) {
517
+ console.error("Failed to create gain node for volume control", error);
518
+ }
519
+ }
506
520
  const speakingHandler = (state) => {
507
521
  currentState = state;
508
522
  listeners.forEach((listener) => listener(state));
509
- if (options.muteWhenSilent) {
510
- if (!state.speaking && !track.isMuted) {
511
- track.mute().catch((error) => console.error("mute failed", error));
523
+ if (options.muteWhenSilent && gainNode) {
524
+ if (!state.speaking && gainNode.gain.value > 0) {
525
+ gainNode.gain.value = 0;
512
526
  mutedByController = true;
513
527
  }
514
528
  if (state.speaking && mutedByController) {
515
- track.unmute().catch((error) => console.error("unmute failed", error));
529
+ gainNode.gain.value = 1;
516
530
  mutedByController = false;
517
531
  }
518
532
  }
@@ -544,9 +558,15 @@ async function attachSpeakingDetectionToTrack(track, options = {}) {
544
558
  pipeline.events.off("speakingChange", speakingHandler);
545
559
  pipeline.events.off("error", errorHandler);
546
560
  listeners.clear();
547
- if (mutedByController && !track.isMuted) {
548
- track.unmute().catch((error) => console.error("unmute failed", error));
549
- mutedByController = false;
561
+ if (gainNode) {
562
+ if (mutedByController && gainNode.gain.value === 0) {
563
+ gainNode.gain.value = 1;
564
+ mutedByController = false;
565
+ }
566
+ try {
567
+ gainNode.disconnect();
568
+ } catch (error) {
569
+ }
550
570
  }
551
571
  pipeline.dispose();
552
572
  if (originalTrack.readyState === "live") {
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import "./chunk-WBQAMGXK.mjs";
2
2
  import {
3
3
  attachSpeakingDetectionToRemoteTrack,
4
4
  attachSpeakingDetectionToTrack
5
- } from "./chunk-Z36BDQQV.mjs";
5
+ } from "./chunk-HCEWI3JP.mjs";
6
6
  import "./chunk-7DOV5ZIH.mjs";
7
7
  import "./chunk-IS37FHDN.mjs";
8
8
  import "./chunk-47YTMONE.mjs";
@@ -498,16 +498,30 @@ async function attachSpeakingDetectionToTrack(track, options = {}) {
498
498
  const listeners = /* @__PURE__ */ new Set();
499
499
  let mutedByController = false;
500
500
  let currentState = pipeline.state;
501
+ let gainNode = null;
502
+ if (options.muteWhenSilent) {
503
+ try {
504
+ const audioContext = new AudioContext();
505
+ const source = audioContext.createMediaStreamSource(
506
+ new MediaStream([pipeline.processedTrack])
507
+ );
508
+ gainNode = audioContext.createGain();
509
+ source.connect(gainNode);
510
+ gainNode.connect(audioContext.destination);
511
+ } catch (error) {
512
+ console.error("Failed to create gain node for volume control", error);
513
+ }
514
+ }
501
515
  const speakingHandler = (state) => {
502
516
  currentState = state;
503
517
  listeners.forEach((listener) => listener(state));
504
- if (options.muteWhenSilent) {
505
- if (!state.speaking && !track.isMuted) {
506
- track.mute().catch((error) => console.error("mute failed", error));
518
+ if (options.muteWhenSilent && gainNode) {
519
+ if (!state.speaking && gainNode.gain.value > 0) {
520
+ gainNode.gain.value = 0;
507
521
  mutedByController = true;
508
522
  }
509
523
  if (state.speaking && mutedByController) {
510
- track.unmute().catch((error) => console.error("unmute failed", error));
524
+ gainNode.gain.value = 1;
511
525
  mutedByController = false;
512
526
  }
513
527
  }
@@ -539,9 +553,15 @@ async function attachSpeakingDetectionToTrack(track, options = {}) {
539
553
  pipeline.events.off("speakingChange", speakingHandler);
540
554
  pipeline.events.off("error", errorHandler);
541
555
  listeners.clear();
542
- if (mutedByController && !track.isMuted) {
543
- track.unmute().catch((error) => console.error("unmute failed", error));
544
- mutedByController = false;
556
+ if (gainNode) {
557
+ if (mutedByController && gainNode.gain.value === 0) {
558
+ gainNode.gain.value = 1;
559
+ mutedByController = false;
560
+ }
561
+ try {
562
+ gainNode.disconnect();
563
+ } catch (error) {
564
+ }
545
565
  }
546
566
  pipeline.dispose();
547
567
  if (originalTrack.readyState === "live") {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  attachSpeakingDetectionToRemoteTrack,
3
3
  attachSpeakingDetectionToTrack
4
- } from "../chunk-Z36BDQQV.mjs";
4
+ } from "../chunk-HCEWI3JP.mjs";
5
5
  import "../chunk-7DOV5ZIH.mjs";
6
6
  import "../chunk-IS37FHDN.mjs";
7
7
  import "../chunk-47YTMONE.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensamin/audio",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "author": {
5
5
  "email": "aloisianer@proton.me",
6
6
  "name": "Alois"
@@ -19,7 +19,7 @@
19
19
  "typescript": "^5.9.3"
20
20
  },
21
21
  "dependencies": {
22
- "deepfilternet3-noise-filter": "^1.1.2",
22
+ "deepfilternet3-noise-filter": "^1.1.4",
23
23
  "mitt": "^3.0.1"
24
24
  },
25
25
  "peerDependencies": {