@waveform-playlist/playout 5.0.0-alpha.0

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/index.js ADDED
@@ -0,0 +1,618 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ TonePlayout: () => TonePlayout,
24
+ ToneTrack: () => ToneTrack,
25
+ applyFadeIn: () => applyFadeIn,
26
+ applyFadeOut: () => applyFadeOut,
27
+ closeGlobalAudioContext: () => closeGlobalAudioContext,
28
+ getGlobalAudioContext: () => getGlobalAudioContext,
29
+ getGlobalAudioContextState: () => getGlobalAudioContextState,
30
+ getGlobalContext: () => getGlobalContext,
31
+ getGlobalToneContext: () => getGlobalToneContext,
32
+ getMediaStreamSource: () => getMediaStreamSource,
33
+ hasMediaStreamSource: () => hasMediaStreamSource,
34
+ releaseMediaStreamSource: () => releaseMediaStreamSource,
35
+ resumeGlobalAudioContext: () => resumeGlobalAudioContext
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/TonePlayout.ts
40
+ var import_tone2 = require("tone");
41
+
42
+ // src/ToneTrack.ts
43
+ var import_tone = require("tone");
44
+
45
+ // src/fades.ts
46
+ function linearCurve(length, fadeIn) {
47
+ const curve = new Float32Array(length);
48
+ const scale = length - 1;
49
+ for (let i = 0; i < length; i++) {
50
+ const x = i / scale;
51
+ curve[i] = fadeIn ? x : 1 - x;
52
+ }
53
+ return curve;
54
+ }
55
+ function exponentialCurve(length, fadeIn) {
56
+ const curve = new Float32Array(length);
57
+ const scale = length - 1;
58
+ for (let i = 0; i < length; i++) {
59
+ const x = i / scale;
60
+ const index = fadeIn ? i : length - 1 - i;
61
+ curve[index] = Math.exp(2 * x - 1) / Math.E;
62
+ }
63
+ return curve;
64
+ }
65
+ function sCurveCurve(length, fadeIn) {
66
+ const curve = new Float32Array(length);
67
+ const phase = fadeIn ? Math.PI / 2 : -Math.PI / 2;
68
+ for (let i = 0; i < length; i++) {
69
+ curve[i] = Math.sin(Math.PI * i / length - phase) / 2 + 0.5;
70
+ }
71
+ return curve;
72
+ }
73
+ function logarithmicCurve(length, fadeIn, base = 10) {
74
+ const curve = new Float32Array(length);
75
+ for (let i = 0; i < length; i++) {
76
+ const index = fadeIn ? i : length - 1 - i;
77
+ const x = i / length;
78
+ curve[index] = Math.log(1 + base * x) / Math.log(1 + base);
79
+ }
80
+ return curve;
81
+ }
82
+ function generateCurve(type, length, fadeIn) {
83
+ switch (type) {
84
+ case "linear":
85
+ return linearCurve(length, fadeIn);
86
+ case "exponential":
87
+ return exponentialCurve(length, fadeIn);
88
+ case "sCurve":
89
+ return sCurveCurve(length, fadeIn);
90
+ case "logarithmic":
91
+ return logarithmicCurve(length, fadeIn);
92
+ default:
93
+ return linearCurve(length, fadeIn);
94
+ }
95
+ }
96
+ function applyFadeIn(param, startTime, duration, type = "linear", startValue = 0, endValue = 1) {
97
+ if (duration <= 0) return;
98
+ if (type === "linear") {
99
+ param.setValueAtTime(startValue, startTime);
100
+ param.linearRampToValueAtTime(endValue, startTime + duration);
101
+ } else if (type === "exponential") {
102
+ param.setValueAtTime(Math.max(startValue, 1e-3), startTime);
103
+ param.exponentialRampToValueAtTime(Math.max(endValue, 1e-3), startTime + duration);
104
+ } else {
105
+ const curve = generateCurve(type, 1e4, true);
106
+ const scaledCurve = new Float32Array(curve.length);
107
+ const range = endValue - startValue;
108
+ for (let i = 0; i < curve.length; i++) {
109
+ scaledCurve[i] = startValue + curve[i] * range;
110
+ }
111
+ param.setValueCurveAtTime(scaledCurve, startTime, duration);
112
+ }
113
+ }
114
+ function applyFadeOut(param, startTime, duration, type = "linear", startValue = 1, endValue = 0) {
115
+ if (duration <= 0) return;
116
+ if (type === "linear") {
117
+ param.setValueAtTime(startValue, startTime);
118
+ param.linearRampToValueAtTime(endValue, startTime + duration);
119
+ } else if (type === "exponential") {
120
+ param.setValueAtTime(Math.max(startValue, 1e-3), startTime);
121
+ param.exponentialRampToValueAtTime(Math.max(endValue, 1e-3), startTime + duration);
122
+ } else {
123
+ const curve = generateCurve(type, 1e4, false);
124
+ const scaledCurve = new Float32Array(curve.length);
125
+ const range = startValue - endValue;
126
+ for (let i = 0; i < curve.length; i++) {
127
+ scaledCurve[i] = endValue + curve[i] * range;
128
+ }
129
+ param.setValueCurveAtTime(scaledCurve, startTime, duration);
130
+ }
131
+ }
132
+
133
+ // src/ToneTrack.ts
134
+ var ToneTrack = class {
135
+ // Count of currently playing clips
136
+ constructor(options) {
137
+ this.activePlayers = 0;
138
+ this.track = options.track;
139
+ this.volumeNode = new import_tone.Volume(this.gainToDb(options.track.gain));
140
+ this.panNode = new import_tone.Panner(options.track.stereoPan);
141
+ this.muteGain = new import_tone.Gain(options.track.muted ? 0 : 1);
142
+ const destination = options.destination || (0, import_tone.getDestination)();
143
+ if (options.effects) {
144
+ const cleanup = options.effects(this.muteGain, destination, false);
145
+ if (cleanup) {
146
+ this.effectsCleanup = cleanup;
147
+ }
148
+ } else {
149
+ this.muteGain.connect(destination);
150
+ }
151
+ const clipInfos = options.clips || (options.buffer ? [{
152
+ buffer: options.buffer,
153
+ startTime: 0,
154
+ // Legacy: single buffer starts at timeline position 0
155
+ duration: options.buffer.duration,
156
+ // Legacy: play full buffer duration
157
+ offset: 0,
158
+ fadeIn: options.track.fadeIn,
159
+ fadeOut: options.track.fadeOut,
160
+ gain: 1
161
+ }] : []);
162
+ this.clips = clipInfos.map((clipInfo) => {
163
+ const player = new import_tone.Player({
164
+ url: clipInfo.buffer,
165
+ loop: false,
166
+ onstop: () => {
167
+ this.activePlayers--;
168
+ if (this.activePlayers === 0 && this.onStopCallback) {
169
+ this.onStopCallback();
170
+ }
171
+ }
172
+ });
173
+ const fadeGain = new import_tone.Gain(clipInfo.gain);
174
+ player.connect(fadeGain);
175
+ fadeGain.chain(this.volumeNode, this.panNode, this.muteGain);
176
+ return {
177
+ player,
178
+ clipInfo,
179
+ fadeGain,
180
+ pausedPosition: 0,
181
+ playStartTime: 0
182
+ };
183
+ });
184
+ }
185
+ /**
186
+ * Schedule fade envelopes for a clip at the given start time
187
+ */
188
+ scheduleFades(clipPlayer, clipStartTime, clipOffset = 0) {
189
+ const { clipInfo, fadeGain } = clipPlayer;
190
+ const audioParam = fadeGain.gain._param;
191
+ audioParam.cancelScheduledValues(0);
192
+ const skipTime = clipOffset - clipInfo.offset;
193
+ if (clipInfo.fadeIn && skipTime < clipInfo.fadeIn.duration) {
194
+ const fadeInDuration = clipInfo.fadeIn.duration;
195
+ if (skipTime <= 0) {
196
+ applyFadeIn(
197
+ audioParam,
198
+ clipStartTime,
199
+ fadeInDuration,
200
+ clipInfo.fadeIn.type || "linear",
201
+ 0,
202
+ clipInfo.gain
203
+ );
204
+ } else {
205
+ const remainingFadeDuration = fadeInDuration - skipTime;
206
+ const fadeProgress = skipTime / fadeInDuration;
207
+ const startValue = clipInfo.gain * fadeProgress;
208
+ applyFadeIn(
209
+ audioParam,
210
+ clipStartTime,
211
+ remainingFadeDuration,
212
+ clipInfo.fadeIn.type || "linear",
213
+ startValue,
214
+ clipInfo.gain
215
+ );
216
+ }
217
+ } else {
218
+ audioParam.setValueAtTime(clipInfo.gain, clipStartTime);
219
+ }
220
+ if (clipInfo.fadeOut) {
221
+ const fadeOutStart = clipInfo.duration - clipInfo.fadeOut.duration;
222
+ const fadeOutStartInClip = fadeOutStart - skipTime;
223
+ if (fadeOutStartInClip > 0) {
224
+ const absoluteFadeOutStart = clipStartTime + fadeOutStartInClip;
225
+ applyFadeOut(
226
+ audioParam,
227
+ absoluteFadeOutStart,
228
+ clipInfo.fadeOut.duration,
229
+ clipInfo.fadeOut.type || "linear",
230
+ clipInfo.gain,
231
+ 0
232
+ );
233
+ } else if (fadeOutStartInClip > -clipInfo.fadeOut.duration) {
234
+ const elapsedFadeOut = -fadeOutStartInClip;
235
+ const remainingFadeDuration = clipInfo.fadeOut.duration - elapsedFadeOut;
236
+ const fadeProgress = elapsedFadeOut / clipInfo.fadeOut.duration;
237
+ const startValue = clipInfo.gain * (1 - fadeProgress);
238
+ applyFadeOut(
239
+ audioParam,
240
+ clipStartTime,
241
+ remainingFadeDuration,
242
+ clipInfo.fadeOut.type || "linear",
243
+ startValue,
244
+ 0
245
+ );
246
+ }
247
+ }
248
+ }
249
+ gainToDb(gain) {
250
+ return 20 * Math.log10(gain);
251
+ }
252
+ setVolume(gain) {
253
+ this.track.gain = gain;
254
+ this.volumeNode.volume.value = this.gainToDb(gain);
255
+ }
256
+ setPan(pan) {
257
+ this.track.stereoPan = pan;
258
+ this.panNode.pan.value = pan;
259
+ }
260
+ setMute(muted) {
261
+ this.track.muted = muted;
262
+ this.muteGain.gain.value = muted ? 0 : 1;
263
+ }
264
+ setSolo(soloed) {
265
+ this.track.soloed = soloed;
266
+ }
267
+ play(when, offset = 0, duration) {
268
+ const startWhen = when ?? (0, import_tone.now)();
269
+ if (this.isPlaying) {
270
+ this.stop();
271
+ }
272
+ this.activePlayers = 0;
273
+ this.clips.forEach((clipPlayer) => {
274
+ const { player, clipInfo } = clipPlayer;
275
+ const playbackPosition = offset;
276
+ const clipStart = clipInfo.startTime;
277
+ const clipEnd = clipInfo.startTime + clipInfo.duration;
278
+ if (playbackPosition < clipEnd) {
279
+ this.activePlayers++;
280
+ clipPlayer.playStartTime = (0, import_tone.now)();
281
+ if (playbackPosition >= clipStart) {
282
+ const clipOffset = playbackPosition - clipStart + clipInfo.offset;
283
+ const remainingDuration = clipInfo.duration - (playbackPosition - clipStart);
284
+ const clipDuration = duration ? Math.min(duration, remainingDuration) : remainingDuration;
285
+ clipPlayer.pausedPosition = clipOffset;
286
+ this.scheduleFades(clipPlayer, startWhen, clipOffset);
287
+ player.start(startWhen, clipOffset, clipDuration);
288
+ } else {
289
+ const delay = clipStart - playbackPosition;
290
+ const clipDuration = duration ? Math.min(duration - delay, clipInfo.duration) : clipInfo.duration;
291
+ if (delay < (duration ?? Infinity)) {
292
+ clipPlayer.pausedPosition = clipInfo.offset;
293
+ this.scheduleFades(clipPlayer, startWhen + delay, clipInfo.offset);
294
+ player.start(startWhen + delay, clipInfo.offset, clipDuration);
295
+ } else {
296
+ this.activePlayers--;
297
+ }
298
+ }
299
+ }
300
+ });
301
+ }
302
+ pause() {
303
+ this.clips.forEach((clipPlayer) => {
304
+ if (clipPlayer.player.state === "started") {
305
+ const elapsed = ((0, import_tone.now)() - clipPlayer.playStartTime) * clipPlayer.player.playbackRate;
306
+ clipPlayer.pausedPosition = clipPlayer.pausedPosition + elapsed;
307
+ }
308
+ clipPlayer.player.stop();
309
+ });
310
+ this.activePlayers = 0;
311
+ }
312
+ stop(when) {
313
+ const stopWhen = when ?? (0, import_tone.now)();
314
+ this.clips.forEach((clipPlayer) => {
315
+ clipPlayer.player.stop(stopWhen);
316
+ clipPlayer.pausedPosition = 0;
317
+ });
318
+ this.activePlayers = 0;
319
+ }
320
+ dispose() {
321
+ if (this.effectsCleanup) {
322
+ this.effectsCleanup();
323
+ }
324
+ this.clips.forEach((clipPlayer) => {
325
+ clipPlayer.player.dispose();
326
+ clipPlayer.fadeGain.dispose();
327
+ });
328
+ this.volumeNode.dispose();
329
+ this.panNode.dispose();
330
+ this.muteGain.dispose();
331
+ }
332
+ get id() {
333
+ return this.track.id;
334
+ }
335
+ get duration() {
336
+ if (this.clips.length === 0) return 0;
337
+ const lastClip = this.clips[this.clips.length - 1];
338
+ return lastClip.clipInfo.startTime + lastClip.clipInfo.duration;
339
+ }
340
+ get buffer() {
341
+ return this.clips[0]?.clipInfo.buffer;
342
+ }
343
+ get isPlaying() {
344
+ return this.clips.some((clipPlayer) => clipPlayer.player.state === "started");
345
+ }
346
+ get muted() {
347
+ return this.track.muted;
348
+ }
349
+ get startTime() {
350
+ return this.track.startTime;
351
+ }
352
+ setOnStopCallback(callback) {
353
+ this.onStopCallback = callback;
354
+ }
355
+ };
356
+
357
+ // src/TonePlayout.ts
358
+ var TonePlayout = class {
359
+ constructor(options = {}) {
360
+ this.tracks = /* @__PURE__ */ new Map();
361
+ this.isInitialized = false;
362
+ this.soloedTracks = /* @__PURE__ */ new Set();
363
+ this.manualMuteState = /* @__PURE__ */ new Map();
364
+ this.activeTracks = /* @__PURE__ */ new Map();
365
+ // Map track ID to session ID
366
+ this.playbackSessionId = 0;
367
+ this.masterVolume = new import_tone2.Volume(this.gainToDb(options.masterGain ?? 1));
368
+ if (options.effects) {
369
+ const cleanup = options.effects(this.masterVolume, (0, import_tone2.getDestination)(), false);
370
+ if (cleanup) {
371
+ this.effectsCleanup = cleanup;
372
+ }
373
+ } else {
374
+ this.masterVolume.toDestination();
375
+ }
376
+ if (options.tracks) {
377
+ options.tracks.forEach((track) => {
378
+ this.tracks.set(track.id, track);
379
+ this.manualMuteState.set(track.id, track.muted);
380
+ });
381
+ }
382
+ }
383
+ gainToDb(gain) {
384
+ return 20 * Math.log10(gain);
385
+ }
386
+ async init() {
387
+ if (this.isInitialized) return;
388
+ await (0, import_tone2.start)();
389
+ this.isInitialized = true;
390
+ }
391
+ addTrack(trackOptions) {
392
+ const optionsWithDestination = {
393
+ ...trackOptions,
394
+ destination: this.masterVolume
395
+ };
396
+ const toneTrack = new ToneTrack(optionsWithDestination);
397
+ this.tracks.set(toneTrack.id, toneTrack);
398
+ this.manualMuteState.set(toneTrack.id, trackOptions.track.muted ?? false);
399
+ return toneTrack;
400
+ }
401
+ removeTrack(trackId) {
402
+ const track = this.tracks.get(trackId);
403
+ if (track) {
404
+ track.dispose();
405
+ this.tracks.delete(trackId);
406
+ this.manualMuteState.delete(trackId);
407
+ this.soloedTracks.delete(trackId);
408
+ }
409
+ }
410
+ getTrack(trackId) {
411
+ return this.tracks.get(trackId);
412
+ }
413
+ play(when, offset, duration) {
414
+ if (!this.isInitialized) {
415
+ console.warn("TonePlayout not initialized. Call init() first.");
416
+ return;
417
+ }
418
+ const startTime = when ?? (0, import_tone2.now)();
419
+ const playbackPosition = offset ?? 0;
420
+ this.playbackSessionId++;
421
+ const currentSessionId = this.playbackSessionId;
422
+ this.activeTracks.clear();
423
+ this.tracks.forEach((toneTrack) => {
424
+ const trackStartTime = toneTrack.startTime;
425
+ if (playbackPosition >= trackStartTime) {
426
+ const bufferOffset = playbackPosition - trackStartTime;
427
+ if (duration !== void 0) {
428
+ this.activeTracks.set(toneTrack.id, currentSessionId);
429
+ toneTrack.setOnStopCallback(() => {
430
+ if (this.activeTracks.get(toneTrack.id) === currentSessionId) {
431
+ this.activeTracks.delete(toneTrack.id);
432
+ if (this.activeTracks.size === 0 && this.onPlaybackCompleteCallback) {
433
+ this.onPlaybackCompleteCallback();
434
+ }
435
+ }
436
+ });
437
+ }
438
+ toneTrack.play(startTime, bufferOffset, duration);
439
+ } else {
440
+ const delay = trackStartTime - playbackPosition;
441
+ if (duration !== void 0) {
442
+ this.activeTracks.set(toneTrack.id, currentSessionId);
443
+ toneTrack.setOnStopCallback(() => {
444
+ if (this.activeTracks.get(toneTrack.id) === currentSessionId) {
445
+ this.activeTracks.delete(toneTrack.id);
446
+ if (this.activeTracks.size === 0 && this.onPlaybackCompleteCallback) {
447
+ this.onPlaybackCompleteCallback();
448
+ }
449
+ }
450
+ });
451
+ }
452
+ toneTrack.play(startTime + delay, 0, duration);
453
+ }
454
+ });
455
+ if (offset !== void 0) {
456
+ (0, import_tone2.getTransport)().start(startTime, offset);
457
+ } else {
458
+ (0, import_tone2.getTransport)().start(startTime);
459
+ }
460
+ }
461
+ pause() {
462
+ (0, import_tone2.getTransport)().pause();
463
+ this.tracks.forEach((track) => {
464
+ track.pause();
465
+ });
466
+ }
467
+ stop() {
468
+ (0, import_tone2.getTransport)().stop();
469
+ this.tracks.forEach((track) => {
470
+ track.stop();
471
+ });
472
+ }
473
+ setMasterGain(gain) {
474
+ this.masterVolume.volume.value = this.gainToDb(gain);
475
+ }
476
+ setSolo(trackId, soloed) {
477
+ const track = this.tracks.get(trackId);
478
+ if (track) {
479
+ track.setSolo(soloed);
480
+ if (soloed) {
481
+ this.soloedTracks.add(trackId);
482
+ } else {
483
+ this.soloedTracks.delete(trackId);
484
+ }
485
+ this.updateSoloMuting();
486
+ }
487
+ }
488
+ updateSoloMuting() {
489
+ const hasSoloedTracks = this.soloedTracks.size > 0;
490
+ this.tracks.forEach((track, id) => {
491
+ if (hasSoloedTracks) {
492
+ if (!this.soloedTracks.has(id)) {
493
+ track.setMute(true);
494
+ } else {
495
+ const manuallyMuted = this.manualMuteState.get(id) ?? false;
496
+ track.setMute(manuallyMuted);
497
+ }
498
+ } else {
499
+ const manuallyMuted = this.manualMuteState.get(id) ?? false;
500
+ track.setMute(manuallyMuted);
501
+ }
502
+ });
503
+ }
504
+ setMute(trackId, muted) {
505
+ const track = this.tracks.get(trackId);
506
+ if (track) {
507
+ this.manualMuteState.set(trackId, muted);
508
+ track.setMute(muted);
509
+ }
510
+ }
511
+ getCurrentTime() {
512
+ return (0, import_tone2.getTransport)().seconds;
513
+ }
514
+ seekTo(time) {
515
+ (0, import_tone2.getTransport)().seconds = time;
516
+ }
517
+ dispose() {
518
+ this.tracks.forEach((track) => {
519
+ track.dispose();
520
+ });
521
+ this.tracks.clear();
522
+ if (this.effectsCleanup) {
523
+ this.effectsCleanup();
524
+ }
525
+ this.masterVolume.dispose();
526
+ }
527
+ get context() {
528
+ return (0, import_tone2.getContext)();
529
+ }
530
+ get sampleRate() {
531
+ return (0, import_tone2.getContext)().sampleRate;
532
+ }
533
+ setOnPlaybackComplete(callback) {
534
+ this.onPlaybackCompleteCallback = callback;
535
+ }
536
+ };
537
+
538
+ // src/audioContext.ts
539
+ var import_tone3 = require("tone");
540
+ var globalToneContext = null;
541
+ function getGlobalContext() {
542
+ if (!globalToneContext) {
543
+ globalToneContext = new import_tone3.Context();
544
+ (0, import_tone3.setContext)(globalToneContext);
545
+ }
546
+ return globalToneContext;
547
+ }
548
+ function getGlobalAudioContext() {
549
+ return getGlobalContext().rawContext;
550
+ }
551
+ function getGlobalToneContext() {
552
+ return getGlobalContext();
553
+ }
554
+ async function resumeGlobalAudioContext() {
555
+ const context = getGlobalContext();
556
+ if (context.state !== "running") {
557
+ await context.resume();
558
+ }
559
+ }
560
+ function getGlobalAudioContextState() {
561
+ return globalToneContext?.rawContext.state || "suspended";
562
+ }
563
+ async function closeGlobalAudioContext() {
564
+ if (globalToneContext && globalToneContext.rawContext.state !== "closed") {
565
+ await globalToneContext.close();
566
+ globalToneContext = null;
567
+ }
568
+ }
569
+
570
+ // src/mediaStreamSourceManager.ts
571
+ var import_tone4 = require("tone");
572
+ var streamSources = /* @__PURE__ */ new Map();
573
+ var streamCleanupHandlers = /* @__PURE__ */ new Map();
574
+ function getMediaStreamSource(stream) {
575
+ if (streamSources.has(stream)) {
576
+ return streamSources.get(stream);
577
+ }
578
+ const context = (0, import_tone4.getContext)();
579
+ const source = context.createMediaStreamSource(stream);
580
+ streamSources.set(stream, source);
581
+ const cleanup = () => {
582
+ source.disconnect();
583
+ streamSources.delete(stream);
584
+ streamCleanupHandlers.delete(stream);
585
+ stream.removeEventListener("ended", cleanup);
586
+ stream.removeEventListener("inactive", cleanup);
587
+ };
588
+ streamCleanupHandlers.set(stream, cleanup);
589
+ stream.addEventListener("ended", cleanup);
590
+ stream.addEventListener("inactive", cleanup);
591
+ return source;
592
+ }
593
+ function releaseMediaStreamSource(stream) {
594
+ const cleanup = streamCleanupHandlers.get(stream);
595
+ if (cleanup) {
596
+ cleanup();
597
+ }
598
+ }
599
+ function hasMediaStreamSource(stream) {
600
+ return streamSources.has(stream);
601
+ }
602
+ // Annotate the CommonJS export names for ESM import in node:
603
+ 0 && (module.exports = {
604
+ TonePlayout,
605
+ ToneTrack,
606
+ applyFadeIn,
607
+ applyFadeOut,
608
+ closeGlobalAudioContext,
609
+ getGlobalAudioContext,
610
+ getGlobalAudioContextState,
611
+ getGlobalContext,
612
+ getGlobalToneContext,
613
+ getMediaStreamSource,
614
+ hasMediaStreamSource,
615
+ releaseMediaStreamSource,
616
+ resumeGlobalAudioContext
617
+ });
618
+ //# sourceMappingURL=index.js.map