audio-channel-queue 1.5.0 → 1.7.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/errors.js ADDED
@@ -0,0 +1,461 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Error handling, retry logic, and recovery mechanisms for the audio-channel-queue package
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || function (mod) {
22
+ if (mod && mod.__esModule) return mod;
23
+ var result = {};
24
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
25
+ __setModuleDefault(result, mod);
26
+ return result;
27
+ };
28
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
29
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30
+ return new (P || (P = Promise))(function (resolve, reject) {
31
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
35
+ });
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.createProtectedAudioElement = exports.handleAudioError = exports.setupAudioErrorHandling = exports.categorizeError = exports.emitAudioError = exports.retryFailedAudio = exports.getErrorRecovery = exports.setErrorRecovery = exports.getRetryConfig = exports.setRetryConfig = exports.offAudioError = exports.onAudioError = void 0;
39
+ const info_1 = require("./info");
40
+ const utils_1 = require("./utils");
41
+ let globalRetryConfig = {
42
+ enabled: true,
43
+ maxRetries: 3,
44
+ baseDelay: 1000,
45
+ exponentialBackoff: true,
46
+ timeoutMs: 10000,
47
+ skipOnFailure: false
48
+ };
49
+ let globalErrorRecovery = {
50
+ autoRetry: true,
51
+ showUserFeedback: false,
52
+ logErrorsToAnalytics: false,
53
+ preserveQueueOnError: true,
54
+ fallbackToNextTrack: true
55
+ };
56
+ const retryAttempts = new WeakMap();
57
+ const loadTimeouts = new WeakMap();
58
+ /**
59
+ * Subscribes to audio error events for a specific channel
60
+ * @param channelNumber - The channel number to listen to (defaults to 0)
61
+ * @param callback - Function to call when an audio error occurs
62
+ * @example
63
+ * ```typescript
64
+ * onAudioError(0, (errorInfo) => {
65
+ * console.log(`Audio error: ${errorInfo.error.message}`);
66
+ * console.log(`Error type: ${errorInfo.errorType}`);
67
+ * });
68
+ * ```
69
+ */
70
+ const onAudioError = (channelNumber = 0, callback) => {
71
+ // Ensure channel exists
72
+ while (info_1.audioChannels.length <= channelNumber) {
73
+ info_1.audioChannels.push({
74
+ audioCompleteCallbacks: new Set(),
75
+ audioErrorCallbacks: new Set(),
76
+ audioPauseCallbacks: new Set(),
77
+ audioResumeCallbacks: new Set(),
78
+ audioStartCallbacks: new Set(),
79
+ isPaused: false,
80
+ progressCallbacks: new Map(),
81
+ queue: [],
82
+ queueChangeCallbacks: new Set(),
83
+ volume: 1.0
84
+ });
85
+ }
86
+ const channel = info_1.audioChannels[channelNumber];
87
+ if (!channel.audioErrorCallbacks) {
88
+ channel.audioErrorCallbacks = new Set();
89
+ }
90
+ channel.audioErrorCallbacks.add(callback);
91
+ };
92
+ exports.onAudioError = onAudioError;
93
+ /**
94
+ * Unsubscribes from audio error events for a specific channel
95
+ * @param channelNumber - The channel number to stop listening to (defaults to 0)
96
+ * @param callback - The specific callback to remove (optional - if not provided, removes all)
97
+ * @example
98
+ * ```typescript
99
+ * offAudioError(0); // Remove all error callbacks for channel 0
100
+ * offAudioError(0, specificCallback); // Remove specific callback
101
+ * ```
102
+ */
103
+ const offAudioError = (channelNumber = 0, callback) => {
104
+ const channel = info_1.audioChannels[channelNumber];
105
+ if (!(channel === null || channel === void 0 ? void 0 : channel.audioErrorCallbacks))
106
+ return;
107
+ if (callback) {
108
+ channel.audioErrorCallbacks.delete(callback);
109
+ }
110
+ else {
111
+ channel.audioErrorCallbacks.clear();
112
+ }
113
+ };
114
+ exports.offAudioError = offAudioError;
115
+ /**
116
+ * Sets the global retry configuration for audio loading failures
117
+ * @param config - Retry configuration options
118
+ * @example
119
+ * ```typescript
120
+ * setRetryConfig({
121
+ * enabled: true,
122
+ * maxRetries: 5,
123
+ * baseDelay: 1000,
124
+ * exponentialBackoff: true,
125
+ * timeoutMs: 15000,
126
+ * fallbackUrls: ['https://cdn.backup.com/audio/'],
127
+ * skipOnFailure: true
128
+ * });
129
+ * ```
130
+ */
131
+ const setRetryConfig = (config) => {
132
+ globalRetryConfig = Object.assign(Object.assign({}, globalRetryConfig), config);
133
+ };
134
+ exports.setRetryConfig = setRetryConfig;
135
+ /**
136
+ * Gets the current global retry configuration
137
+ * @returns Current retry configuration
138
+ * @example
139
+ * ```typescript
140
+ * const config = getRetryConfig();
141
+ * console.log(`Max retries: ${config.maxRetries}`);
142
+ * ```
143
+ */
144
+ const getRetryConfig = () => {
145
+ return Object.assign({}, globalRetryConfig);
146
+ };
147
+ exports.getRetryConfig = getRetryConfig;
148
+ /**
149
+ * Sets the global error recovery configuration
150
+ * @param options - Error recovery options
151
+ * @example
152
+ * ```typescript
153
+ * setErrorRecovery({
154
+ * autoRetry: true,
155
+ * showUserFeedback: true,
156
+ * logErrorsToAnalytics: true,
157
+ * preserveQueueOnError: true,
158
+ * fallbackToNextTrack: true
159
+ * });
160
+ * ```
161
+ */
162
+ const setErrorRecovery = (options) => {
163
+ globalErrorRecovery = Object.assign(Object.assign({}, globalErrorRecovery), options);
164
+ };
165
+ exports.setErrorRecovery = setErrorRecovery;
166
+ /**
167
+ * Gets the current global error recovery configuration
168
+ * @returns Current error recovery configuration
169
+ * @example
170
+ * ```typescript
171
+ * const recovery = getErrorRecovery();
172
+ * console.log(`Auto retry enabled: ${recovery.autoRetry}`);
173
+ * ```
174
+ */
175
+ const getErrorRecovery = () => {
176
+ return Object.assign({}, globalErrorRecovery);
177
+ };
178
+ exports.getErrorRecovery = getErrorRecovery;
179
+ /**
180
+ * Manually retries loading failed audio for a specific channel
181
+ * @param channelNumber - The channel number to retry (defaults to 0)
182
+ * @returns Promise that resolves to true if retry was successful, false otherwise
183
+ * @example
184
+ * ```typescript
185
+ * const success = await retryFailedAudio(0);
186
+ * if (success) {
187
+ * console.log('Audio retry successful');
188
+ * } else {
189
+ * console.log('Audio retry failed');
190
+ * }
191
+ * ```
192
+ */
193
+ const retryFailedAudio = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (channelNumber = 0) {
194
+ const channel = info_1.audioChannels[channelNumber];
195
+ if (!channel || channel.queue.length === 0)
196
+ return false;
197
+ const currentAudio = channel.queue[0];
198
+ const currentAttempts = retryAttempts.get(currentAudio) || 0;
199
+ if (currentAttempts >= globalRetryConfig.maxRetries) {
200
+ return false;
201
+ }
202
+ try {
203
+ // Reset the audio element
204
+ currentAudio.currentTime = 0;
205
+ yield currentAudio.play();
206
+ // Reset retry counter on successful play
207
+ retryAttempts.delete(currentAudio);
208
+ return true;
209
+ }
210
+ catch (error) {
211
+ // Increment retry counter
212
+ retryAttempts.set(currentAudio, currentAttempts + 1);
213
+ return false;
214
+ }
215
+ });
216
+ exports.retryFailedAudio = retryFailedAudio;
217
+ /**
218
+ * Emits an audio error event to all registered listeners for a specific channel
219
+ * @param channelNumber - The channel number where the error occurred
220
+ * @param errorInfo - Information about the error
221
+ * @param audioChannels - Array of audio channels
222
+ * @internal
223
+ */
224
+ const emitAudioError = (channelNumber, errorInfo, audioChannels) => {
225
+ const channel = audioChannels[channelNumber];
226
+ if (!(channel === null || channel === void 0 ? void 0 : channel.audioErrorCallbacks))
227
+ return;
228
+ // Log to analytics if enabled
229
+ if (globalErrorRecovery.logErrorsToAnalytics) {
230
+ console.warn('Audio Error Analytics:', errorInfo);
231
+ }
232
+ channel.audioErrorCallbacks.forEach(callback => {
233
+ try {
234
+ callback(errorInfo);
235
+ }
236
+ catch (error) {
237
+ console.error('Error in audio error callback:', error);
238
+ }
239
+ });
240
+ };
241
+ exports.emitAudioError = emitAudioError;
242
+ /**
243
+ * Determines the error type based on the error object and context
244
+ * @param error - The error that occurred
245
+ * @param audio - The audio element that failed
246
+ * @returns The categorized error type
247
+ * @internal
248
+ */
249
+ const categorizeError = (error, audio) => {
250
+ const errorMessage = error.message.toLowerCase();
251
+ if (errorMessage.includes('network') || errorMessage.includes('fetch')) {
252
+ return 'network';
253
+ }
254
+ // Check for unsupported format first (more specific than decode)
255
+ if (errorMessage.includes('not supported') || errorMessage.includes('unsupported') ||
256
+ errorMessage.includes('format not supported')) {
257
+ return 'unsupported';
258
+ }
259
+ if (errorMessage.includes('decode') || errorMessage.includes('format')) {
260
+ return 'decode';
261
+ }
262
+ if (errorMessage.includes('permission') || errorMessage.includes('blocked')) {
263
+ return 'permission';
264
+ }
265
+ if (errorMessage.includes('abort')) {
266
+ return 'abort';
267
+ }
268
+ if (errorMessage.includes('timeout')) {
269
+ return 'timeout';
270
+ }
271
+ // Check audio element network state for more context
272
+ if (audio.networkState === HTMLMediaElement.NETWORK_NO_SOURCE) {
273
+ return 'network';
274
+ }
275
+ if (audio.networkState === HTMLMediaElement.NETWORK_LOADING) {
276
+ return 'timeout';
277
+ }
278
+ return 'unknown';
279
+ };
280
+ exports.categorizeError = categorizeError;
281
+ /**
282
+ * Sets up comprehensive error handling for an audio element
283
+ * @param audio - The audio element to set up error handling for
284
+ * @param channelNumber - The channel number this audio belongs to
285
+ * @param originalUrl - The original URL that was requested
286
+ * @param onError - Callback for when an error occurs
287
+ * @internal
288
+ */
289
+ const setupAudioErrorHandling = (audio, channelNumber, originalUrl, onError) => {
290
+ const channel = info_1.audioChannels[channelNumber];
291
+ if (!channel)
292
+ return;
293
+ // Set up loading timeout with test environment compatibility
294
+ let timeoutId;
295
+ if (typeof setTimeout !== 'undefined') {
296
+ timeoutId = setTimeout(() => {
297
+ if (audio.networkState === HTMLMediaElement.NETWORK_LOADING) {
298
+ const timeoutError = new Error(`Audio loading timeout after ${globalRetryConfig.timeoutMs}ms`);
299
+ (0, exports.handleAudioError)(audio, channelNumber, originalUrl, timeoutError);
300
+ }
301
+ }, globalRetryConfig.timeoutMs);
302
+ loadTimeouts.set(audio, timeoutId);
303
+ }
304
+ // Clear timeout when metadata loads successfully
305
+ const handleLoadSuccess = () => {
306
+ if (typeof setTimeout !== 'undefined') {
307
+ const timeoutId = loadTimeouts.get(audio);
308
+ if (timeoutId) {
309
+ clearTimeout(timeoutId);
310
+ loadTimeouts.delete(audio);
311
+ }
312
+ }
313
+ };
314
+ // Handle various error events
315
+ const handleError = (event) => {
316
+ var _a;
317
+ if (typeof setTimeout !== 'undefined') {
318
+ const timeoutId = loadTimeouts.get(audio);
319
+ if (timeoutId) {
320
+ clearTimeout(timeoutId);
321
+ loadTimeouts.delete(audio);
322
+ }
323
+ }
324
+ const error = new Error(`Audio loading failed: ${((_a = audio.error) === null || _a === void 0 ? void 0 : _a.message) || 'Unknown error'}`);
325
+ (0, exports.handleAudioError)(audio, channelNumber, originalUrl, error);
326
+ };
327
+ const handleAbort = () => {
328
+ const error = new Error('Audio loading was aborted');
329
+ (0, exports.handleAudioError)(audio, channelNumber, originalUrl, error);
330
+ };
331
+ const handleStall = () => {
332
+ const error = new Error('Audio loading stalled');
333
+ (0, exports.handleAudioError)(audio, channelNumber, originalUrl, error);
334
+ };
335
+ // Add event listeners
336
+ audio.addEventListener('error', handleError);
337
+ audio.addEventListener('abort', handleAbort);
338
+ audio.addEventListener('stalled', handleStall);
339
+ audio.addEventListener('loadedmetadata', handleLoadSuccess);
340
+ audio.addEventListener('canplay', handleLoadSuccess);
341
+ // Custom play error handling
342
+ if (onError) {
343
+ const originalPlay = audio.play.bind(audio);
344
+ const wrappedPlay = () => __awaiter(void 0, void 0, void 0, function* () {
345
+ try {
346
+ yield originalPlay();
347
+ }
348
+ catch (error) {
349
+ yield onError(error);
350
+ throw error;
351
+ }
352
+ });
353
+ audio.play = wrappedPlay;
354
+ }
355
+ };
356
+ exports.setupAudioErrorHandling = setupAudioErrorHandling;
357
+ /**
358
+ * Handles audio errors with retry logic and recovery mechanisms
359
+ * @param audio - The audio element that failed
360
+ * @param channelNumber - The channel number
361
+ * @param originalUrl - The original URL that was requested
362
+ * @param error - The error that occurred
363
+ * @internal
364
+ */
365
+ const handleAudioError = (audio, channelNumber, originalUrl, error) => __awaiter(void 0, void 0, void 0, function* () {
366
+ const channel = info_1.audioChannels[channelNumber];
367
+ if (!channel)
368
+ return;
369
+ const currentAttempts = retryAttempts.get(audio) || 0;
370
+ const retryConfig = channel.retryConfig || globalRetryConfig;
371
+ const errorInfo = {
372
+ channelNumber,
373
+ src: originalUrl,
374
+ fileName: (0, utils_1.extractFileName)(originalUrl),
375
+ error,
376
+ errorType: (0, exports.categorizeError)(error, audio),
377
+ timestamp: Date.now(),
378
+ retryAttempt: currentAttempts,
379
+ remainingInQueue: channel.queue.length - 1
380
+ };
381
+ // Emit error event
382
+ (0, exports.emitAudioError)(channelNumber, errorInfo, info_1.audioChannels);
383
+ // Attempt retry if enabled and within limits
384
+ if (retryConfig.enabled && currentAttempts < retryConfig.maxRetries && globalErrorRecovery.autoRetry) {
385
+ const delay = retryConfig.exponentialBackoff
386
+ ? retryConfig.baseDelay * Math.pow(2, currentAttempts)
387
+ : retryConfig.baseDelay;
388
+ retryAttempts.set(audio, currentAttempts + 1);
389
+ const retryFunction = () => __awaiter(void 0, void 0, void 0, function* () {
390
+ try {
391
+ // Try fallback URLs if available
392
+ if (retryConfig.fallbackUrls && retryConfig.fallbackUrls.length > 0) {
393
+ const fallbackIndex = currentAttempts % retryConfig.fallbackUrls.length;
394
+ const fallbackUrl = retryConfig.fallbackUrls[fallbackIndex] + (0, utils_1.extractFileName)(originalUrl);
395
+ audio.src = fallbackUrl;
396
+ }
397
+ yield audio.load();
398
+ yield audio.play();
399
+ // Reset retry counter on success
400
+ retryAttempts.delete(audio);
401
+ }
402
+ catch (retryError) {
403
+ yield (0, exports.handleAudioError)(audio, channelNumber, originalUrl, retryError);
404
+ }
405
+ });
406
+ setTimeout(retryFunction, delay);
407
+ }
408
+ else {
409
+ // Max retries reached or retry disabled
410
+ if (retryConfig.skipOnFailure || globalErrorRecovery.fallbackToNextTrack) {
411
+ // Skip to next track in queue
412
+ channel.queue.shift();
413
+ // Import and use playAudioQueue to continue with next track
414
+ const { playAudioQueue } = yield Promise.resolve().then(() => __importStar(require('./core')));
415
+ playAudioQueue(channelNumber).catch(console.error);
416
+ }
417
+ else if (!globalErrorRecovery.preserveQueueOnError) {
418
+ // Clear the entire queue on failure
419
+ channel.queue = [];
420
+ }
421
+ }
422
+ });
423
+ exports.handleAudioError = handleAudioError;
424
+ /**
425
+ * Creates a timeout-protected audio element with comprehensive error handling
426
+ * @param url - The audio URL to load
427
+ * @param channelNumber - The channel number this audio belongs to
428
+ * @returns Promise that resolves to the configured audio element
429
+ * @internal
430
+ */
431
+ const createProtectedAudioElement = (url, channelNumber) => __awaiter(void 0, void 0, void 0, function* () {
432
+ const audio = new Audio();
433
+ return new Promise((resolve, reject) => {
434
+ const cleanup = () => {
435
+ const timeoutId = loadTimeouts.get(audio);
436
+ if (timeoutId) {
437
+ clearTimeout(timeoutId);
438
+ loadTimeouts.delete(audio);
439
+ }
440
+ };
441
+ const handleSuccess = () => {
442
+ cleanup();
443
+ resolve(audio);
444
+ };
445
+ const handleError = (error) => {
446
+ cleanup();
447
+ reject(error);
448
+ };
449
+ // Set up error handling
450
+ (0, exports.setupAudioErrorHandling)(audio, channelNumber, url, (error) => __awaiter(void 0, void 0, void 0, function* () {
451
+ handleError(error);
452
+ }));
453
+ // Set up success handlers
454
+ audio.addEventListener('canplay', handleSuccess, { once: true });
455
+ audio.addEventListener('loadedmetadata', handleSuccess, { once: true });
456
+ // Start loading
457
+ audio.src = url;
458
+ audio.load();
459
+ });
460
+ });
461
+ exports.createProtectedAudioElement = createProtectedAudioElement;
package/dist/events.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @fileoverview Event handling and emission for the audio-channel-queue package
3
3
  */
4
- import { AudioStartInfo, AudioCompleteInfo, ExtendedAudioQueueChannel } from './types';
4
+ import { AudioStartInfo, AudioCompleteInfo, ExtendedAudioQueueChannel, AudioInfo } from './types';
5
5
  /**
6
6
  * Emits a queue change event to all registered listeners for a specific channel
7
7
  * @param channelNumber - The channel number that experienced a queue change
@@ -34,6 +34,28 @@ export declare const emitAudioStart: (channelNumber: number, audioInfo: AudioSta
34
34
  * ```
35
35
  */
36
36
  export declare const emitAudioComplete: (channelNumber: number, audioInfo: AudioCompleteInfo, audioChannels: ExtendedAudioQueueChannel[]) => void;
37
+ /**
38
+ * Emits an audio pause event to all registered listeners for a specific channel
39
+ * @param channelNumber - The channel number where audio was paused
40
+ * @param audioInfo - Information about the audio that was paused
41
+ * @param audioChannels - Array of audio channels
42
+ * @example
43
+ * ```typescript
44
+ * emitAudioPause(0, audioInfo, audioChannels);
45
+ * ```
46
+ */
47
+ export declare const emitAudioPause: (channelNumber: number, audioInfo: AudioInfo, audioChannels: ExtendedAudioQueueChannel[]) => void;
48
+ /**
49
+ * Emits an audio resume event to all registered listeners for a specific channel
50
+ * @param channelNumber - The channel number where audio was resumed
51
+ * @param audioInfo - Information about the audio that was resumed
52
+ * @param audioChannels - Array of audio channels
53
+ * @example
54
+ * ```typescript
55
+ * emitAudioResume(0, audioInfo, audioChannels);
56
+ * ```
57
+ */
58
+ export declare const emitAudioResume: (channelNumber: number, audioInfo: AudioInfo, audioChannels: ExtendedAudioQueueChannel[]) => void;
37
59
  /**
38
60
  * Sets up comprehensive progress tracking for an audio element
39
61
  * @param audio - The HTML audio element to track
package/dist/events.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * @fileoverview Event handling and emission for the audio-channel-queue package
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.cleanupProgressTracking = exports.setupProgressTracking = exports.emitAudioComplete = exports.emitAudioStart = exports.emitQueueChange = void 0;
6
+ exports.cleanupProgressTracking = exports.setupProgressTracking = exports.emitAudioResume = exports.emitAudioPause = exports.emitAudioComplete = exports.emitAudioStart = exports.emitQueueChange = void 0;
7
7
  const utils_1 = require("./utils");
8
8
  /**
9
9
  * Emits a queue change event to all registered listeners for a specific channel
@@ -79,6 +79,54 @@ const emitAudioComplete = (channelNumber, audioInfo, audioChannels) => {
79
79
  });
80
80
  };
81
81
  exports.emitAudioComplete = emitAudioComplete;
82
+ /**
83
+ * Emits an audio pause event to all registered listeners for a specific channel
84
+ * @param channelNumber - The channel number where audio was paused
85
+ * @param audioInfo - Information about the audio that was paused
86
+ * @param audioChannels - Array of audio channels
87
+ * @example
88
+ * ```typescript
89
+ * emitAudioPause(0, audioInfo, audioChannels);
90
+ * ```
91
+ */
92
+ const emitAudioPause = (channelNumber, audioInfo, audioChannels) => {
93
+ const channel = audioChannels[channelNumber];
94
+ if (!channel || !channel.audioPauseCallbacks)
95
+ return;
96
+ channel.audioPauseCallbacks.forEach(callback => {
97
+ try {
98
+ callback(channelNumber, audioInfo);
99
+ }
100
+ catch (error) {
101
+ console.error('Error in audio pause callback:', error);
102
+ }
103
+ });
104
+ };
105
+ exports.emitAudioPause = emitAudioPause;
106
+ /**
107
+ * Emits an audio resume event to all registered listeners for a specific channel
108
+ * @param channelNumber - The channel number where audio was resumed
109
+ * @param audioInfo - Information about the audio that was resumed
110
+ * @param audioChannels - Array of audio channels
111
+ * @example
112
+ * ```typescript
113
+ * emitAudioResume(0, audioInfo, audioChannels);
114
+ * ```
115
+ */
116
+ const emitAudioResume = (channelNumber, audioInfo, audioChannels) => {
117
+ const channel = audioChannels[channelNumber];
118
+ if (!channel || !channel.audioResumeCallbacks)
119
+ return;
120
+ channel.audioResumeCallbacks.forEach(callback => {
121
+ try {
122
+ callback(channelNumber, audioInfo);
123
+ }
124
+ catch (error) {
125
+ console.error('Error in audio resume callback:', error);
126
+ }
127
+ });
128
+ };
129
+ exports.emitAudioResume = emitAudioResume;
82
130
  // Store listener functions for cleanup
83
131
  const progressListeners = new WeakMap();
84
132
  /**
@@ -111,7 +159,7 @@ const setupProgressTracking = (audio, channelNumber, audioChannels) => {
111
159
  const allCallbacks = new Set([...audioCallbacks, ...channelCallbacks]);
112
160
  if (allCallbacks.size === 0)
113
161
  return;
114
- const info = (0, utils_1.getAudioInfoFromElement)(audio);
162
+ const info = (0, utils_1.getAudioInfoFromElement)(audio, channelNumber, audioChannels);
115
163
  if (info) {
116
164
  allCallbacks.forEach((callback) => {
117
165
  try {
package/dist/index.d.ts CHANGED
@@ -1,23 +1,13 @@
1
1
  /**
2
2
  * @fileoverview Main entry point for the audio-channel-queue package
3
- *
4
- * A comprehensive audio queue management system with real-time progress tracking,
5
- * multi-channel support, and extensive event handling capabilities.
6
- *
7
- * @example Basic Usage
8
- * ```typescript
9
- * import { queueAudio, onAudioProgress } from 'audio-channel-queue';
10
- *
11
- * // Queue an audio file
12
- * await queueAudio('song.mp3');
13
- *
14
- * // Track progress
15
- * onAudioProgress(0, (info) => {
16
- * console.log(`Progress: ${info.progress * 100}%`);
17
- * });
18
- * ```
3
+ * Exports all public functions and types for audio queue management, pause/resume controls,
4
+ * volume management with ducking, progress tracking, and comprehensive event system
19
5
  */
20
- export type { AudioCompleteCallback, AudioCompleteInfo, AudioInfo, AudioQueue, AudioQueueChannel, AudioStartCallback, AudioStartInfo, ExtendedAudioQueueChannel, ProgressCallback, QueueChangeCallback, QueueItem, QueueSnapshot } from './types';
21
- export { playAudioQueue, queueAudio, stopAllAudio, stopAllAudioInChannel, stopCurrentAudioInChannel } from './core';
22
- export { audioChannels, getAllChannelsInfo, getCurrentAudioInfo, getQueueSnapshot, offAudioProgress, onAudioComplete, onAudioProgress, onAudioStart, onQueueChange, offQueueChange } from './info';
6
+ export { queueAudio, queueAudioPriority, stopCurrentAudioInChannel, stopAllAudioInChannel, stopAllAudio, playAudioQueue } from './core';
7
+ export { getErrorRecovery, getRetryConfig, offAudioError, onAudioError, retryFailedAudio, setErrorRecovery, setRetryConfig, } from './errors';
8
+ export { getAllChannelsPauseState, isChannelPaused, pauseAllChannels, pauseChannel, resumeAllChannels, resumeChannel, togglePauseAllChannels, togglePauseChannel, } from './pause';
9
+ export { clearVolumeDucking, getAllChannelsVolume, getChannelVolume, setAllChannelsVolume, setChannelVolume, setVolumeDucking, } from './volume';
10
+ export { getAllChannelsInfo, getCurrentAudioInfo, getQueueSnapshot, offAudioPause, offAudioProgress, offAudioResume, offQueueChange, onAudioComplete, onAudioPause, onAudioProgress, onAudioResume, onAudioStart, onQueueChange, } from './info';
11
+ export { audioChannels } from './info';
23
12
  export { cleanWebpackFilename, createQueueSnapshot, extractFileName, getAudioInfoFromElement } from './utils';
13
+ export type { AudioCompleteCallback, AudioCompleteInfo, AudioErrorCallback, AudioErrorInfo, AudioInfo, AudioPauseCallback, AudioQueueOptions, AudioResumeCallback, AudioStartCallback, AudioStartInfo, ErrorRecoveryOptions, ExtendedAudioQueueChannel, ProgressCallback, QueueChangeCallback, QueueItem, QueueSnapshot, RetryConfig, VolumeConfig } from './types';