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/src/events.ts CHANGED
@@ -1,189 +1,243 @@
1
- /**
2
- * @fileoverview Event handling and emission for the audio-channel-queue package
3
- */
4
-
5
- import {
6
- AudioStartInfo,
7
- AudioCompleteInfo,
8
- ExtendedAudioQueueChannel,
9
- QueueSnapshot,
10
- ProgressCallback,
11
- AudioInfo,
12
- } from './types';
13
- import { createQueueSnapshot, getAudioInfoFromElement } from './utils';
14
-
15
- /**
16
- * Emits a queue change event to all registered listeners for a specific channel
17
- * @param channelNumber - The channel number that experienced a queue change
18
- * @param audioChannels - Array of audio channels
19
- * @example
20
- * ```typescript
21
- * emitQueueChange(0, audioChannels); // Notifies all queue change listeners
22
- * ```
23
- */
24
- export const emitQueueChange = (
25
- channelNumber: number,
26
- audioChannels: ExtendedAudioQueueChannel[]
27
- ): void => {
28
- const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
29
- if (!channel || !channel.queueChangeCallbacks) return;
30
-
31
- const snapshot: QueueSnapshot | null = createQueueSnapshot(channelNumber, audioChannels);
32
- if (!snapshot) return;
33
-
34
- channel.queueChangeCallbacks.forEach(callback => {
35
- try {
36
- callback(snapshot);
37
- } catch (error) {
38
- console.error('Error in queue change callback:', error);
39
- }
40
- });
41
- };
42
-
43
- /**
44
- * Emits an audio start event to all registered listeners for a specific channel
45
- * @param channelNumber - The channel number where audio started
46
- * @param audioInfo - Information about the audio that started
47
- * @param audioChannels - Array of audio channels
48
- * @example
49
- * ```typescript
50
- * emitAudioStart(0, { src: 'song.mp3', fileName: 'song.mp3', duration: 180000, channelNumber: 0 }, audioChannels);
51
- * ```
52
- */
53
- export const emitAudioStart = (
54
- channelNumber: number,
55
- audioInfo: AudioStartInfo,
56
- audioChannels: ExtendedAudioQueueChannel[]
57
- ): void => {
58
- const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
59
- if (!channel || !channel.audioStartCallbacks) return;
60
-
61
- channel.audioStartCallbacks.forEach(callback => {
62
- try {
63
- callback(audioInfo);
64
- } catch (error) {
65
- console.error('Error in audio start callback:', error);
66
- }
67
- });
68
- };
69
-
70
- /**
71
- * Emits an audio complete event to all registered listeners for a specific channel
72
- * @param channelNumber - The channel number where audio completed
73
- * @param audioInfo - Information about the audio that completed
74
- * @param audioChannels - Array of audio channels
75
- * @example
76
- * ```typescript
77
- * emitAudioComplete(0, { src: 'song.mp3', fileName: 'song.mp3', channelNumber: 0, remainingInQueue: 2 }, audioChannels);
78
- * ```
79
- */
80
- export const emitAudioComplete = (
81
- channelNumber: number,
82
- audioInfo: AudioCompleteInfo,
83
- audioChannels: ExtendedAudioQueueChannel[]
84
- ): void => {
85
- const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
86
- if (!channel || !channel.audioCompleteCallbacks) return;
87
-
88
- channel.audioCompleteCallbacks.forEach(callback => {
89
- try {
90
- callback(audioInfo);
91
- } catch (error) {
92
- console.error('Error in audio complete callback:', error);
93
- }
94
- });
95
- };
96
-
97
- // Store listener functions for cleanup
98
- const progressListeners = new WeakMap<HTMLAudioElement, () => void>();
99
-
100
- /**
101
- * Sets up comprehensive progress tracking for an audio element
102
- * @param audio - The HTML audio element to track
103
- * @param channelNumber - The channel number this audio belongs to
104
- * @param audioChannels - Array of audio channels
105
- * @example
106
- * ```typescript
107
- * const audioElement = new Audio('song.mp3');
108
- * setupProgressTracking(audioElement, 0, audioChannels);
109
- * ```
110
- */
111
- export const setupProgressTracking = (
112
- audio: HTMLAudioElement,
113
- channelNumber: number,
114
- audioChannels: ExtendedAudioQueueChannel[]
115
- ): void => {
116
- const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
117
- if (!channel) return;
118
-
119
- if (!channel.progressCallbacks) {
120
- channel.progressCallbacks = new Map();
121
- }
122
-
123
- // Don't set up tracking if already exists
124
- if (progressListeners.has(audio)) return;
125
-
126
- const updateProgress = (): void => {
127
- // Get callbacks for this specific audio element AND the channel-wide callbacks
128
- const audioCallbacks: Set<ProgressCallback> = channel.progressCallbacks?.get(audio) || new Set();
129
- const channelCallbacks: Set<ProgressCallback> = channel.progressCallbacks?.get(null as any) || new Set();
130
-
131
- // Combine both sets of callbacks
132
- const allCallbacks: Set<ProgressCallback> = new Set([...audioCallbacks, ...channelCallbacks]);
133
-
134
- if (allCallbacks.size === 0) return;
135
-
136
- const info: AudioInfo | null = getAudioInfoFromElement(audio);
137
- if (info) {
138
- allCallbacks.forEach((callback: ProgressCallback) => {
139
- try {
140
- callback(info);
141
- } catch (error) {
142
- console.error('Error in progress callback:', error);
143
- }
144
- });
145
- }
146
- };
147
-
148
- // Store the listener function for cleanup
149
- progressListeners.set(audio, updateProgress);
150
-
151
- // Set up comprehensive event listeners for progress tracking
152
- audio.addEventListener('timeupdate', updateProgress);
153
- audio.addEventListener('loadedmetadata', updateProgress);
154
- audio.addEventListener('play', updateProgress);
155
- audio.addEventListener('pause', updateProgress);
156
- audio.addEventListener('ended', updateProgress);
157
- };
158
-
159
- /**
160
- * Cleans up progress tracking for an audio element to prevent memory leaks
161
- * @param audio - The HTML audio element to clean up
162
- * @param channelNumber - The channel number this audio belongs to
163
- * @param audioChannels - Array of audio channels
164
- * @example
165
- * ```typescript
166
- * cleanupProgressTracking(audioElement, 0, audioChannels);
167
- * ```
168
- */
169
- export const cleanupProgressTracking = (
170
- audio: HTMLAudioElement,
171
- channelNumber: number,
172
- audioChannels: ExtendedAudioQueueChannel[]
173
- ): void => {
174
- const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
175
- if (!channel || !channel.progressCallbacks) return;
176
-
177
- // Remove event listeners
178
- const updateProgress: (() => void) | undefined = progressListeners.get(audio);
179
- if (updateProgress) {
180
- audio.removeEventListener('timeupdate', updateProgress);
181
- audio.removeEventListener('loadedmetadata', updateProgress);
182
- audio.removeEventListener('play', updateProgress);
183
- audio.removeEventListener('pause', updateProgress);
184
- audio.removeEventListener('ended', updateProgress);
185
- progressListeners.delete(audio);
186
- }
187
-
188
- channel.progressCallbacks.delete(audio);
1
+ /**
2
+ * @fileoverview Event handling and emission for the audio-channel-queue package
3
+ */
4
+
5
+ import {
6
+ AudioStartInfo,
7
+ AudioCompleteInfo,
8
+ ExtendedAudioQueueChannel,
9
+ QueueSnapshot,
10
+ ProgressCallback,
11
+ AudioInfo,
12
+ } from './types';
13
+ import { createQueueSnapshot, getAudioInfoFromElement } from './utils';
14
+
15
+ /**
16
+ * Emits a queue change event to all registered listeners for a specific channel
17
+ * @param channelNumber - The channel number that experienced a queue change
18
+ * @param audioChannels - Array of audio channels
19
+ * @example
20
+ * ```typescript
21
+ * emitQueueChange(0, audioChannels); // Notifies all queue change listeners
22
+ * ```
23
+ */
24
+ export const emitQueueChange = (
25
+ channelNumber: number,
26
+ audioChannels: ExtendedAudioQueueChannel[]
27
+ ): void => {
28
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
29
+ if (!channel || !channel.queueChangeCallbacks) return;
30
+
31
+ const snapshot: QueueSnapshot | null = createQueueSnapshot(channelNumber, audioChannels);
32
+ if (!snapshot) return;
33
+
34
+ channel.queueChangeCallbacks.forEach(callback => {
35
+ try {
36
+ callback(snapshot);
37
+ } catch (error) {
38
+ console.error('Error in queue change callback:', error);
39
+ }
40
+ });
41
+ };
42
+
43
+ /**
44
+ * Emits an audio start event to all registered listeners for a specific channel
45
+ * @param channelNumber - The channel number where audio started
46
+ * @param audioInfo - Information about the audio that started
47
+ * @param audioChannels - Array of audio channels
48
+ * @example
49
+ * ```typescript
50
+ * emitAudioStart(0, { src: 'song.mp3', fileName: 'song.mp3', duration: 180000, channelNumber: 0 }, audioChannels);
51
+ * ```
52
+ */
53
+ export const emitAudioStart = (
54
+ channelNumber: number,
55
+ audioInfo: AudioStartInfo,
56
+ audioChannels: ExtendedAudioQueueChannel[]
57
+ ): void => {
58
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
59
+ if (!channel || !channel.audioStartCallbacks) return;
60
+
61
+ channel.audioStartCallbacks.forEach(callback => {
62
+ try {
63
+ callback(audioInfo);
64
+ } catch (error) {
65
+ console.error('Error in audio start callback:', error);
66
+ }
67
+ });
68
+ };
69
+
70
+ /**
71
+ * Emits an audio complete event to all registered listeners for a specific channel
72
+ * @param channelNumber - The channel number where audio completed
73
+ * @param audioInfo - Information about the audio that completed
74
+ * @param audioChannels - Array of audio channels
75
+ * @example
76
+ * ```typescript
77
+ * emitAudioComplete(0, { src: 'song.mp3', fileName: 'song.mp3', channelNumber: 0, remainingInQueue: 2 }, audioChannels);
78
+ * ```
79
+ */
80
+ export const emitAudioComplete = (
81
+ channelNumber: number,
82
+ audioInfo: AudioCompleteInfo,
83
+ audioChannels: ExtendedAudioQueueChannel[]
84
+ ): void => {
85
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
86
+ if (!channel || !channel.audioCompleteCallbacks) return;
87
+
88
+ channel.audioCompleteCallbacks.forEach(callback => {
89
+ try {
90
+ callback(audioInfo);
91
+ } catch (error) {
92
+ console.error('Error in audio complete callback:', error);
93
+ }
94
+ });
95
+ };
96
+
97
+ /**
98
+ * Emits an audio pause event to all registered listeners for a specific channel
99
+ * @param channelNumber - The channel number where audio was paused
100
+ * @param audioInfo - Information about the audio that was paused
101
+ * @param audioChannels - Array of audio channels
102
+ * @example
103
+ * ```typescript
104
+ * emitAudioPause(0, audioInfo, audioChannels);
105
+ * ```
106
+ */
107
+ export const emitAudioPause = (
108
+ channelNumber: number,
109
+ audioInfo: AudioInfo,
110
+ audioChannels: ExtendedAudioQueueChannel[]
111
+ ): void => {
112
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
113
+ if (!channel || !channel.audioPauseCallbacks) return;
114
+
115
+ channel.audioPauseCallbacks.forEach(callback => {
116
+ try {
117
+ callback(channelNumber, audioInfo);
118
+ } catch (error) {
119
+ console.error('Error in audio pause callback:', error);
120
+ }
121
+ });
122
+ };
123
+
124
+ /**
125
+ * Emits an audio resume event to all registered listeners for a specific channel
126
+ * @param channelNumber - The channel number where audio was resumed
127
+ * @param audioInfo - Information about the audio that was resumed
128
+ * @param audioChannels - Array of audio channels
129
+ * @example
130
+ * ```typescript
131
+ * emitAudioResume(0, audioInfo, audioChannels);
132
+ * ```
133
+ */
134
+ export const emitAudioResume = (
135
+ channelNumber: number,
136
+ audioInfo: AudioInfo,
137
+ audioChannels: ExtendedAudioQueueChannel[]
138
+ ): void => {
139
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
140
+ if (!channel || !channel.audioResumeCallbacks) return;
141
+
142
+ channel.audioResumeCallbacks.forEach(callback => {
143
+ try {
144
+ callback(channelNumber, audioInfo);
145
+ } catch (error) {
146
+ console.error('Error in audio resume callback:', error);
147
+ }
148
+ });
149
+ };
150
+
151
+ // Store listener functions for cleanup
152
+ const progressListeners = new WeakMap<HTMLAudioElement, () => void>();
153
+
154
+ /**
155
+ * Sets up comprehensive progress tracking for an audio element
156
+ * @param audio - The HTML audio element to track
157
+ * @param channelNumber - The channel number this audio belongs to
158
+ * @param audioChannels - Array of audio channels
159
+ * @example
160
+ * ```typescript
161
+ * const audioElement = new Audio('song.mp3');
162
+ * setupProgressTracking(audioElement, 0, audioChannels);
163
+ * ```
164
+ */
165
+ export const setupProgressTracking = (
166
+ audio: HTMLAudioElement,
167
+ channelNumber: number,
168
+ audioChannels: ExtendedAudioQueueChannel[]
169
+ ): void => {
170
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
171
+ if (!channel) return;
172
+
173
+ if (!channel.progressCallbacks) {
174
+ channel.progressCallbacks = new Map();
175
+ }
176
+
177
+ // Don't set up tracking if already exists
178
+ if (progressListeners.has(audio)) return;
179
+
180
+ const updateProgress = (): void => {
181
+ // Get callbacks for this specific audio element AND the channel-wide callbacks
182
+ const audioCallbacks: Set<ProgressCallback> = channel.progressCallbacks?.get(audio) || new Set();
183
+ const channelCallbacks: Set<ProgressCallback> = channel.progressCallbacks?.get(null as any) || new Set();
184
+
185
+ // Combine both sets of callbacks
186
+ const allCallbacks: Set<ProgressCallback> = new Set([...audioCallbacks, ...channelCallbacks]);
187
+
188
+ if (allCallbacks.size === 0) return;
189
+
190
+ const info: AudioInfo | null = getAudioInfoFromElement(audio, channelNumber, audioChannels);
191
+ if (info) {
192
+ allCallbacks.forEach((callback: ProgressCallback) => {
193
+ try {
194
+ callback(info);
195
+ } catch (error) {
196
+ console.error('Error in progress callback:', error);
197
+ }
198
+ });
199
+ }
200
+ };
201
+
202
+ // Store the listener function for cleanup
203
+ progressListeners.set(audio, updateProgress);
204
+
205
+ // Set up comprehensive event listeners for progress tracking
206
+ audio.addEventListener('timeupdate', updateProgress);
207
+ audio.addEventListener('loadedmetadata', updateProgress);
208
+ audio.addEventListener('play', updateProgress);
209
+ audio.addEventListener('pause', updateProgress);
210
+ audio.addEventListener('ended', updateProgress);
211
+ };
212
+
213
+ /**
214
+ * Cleans up progress tracking for an audio element to prevent memory leaks
215
+ * @param audio - The HTML audio element to clean up
216
+ * @param channelNumber - The channel number this audio belongs to
217
+ * @param audioChannels - Array of audio channels
218
+ * @example
219
+ * ```typescript
220
+ * cleanupProgressTracking(audioElement, 0, audioChannels);
221
+ * ```
222
+ */
223
+ export const cleanupProgressTracking = (
224
+ audio: HTMLAudioElement,
225
+ channelNumber: number,
226
+ audioChannels: ExtendedAudioQueueChannel[]
227
+ ): void => {
228
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
229
+ if (!channel || !channel.progressCallbacks) return;
230
+
231
+ // Remove event listeners
232
+ const updateProgress: (() => void) | undefined = progressListeners.get(audio);
233
+ if (updateProgress) {
234
+ audio.removeEventListener('timeupdate', updateProgress);
235
+ audio.removeEventListener('loadedmetadata', updateProgress);
236
+ audio.removeEventListener('play', updateProgress);
237
+ audio.removeEventListener('pause', updateProgress);
238
+ audio.removeEventListener('ended', updateProgress);
239
+ progressListeners.delete(audio);
240
+ }
241
+
242
+ channel.progressCallbacks.delete(audio);
189
243
  };
package/src/index.ts CHANGED
@@ -1,66 +1,91 @@
1
- /**
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
- * ```
19
- */
20
-
21
- // Export all type definitions
22
- export type {
23
- AudioCompleteCallback,
24
- AudioCompleteInfo,
25
- AudioInfo,
26
- AudioQueue,
27
- AudioQueueChannel,
28
- AudioStartCallback,
29
- AudioStartInfo,
30
- ExtendedAudioQueueChannel,
31
- ProgressCallback,
32
- QueueChangeCallback,
33
- QueueItem,
34
- QueueSnapshot
35
- } from './types';
36
-
37
- // Export core queue management functions
38
- export {
39
- playAudioQueue,
40
- queueAudio,
41
- stopAllAudio,
42
- stopAllAudioInChannel,
43
- stopCurrentAudioInChannel
44
- } from './core';
45
-
46
- // Export audio information and progress tracking functions
47
- export {
48
- audioChannels,
49
- getAllChannelsInfo,
50
- getCurrentAudioInfo,
51
- getQueueSnapshot,
52
- offAudioProgress,
53
- onAudioComplete,
54
- onAudioProgress,
55
- onAudioStart,
56
- onQueueChange,
57
- offQueueChange
58
- } from './info';
59
-
60
- // Export utility functions (for advanced usage)
61
- export {
62
- cleanWebpackFilename,
63
- createQueueSnapshot,
64
- extractFileName,
65
- getAudioInfoFromElement
66
- } from './utils';
1
+ /**
2
+ * @fileoverview Main entry point for the audio-channel-queue package
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
5
+ */
6
+
7
+ // Core queue management functions
8
+ export { queueAudio, queueAudioPriority, stopCurrentAudioInChannel, stopAllAudioInChannel, stopAllAudio, playAudioQueue } from './core';
9
+
10
+ // Error handling and recovery functions
11
+ export {
12
+ getErrorRecovery,
13
+ getRetryConfig,
14
+ offAudioError,
15
+ onAudioError,
16
+ retryFailedAudio,
17
+ setErrorRecovery,
18
+ setRetryConfig,
19
+ } from './errors';
20
+
21
+ // Pause and resume management functions
22
+ export {
23
+ getAllChannelsPauseState,
24
+ isChannelPaused,
25
+ pauseAllChannels,
26
+ pauseChannel,
27
+ resumeAllChannels,
28
+ resumeChannel,
29
+ togglePauseAllChannels,
30
+ togglePauseChannel,
31
+ } from './pause';
32
+
33
+ // Volume control and ducking functions
34
+ export {
35
+ clearVolumeDucking,
36
+ getAllChannelsVolume,
37
+ getChannelVolume,
38
+ setAllChannelsVolume,
39
+ setChannelVolume,
40
+ setVolumeDucking,
41
+ } from './volume';
42
+
43
+ // Audio information and progress tracking functions
44
+ export {
45
+ getAllChannelsInfo,
46
+ getCurrentAudioInfo,
47
+ getQueueSnapshot,
48
+ offAudioPause,
49
+ offAudioProgress,
50
+ offAudioResume,
51
+ offQueueChange,
52
+ onAudioComplete,
53
+ onAudioPause,
54
+ onAudioProgress,
55
+ onAudioResume,
56
+ onAudioStart,
57
+ onQueueChange,
58
+ } from './info';
59
+
60
+ // Core data access for legacy compatibility
61
+ export { audioChannels } from './info';
62
+
63
+ // Utility helper functions
64
+ export {
65
+ cleanWebpackFilename,
66
+ createQueueSnapshot,
67
+ extractFileName,
68
+ getAudioInfoFromElement
69
+ } from './utils';
70
+
71
+ // TypeScript type definitions and interfaces
72
+ export type {
73
+ AudioCompleteCallback,
74
+ AudioCompleteInfo,
75
+ AudioErrorCallback,
76
+ AudioErrorInfo,
77
+ AudioInfo,
78
+ AudioPauseCallback,
79
+ AudioQueueOptions,
80
+ AudioResumeCallback,
81
+ AudioStartCallback,
82
+ AudioStartInfo,
83
+ ErrorRecoveryOptions,
84
+ ExtendedAudioQueueChannel,
85
+ ProgressCallback,
86
+ QueueChangeCallback,
87
+ QueueItem,
88
+ QueueSnapshot,
89
+ RetryConfig,
90
+ VolumeConfig
91
+ } from './types';