audio-channel-queue 1.4.0 → 1.5.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 +249 -13
- package/dist/core.d.ts +53 -0
- package/dist/core.js +189 -0
- package/dist/events.d.ts +59 -0
- package/dist/events.js +162 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +47 -0
- package/dist/info.d.ts +122 -0
- package/dist/info.js +240 -0
- package/dist/types.d.ts +115 -0
- package/dist/types.js +5 -0
- package/dist/utils.d.ts +52 -0
- package/dist/utils.js +106 -0
- package/package.json +7 -4
- package/src/core.ts +209 -0
- package/src/events.ts +189 -0
- package/src/index.ts +66 -0
- package/src/info.ts +262 -0
- package/src/types.ts +127 -0
- package/src/utils.ts +109 -0
- package/dist/audio.d.ts +0 -10
- package/dist/audio.js +0 -66
package/src/events.ts
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
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);
|
|
189
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
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';
|
package/src/info.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Audio information and progress tracking functions for the audio-channel-queue package
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
AudioInfo,
|
|
7
|
+
QueueSnapshot,
|
|
8
|
+
ProgressCallback,
|
|
9
|
+
QueueChangeCallback,
|
|
10
|
+
AudioStartCallback,
|
|
11
|
+
AudioCompleteCallback,
|
|
12
|
+
ExtendedAudioQueueChannel
|
|
13
|
+
} from './types';
|
|
14
|
+
import { getAudioInfoFromElement, createQueueSnapshot } from './utils';
|
|
15
|
+
import { setupProgressTracking, cleanupProgressTracking } from './events';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Global array of extended audio queue channels
|
|
19
|
+
*/
|
|
20
|
+
export const audioChannels: ExtendedAudioQueueChannel[] = [];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Gets current audio information for a specific channel
|
|
24
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
25
|
+
* @returns AudioInfo object or null if no audio is playing
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const info = getCurrentAudioInfo(0);
|
|
29
|
+
* if (info) {
|
|
30
|
+
* console.log(`Currently playing: ${info.fileName}`);
|
|
31
|
+
* console.log(`Progress: ${(info.progress * 100).toFixed(1)}%`);
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const getCurrentAudioInfo = (channelNumber: number = 0): AudioInfo | null => {
|
|
36
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
37
|
+
if (!channel || channel.queue.length === 0) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
42
|
+
return getAudioInfoFromElement(currentAudio);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Gets audio information for all channels
|
|
47
|
+
* @returns Array of AudioInfo objects (null for channels with no audio)
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const allInfo = getAllChannelsInfo();
|
|
51
|
+
* allInfo.forEach((info, channel) => {
|
|
52
|
+
* if (info) {
|
|
53
|
+
* console.log(`Channel ${channel}: ${info.fileName}`);
|
|
54
|
+
* }
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const getAllChannelsInfo = (): (AudioInfo | null)[] => {
|
|
59
|
+
const allChannelsInfo: (AudioInfo | null)[] = [];
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < audioChannels.length; i++) {
|
|
62
|
+
allChannelsInfo.push(getCurrentAudioInfo(i));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return allChannelsInfo;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Gets a complete snapshot of the queue state for a specific channel
|
|
70
|
+
* @param channelNumber - The channel number
|
|
71
|
+
* @returns QueueSnapshot object or null if channel doesn't exist
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const snapshot = getQueueSnapshot(0);
|
|
75
|
+
* if (snapshot) {
|
|
76
|
+
* console.log(`Queue has ${snapshot.totalItems} items`);
|
|
77
|
+
* console.log(`Currently playing: ${snapshot.items[0]?.fileName}`);
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export const getQueueSnapshot = (channelNumber: number): QueueSnapshot | null => {
|
|
82
|
+
return createQueueSnapshot(channelNumber, audioChannels);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Subscribes to real-time progress updates for a specific channel
|
|
87
|
+
* @param channelNumber - The channel number
|
|
88
|
+
* @param callback - Function to call with audio info updates
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* onAudioProgress(0, (info) => {
|
|
92
|
+
* updateProgressBar(info.progress);
|
|
93
|
+
* updateTimeDisplay(info.currentTime, info.duration);
|
|
94
|
+
* });
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export const onAudioProgress = (channelNumber: number, callback: ProgressCallback): void => {
|
|
98
|
+
if (!audioChannels[channelNumber]) {
|
|
99
|
+
audioChannels[channelNumber] = {
|
|
100
|
+
audioCompleteCallbacks: new Set(),
|
|
101
|
+
audioStartCallbacks: new Set(),
|
|
102
|
+
progressCallbacks: new Map(),
|
|
103
|
+
queue: [],
|
|
104
|
+
queueChangeCallbacks: new Set()
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
109
|
+
if (!channel.progressCallbacks) {
|
|
110
|
+
channel.progressCallbacks = new Map();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Add callback for current audio if exists
|
|
114
|
+
if (channel.queue.length > 0) {
|
|
115
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
116
|
+
if (!channel.progressCallbacks.has(currentAudio)) {
|
|
117
|
+
channel.progressCallbacks.set(currentAudio, new Set());
|
|
118
|
+
}
|
|
119
|
+
channel.progressCallbacks.get(currentAudio)!.add(callback);
|
|
120
|
+
|
|
121
|
+
// Set up tracking if not already done
|
|
122
|
+
setupProgressTracking(currentAudio, channelNumber, audioChannels);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Store callback for future audio elements in this channel
|
|
126
|
+
if (!channel.progressCallbacks.has(null as any)) {
|
|
127
|
+
channel.progressCallbacks.set(null as any, new Set());
|
|
128
|
+
}
|
|
129
|
+
channel.progressCallbacks.get(null as any)!.add(callback);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Removes progress listeners for a specific channel
|
|
134
|
+
* @param channelNumber - The channel number
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* offAudioProgress(0); // Stop receiving progress updates for channel 0
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export const offAudioProgress = (channelNumber: number): void => {
|
|
141
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
142
|
+
if (!channel || !channel.progressCallbacks) return;
|
|
143
|
+
|
|
144
|
+
// Clean up event listeners for current audio if exists
|
|
145
|
+
if (channel.queue.length > 0) {
|
|
146
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
147
|
+
cleanupProgressTracking(currentAudio, channelNumber, audioChannels);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Clear all callbacks for this channel
|
|
151
|
+
channel.progressCallbacks.clear();
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Subscribes to queue change events for a specific channel
|
|
156
|
+
* @param channelNumber - The channel number to monitor
|
|
157
|
+
* @param callback - Function to call when queue changes
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* onQueueChange(0, (snapshot) => {
|
|
161
|
+
* updateQueueDisplay(snapshot.items);
|
|
162
|
+
* updateQueueCount(snapshot.totalItems);
|
|
163
|
+
* });
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export const onQueueChange = (channelNumber: number, callback: QueueChangeCallback): void => {
|
|
167
|
+
if (!audioChannels[channelNumber]) {
|
|
168
|
+
audioChannels[channelNumber] = {
|
|
169
|
+
audioCompleteCallbacks: new Set(),
|
|
170
|
+
audioStartCallbacks: new Set(),
|
|
171
|
+
progressCallbacks: new Map(),
|
|
172
|
+
queue: [],
|
|
173
|
+
queueChangeCallbacks: new Set()
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
178
|
+
if (!channel.queueChangeCallbacks) {
|
|
179
|
+
channel.queueChangeCallbacks = new Set();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
channel.queueChangeCallbacks.add(callback);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Removes queue change listeners for a specific channel
|
|
187
|
+
* @param channelNumber - The channel number
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* offQueueChange(0); // Stop receiving queue change notifications for channel 0
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export const offQueueChange = (channelNumber: number): void => {
|
|
194
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
195
|
+
if (!channel || !channel.queueChangeCallbacks) return;
|
|
196
|
+
|
|
197
|
+
channel.queueChangeCallbacks.clear();
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Subscribes to audio start events for a specific channel
|
|
202
|
+
* @param channelNumber - The channel number to monitor
|
|
203
|
+
* @param callback - Function to call when audio starts playing
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* onAudioStart(0, (info) => {
|
|
207
|
+
* showNowPlaying(info.fileName);
|
|
208
|
+
* setTotalDuration(info.duration);
|
|
209
|
+
* });
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
export const onAudioStart = (channelNumber: number, callback: AudioStartCallback): void => {
|
|
213
|
+
if (!audioChannels[channelNumber]) {
|
|
214
|
+
audioChannels[channelNumber] = {
|
|
215
|
+
audioCompleteCallbacks: new Set(),
|
|
216
|
+
audioStartCallbacks: new Set(),
|
|
217
|
+
progressCallbacks: new Map(),
|
|
218
|
+
queue: [],
|
|
219
|
+
queueChangeCallbacks: new Set()
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
224
|
+
if (!channel.audioStartCallbacks) {
|
|
225
|
+
channel.audioStartCallbacks = new Set();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
channel.audioStartCallbacks.add(callback);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Subscribes to audio complete events for a specific channel
|
|
233
|
+
* @param channelNumber - The channel number to monitor
|
|
234
|
+
* @param callback - Function to call when audio completes
|
|
235
|
+
* @example
|
|
236
|
+
* ```typescript
|
|
237
|
+
* onAudioComplete(0, (info) => {
|
|
238
|
+
* logPlaybackComplete(info.fileName);
|
|
239
|
+
* if (info.remainingInQueue === 0) {
|
|
240
|
+
* showQueueComplete();
|
|
241
|
+
* }
|
|
242
|
+
* });
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
export const onAudioComplete = (channelNumber: number, callback: AudioCompleteCallback): void => {
|
|
246
|
+
if (!audioChannels[channelNumber]) {
|
|
247
|
+
audioChannels[channelNumber] = {
|
|
248
|
+
audioCompleteCallbacks: new Set(),
|
|
249
|
+
audioStartCallbacks: new Set(),
|
|
250
|
+
progressCallbacks: new Map(),
|
|
251
|
+
queue: [],
|
|
252
|
+
queueChangeCallbacks: new Set()
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
257
|
+
if (!channel.audioCompleteCallbacks) {
|
|
258
|
+
channel.audioCompleteCallbacks = new Set();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
channel.audioCompleteCallbacks.add(callback);
|
|
262
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for the audio-channel-queue package
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Array of HTMLAudioElement objects representing an audio queue
|
|
7
|
+
*/
|
|
8
|
+
export type AudioQueue = HTMLAudioElement[];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Basic audio queue channel structure
|
|
12
|
+
*/
|
|
13
|
+
export type AudioQueueChannel = {
|
|
14
|
+
queue: AudioQueue;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Comprehensive audio information interface providing metadata about currently playing audio
|
|
19
|
+
*/
|
|
20
|
+
export interface AudioInfo {
|
|
21
|
+
/** Current playback position in milliseconds */
|
|
22
|
+
currentTime: number;
|
|
23
|
+
/** Total audio duration in milliseconds */
|
|
24
|
+
duration: number;
|
|
25
|
+
/** Extracted filename from the source URL */
|
|
26
|
+
fileName: string;
|
|
27
|
+
/** Whether the audio is currently playing */
|
|
28
|
+
isPlaying: boolean;
|
|
29
|
+
/** Playback progress as a decimal (0-1) */
|
|
30
|
+
progress: number;
|
|
31
|
+
/** Audio file source URL */
|
|
32
|
+
src: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Information provided when an audio file completes playback
|
|
37
|
+
*/
|
|
38
|
+
export interface AudioCompleteInfo {
|
|
39
|
+
/** Channel number where the audio completed */
|
|
40
|
+
channelNumber: number;
|
|
41
|
+
/** Extracted filename from the source URL */
|
|
42
|
+
fileName: string;
|
|
43
|
+
/** Number of audio files remaining in the queue after completion */
|
|
44
|
+
remainingInQueue: number;
|
|
45
|
+
/** Audio file source URL */
|
|
46
|
+
src: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Information provided when an audio file starts playing
|
|
51
|
+
*/
|
|
52
|
+
export interface AudioStartInfo {
|
|
53
|
+
/** Channel number where the audio is starting */
|
|
54
|
+
channelNumber: number;
|
|
55
|
+
/** Total audio duration in milliseconds */
|
|
56
|
+
duration: number;
|
|
57
|
+
/** Extracted filename from the source URL */
|
|
58
|
+
fileName: string;
|
|
59
|
+
/** Audio file source URL */
|
|
60
|
+
src: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Information about a single item in an audio queue
|
|
65
|
+
*/
|
|
66
|
+
export interface QueueItem {
|
|
67
|
+
/** Total audio duration in milliseconds */
|
|
68
|
+
duration: number;
|
|
69
|
+
/** Extracted filename from the source URL */
|
|
70
|
+
fileName: string;
|
|
71
|
+
/** Whether this item is currently playing */
|
|
72
|
+
isCurrentlyPlaying: boolean;
|
|
73
|
+
/** Audio file source URL */
|
|
74
|
+
src: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Complete snapshot of a queue's current state
|
|
79
|
+
*/
|
|
80
|
+
export interface QueueSnapshot {
|
|
81
|
+
/** Channel number this snapshot represents */
|
|
82
|
+
channelNumber: number;
|
|
83
|
+
/** Zero-based index of the currently playing item */
|
|
84
|
+
currentIndex: number;
|
|
85
|
+
/** Array of audio items in the queue with their metadata */
|
|
86
|
+
items: QueueItem[];
|
|
87
|
+
/** Total number of items in the queue */
|
|
88
|
+
totalItems: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Callback function type for audio progress updates
|
|
93
|
+
* @param info Current audio information
|
|
94
|
+
*/
|
|
95
|
+
export type ProgressCallback = (info: AudioInfo) => void;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Callback function type for queue change notifications
|
|
99
|
+
* @param queueSnapshot Current state of the queue
|
|
100
|
+
*/
|
|
101
|
+
export type QueueChangeCallback = (queueSnapshot: QueueSnapshot) => void;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Callback function type for audio start notifications
|
|
105
|
+
* @param audioInfo Information about the audio that started
|
|
106
|
+
*/
|
|
107
|
+
export type AudioStartCallback = (audioInfo: AudioStartInfo) => void;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Callback function type for audio complete notifications
|
|
111
|
+
* @param audioInfo Information about the audio that completed
|
|
112
|
+
*/
|
|
113
|
+
export type AudioCompleteCallback = (audioInfo: AudioCompleteInfo) => void;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Extended audio queue channel with event callback management
|
|
117
|
+
*/
|
|
118
|
+
export type ExtendedAudioQueueChannel = AudioQueueChannel & {
|
|
119
|
+
/** Set of callbacks for audio completion events */
|
|
120
|
+
audioCompleteCallbacks?: Set<AudioCompleteCallback>;
|
|
121
|
+
/** Set of callbacks for audio start events */
|
|
122
|
+
audioStartCallbacks?: Set<AudioStartCallback>;
|
|
123
|
+
/** Map of audio elements to their progress callback sets */
|
|
124
|
+
progressCallbacks?: Map<HTMLAudioElement, Set<ProgressCallback>>;
|
|
125
|
+
/** Set of callbacks for queue change events */
|
|
126
|
+
queueChangeCallbacks?: Set<QueueChangeCallback>;
|
|
127
|
+
}
|