@viji-dev/core 0.5.5 → 0.5.6

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.
@@ -1897,7 +1897,7 @@ class EssentiaOnsetDetection {
1897
1897
  this.initPromise = (async () => {
1898
1898
  try {
1899
1899
  const essentiaModule = await import("./essentia.js-core.es-DnrJE0uR.js");
1900
- const wasmModule = await import("./essentia-wasm.web-C58CPq4U.js").then((n) => n.e);
1900
+ const wasmModule = await import("./essentia-wasm.web-B2bIxnGE.js").then((n) => n.e);
1901
1901
  const EssentiaClass = essentiaModule.Essentia || essentiaModule.default?.Essentia || essentiaModule.default;
1902
1902
  let WASMModule = wasmModule.default || wasmModule.EssentiaWASM || wasmModule.default?.EssentiaWASM;
1903
1903
  if (!WASMModule) {
@@ -7422,6 +7422,7 @@ class AudioChannel {
7422
7422
  if (this.workletNode) {
7423
7423
  try {
7424
7424
  this.workletNode.port.onmessage = null;
7425
+ this.workletNode.port.close();
7425
7426
  this.workletNode.disconnect();
7426
7427
  } catch (_) {
7427
7428
  }
@@ -7471,6 +7472,14 @@ class AudioSystem {
7471
7472
  onsetLogBuffer = [];
7472
7473
  // Debug logging control
7473
7474
  debugMode = false;
7475
+ /**
7476
+ * One-way lifecycle flag flipped at the top of `resetAudioState()`.
7477
+ * Gates re-entry into `ensureAudioContext()` and the public stream-mutation
7478
+ * entry points so an in-flight async caller (e.g. a worker RPC firing
7479
+ * mid-teardown) cannot resurrect a fresh `AudioContext` after destroy
7480
+ * has already nulled the field. AudioSystem is single-use after reset.
7481
+ */
7482
+ destroyed = false;
7474
7483
  // Diagnostic logger
7475
7484
  diagnosticLogger = new DiagnosticLogger();
7476
7485
  // Industry-grade audio analysis modules (4-layer architecture)
@@ -8056,6 +8065,7 @@ class AudioSystem {
8056
8065
  * Handle audio stream update for main stream (called from VijiCore)
8057
8066
  */
8058
8067
  handleAudioStreamUpdate(data) {
8068
+ if (this.destroyed) return;
8059
8069
  try {
8060
8070
  if (data.audioStream) {
8061
8071
  this.setAudioStream(data.audioStream);
@@ -8072,6 +8082,9 @@ class AudioSystem {
8072
8082
  * Ensure the shared AudioContext is created and resumed.
8073
8083
  */
8074
8084
  async ensureAudioContext() {
8085
+ if (this.destroyed) {
8086
+ throw new Error("AudioSystem is destroyed");
8087
+ }
8075
8088
  if (!this.audioContext) {
8076
8089
  this.audioContext = new AudioContext();
8077
8090
  }
@@ -8123,6 +8136,7 @@ class AudioSystem {
8123
8136
  if (ch.workletNode) {
8124
8137
  try {
8125
8138
  ch.workletNode.port.onmessage = null;
8139
+ ch.workletNode.port.close();
8126
8140
  ch.workletNode.disconnect();
8127
8141
  } catch {
8128
8142
  }
@@ -8173,6 +8187,7 @@ class AudioSystem {
8173
8187
  * Set the main audio stream for analysis (preserves original public API surface).
8174
8188
  */
8175
8189
  async setAudioStream(audioStream) {
8190
+ if (this.destroyed) return;
8176
8191
  this.disconnectMainStream();
8177
8192
  this.resetEssentiaBandHistories();
8178
8193
  await this.connectChannel(this.mainChannel, audioStream, true);
@@ -8444,8 +8459,14 @@ class AudioSystem {
8444
8459
  /**
8445
8460
  * Reset all audio state (called when destroying).
8446
8461
  * Disconnects all channels, closes AudioContext, resets all modules.
8462
+ *
8463
+ * Returns a Promise that resolves once `AudioContext.close()` has fully
8464
+ * transitioned the context to `closed`. Callers tearing the system down
8465
+ * (e.g. `VijiCore.destroy()`) MUST await this; otherwise Blink keeps the
8466
+ * context alive in `Pending activities` and leaks ~4 MB per cycle.
8447
8467
  */
8448
- resetAudioState() {
8468
+ async resetAudioState() {
8469
+ this.destroyed = true;
8449
8470
  this.stopAnalysisLoop();
8450
8471
  this.stopStalenessTimer();
8451
8472
  this.stopIdleTicker();
@@ -8458,9 +8479,14 @@ class AudioSystem {
8458
8479
  this.mainChannel.audioState.isConnected = false;
8459
8480
  this.mainChannel.isAnalysisRunning = false;
8460
8481
  this.mainChannel.currentStream = null;
8461
- if (this.audioContext && this.audioContext.state !== "closed") {
8462
- this.audioContext.close();
8463
- this.audioContext = null;
8482
+ const ctxToClose = this.audioContext;
8483
+ this.audioContext = null;
8484
+ if (ctxToClose && ctxToClose.state !== "closed") {
8485
+ try {
8486
+ await ctxToClose.close();
8487
+ } catch (e) {
8488
+ this.debugLog(`AudioContext.close() rejected: ${e?.message ?? e}`);
8489
+ }
8464
8490
  }
8465
8491
  this.workletRegistered = false;
8466
8492
  this.onsetDetection.reset();
@@ -8482,6 +8508,7 @@ class AudioSystem {
8482
8508
  * @param stream The MediaStream to analyze
8483
8509
  */
8484
8510
  async addStream(streamIndex, stream) {
8511
+ if (this.destroyed) return;
8485
8512
  if (this.additionalChannels.has(streamIndex)) {
8486
8513
  this.removeStream(streamIndex);
8487
8514
  }
@@ -8511,6 +8538,7 @@ class AudioSystem {
8511
8538
  * Mirrors video's reinitializeAdditionalCoordinators pattern.
8512
8539
  */
8513
8540
  async reinitializeAdditionalChannels(streams, baseIndex) {
8541
+ if (this.destroyed) return;
8514
8542
  const toRemove = [];
8515
8543
  for (const [idx, ch] of this.additionalChannels) {
8516
8544
  if (idx >= baseIndex && idx < baseIndex + 100) {
@@ -8628,6 +8656,7 @@ class AudioSystem {
8628
8656
  // do when audio is active.
8629
8657
  // ─────────────────────────────────────────────────────────────────────────
8630
8658
  startIdleTicker() {
8659
+ if (this.destroyed) return;
8631
8660
  if (this.idleTickerHandle !== null) return;
8632
8661
  if (typeof requestAnimationFrame === "undefined") return;
8633
8662
  this.idleTickerLastTime = performance.now();
@@ -8642,6 +8671,7 @@ class AudioSystem {
8642
8671
  }
8643
8672
  tickIdle(now) {
8644
8673
  this.idleTickerHandle = null;
8674
+ if (this.destroyed) return;
8645
8675
  if (this.mainChannel.audioState.isConnected) return;
8646
8676
  const dtMs = Math.min(100, now - this.idleTickerLastTime);
8647
8677
  this.idleTickerLastTime = now;
@@ -11630,7 +11660,7 @@ class VijiCore {
11630
11660
  }
11631
11661
  this.deviceAudioStreamIndices.clear();
11632
11662
  if (this.audioSystem) {
11633
- this.audioSystem.resetAudioState();
11663
+ await this.audioSystem.resetAudioState();
11634
11664
  this.audioSystem = null;
11635
11665
  }
11636
11666
  this.currentAudioStream = null;
@@ -11723,7 +11753,7 @@ function validateCoreStatePayload(state) {
11723
11753
  }
11724
11754
  return null;
11725
11755
  }
11726
- const VERSION = "0.5.5";
11756
+ const VERSION = "0.5.6";
11727
11757
  export {
11728
11758
  AudioSystem as A,
11729
11759
  VERSION as V,
@@ -11731,4 +11761,4 @@ export {
11731
11761
  VijiCoreError as b,
11732
11762
  getDefaultExportFromCjs as g
11733
11763
  };
11734
- //# sourceMappingURL=index-DsJxKERc.js.map
11764
+ //# sourceMappingURL=index-Yg6_UX8C.js.map