audio-channel-queue 1.7.0 → 1.9.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/core.js +4 -3
- package/dist/errors.js +27 -17
- package/dist/events.js +21 -14
- package/dist/index.d.ts +6 -5
- package/dist/index.js +16 -1
- package/dist/info.js +8 -7
- package/dist/pause.d.ts +83 -0
- package/dist/pause.js +258 -3
- package/dist/types.d.ts +53 -4
- package/dist/types.js +25 -0
- package/dist/utils.js +4 -3
- package/dist/volume.d.ts +28 -3
- package/dist/volume.js +77 -15
- package/package.json +8 -3
- package/src/core.ts +59 -42
- package/src/errors.ts +504 -480
- package/src/events.ts +36 -27
- package/src/index.ts +60 -39
- package/src/info.ts +23 -22
- package/src/pause.ts +328 -23
- package/src/types.ts +57 -3
- package/src/utils.ts +7 -7
- package/src/volume.ts +92 -30
package/src/volume.ts
CHANGED
|
@@ -2,20 +2,55 @@
|
|
|
2
2
|
* @fileoverview Volume management functions for the audio-channel-queue package
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { ExtendedAudioQueueChannel, VolumeConfig } from './types';
|
|
5
|
+
import { ExtendedAudioQueueChannel, VolumeConfig, FadeType, FadeConfig, EasingType } from './types';
|
|
6
6
|
import { audioChannels } from './info';
|
|
7
7
|
|
|
8
8
|
// Store active volume transitions to handle interruptions
|
|
9
|
-
const activeTransitions
|
|
9
|
+
const activeTransitions: Map<number, number> = new Map();
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Predefined fade configurations for different transition types
|
|
13
|
+
*/
|
|
14
|
+
const fadeConfigs: Record<FadeType, FadeConfig> = {
|
|
15
|
+
[FadeType.Dramatic]: {
|
|
16
|
+
duration: 800,
|
|
17
|
+
pauseCurve: EasingType.EaseIn,
|
|
18
|
+
resumeCurve: EasingType.EaseOut
|
|
19
|
+
},
|
|
20
|
+
[FadeType.Gentle]: {
|
|
21
|
+
duration: 800,
|
|
22
|
+
pauseCurve: EasingType.EaseOut,
|
|
23
|
+
resumeCurve: EasingType.EaseIn
|
|
24
|
+
},
|
|
25
|
+
[FadeType.Linear]: {
|
|
26
|
+
duration: 800,
|
|
27
|
+
pauseCurve: EasingType.Linear,
|
|
28
|
+
resumeCurve: EasingType.Linear
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets the fade configuration for a specific fade type
|
|
34
|
+
* @param fadeType - The fade type to get configuration for
|
|
35
|
+
* @returns Fade configuration object
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const config = getFadeConfig('gentle');
|
|
39
|
+
* console.log(`Gentle fade duration: ${config.duration}ms`);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export const getFadeConfig = (fadeType: FadeType): FadeConfig => {
|
|
43
|
+
return { ...fadeConfigs[fadeType] };
|
|
44
|
+
};
|
|
10
45
|
|
|
11
46
|
/**
|
|
12
47
|
* Easing functions for smooth volume transitions
|
|
13
48
|
*/
|
|
14
|
-
const easingFunctions = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
49
|
+
const easingFunctions: Record<EasingType, (t: number) => number> = {
|
|
50
|
+
[EasingType.Linear]: (t: number): number => t,
|
|
51
|
+
[EasingType.EaseIn]: (t: number): number => t * t,
|
|
52
|
+
[EasingType.EaseOut]: (t: number): number => t * (2 - t),
|
|
53
|
+
[EasingType.EaseInOut]: (t: number): number => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t)
|
|
19
54
|
};
|
|
20
55
|
|
|
21
56
|
/**
|
|
@@ -34,7 +69,7 @@ export const transitionVolume = async (
|
|
|
34
69
|
channelNumber: number,
|
|
35
70
|
targetVolume: number,
|
|
36
71
|
duration: number = 250,
|
|
37
|
-
easing:
|
|
72
|
+
easing: EasingType = EasingType.EaseOut
|
|
38
73
|
): Promise<void> => {
|
|
39
74
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
40
75
|
if (!channel || channel.queue.length === 0) return;
|
|
@@ -42,10 +77,17 @@ export const transitionVolume = async (
|
|
|
42
77
|
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
43
78
|
const startVolume: number = currentAudio.volume;
|
|
44
79
|
const volumeDelta: number = targetVolume - startVolume;
|
|
45
|
-
|
|
80
|
+
|
|
46
81
|
// Cancel any existing transition for this channel
|
|
47
82
|
if (activeTransitions.has(channelNumber)) {
|
|
48
|
-
|
|
83
|
+
const transitionId = activeTransitions.get(channelNumber);
|
|
84
|
+
if (transitionId) {
|
|
85
|
+
// Handle both requestAnimationFrame and setTimeout IDs
|
|
86
|
+
if (typeof cancelAnimationFrame !== 'undefined') {
|
|
87
|
+
cancelAnimationFrame(transitionId);
|
|
88
|
+
}
|
|
89
|
+
clearTimeout(transitionId);
|
|
90
|
+
}
|
|
49
91
|
activeTransitions.delete(channelNumber);
|
|
50
92
|
}
|
|
51
93
|
|
|
@@ -72,10 +114,10 @@ export const transitionVolume = async (
|
|
|
72
114
|
const elapsed: number = performance.now() - startTime;
|
|
73
115
|
const progress: number = Math.min(elapsed / duration, 1);
|
|
74
116
|
const easedProgress: number = easingFn(progress);
|
|
75
|
-
|
|
76
|
-
const currentVolume: number = startVolume +
|
|
117
|
+
|
|
118
|
+
const currentVolume: number = startVolume + volumeDelta * easedProgress;
|
|
77
119
|
const clampedVolume: number = Math.max(0, Math.min(1, currentVolume));
|
|
78
|
-
|
|
120
|
+
|
|
79
121
|
// Apply volume to both channel config and current audio
|
|
80
122
|
channel.volume = clampedVolume;
|
|
81
123
|
if (channel.queue.length > 0) {
|
|
@@ -116,13 +158,13 @@ export const transitionVolume = async (
|
|
|
116
158
|
* ```
|
|
117
159
|
*/
|
|
118
160
|
export const setChannelVolume = async (
|
|
119
|
-
channelNumber: number,
|
|
161
|
+
channelNumber: number,
|
|
120
162
|
volume: number,
|
|
121
163
|
transitionDuration?: number,
|
|
122
|
-
easing?:
|
|
164
|
+
easing?: EasingType
|
|
123
165
|
): Promise<void> => {
|
|
124
166
|
const clampedVolume: number = Math.max(0, Math.min(1, volume));
|
|
125
|
-
|
|
167
|
+
|
|
126
168
|
if (!audioChannels[channelNumber]) {
|
|
127
169
|
audioChannels[channelNumber] = {
|
|
128
170
|
audioCompleteCallbacks: new Set(),
|
|
@@ -166,7 +208,7 @@ export const setChannelVolume = async (
|
|
|
166
208
|
*/
|
|
167
209
|
export const getChannelVolume = (channelNumber: number = 0): number => {
|
|
168
210
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
169
|
-
return channel?.volume
|
|
211
|
+
return channel?.volume ?? 1.0;
|
|
170
212
|
};
|
|
171
213
|
|
|
172
214
|
/**
|
|
@@ -181,9 +223,7 @@ export const getChannelVolume = (channelNumber: number = 0): number => {
|
|
|
181
223
|
* ```
|
|
182
224
|
*/
|
|
183
225
|
export const getAllChannelsVolume = (): number[] => {
|
|
184
|
-
return audioChannels.map((channel: ExtendedAudioQueueChannel) =>
|
|
185
|
-
channel?.volume || 1.0
|
|
186
|
-
);
|
|
226
|
+
return audioChannels.map((channel: ExtendedAudioQueueChannel) => channel?.volume ?? 1.0);
|
|
187
227
|
};
|
|
188
228
|
|
|
189
229
|
/**
|
|
@@ -279,11 +319,11 @@ export const applyVolumeDucking = async (activeChannelNumber: number): Promise<v
|
|
|
279
319
|
audioChannels.forEach((channel: ExtendedAudioQueueChannel, channelNumber: number) => {
|
|
280
320
|
if (channel?.volumeConfig) {
|
|
281
321
|
const config: VolumeConfig = channel.volumeConfig;
|
|
282
|
-
|
|
322
|
+
|
|
283
323
|
if (activeChannelNumber === config.priorityChannel) {
|
|
284
|
-
const duration = config.duckTransitionDuration
|
|
285
|
-
const easing = config.transitionEasing
|
|
286
|
-
|
|
324
|
+
const duration = config.duckTransitionDuration ?? 250;
|
|
325
|
+
const easing = config.transitionEasing ?? EasingType.EaseOut;
|
|
326
|
+
|
|
287
327
|
// Priority channel is active, duck other channels
|
|
288
328
|
if (channelNumber === config.priorityChannel) {
|
|
289
329
|
transitionPromises.push(
|
|
@@ -302,6 +342,28 @@ export const applyVolumeDucking = async (activeChannelNumber: number): Promise<v
|
|
|
302
342
|
await Promise.all(transitionPromises);
|
|
303
343
|
};
|
|
304
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Fades the volume for a specific channel over time (alias for transitionVolume with improved naming)
|
|
347
|
+
* @param channelNumber - The channel number to fade
|
|
348
|
+
* @param targetVolume - Target volume level (0-1)
|
|
349
|
+
* @param duration - Fade duration in milliseconds (defaults to 250)
|
|
350
|
+
* @param easing - Easing function type (defaults to 'ease-out')
|
|
351
|
+
* @returns Promise that resolves when fade completes
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* await fadeVolume(0, 0, 800, 'ease-in'); // Fade out over 800ms
|
|
355
|
+
* await fadeVolume(0, 1, 600, 'ease-out'); // Fade in over 600ms
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
export const fadeVolume = async (
|
|
359
|
+
channelNumber: number,
|
|
360
|
+
targetVolume: number,
|
|
361
|
+
duration: number = 250,
|
|
362
|
+
easing: EasingType = EasingType.EaseOut
|
|
363
|
+
): Promise<void> => {
|
|
364
|
+
return transitionVolume(channelNumber, targetVolume, duration, easing);
|
|
365
|
+
};
|
|
366
|
+
|
|
305
367
|
/**
|
|
306
368
|
* Restores normal volume levels when priority channel stops with smooth transitions
|
|
307
369
|
* @param stoppedChannelNumber - The channel that just stopped playing
|
|
@@ -313,14 +375,14 @@ export const restoreVolumeLevels = async (stoppedChannelNumber: number): Promise
|
|
|
313
375
|
audioChannels.forEach((channel: ExtendedAudioQueueChannel, channelNumber: number) => {
|
|
314
376
|
if (channel?.volumeConfig) {
|
|
315
377
|
const config: VolumeConfig = channel.volumeConfig;
|
|
316
|
-
|
|
378
|
+
|
|
317
379
|
if (stoppedChannelNumber === config.priorityChannel) {
|
|
318
|
-
const duration = config.restoreTransitionDuration
|
|
319
|
-
const easing = config.transitionEasing
|
|
320
|
-
|
|
380
|
+
const duration = config.restoreTransitionDuration ?? 500;
|
|
381
|
+
const easing = config.transitionEasing ?? EasingType.EaseOut;
|
|
382
|
+
|
|
321
383
|
// Priority channel stopped, restore normal volumes
|
|
322
384
|
transitionPromises.push(
|
|
323
|
-
transitionVolume(channelNumber, channel.volume
|
|
385
|
+
transitionVolume(channelNumber, channel.volume ?? 1.0, duration, easing)
|
|
324
386
|
);
|
|
325
387
|
}
|
|
326
388
|
}
|
|
@@ -328,4 +390,4 @@ export const restoreVolumeLevels = async (stoppedChannelNumber: number): Promise
|
|
|
328
390
|
|
|
329
391
|
// Wait for all transitions to complete
|
|
330
392
|
await Promise.all(transitionPromises);
|
|
331
|
-
};
|
|
393
|
+
};
|