audio-channel-queue 1.11.0 → 1.12.1-beta.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/README.md +48 -25
- package/dist/core.js +6 -3
- package/dist/errors.d.ts +4 -4
- package/dist/errors.js +12 -51
- package/dist/index.d.ts +4 -3
- package/dist/index.js +19 -5
- package/dist/info.d.ts +20 -15
- package/dist/info.js +20 -15
- package/dist/types.d.ts +103 -24
- package/dist/types.js +17 -4
- package/dist/volume.d.ts +15 -14
- package/dist/volume.js +131 -33
- package/dist/web-audio.d.ts +156 -0
- package/dist/web-audio.js +327 -0
- package/package.json +1 -1
- package/src/core.ts +14 -4
- package/src/errors.ts +15 -64
- package/src/index.ts +31 -6
- package/src/info.ts +20 -15
- package/src/types.ts +107 -24
- package/src/volume.ts +158 -36
- package/src/web-audio.ts +331 -0
package/src/errors.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import {
|
|
6
6
|
AudioErrorInfo,
|
|
7
7
|
AudioErrorCallback,
|
|
8
|
+
AudioErrorType,
|
|
8
9
|
RetryConfig,
|
|
9
10
|
ErrorRecoveryOptions,
|
|
10
11
|
ExtendedAudioQueueChannel,
|
|
@@ -17,6 +18,7 @@ let globalRetryConfig: RetryConfig = {
|
|
|
17
18
|
baseDelay: 1000,
|
|
18
19
|
enabled: true,
|
|
19
20
|
exponentialBackoff: true,
|
|
21
|
+
fallbackUrls: [],
|
|
20
22
|
maxRetries: 3,
|
|
21
23
|
skipOnFailure: false,
|
|
22
24
|
timeoutMs: 10000
|
|
@@ -32,8 +34,6 @@ let globalErrorRecovery: ErrorRecoveryOptions = {
|
|
|
32
34
|
|
|
33
35
|
const retryAttempts: WeakMap<HTMLAudioElement, number> = new WeakMap();
|
|
34
36
|
|
|
35
|
-
const loadTimeouts: WeakMap<HTMLAudioElement, number> = new WeakMap();
|
|
36
|
-
|
|
37
37
|
/**
|
|
38
38
|
* Subscribes to audio error events for a specific channel
|
|
39
39
|
* @param channelNumber - The channel number to listen to (defaults to 0)
|
|
@@ -143,10 +143,10 @@ export const getRetryConfig = (): RetryConfig => {
|
|
|
143
143
|
* ```typescript
|
|
144
144
|
* setErrorRecovery({
|
|
145
145
|
* autoRetry: true,
|
|
146
|
-
*
|
|
146
|
+
* fallbackToNextTrack: true,
|
|
147
147
|
* logErrorsToAnalytics: true,
|
|
148
148
|
* preserveQueueOnError: true,
|
|
149
|
-
*
|
|
149
|
+
* showUserFeedback: true
|
|
150
150
|
* });
|
|
151
151
|
* ```
|
|
152
152
|
*/
|
|
@@ -247,14 +247,11 @@ export const emitAudioError = (
|
|
|
247
247
|
* @returns The categorized error type
|
|
248
248
|
* @internal
|
|
249
249
|
*/
|
|
250
|
-
export const categorizeError = (
|
|
251
|
-
error: Error,
|
|
252
|
-
audio: HTMLAudioElement
|
|
253
|
-
): AudioErrorInfo['errorType'] => {
|
|
250
|
+
export const categorizeError = (error: Error, audio: HTMLAudioElement): AudioErrorType => {
|
|
254
251
|
const errorMessage = error.message.toLowerCase();
|
|
255
252
|
|
|
256
253
|
if (errorMessage.includes('network') || errorMessage.includes('fetch')) {
|
|
257
|
-
return
|
|
254
|
+
return AudioErrorType.Network;
|
|
258
255
|
}
|
|
259
256
|
|
|
260
257
|
// Check for unsupported format first (more specific than decode)
|
|
@@ -263,35 +260,35 @@ export const categorizeError = (
|
|
|
263
260
|
errorMessage.includes('unsupported') ||
|
|
264
261
|
errorMessage.includes('format not supported')
|
|
265
262
|
) {
|
|
266
|
-
return
|
|
263
|
+
return AudioErrorType.Unsupported;
|
|
267
264
|
}
|
|
268
265
|
|
|
269
266
|
if (errorMessage.includes('decode') || errorMessage.includes('format')) {
|
|
270
|
-
return
|
|
267
|
+
return AudioErrorType.Decode;
|
|
271
268
|
}
|
|
272
269
|
|
|
273
270
|
if (errorMessage.includes('permission') || errorMessage.includes('blocked')) {
|
|
274
|
-
return
|
|
271
|
+
return AudioErrorType.Permission;
|
|
275
272
|
}
|
|
276
273
|
|
|
277
274
|
if (errorMessage.includes('abort')) {
|
|
278
|
-
return
|
|
275
|
+
return AudioErrorType.Abort;
|
|
279
276
|
}
|
|
280
277
|
|
|
281
278
|
if (errorMessage.includes('timeout')) {
|
|
282
|
-
return
|
|
279
|
+
return AudioErrorType.Timeout;
|
|
283
280
|
}
|
|
284
281
|
|
|
285
282
|
// Check audio element network state for more context
|
|
286
283
|
if (audio.networkState === HTMLMediaElement.NETWORK_NO_SOURCE) {
|
|
287
|
-
return
|
|
284
|
+
return AudioErrorType.Network;
|
|
288
285
|
}
|
|
289
286
|
|
|
290
287
|
if (audio.networkState === HTMLMediaElement.NETWORK_LOADING) {
|
|
291
|
-
return
|
|
288
|
+
return AudioErrorType.Timeout;
|
|
292
289
|
}
|
|
293
290
|
|
|
294
|
-
return
|
|
291
|
+
return AudioErrorType.Unknown;
|
|
295
292
|
};
|
|
296
293
|
|
|
297
294
|
/**
|
|
@@ -311,42 +308,8 @@ export const setupAudioErrorHandling = (
|
|
|
311
308
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
312
309
|
if (!channel) return;
|
|
313
310
|
|
|
314
|
-
// Set up loading timeout with test environment compatibility
|
|
315
|
-
let timeoutId: number;
|
|
316
|
-
if (typeof setTimeout !== 'undefined') {
|
|
317
|
-
timeoutId = setTimeout(() => {
|
|
318
|
-
if (audio.networkState === HTMLMediaElement.NETWORK_LOADING) {
|
|
319
|
-
const timeoutError = new Error(
|
|
320
|
-
`Audio loading timeout after ${globalRetryConfig.timeoutMs}ms`
|
|
321
|
-
);
|
|
322
|
-
handleAudioError(audio, channelNumber, originalUrl, timeoutError);
|
|
323
|
-
}
|
|
324
|
-
}, globalRetryConfig.timeoutMs) as unknown as number;
|
|
325
|
-
|
|
326
|
-
loadTimeouts.set(audio, timeoutId);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Clear timeout when metadata loads successfully
|
|
330
|
-
const handleLoadSuccess = (): void => {
|
|
331
|
-
if (typeof setTimeout !== 'undefined') {
|
|
332
|
-
const timeoutId = loadTimeouts.get(audio);
|
|
333
|
-
if (timeoutId) {
|
|
334
|
-
clearTimeout(timeoutId);
|
|
335
|
-
loadTimeouts.delete(audio);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
311
|
// Handle various error events
|
|
341
312
|
const handleError = (_event: Event): void => {
|
|
342
|
-
if (typeof setTimeout !== 'undefined') {
|
|
343
|
-
const timeoutId = loadTimeouts.get(audio);
|
|
344
|
-
if (timeoutId) {
|
|
345
|
-
clearTimeout(timeoutId);
|
|
346
|
-
loadTimeouts.delete(audio);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
313
|
const error = new Error(`Audio loading failed: ${audio.error?.message || 'Unknown error'}`);
|
|
351
314
|
handleAudioError(audio, channelNumber, originalUrl, error);
|
|
352
315
|
};
|
|
@@ -365,8 +328,6 @@ export const setupAudioErrorHandling = (
|
|
|
365
328
|
audio.addEventListener('error', handleError);
|
|
366
329
|
audio.addEventListener('abort', handleAbort);
|
|
367
330
|
audio.addEventListener('stalled', handleStall);
|
|
368
|
-
audio.addEventListener('loadedmetadata', handleLoadSuccess);
|
|
369
|
-
audio.addEventListener('canplay', handleLoadSuccess);
|
|
370
331
|
|
|
371
332
|
// Custom play error handling
|
|
372
333
|
if (onError) {
|
|
@@ -424,7 +385,7 @@ export const handleAudioError = async (
|
|
|
424
385
|
currentAttempts < retryConfig.maxRetries &&
|
|
425
386
|
globalErrorRecovery.autoRetry
|
|
426
387
|
) {
|
|
427
|
-
const delay = retryConfig.exponentialBackoff
|
|
388
|
+
const delay: number = retryConfig.exponentialBackoff
|
|
428
389
|
? retryConfig.baseDelay * Math.pow(2, currentAttempts)
|
|
429
390
|
: retryConfig.baseDelay;
|
|
430
391
|
|
|
@@ -482,21 +443,11 @@ export const createProtectedAudioElement = async (
|
|
|
482
443
|
const audio = new Audio();
|
|
483
444
|
|
|
484
445
|
return new Promise((resolve, reject) => {
|
|
485
|
-
const cleanup = (): void => {
|
|
486
|
-
const timeoutId = loadTimeouts.get(audio);
|
|
487
|
-
if (timeoutId) {
|
|
488
|
-
clearTimeout(timeoutId);
|
|
489
|
-
loadTimeouts.delete(audio);
|
|
490
|
-
}
|
|
491
|
-
};
|
|
492
|
-
|
|
493
446
|
const handleSuccess = (): void => {
|
|
494
|
-
cleanup();
|
|
495
447
|
resolve(audio);
|
|
496
448
|
};
|
|
497
449
|
|
|
498
450
|
const handleError = (error: Error): void => {
|
|
499
|
-
cleanup();
|
|
500
451
|
reject(error);
|
|
501
452
|
};
|
|
502
453
|
|
package/src/index.ts
CHANGED
|
@@ -60,19 +60,34 @@ export {
|
|
|
60
60
|
|
|
61
61
|
// Volume control and ducking functions
|
|
62
62
|
export {
|
|
63
|
+
cancelAllVolumeTransitions,
|
|
64
|
+
cancelVolumeTransition,
|
|
63
65
|
clearVolumeDucking,
|
|
64
|
-
fadeVolume,
|
|
65
66
|
getAllChannelsVolume,
|
|
66
67
|
getChannelVolume,
|
|
67
68
|
getFadeConfig,
|
|
68
69
|
setAllChannelsVolume,
|
|
69
70
|
setChannelVolume,
|
|
70
71
|
setVolumeDucking,
|
|
71
|
-
transitionVolume
|
|
72
|
-
cancelVolumeTransition,
|
|
73
|
-
cancelAllVolumeTransitions
|
|
72
|
+
transitionVolume
|
|
74
73
|
} from './volume';
|
|
75
74
|
|
|
75
|
+
// Web Audio API support functions
|
|
76
|
+
export {
|
|
77
|
+
cleanupWebAudioNodes,
|
|
78
|
+
createWebAudioNodes,
|
|
79
|
+
getAudioContext,
|
|
80
|
+
getWebAudioConfig,
|
|
81
|
+
getWebAudioSupport,
|
|
82
|
+
getWebAudioVolume,
|
|
83
|
+
isIOSDevice,
|
|
84
|
+
isWebAudioSupported,
|
|
85
|
+
resumeAudioContext,
|
|
86
|
+
setWebAudioConfig,
|
|
87
|
+
setWebAudioVolume,
|
|
88
|
+
shouldUseWebAudio
|
|
89
|
+
} from './web-audio';
|
|
90
|
+
|
|
76
91
|
// Audio information and progress tracking functions
|
|
77
92
|
export {
|
|
78
93
|
getAllChannelsInfo,
|
|
@@ -123,13 +138,23 @@ export type {
|
|
|
123
138
|
FadeConfig,
|
|
124
139
|
ProgressCallback,
|
|
125
140
|
QueueChangeCallback,
|
|
141
|
+
QueueConfig,
|
|
126
142
|
QueueItem,
|
|
127
143
|
QueueManipulationResult,
|
|
128
144
|
QueueSnapshot,
|
|
129
145
|
RetryConfig,
|
|
130
146
|
VolumeConfig,
|
|
131
|
-
|
|
147
|
+
WebAudioConfig,
|
|
148
|
+
WebAudioNodeSet,
|
|
149
|
+
WebAudioSupport
|
|
132
150
|
} from './types';
|
|
133
151
|
|
|
134
152
|
// Enums and constants
|
|
135
|
-
export {
|
|
153
|
+
export {
|
|
154
|
+
AudioErrorType,
|
|
155
|
+
EasingType,
|
|
156
|
+
FadeType,
|
|
157
|
+
MAX_CHANNELS,
|
|
158
|
+
TimerType,
|
|
159
|
+
GLOBAL_PROGRESS_KEY
|
|
160
|
+
} from './types';
|
package/src/info.ts
CHANGED
|
@@ -351,13 +351,14 @@ export const onQueueChange = (channelNumber: number, callback: QueueChangeCallba
|
|
|
351
351
|
|
|
352
352
|
/**
|
|
353
353
|
* Removes queue change listeners for a specific channel
|
|
354
|
-
* @param channelNumber - The channel number
|
|
354
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
355
355
|
* @example
|
|
356
356
|
* ```typescript
|
|
357
|
-
* offQueueChange(
|
|
357
|
+
* offQueueChange(); // Stop receiving queue change notifications for default channel (0)
|
|
358
|
+
* offQueueChange(1); // Stop receiving queue change notifications for channel 1
|
|
358
359
|
* ```
|
|
359
360
|
*/
|
|
360
|
-
export const offQueueChange = (channelNumber: number): void => {
|
|
361
|
+
export const offQueueChange = (channelNumber: number = 0): void => {
|
|
361
362
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
362
363
|
if (!channel?.queueChangeCallbacks) return;
|
|
363
364
|
|
|
@@ -524,13 +525,14 @@ export const onAudioResume = (channelNumber: number, callback: AudioResumeCallba
|
|
|
524
525
|
|
|
525
526
|
/**
|
|
526
527
|
* Removes pause event listeners for a specific channel
|
|
527
|
-
* @param channelNumber - The channel number
|
|
528
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
528
529
|
* @example
|
|
529
530
|
* ```typescript
|
|
530
|
-
* offAudioPause(
|
|
531
|
+
* offAudioPause(); // Stop receiving pause notifications for default channel (0)
|
|
532
|
+
* offAudioPause(1); // Stop receiving pause notifications for channel 1
|
|
531
533
|
* ```
|
|
532
534
|
*/
|
|
533
|
-
export const offAudioPause = (channelNumber: number): void => {
|
|
535
|
+
export const offAudioPause = (channelNumber: number = 0): void => {
|
|
534
536
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
535
537
|
if (!channel?.audioPauseCallbacks) return;
|
|
536
538
|
|
|
@@ -539,13 +541,14 @@ export const offAudioPause = (channelNumber: number): void => {
|
|
|
539
541
|
|
|
540
542
|
/**
|
|
541
543
|
* Removes resume event listeners for a specific channel
|
|
542
|
-
* @param channelNumber - The channel number
|
|
544
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
543
545
|
* @example
|
|
544
546
|
* ```typescript
|
|
545
|
-
* offAudioResume(
|
|
547
|
+
* offAudioResume(); // Stop receiving resume notifications for default channel (0)
|
|
548
|
+
* offAudioResume(1); // Stop receiving resume notifications for channel 1
|
|
546
549
|
* ```
|
|
547
550
|
*/
|
|
548
|
-
export const offAudioResume = (channelNumber: number): void => {
|
|
551
|
+
export const offAudioResume = (channelNumber: number = 0): void => {
|
|
549
552
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
550
553
|
if (!channel?.audioResumeCallbacks) return;
|
|
551
554
|
|
|
@@ -554,13 +557,14 @@ export const offAudioResume = (channelNumber: number): void => {
|
|
|
554
557
|
|
|
555
558
|
/**
|
|
556
559
|
* Removes audio start event listeners for a specific channel
|
|
557
|
-
* @param channelNumber - The channel number
|
|
560
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
558
561
|
* @example
|
|
559
562
|
* ```typescript
|
|
560
|
-
* offAudioStart(
|
|
563
|
+
* offAudioStart(); // Stop receiving start notifications for default channel (0)
|
|
564
|
+
* offAudioStart(1); // Stop receiving start notifications for channel 1
|
|
561
565
|
* ```
|
|
562
566
|
*/
|
|
563
|
-
export const offAudioStart = (channelNumber: number): void => {
|
|
567
|
+
export const offAudioStart = (channelNumber: number = 0): void => {
|
|
564
568
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
565
569
|
if (!channel?.audioStartCallbacks) return;
|
|
566
570
|
|
|
@@ -569,13 +573,14 @@ export const offAudioStart = (channelNumber: number): void => {
|
|
|
569
573
|
|
|
570
574
|
/**
|
|
571
575
|
* Removes audio complete event listeners for a specific channel
|
|
572
|
-
* @param channelNumber - The channel number
|
|
576
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
573
577
|
* @example
|
|
574
578
|
* ```typescript
|
|
575
|
-
* offAudioComplete(
|
|
579
|
+
* offAudioComplete(); // Stop receiving completion notifications for default channel (0)
|
|
580
|
+
* offAudioComplete(1); // Stop receiving completion notifications for channel 1
|
|
576
581
|
* ```
|
|
577
582
|
*/
|
|
578
|
-
export const offAudioComplete = (channelNumber: number): void => {
|
|
583
|
+
export const offAudioComplete = (channelNumber: number = 0): void => {
|
|
579
584
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
580
585
|
if (!channel?.audioCompleteCallbacks) return;
|
|
581
586
|
|
package/src/types.ts
CHANGED
|
@@ -29,15 +29,15 @@ export interface AudioQueueChannel {
|
|
|
29
29
|
* Volume ducking configuration for channels
|
|
30
30
|
*/
|
|
31
31
|
export interface VolumeConfig {
|
|
32
|
+
/** Duration in milliseconds for volume duck transition (defaults to 250ms) */
|
|
33
|
+
duckTransitionDuration?: number;
|
|
34
|
+
/** Volume level for all other channels when priority channel is active (0-1) */
|
|
35
|
+
duckingVolume: number;
|
|
32
36
|
/** The channel number that should have priority */
|
|
33
37
|
priorityChannel: number;
|
|
34
38
|
/** Volume level for the priority channel (0-1) */
|
|
35
39
|
priorityVolume: number;
|
|
36
|
-
/**
|
|
37
|
-
duckingVolume: number;
|
|
38
|
-
/** Duration in milliseconds for volume duck transition (defaults to 250ms) */
|
|
39
|
-
duckTransitionDuration?: number;
|
|
40
|
-
/** Duration in milliseconds for volume restore transition (defaults to 500ms) */
|
|
40
|
+
/** Duration in milliseconds for volume restore transition (defaults to 250ms) */
|
|
41
41
|
restoreTransitionDuration?: number;
|
|
42
42
|
/** Easing function for volume transitions (defaults to 'ease-out') */
|
|
43
43
|
transitionEasing?: EasingType;
|
|
@@ -53,8 +53,6 @@ export interface AudioQueueOptions {
|
|
|
53
53
|
loop?: boolean;
|
|
54
54
|
/** Maximum number of items allowed in the queue (defaults to unlimited) */
|
|
55
55
|
maxQueueSize?: number;
|
|
56
|
-
/** @deprecated Use addToFront instead. Legacy support for priority queuing */
|
|
57
|
-
priority?: boolean;
|
|
58
56
|
/** Volume level for this specific audio (0-1) */
|
|
59
57
|
volume?: number;
|
|
60
58
|
}
|
|
@@ -212,41 +210,74 @@ export type AudioPauseCallback = (channelNumber: number, audioInfo: AudioInfo) =
|
|
|
212
210
|
export type AudioResumeCallback = (channelNumber: number, audioInfo: AudioInfo) => void;
|
|
213
211
|
|
|
214
212
|
/**
|
|
215
|
-
*
|
|
213
|
+
* Types of audio errors that can occur during playback
|
|
214
|
+
*/
|
|
215
|
+
export enum AudioErrorType {
|
|
216
|
+
Abort = 'abort',
|
|
217
|
+
Decode = 'decode',
|
|
218
|
+
Network = 'network',
|
|
219
|
+
Permission = 'permission',
|
|
220
|
+
Timeout = 'timeout',
|
|
221
|
+
Unknown = 'unknown',
|
|
222
|
+
Unsupported = 'unsupported'
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Information about an audio error that occurred during playback or loading
|
|
216
227
|
*/
|
|
217
228
|
export interface AudioErrorInfo {
|
|
229
|
+
/** Channel number where the error occurred */
|
|
218
230
|
channelNumber: number;
|
|
219
|
-
|
|
220
|
-
fileName: string;
|
|
231
|
+
/** The actual error object that was thrown */
|
|
221
232
|
error: Error;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
233
|
+
/** Categorized type of error for handling different scenarios */
|
|
234
|
+
errorType: AudioErrorType;
|
|
235
|
+
/** Extracted filename from the source URL */
|
|
236
|
+
fileName: string;
|
|
237
|
+
/** Number of audio files remaining in the queue after this error */
|
|
225
238
|
remainingInQueue: number;
|
|
239
|
+
/** Current retry attempt number (if retrying is enabled) */
|
|
240
|
+
retryAttempt?: number;
|
|
241
|
+
/** Audio file source URL that failed */
|
|
242
|
+
src: string;
|
|
243
|
+
/** Unix timestamp when the error occurred */
|
|
244
|
+
timestamp: number;
|
|
226
245
|
}
|
|
227
246
|
|
|
228
247
|
/**
|
|
229
248
|
* Configuration for automatic retry behavior when audio fails to load or play
|
|
230
249
|
*/
|
|
231
250
|
export interface RetryConfig {
|
|
232
|
-
|
|
233
|
-
maxRetries: number;
|
|
251
|
+
/** Initial delay in milliseconds before first retry attempt */
|
|
234
252
|
baseDelay: number;
|
|
253
|
+
/** Whether automatic retries are enabled for this channel */
|
|
254
|
+
enabled: boolean;
|
|
255
|
+
/** Whether to use exponential backoff (doubling delay each retry) */
|
|
235
256
|
exponentialBackoff: boolean;
|
|
236
|
-
|
|
237
|
-
fallbackUrls
|
|
257
|
+
/** Alternative URLs to try if the primary source fails */
|
|
258
|
+
fallbackUrls: string[];
|
|
259
|
+
/** Maximum number of retry attempts before giving up */
|
|
260
|
+
maxRetries: number;
|
|
261
|
+
/** Whether to skip to next track in queue if all retries fail */
|
|
238
262
|
skipOnFailure: boolean;
|
|
263
|
+
/** Timeout in milliseconds for each individual retry attempt */
|
|
264
|
+
timeoutMs: number;
|
|
239
265
|
}
|
|
240
266
|
|
|
241
267
|
/**
|
|
242
|
-
* Configuration options for error recovery mechanisms
|
|
268
|
+
* Configuration options for error recovery mechanisms across the audio system
|
|
243
269
|
*/
|
|
244
270
|
export interface ErrorRecoveryOptions {
|
|
271
|
+
/** Whether to automatically retry failed audio loads/plays */
|
|
245
272
|
autoRetry: boolean;
|
|
246
|
-
|
|
273
|
+
/** Whether to automatically skip to next track when current fails */
|
|
274
|
+
fallbackToNextTrack: boolean;
|
|
275
|
+
/** Whether to send error data to analytics systems */
|
|
247
276
|
logErrorsToAnalytics: boolean;
|
|
277
|
+
/** Whether to maintain queue integrity when errors occur */
|
|
248
278
|
preserveQueueOnError: boolean;
|
|
249
|
-
|
|
279
|
+
/** Whether to display user-visible error feedback */
|
|
280
|
+
showUserFeedback: boolean;
|
|
250
281
|
}
|
|
251
282
|
|
|
252
283
|
/**
|
|
@@ -255,29 +286,81 @@ export interface ErrorRecoveryOptions {
|
|
|
255
286
|
export type AudioErrorCallback = (errorInfo: AudioErrorInfo) => void;
|
|
256
287
|
|
|
257
288
|
/**
|
|
258
|
-
*
|
|
289
|
+
* Web Audio API configuration options
|
|
290
|
+
*/
|
|
291
|
+
export interface WebAudioConfig {
|
|
292
|
+
/** Whether to automatically use Web Audio API on iOS devices */
|
|
293
|
+
autoDetectIOS: boolean;
|
|
294
|
+
/** Whether Web Audio API support is enabled */
|
|
295
|
+
enabled: boolean;
|
|
296
|
+
/** Whether to force Web Audio API usage on all devices */
|
|
297
|
+
forceWebAudio: boolean;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Web Audio API support information
|
|
302
|
+
*/
|
|
303
|
+
export interface WebAudioSupport {
|
|
304
|
+
/** Whether Web Audio API is available in the current environment */
|
|
305
|
+
available: boolean;
|
|
306
|
+
/** Whether the current device is iOS */
|
|
307
|
+
isIOS: boolean;
|
|
308
|
+
/** Whether Web Audio API is currently being used */
|
|
309
|
+
usingWebAudio: boolean;
|
|
310
|
+
/** Reason for current Web Audio API usage state */
|
|
311
|
+
reason: string;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Web Audio API node set for audio element control
|
|
316
|
+
*/
|
|
317
|
+
export interface WebAudioNodeSet {
|
|
318
|
+
/** Gain node for volume control */
|
|
319
|
+
gainNode: GainNode;
|
|
320
|
+
/** Media element source node */
|
|
321
|
+
sourceNode: MediaElementAudioSourceNode;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Extended audio channel with comprehensive queue management, callback support, and state tracking
|
|
259
326
|
*/
|
|
260
327
|
export interface ExtendedAudioQueueChannel {
|
|
328
|
+
/** Set of callbacks triggered when audio completes playback */
|
|
261
329
|
audioCompleteCallbacks: Set<AudioCompleteCallback>;
|
|
330
|
+
/** Set of callbacks triggered when audio errors occur */
|
|
262
331
|
audioErrorCallbacks: Set<AudioErrorCallback>;
|
|
332
|
+
/** Set of callbacks triggered when audio is paused */
|
|
263
333
|
audioPauseCallbacks: Set<AudioPauseCallback>;
|
|
334
|
+
/** Set of callbacks triggered when audio is resumed */
|
|
264
335
|
audioResumeCallbacks: Set<AudioResumeCallback>;
|
|
336
|
+
/** Set of callbacks triggered when audio starts playing */
|
|
265
337
|
audioStartCallbacks: Set<AudioStartCallback>;
|
|
338
|
+
/** Current fade state if pause/resume with fade is active */
|
|
266
339
|
fadeState?: ChannelFadeState;
|
|
340
|
+
/** Whether the channel is currently paused */
|
|
267
341
|
isPaused: boolean;
|
|
268
342
|
/** Active operation lock to prevent race conditions */
|
|
269
343
|
isLocked?: boolean;
|
|
270
344
|
/** Maximum allowed queue size for this channel */
|
|
271
345
|
maxQueueSize?: number;
|
|
346
|
+
/** Map of progress callbacks keyed by audio element or global symbol */
|
|
272
347
|
progressCallbacks: Map<HTMLAudioElement | typeof GLOBAL_PROGRESS_KEY, Set<ProgressCallback>>;
|
|
348
|
+
/** Array of HTMLAudioElement objects in the queue */
|
|
273
349
|
queue: HTMLAudioElement[];
|
|
350
|
+
/** Set of callbacks triggered when the queue changes */
|
|
274
351
|
queueChangeCallbacks: Set<QueueChangeCallback>;
|
|
352
|
+
/** Retry configuration for failed audio loads/plays */
|
|
275
353
|
retryConfig?: RetryConfig;
|
|
354
|
+
/** Current volume level for the channel (0-1) */
|
|
276
355
|
volume: number;
|
|
356
|
+
/** Web Audio API context for this channel */
|
|
357
|
+
webAudioContext?: AudioContext;
|
|
358
|
+
/** Map of Web Audio API nodes for each audio element */
|
|
359
|
+
webAudioNodes?: Map<HTMLAudioElement, WebAudioNodeSet>;
|
|
277
360
|
}
|
|
278
361
|
|
|
279
362
|
/**
|
|
280
|
-
* Easing function types for volume transitions
|
|
363
|
+
* Easing function types for smooth volume transitions and animations
|
|
281
364
|
*/
|
|
282
365
|
export enum EasingType {
|
|
283
366
|
Linear = 'linear',
|
|
@@ -287,7 +370,7 @@ export enum EasingType {
|
|
|
287
370
|
}
|
|
288
371
|
|
|
289
372
|
/**
|
|
290
|
-
*
|
|
373
|
+
* Predefined fade types for pause/resume operations with different transition characteristics
|
|
291
374
|
*/
|
|
292
375
|
export enum FadeType {
|
|
293
376
|
Linear = 'linear',
|
|
@@ -296,7 +379,7 @@ export enum FadeType {
|
|
|
296
379
|
}
|
|
297
380
|
|
|
298
381
|
/**
|
|
299
|
-
* Timer types for volume transitions to ensure proper cleanup
|
|
382
|
+
* Timer implementation types used for volume transitions to ensure proper cleanup
|
|
300
383
|
*/
|
|
301
384
|
export enum TimerType {
|
|
302
385
|
RequestAnimationFrame = 'raf',
|