audio-channel-queue 1.5.0 → 1.6.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,104 @@
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
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, pause/resume functionality, volume control with ducking,
6
+ * looping capabilities, and extensive event handling.
7
+ *
8
+ * @example Basic Usage
9
+ * ```typescript
10
+ * import { queueAudio, onAudioProgress, pauseChannel } from 'audio-channel-queue';
11
+ *
12
+ * // Queue an audio file
13
+ * await queueAudio('song.mp3');
14
+ *
15
+ * // Track progress
16
+ * onAudioProgress(0, (info) => {
17
+ * console.log(`Progress: ${info.progress * 100}%`);
18
+ * });
19
+ *
20
+ * // Pause playback
21
+ * await pauseChannel(0);
22
+ * ```
23
+ */
24
+
25
+ // Export all type definitions
26
+ export type {
27
+ AudioCompleteCallback,
28
+ AudioCompleteInfo,
29
+ AudioInfo,
30
+ AudioPauseCallback,
31
+ AudioQueue,
32
+ AudioQueueChannel,
33
+ AudioQueueOptions,
34
+ AudioResumeCallback,
35
+ AudioStartCallback,
36
+ AudioStartInfo,
37
+ ExtendedAudioQueueChannel,
38
+ ProgressCallback,
39
+ QueueChangeCallback,
40
+ QueueItem,
41
+ QueueSnapshot,
42
+ VolumeConfig
43
+ } from './types';
44
+
45
+ // Export core queue management functions
46
+ export {
47
+ playAudioQueue,
48
+ queueAudio,
49
+ queueAudioPriority,
50
+ stopAllAudio,
51
+ stopAllAudioInChannel,
52
+ stopCurrentAudioInChannel
53
+ } from './core';
54
+
55
+ // Export pause and resume functionality
56
+ export {
57
+ getAllChannelsPauseState,
58
+ isChannelPaused,
59
+ pauseAllChannels,
60
+ pauseChannel,
61
+ resumeAllChannels,
62
+ resumeChannel,
63
+ togglePauseAllChannels,
64
+ togglePauseChannel
65
+ } from './pause';
66
+
67
+ // Export volume control functions
68
+ export {
69
+ applyVolumeDucking,
70
+ clearVolumeDucking,
71
+ getAllChannelsVolume,
72
+ getChannelVolume,
73
+ restoreVolumeLevels,
74
+ setAllChannelsVolume,
75
+ setChannelVolume,
76
+ setVolumeDucking,
77
+ transitionVolume
78
+ } from './volume';
79
+
80
+ // Export audio information and progress tracking functions
81
+ export {
82
+ audioChannels,
83
+ getAllChannelsInfo,
84
+ getCurrentAudioInfo,
85
+ getQueueSnapshot,
86
+ offAudioPause,
87
+ offAudioProgress,
88
+ offAudioResume,
89
+ offQueueChange,
90
+ onAudioComplete,
91
+ onAudioPause,
92
+ onAudioProgress,
93
+ onAudioResume,
94
+ onAudioStart,
95
+ onQueueChange
96
+ } from './info';
97
+
98
+ // Export utility functions (for advanced usage)
99
+ export {
100
+ cleanWebpackFilename,
101
+ createQueueSnapshot,
102
+ extractFileName,
103
+ getAudioInfoFromElement
66
104
  } from './utils';