audio-channel-queue 1.12.0 → 1.12.1-beta.2
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 +56 -15
- package/dist/core.js +3 -0
- package/dist/errors.js +0 -40
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -2
- package/dist/types.d.ts +37 -0
- package/dist/volume.d.ts +40 -0
- package/dist/volume.js +182 -16
- package/dist/web-audio.d.ts +156 -0
- package/dist/web-audio.js +327 -0
- package/package.json +5 -2
- package/src/core.ts +11 -1
- package/src/errors.ts +1 -49
- package/src/index.ts +22 -1
- package/src/types.ts +40 -0
- package/src/volume.ts +214 -14
- package/src/web-audio.ts +331 -0
package/dist/volume.js
CHANGED
|
@@ -12,13 +12,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
12
12
|
});
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.cancelAllVolumeTransitions = exports.cancelVolumeTransition = exports.restoreVolumeLevels = exports.applyVolumeDucking = exports.clearVolumeDucking = exports.setVolumeDucking = exports.setAllChannelsVolume = exports.getAllChannelsVolume = exports.getChannelVolume = exports.setChannelVolume = exports.transitionVolume = exports.getFadeConfig = void 0;
|
|
15
|
+
exports.cleanupWebAudioForAudio = exports.initializeWebAudioForAudio = exports.cancelAllVolumeTransitions = exports.cancelVolumeTransition = exports.restoreVolumeLevels = exports.applyVolumeDucking = exports.clearVolumeDucking = exports.setVolumeDucking = exports.getGlobalVolume = exports.setGlobalVolume = exports.setAllChannelsVolume = exports.getAllChannelsVolume = exports.getChannelVolume = exports.setChannelVolume = exports.transitionVolume = exports.getFadeConfig = void 0;
|
|
16
16
|
const types_1 = require("./types");
|
|
17
17
|
const info_1 = require("./info");
|
|
18
|
+
const web_audio_1 = require("./web-audio");
|
|
18
19
|
// Store active volume transitions to handle interruptions
|
|
19
20
|
const activeTransitions = new Map();
|
|
20
21
|
// Track which timer type was used for each channel
|
|
21
22
|
const timerTypes = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Global volume multiplier that affects all channels
|
|
25
|
+
* Acts as a global volume control (0-1)
|
|
26
|
+
*/
|
|
27
|
+
let globalVolume = 1.0;
|
|
22
28
|
/**
|
|
23
29
|
* Global volume ducking configuration
|
|
24
30
|
* Stores the volume ducking settings that apply to all channels
|
|
@@ -119,7 +125,7 @@ const transitionVolume = (channelNumber_1, targetVolume_1, ...args_1) => __await
|
|
|
119
125
|
const startTime = performance.now();
|
|
120
126
|
const easingFn = easingFunctions[easing];
|
|
121
127
|
return new Promise((resolve) => {
|
|
122
|
-
const updateVolume = () => {
|
|
128
|
+
const updateVolume = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
129
|
const elapsed = performance.now() - startTime;
|
|
124
130
|
const progress = Math.min(elapsed / duration, 1);
|
|
125
131
|
const easedProgress = easingFn(progress);
|
|
@@ -128,7 +134,7 @@ const transitionVolume = (channelNumber_1, targetVolume_1, ...args_1) => __await
|
|
|
128
134
|
// Apply volume to both channel config and current audio
|
|
129
135
|
channel.volume = clampedVolume;
|
|
130
136
|
if (channel.queue.length > 0) {
|
|
131
|
-
channel.queue[0]
|
|
137
|
+
yield setVolumeForAudio(channel.queue[0], clampedVolume, channelNumber);
|
|
132
138
|
}
|
|
133
139
|
if (progress >= 1) {
|
|
134
140
|
// Transition complete
|
|
@@ -139,24 +145,25 @@ const transitionVolume = (channelNumber_1, targetVolume_1, ...args_1) => __await
|
|
|
139
145
|
else {
|
|
140
146
|
// Use requestAnimationFrame in browser, setTimeout in tests
|
|
141
147
|
if (typeof requestAnimationFrame !== 'undefined') {
|
|
142
|
-
const rafId = requestAnimationFrame(updateVolume);
|
|
148
|
+
const rafId = requestAnimationFrame(() => updateVolume());
|
|
143
149
|
activeTransitions.set(channelNumber, rafId);
|
|
144
150
|
timerTypes.set(channelNumber, types_1.TimerType.RequestAnimationFrame);
|
|
145
151
|
}
|
|
146
152
|
else {
|
|
147
153
|
// In test environment, use shorter intervals
|
|
148
|
-
const timeoutId = setTimeout(updateVolume, 1);
|
|
154
|
+
const timeoutId = setTimeout(() => updateVolume(), 1);
|
|
149
155
|
activeTransitions.set(channelNumber, timeoutId);
|
|
150
156
|
timerTypes.set(channelNumber, types_1.TimerType.Timeout);
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
|
-
};
|
|
159
|
+
});
|
|
154
160
|
updateVolume();
|
|
155
161
|
});
|
|
156
162
|
});
|
|
157
163
|
exports.transitionVolume = transitionVolume;
|
|
158
164
|
/**
|
|
159
165
|
* Sets the volume for a specific channel with optional smooth transition
|
|
166
|
+
* Automatically uses Web Audio API on iOS devices for enhanced volume control
|
|
160
167
|
* @param channelNumber - The channel number to set volume for
|
|
161
168
|
* @param volume - Volume level (0-1)
|
|
162
169
|
* @param transitionDuration - Optional transition duration in milliseconds
|
|
@@ -192,17 +199,21 @@ const setChannelVolume = (channelNumber, volume, transitionDuration, easing) =>
|
|
|
192
199
|
};
|
|
193
200
|
return;
|
|
194
201
|
}
|
|
202
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
203
|
+
// Initialize Web Audio API if needed and supported
|
|
204
|
+
if ((0, web_audio_1.shouldUseWebAudio)() && !channel.webAudioContext) {
|
|
205
|
+
yield initializeWebAudioForChannel(channelNumber);
|
|
206
|
+
}
|
|
195
207
|
if (transitionDuration && transitionDuration > 0) {
|
|
196
208
|
// Smooth transition
|
|
197
209
|
yield (0, exports.transitionVolume)(channelNumber, clampedVolume, transitionDuration, easing);
|
|
198
210
|
}
|
|
199
211
|
else {
|
|
200
212
|
// Instant change (backward compatibility)
|
|
201
|
-
|
|
202
|
-
const channel = info_1.audioChannels[channelNumber];
|
|
213
|
+
channel.volume = clampedVolume;
|
|
203
214
|
if (channel.queue.length > 0) {
|
|
204
215
|
const currentAudio = channel.queue[0];
|
|
205
|
-
currentAudio
|
|
216
|
+
yield setVolumeForAudio(currentAudio, clampedVolume, channelNumber);
|
|
206
217
|
}
|
|
207
218
|
}
|
|
208
219
|
});
|
|
@@ -255,6 +266,48 @@ const setAllChannelsVolume = (volume) => __awaiter(void 0, void 0, void 0, funct
|
|
|
255
266
|
yield Promise.all(promises);
|
|
256
267
|
});
|
|
257
268
|
exports.setAllChannelsVolume = setAllChannelsVolume;
|
|
269
|
+
/**
|
|
270
|
+
* Sets the global volume multiplier that affects all channels
|
|
271
|
+
* This acts as a global volume control - individual channel volumes are multiplied by this value
|
|
272
|
+
* @param volume - Global volume level (0-1, will be clamped to this range)
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* // Set channel-specific volumes
|
|
276
|
+
* await setChannelVolume(0, 0.8); // SFX at 80%
|
|
277
|
+
* await setChannelVolume(1, 0.6); // Music at 60%
|
|
278
|
+
*
|
|
279
|
+
* // Apply global volume of 50% - all channels play at half their set volume
|
|
280
|
+
* await setGlobalVolume(0.5); // SFX now plays at 40%, music at 30%
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
const setGlobalVolume = (volume) => __awaiter(void 0, void 0, void 0, function* () {
|
|
284
|
+
// Clamp to valid range
|
|
285
|
+
globalVolume = Math.max(0, Math.min(1, volume));
|
|
286
|
+
// Update all currently playing audio to reflect the new global volume
|
|
287
|
+
// Note: setVolumeForAudio internally multiplies channel.volume by globalVolume
|
|
288
|
+
const updatePromises = [];
|
|
289
|
+
info_1.audioChannels.forEach((channel, channelNumber) => {
|
|
290
|
+
if (channel && channel.queue.length > 0) {
|
|
291
|
+
const currentAudio = channel.queue[0];
|
|
292
|
+
updatePromises.push(setVolumeForAudio(currentAudio, channel.volume, channelNumber));
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
yield Promise.all(updatePromises);
|
|
296
|
+
});
|
|
297
|
+
exports.setGlobalVolume = setGlobalVolume;
|
|
298
|
+
/**
|
|
299
|
+
* Gets the current global volume multiplier
|
|
300
|
+
* @returns Current global volume level (0-1), defaults to 1.0
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const globalVol = getGlobalVolume();
|
|
304
|
+
* console.log(`Global volume is ${globalVol * 100}%`);
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
const getGlobalVolume = () => {
|
|
308
|
+
return globalVolume;
|
|
309
|
+
};
|
|
310
|
+
exports.getGlobalVolume = getGlobalVolume;
|
|
258
311
|
/**
|
|
259
312
|
* Configures volume ducking for channels. When the priority channel plays audio,
|
|
260
313
|
* all other channels will be automatically reduced to the ducking volume level
|
|
@@ -333,13 +386,13 @@ const applyVolumeDucking = (activeChannelNumber) => __awaiter(void 0, void 0, vo
|
|
|
333
386
|
// This is the priority channel - set to priority volume
|
|
334
387
|
// Only change audio volume, preserve channel.volume as desired volume
|
|
335
388
|
const currentAudio = channel.queue[0];
|
|
336
|
-
transitionPromises.push(transitionAudioVolume(currentAudio, config.priorityVolume, duration, easing));
|
|
389
|
+
transitionPromises.push(transitionAudioVolume(currentAudio, config.priorityVolume, duration, easing, channelNumber));
|
|
337
390
|
}
|
|
338
391
|
else {
|
|
339
392
|
// This is a background channel - duck it
|
|
340
393
|
// Only change audio volume, preserve channel.volume as desired volume
|
|
341
394
|
const currentAudio = channel.queue[0];
|
|
342
|
-
transitionPromises.push(transitionAudioVolume(currentAudio, config.duckingVolume, duration, easing));
|
|
395
|
+
transitionPromises.push(transitionAudioVolume(currentAudio, config.duckingVolume, duration, easing, channelNumber));
|
|
343
396
|
}
|
|
344
397
|
});
|
|
345
398
|
// Wait for all transitions to complete
|
|
@@ -376,7 +429,7 @@ const restoreVolumeLevels = (stoppedChannelNumber) => __awaiter(void 0, void 0,
|
|
|
376
429
|
const targetVolume = (_c = channel.volume) !== null && _c !== void 0 ? _c : 1.0;
|
|
377
430
|
// Only transition the audio element volume, keep channel.volume as the desired volume
|
|
378
431
|
const currentAudio = channel.queue[0];
|
|
379
|
-
transitionPromises.push(transitionAudioVolume(currentAudio, targetVolume, duration, easing));
|
|
432
|
+
transitionPromises.push(transitionAudioVolume(currentAudio, targetVolume, duration, easing, channelNumber));
|
|
380
433
|
});
|
|
381
434
|
// Wait for all transitions to complete
|
|
382
435
|
yield Promise.all(transitionPromises);
|
|
@@ -385,23 +438,42 @@ exports.restoreVolumeLevels = restoreVolumeLevels;
|
|
|
385
438
|
/**
|
|
386
439
|
* Transitions only the audio element volume without affecting channel.volume
|
|
387
440
|
* This is used for ducking/restoration where channel.volume represents desired volume
|
|
441
|
+
* Uses Web Audio API when available for enhanced volume control
|
|
388
442
|
* @param audio - The audio element to transition
|
|
389
443
|
* @param targetVolume - Target volume level (0-1)
|
|
390
444
|
* @param duration - Transition duration in milliseconds
|
|
391
445
|
* @param easing - Easing function type
|
|
446
|
+
* @param channelNumber - The channel number this audio belongs to (for Web Audio API)
|
|
392
447
|
* @returns Promise that resolves when transition completes
|
|
393
448
|
* @internal
|
|
394
449
|
*/
|
|
395
|
-
const transitionAudioVolume = (audio_1, targetVolume_1, ...args_1) => __awaiter(void 0, [audio_1, targetVolume_1, ...args_1], void 0, function* (audio, targetVolume, duration = 250, easing = types_1.EasingType.EaseOut) {
|
|
450
|
+
const transitionAudioVolume = (audio_1, targetVolume_1, ...args_1) => __awaiter(void 0, [audio_1, targetVolume_1, ...args_1], void 0, function* (audio, targetVolume, duration = 250, easing = types_1.EasingType.EaseOut, channelNumber) {
|
|
451
|
+
// Apply global volume multiplier
|
|
452
|
+
const actualTargetVolume = targetVolume * globalVolume;
|
|
453
|
+
// Try to use Web Audio API if available and channel number is provided
|
|
454
|
+
if (channelNumber !== undefined) {
|
|
455
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
456
|
+
if ((channel === null || channel === void 0 ? void 0 : channel.webAudioContext) && channel.webAudioNodes) {
|
|
457
|
+
const nodes = channel.webAudioNodes.get(audio);
|
|
458
|
+
if (nodes) {
|
|
459
|
+
// Use Web Audio API for smooth transitions
|
|
460
|
+
(0, web_audio_1.setWebAudioVolume)(nodes.gainNode, actualTargetVolume, duration);
|
|
461
|
+
// Also update the audio element's volume property for consistency
|
|
462
|
+
audio.volume = actualTargetVolume;
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// Fallback to standard HTMLAudioElement volume control with manual transition
|
|
396
468
|
const startVolume = audio.volume;
|
|
397
|
-
const volumeDelta =
|
|
469
|
+
const volumeDelta = actualTargetVolume - startVolume;
|
|
398
470
|
// If no change needed, resolve immediately
|
|
399
471
|
if (Math.abs(volumeDelta) < 0.001) {
|
|
400
472
|
return Promise.resolve();
|
|
401
473
|
}
|
|
402
474
|
// Handle zero or negative duration - instant change
|
|
403
475
|
if (duration <= 0) {
|
|
404
|
-
audio.volume =
|
|
476
|
+
audio.volume = actualTargetVolume;
|
|
405
477
|
return Promise.resolve();
|
|
406
478
|
}
|
|
407
479
|
const startTime = performance.now();
|
|
@@ -424,7 +496,8 @@ const transitionAudioVolume = (audio_1, targetVolume_1, ...args_1) => __awaiter(
|
|
|
424
496
|
requestAnimationFrame(updateVolume);
|
|
425
497
|
}
|
|
426
498
|
else {
|
|
427
|
-
|
|
499
|
+
// In test environment, use longer intervals to prevent stack overflow
|
|
500
|
+
setTimeout(updateVolume, 16);
|
|
428
501
|
}
|
|
429
502
|
}
|
|
430
503
|
};
|
|
@@ -467,3 +540,96 @@ const cancelAllVolumeTransitions = () => {
|
|
|
467
540
|
});
|
|
468
541
|
};
|
|
469
542
|
exports.cancelAllVolumeTransitions = cancelAllVolumeTransitions;
|
|
543
|
+
/**
|
|
544
|
+
* Initializes Web Audio API for a specific channel
|
|
545
|
+
* @param channelNumber - The channel number to initialize Web Audio for
|
|
546
|
+
* @internal
|
|
547
|
+
*/
|
|
548
|
+
const initializeWebAudioForChannel = (channelNumber) => __awaiter(void 0, void 0, void 0, function* () {
|
|
549
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
550
|
+
if (!channel || channel.webAudioContext)
|
|
551
|
+
return;
|
|
552
|
+
const audioContext = (0, web_audio_1.getAudioContext)();
|
|
553
|
+
if (!audioContext) {
|
|
554
|
+
throw new Error('AudioContext creation failed');
|
|
555
|
+
}
|
|
556
|
+
// Resume audio context if needed (for autoplay policy)
|
|
557
|
+
yield (0, web_audio_1.resumeAudioContext)(audioContext);
|
|
558
|
+
channel.webAudioContext = audioContext;
|
|
559
|
+
channel.webAudioNodes = new Map();
|
|
560
|
+
// Initialize Web Audio nodes for existing audio elements
|
|
561
|
+
for (const audio of channel.queue) {
|
|
562
|
+
const nodes = (0, web_audio_1.createWebAudioNodes)(audio, audioContext);
|
|
563
|
+
if (!nodes) {
|
|
564
|
+
throw new Error('Node creation failed');
|
|
565
|
+
}
|
|
566
|
+
channel.webAudioNodes.set(audio, nodes);
|
|
567
|
+
// Set initial volume to match channel volume
|
|
568
|
+
nodes.gainNode.gain.value = channel.volume;
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
/**
|
|
572
|
+
* Sets volume for an audio element using the appropriate method (Web Audio API or standard)
|
|
573
|
+
* @param audio - The audio element to set volume for
|
|
574
|
+
* @param volume - Channel volume level (0-1) - will be multiplied by global volume
|
|
575
|
+
* @param channelNumber - The channel number this audio belongs to
|
|
576
|
+
* @param transitionDuration - Optional transition duration in milliseconds
|
|
577
|
+
* @internal
|
|
578
|
+
*/
|
|
579
|
+
const setVolumeForAudio = (audio, volume, channelNumber, transitionDuration) => __awaiter(void 0, void 0, void 0, function* () {
|
|
580
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
581
|
+
// Apply global volume multiplier to the channel volume
|
|
582
|
+
const actualVolume = volume * globalVolume;
|
|
583
|
+
// Use Web Audio API if available and initialized
|
|
584
|
+
if ((channel === null || channel === void 0 ? void 0 : channel.webAudioContext) && channel.webAudioNodes) {
|
|
585
|
+
const nodes = channel.webAudioNodes.get(audio);
|
|
586
|
+
if (nodes) {
|
|
587
|
+
(0, web_audio_1.setWebAudioVolume)(nodes.gainNode, actualVolume, transitionDuration);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
// Fallback to standard HTMLAudioElement volume control
|
|
592
|
+
audio.volume = actualVolume;
|
|
593
|
+
});
|
|
594
|
+
/**
|
|
595
|
+
* Initializes Web Audio API nodes for a new audio element
|
|
596
|
+
* @param audio - The audio element to initialize nodes for
|
|
597
|
+
* @param channelNumber - The channel number this audio belongs to
|
|
598
|
+
* @internal
|
|
599
|
+
*/
|
|
600
|
+
const initializeWebAudioForAudio = (audio, channelNumber) => __awaiter(void 0, void 0, void 0, function* () {
|
|
601
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
602
|
+
if (!channel)
|
|
603
|
+
return;
|
|
604
|
+
// Initialize Web Audio API for the channel if needed
|
|
605
|
+
if ((0, web_audio_1.shouldUseWebAudio)() && !channel.webAudioContext) {
|
|
606
|
+
yield initializeWebAudioForChannel(channelNumber);
|
|
607
|
+
}
|
|
608
|
+
// Create nodes for this specific audio element
|
|
609
|
+
if (channel.webAudioContext && channel.webAudioNodes && !channel.webAudioNodes.has(audio)) {
|
|
610
|
+
const nodes = (0, web_audio_1.createWebAudioNodes)(audio, channel.webAudioContext);
|
|
611
|
+
if (nodes) {
|
|
612
|
+
channel.webAudioNodes.set(audio, nodes);
|
|
613
|
+
// Set initial volume to match channel volume
|
|
614
|
+
nodes.gainNode.gain.value = channel.volume;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
exports.initializeWebAudioForAudio = initializeWebAudioForAudio;
|
|
619
|
+
/**
|
|
620
|
+
* Cleans up Web Audio API nodes for an audio element
|
|
621
|
+
* @param audio - The audio element to clean up nodes for
|
|
622
|
+
* @param channelNumber - The channel number this audio belongs to
|
|
623
|
+
* @internal
|
|
624
|
+
*/
|
|
625
|
+
const cleanupWebAudioForAudio = (audio, channelNumber) => {
|
|
626
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
627
|
+
if (!(channel === null || channel === void 0 ? void 0 : channel.webAudioNodes))
|
|
628
|
+
return;
|
|
629
|
+
const nodes = channel.webAudioNodes.get(audio);
|
|
630
|
+
if (nodes) {
|
|
631
|
+
(0, web_audio_1.cleanupWebAudioNodes)(nodes);
|
|
632
|
+
channel.webAudioNodes.delete(audio);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
exports.cleanupWebAudioForAudio = cleanupWebAudioForAudio;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Web Audio API support for enhanced volume control on iOS and other platforms
|
|
3
|
+
*/
|
|
4
|
+
import { WebAudioConfig, WebAudioSupport, WebAudioNodeSet } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Detects if the current device is iOS
|
|
7
|
+
* @returns True if the device is iOS, false otherwise
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* if (isIOSDevice()) {
|
|
11
|
+
* console.log('Running on iOS device');
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare const isIOSDevice: () => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Checks if Web Audio API is available in the current environment
|
|
18
|
+
* @returns True if Web Audio API is supported, false otherwise
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* if (isWebAudioSupported()) {
|
|
22
|
+
* console.log('Web Audio API is available');
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare const isWebAudioSupported: () => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Determines if Web Audio API should be used based on configuration and device detection
|
|
29
|
+
* @returns True if Web Audio API should be used, false otherwise
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* if (shouldUseWebAudio()) {
|
|
33
|
+
* // Use Web Audio API for volume control
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare const shouldUseWebAudio: () => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Gets information about Web Audio API support and usage
|
|
40
|
+
* @returns Object containing Web Audio API support information
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const support = getWebAudioSupport();
|
|
44
|
+
* console.log(`Using Web Audio: ${support.usingWebAudio}`);
|
|
45
|
+
* console.log(`Reason: ${support.reason}`);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare const getWebAudioSupport: () => WebAudioSupport;
|
|
49
|
+
/**
|
|
50
|
+
* Configures Web Audio API usage
|
|
51
|
+
* @param config - Configuration options for Web Audio API
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // Force Web Audio API usage on all devices
|
|
55
|
+
* setWebAudioConfig({ forceWebAudio: true });
|
|
56
|
+
*
|
|
57
|
+
* // Disable Web Audio API entirely
|
|
58
|
+
* setWebAudioConfig({ enabled: false });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare const setWebAudioConfig: (config: Partial<WebAudioConfig>) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Gets the current Web Audio API configuration
|
|
64
|
+
* @returns Current Web Audio API configuration
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const config = getWebAudioConfig();
|
|
68
|
+
* console.log(`Web Audio enabled: ${config.enabled}`);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare const getWebAudioConfig: () => WebAudioConfig;
|
|
72
|
+
/**
|
|
73
|
+
* Creates or gets an AudioContext for Web Audio API operations
|
|
74
|
+
* @returns AudioContext instance or null if not supported
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const context = getAudioContext();
|
|
78
|
+
* if (context) {
|
|
79
|
+
* console.log('Audio context created successfully');
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare const getAudioContext: () => AudioContext | null;
|
|
84
|
+
/**
|
|
85
|
+
* Creates Web Audio API nodes for an audio element
|
|
86
|
+
* @param audioElement - The HTML audio element to create nodes for
|
|
87
|
+
* @param audioContext - The AudioContext to use
|
|
88
|
+
* @returns Web Audio API node set or null if creation fails
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const audio = new Audio('song.mp3');
|
|
92
|
+
* const context = getAudioContext();
|
|
93
|
+
* if (context) {
|
|
94
|
+
* const nodes = createWebAudioNodes(audio, context);
|
|
95
|
+
* if (nodes) {
|
|
96
|
+
* nodes.gainNode.gain.value = 0.5; // Set volume to 50%
|
|
97
|
+
* }
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare const createWebAudioNodes: (audioElement: HTMLAudioElement, audioContext: AudioContext) => WebAudioNodeSet | null;
|
|
102
|
+
/**
|
|
103
|
+
* Sets volume using Web Audio API gain node
|
|
104
|
+
* @param gainNode - The gain node to set volume on
|
|
105
|
+
* @param volume - Volume level (0-1)
|
|
106
|
+
* @param transitionDuration - Optional transition duration in milliseconds
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const nodes = createWebAudioNodes(audio, context);
|
|
110
|
+
* if (nodes) {
|
|
111
|
+
* setWebAudioVolume(nodes.gainNode, 0.5); // Set to 50% volume
|
|
112
|
+
* setWebAudioVolume(nodes.gainNode, 0.2, 300); // Fade to 20% over 300ms
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare const setWebAudioVolume: (gainNode: GainNode, volume: number, transitionDuration?: number) => void;
|
|
117
|
+
/**
|
|
118
|
+
* Gets the current volume from a Web Audio API gain node
|
|
119
|
+
* @param gainNode - The gain node to get volume from
|
|
120
|
+
* @returns Current volume level (0-1)
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const nodes = createWebAudioNodes(audio, context);
|
|
124
|
+
* if (nodes) {
|
|
125
|
+
* const volume = getWebAudioVolume(nodes.gainNode);
|
|
126
|
+
* console.log(`Current volume: ${volume * 100}%`);
|
|
127
|
+
* }
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export declare const getWebAudioVolume: (gainNode: GainNode) => number;
|
|
131
|
+
/**
|
|
132
|
+
* Resumes an AudioContext if it's in suspended state (required for autoplay policy)
|
|
133
|
+
* @param audioContext - The AudioContext to resume
|
|
134
|
+
* @returns Promise that resolves when context is resumed
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const context = getAudioContext();
|
|
138
|
+
* if (context) {
|
|
139
|
+
* await resumeAudioContext(context);
|
|
140
|
+
* }
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export declare const resumeAudioContext: (audioContext: AudioContext) => Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* Cleans up Web Audio API nodes and connections
|
|
146
|
+
* @param nodes - The Web Audio API node set to clean up
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const nodes = createWebAudioNodes(audio, context);
|
|
150
|
+
* if (nodes) {
|
|
151
|
+
* // Use nodes...
|
|
152
|
+
* cleanupWebAudioNodes(nodes); // Clean up when done
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare const cleanupWebAudioNodes: (nodes: WebAudioNodeSet) => void;
|