audio-channel-queue 1.8.0 → 1.10.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 +197 -313
- package/dist/core.d.ts +59 -1
- package/dist/core.js +333 -41
- package/dist/errors.d.ts +1 -0
- package/dist/errors.js +37 -18
- package/dist/events.js +21 -14
- package/dist/index.d.ts +9 -8
- package/dist/index.js +23 -3
- package/dist/info.d.ts +17 -6
- package/dist/info.js +89 -17
- package/dist/pause.d.ts +24 -12
- package/dist/pause.js +93 -41
- package/dist/queue-manipulation.d.ts +104 -0
- package/dist/queue-manipulation.js +319 -0
- package/dist/types.d.ts +58 -11
- package/dist/types.js +18 -1
- package/dist/utils.d.ts +25 -0
- package/dist/utils.js +102 -13
- package/dist/volume.d.ts +14 -1
- package/dist/volume.js +201 -60
- package/package.json +18 -3
- package/src/core.ts +437 -81
- package/src/errors.ts +516 -480
- package/src/events.ts +36 -27
- package/src/index.ts +68 -43
- package/src/info.ts +129 -30
- package/src/pause.ts +169 -88
- package/src/queue-manipulation.ts +378 -0
- package/src/types.ts +63 -11
- package/src/utils.ts +117 -16
- package/src/volume.ts +250 -81
package/src/events.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* @fileoverview Event handling and emission for the audio-channel-queue package
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
AudioStartInfo,
|
|
7
|
-
AudioCompleteInfo,
|
|
5
|
+
import {
|
|
6
|
+
AudioStartInfo,
|
|
7
|
+
AudioCompleteInfo,
|
|
8
8
|
ExtendedAudioQueueChannel,
|
|
9
9
|
QueueSnapshot,
|
|
10
10
|
ProgressCallback,
|
|
11
11
|
AudioInfo,
|
|
12
|
+
GLOBAL_PROGRESS_KEY
|
|
12
13
|
} from './types';
|
|
13
14
|
import { createQueueSnapshot, getAudioInfoFromElement } from './utils';
|
|
14
15
|
|
|
@@ -22,19 +23,20 @@ import { createQueueSnapshot, getAudioInfoFromElement } from './utils';
|
|
|
22
23
|
* ```
|
|
23
24
|
*/
|
|
24
25
|
export const emitQueueChange = (
|
|
25
|
-
channelNumber: number,
|
|
26
|
+
channelNumber: number,
|
|
26
27
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
27
28
|
): void => {
|
|
28
29
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
29
|
-
if (!channel
|
|
30
|
+
if (!channel?.queueChangeCallbacks) return;
|
|
30
31
|
|
|
31
32
|
const snapshot: QueueSnapshot | null = createQueueSnapshot(channelNumber, audioChannels);
|
|
32
33
|
if (!snapshot) return;
|
|
33
34
|
|
|
34
|
-
channel.queueChangeCallbacks.forEach(callback => {
|
|
35
|
+
channel.queueChangeCallbacks.forEach((callback) => {
|
|
35
36
|
try {
|
|
36
37
|
callback(snapshot);
|
|
37
38
|
} catch (error) {
|
|
39
|
+
// eslint-disable-next-line no-console
|
|
38
40
|
console.error('Error in queue change callback:', error);
|
|
39
41
|
}
|
|
40
42
|
});
|
|
@@ -51,17 +53,18 @@ export const emitQueueChange = (
|
|
|
51
53
|
* ```
|
|
52
54
|
*/
|
|
53
55
|
export const emitAudioStart = (
|
|
54
|
-
channelNumber: number,
|
|
56
|
+
channelNumber: number,
|
|
55
57
|
audioInfo: AudioStartInfo,
|
|
56
58
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
57
59
|
): void => {
|
|
58
60
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
59
|
-
if (!channel
|
|
61
|
+
if (!channel?.audioStartCallbacks) return;
|
|
60
62
|
|
|
61
|
-
channel.audioStartCallbacks.forEach(callback => {
|
|
63
|
+
channel.audioStartCallbacks.forEach((callback) => {
|
|
62
64
|
try {
|
|
63
65
|
callback(audioInfo);
|
|
64
66
|
} catch (error) {
|
|
67
|
+
// eslint-disable-next-line no-console
|
|
65
68
|
console.error('Error in audio start callback:', error);
|
|
66
69
|
}
|
|
67
70
|
});
|
|
@@ -78,17 +81,18 @@ export const emitAudioStart = (
|
|
|
78
81
|
* ```
|
|
79
82
|
*/
|
|
80
83
|
export const emitAudioComplete = (
|
|
81
|
-
channelNumber: number,
|
|
84
|
+
channelNumber: number,
|
|
82
85
|
audioInfo: AudioCompleteInfo,
|
|
83
86
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
84
87
|
): void => {
|
|
85
88
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
86
|
-
if (!channel
|
|
89
|
+
if (!channel?.audioCompleteCallbacks) return;
|
|
87
90
|
|
|
88
|
-
channel.audioCompleteCallbacks.forEach(callback => {
|
|
91
|
+
channel.audioCompleteCallbacks.forEach((callback) => {
|
|
89
92
|
try {
|
|
90
93
|
callback(audioInfo);
|
|
91
94
|
} catch (error) {
|
|
95
|
+
// eslint-disable-next-line no-console
|
|
92
96
|
console.error('Error in audio complete callback:', error);
|
|
93
97
|
}
|
|
94
98
|
});
|
|
@@ -105,17 +109,18 @@ export const emitAudioComplete = (
|
|
|
105
109
|
* ```
|
|
106
110
|
*/
|
|
107
111
|
export const emitAudioPause = (
|
|
108
|
-
channelNumber: number,
|
|
112
|
+
channelNumber: number,
|
|
109
113
|
audioInfo: AudioInfo,
|
|
110
114
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
111
115
|
): void => {
|
|
112
116
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
113
|
-
if (!channel
|
|
117
|
+
if (!channel?.audioPauseCallbacks) return;
|
|
114
118
|
|
|
115
|
-
channel.audioPauseCallbacks.forEach(callback => {
|
|
119
|
+
channel.audioPauseCallbacks.forEach((callback) => {
|
|
116
120
|
try {
|
|
117
121
|
callback(channelNumber, audioInfo);
|
|
118
122
|
} catch (error) {
|
|
123
|
+
// eslint-disable-next-line no-console
|
|
119
124
|
console.error('Error in audio pause callback:', error);
|
|
120
125
|
}
|
|
121
126
|
});
|
|
@@ -132,24 +137,25 @@ export const emitAudioPause = (
|
|
|
132
137
|
* ```
|
|
133
138
|
*/
|
|
134
139
|
export const emitAudioResume = (
|
|
135
|
-
channelNumber: number,
|
|
140
|
+
channelNumber: number,
|
|
136
141
|
audioInfo: AudioInfo,
|
|
137
142
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
138
143
|
): void => {
|
|
139
144
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
140
|
-
if (!channel
|
|
145
|
+
if (!channel?.audioResumeCallbacks) return;
|
|
141
146
|
|
|
142
|
-
channel.audioResumeCallbacks.forEach(callback => {
|
|
147
|
+
channel.audioResumeCallbacks.forEach((callback) => {
|
|
143
148
|
try {
|
|
144
149
|
callback(channelNumber, audioInfo);
|
|
145
150
|
} catch (error) {
|
|
151
|
+
// eslint-disable-next-line no-console
|
|
146
152
|
console.error('Error in audio resume callback:', error);
|
|
147
153
|
}
|
|
148
154
|
});
|
|
149
155
|
};
|
|
150
156
|
|
|
151
157
|
// Store listener functions for cleanup
|
|
152
|
-
const progressListeners
|
|
158
|
+
const progressListeners: WeakMap<HTMLAudioElement, () => void> = new WeakMap();
|
|
153
159
|
|
|
154
160
|
/**
|
|
155
161
|
* Sets up comprehensive progress tracking for an audio element
|
|
@@ -163,7 +169,7 @@ const progressListeners = new WeakMap<HTMLAudioElement, () => void>();
|
|
|
163
169
|
* ```
|
|
164
170
|
*/
|
|
165
171
|
export const setupProgressTracking = (
|
|
166
|
-
audio: HTMLAudioElement,
|
|
172
|
+
audio: HTMLAudioElement,
|
|
167
173
|
channelNumber: number,
|
|
168
174
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
169
175
|
): void => {
|
|
@@ -179,12 +185,14 @@ export const setupProgressTracking = (
|
|
|
179
185
|
|
|
180
186
|
const updateProgress = (): void => {
|
|
181
187
|
// Get callbacks for this specific audio element AND the channel-wide callbacks
|
|
182
|
-
const audioCallbacks: Set<ProgressCallback> =
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
const audioCallbacks: Set<ProgressCallback> =
|
|
189
|
+
channel.progressCallbacks?.get(audio) ?? new Set();
|
|
190
|
+
const channelCallbacks: Set<ProgressCallback> =
|
|
191
|
+
channel.progressCallbacks?.get(GLOBAL_PROGRESS_KEY) ?? new Set();
|
|
192
|
+
|
|
185
193
|
// Combine both sets of callbacks
|
|
186
194
|
const allCallbacks: Set<ProgressCallback> = new Set([...audioCallbacks, ...channelCallbacks]);
|
|
187
|
-
|
|
195
|
+
|
|
188
196
|
if (allCallbacks.size === 0) return;
|
|
189
197
|
|
|
190
198
|
const info: AudioInfo | null = getAudioInfoFromElement(audio, channelNumber, audioChannels);
|
|
@@ -193,6 +201,7 @@ export const setupProgressTracking = (
|
|
|
193
201
|
try {
|
|
194
202
|
callback(info);
|
|
195
203
|
} catch (error) {
|
|
204
|
+
// eslint-disable-next-line no-console
|
|
196
205
|
console.error('Error in progress callback:', error);
|
|
197
206
|
}
|
|
198
207
|
});
|
|
@@ -221,12 +230,12 @@ export const setupProgressTracking = (
|
|
|
221
230
|
* ```
|
|
222
231
|
*/
|
|
223
232
|
export const cleanupProgressTracking = (
|
|
224
|
-
audio: HTMLAudioElement,
|
|
233
|
+
audio: HTMLAudioElement,
|
|
225
234
|
channelNumber: number,
|
|
226
235
|
audioChannels: ExtendedAudioQueueChannel[]
|
|
227
236
|
): void => {
|
|
228
237
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
229
|
-
if (!channel
|
|
238
|
+
if (!channel?.progressCallbacks) return;
|
|
230
239
|
|
|
231
240
|
// Remove event listeners
|
|
232
241
|
const updateProgress: (() => void) | undefined = progressListeners.get(audio);
|
|
@@ -240,4 +249,4 @@ export const cleanupProgressTracking = (
|
|
|
240
249
|
}
|
|
241
250
|
|
|
242
251
|
channel.progressCallbacks.delete(audio);
|
|
243
|
-
};
|
|
252
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -5,65 +5,89 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
// Core queue management functions
|
|
8
|
-
export {
|
|
8
|
+
export {
|
|
9
|
+
queueAudio,
|
|
10
|
+
queueAudioPriority,
|
|
11
|
+
stopCurrentAudioInChannel,
|
|
12
|
+
stopAllAudioInChannel,
|
|
13
|
+
stopAllAudio,
|
|
14
|
+
playAudioQueue,
|
|
15
|
+
destroyChannel,
|
|
16
|
+
destroyAllChannels,
|
|
17
|
+
setQueueConfig,
|
|
18
|
+
getQueueConfig,
|
|
19
|
+
setChannelQueueLimit
|
|
20
|
+
} from './core';
|
|
21
|
+
|
|
22
|
+
// Queue manipulation functions
|
|
23
|
+
export {
|
|
24
|
+
clearQueueAfterCurrent,
|
|
25
|
+
getQueueItemInfo,
|
|
26
|
+
getQueueLength,
|
|
27
|
+
removeQueuedItem,
|
|
28
|
+
reorderQueue,
|
|
29
|
+
swapQueueItems
|
|
30
|
+
} from './queue-manipulation';
|
|
9
31
|
|
|
10
32
|
// Error handling and recovery functions
|
|
11
|
-
export {
|
|
12
|
-
getErrorRecovery,
|
|
13
|
-
getRetryConfig,
|
|
14
|
-
offAudioError,
|
|
15
|
-
onAudioError,
|
|
33
|
+
export {
|
|
34
|
+
getErrorRecovery,
|
|
35
|
+
getRetryConfig,
|
|
36
|
+
offAudioError,
|
|
37
|
+
onAudioError,
|
|
16
38
|
retryFailedAudio,
|
|
17
|
-
setErrorRecovery,
|
|
18
|
-
setRetryConfig
|
|
39
|
+
setErrorRecovery,
|
|
40
|
+
setRetryConfig
|
|
19
41
|
} from './errors';
|
|
20
42
|
|
|
21
43
|
// Pause and resume management functions
|
|
22
|
-
export {
|
|
23
|
-
getAllChannelsPauseState,
|
|
24
|
-
isChannelPaused,
|
|
25
|
-
pauseAllChannels,
|
|
44
|
+
export {
|
|
45
|
+
getAllChannelsPauseState,
|
|
46
|
+
isChannelPaused,
|
|
47
|
+
pauseAllChannels,
|
|
26
48
|
pauseAllWithFade,
|
|
27
|
-
pauseChannel,
|
|
49
|
+
pauseChannel,
|
|
28
50
|
pauseWithFade,
|
|
29
|
-
resumeAllChannels,
|
|
51
|
+
resumeAllChannels,
|
|
30
52
|
resumeAllWithFade,
|
|
31
|
-
resumeChannel,
|
|
53
|
+
resumeChannel,
|
|
32
54
|
resumeWithFade,
|
|
33
55
|
togglePauseAllChannels,
|
|
34
56
|
togglePauseAllWithFade,
|
|
35
57
|
togglePauseChannel,
|
|
36
|
-
togglePauseWithFade
|
|
58
|
+
togglePauseWithFade
|
|
37
59
|
} from './pause';
|
|
38
60
|
|
|
39
61
|
// Volume control and ducking functions
|
|
40
|
-
export {
|
|
62
|
+
export {
|
|
41
63
|
clearVolumeDucking,
|
|
42
64
|
fadeVolume,
|
|
43
|
-
getAllChannelsVolume,
|
|
44
|
-
getChannelVolume,
|
|
65
|
+
getAllChannelsVolume,
|
|
66
|
+
getChannelVolume,
|
|
45
67
|
getFadeConfig,
|
|
46
|
-
setAllChannelsVolume,
|
|
47
|
-
setChannelVolume,
|
|
68
|
+
setAllChannelsVolume,
|
|
69
|
+
setChannelVolume,
|
|
48
70
|
setVolumeDucking,
|
|
49
71
|
transitionVolume,
|
|
72
|
+
cancelVolumeTransition,
|
|
73
|
+
cancelAllVolumeTransitions
|
|
50
74
|
} from './volume';
|
|
51
75
|
|
|
52
76
|
// Audio information and progress tracking functions
|
|
53
|
-
export {
|
|
54
|
-
getAllChannelsInfo,
|
|
55
|
-
getCurrentAudioInfo,
|
|
56
|
-
getQueueSnapshot,
|
|
57
|
-
offAudioPause,
|
|
58
|
-
offAudioProgress,
|
|
77
|
+
export {
|
|
78
|
+
getAllChannelsInfo,
|
|
79
|
+
getCurrentAudioInfo,
|
|
80
|
+
getQueueSnapshot,
|
|
81
|
+
offAudioPause,
|
|
82
|
+
offAudioProgress,
|
|
59
83
|
offAudioResume,
|
|
60
|
-
offQueueChange,
|
|
61
|
-
onAudioComplete,
|
|
62
|
-
onAudioPause,
|
|
63
|
-
onAudioProgress,
|
|
64
|
-
onAudioResume,
|
|
65
|
-
onAudioStart,
|
|
66
|
-
onQueueChange
|
|
84
|
+
offQueueChange,
|
|
85
|
+
onAudioComplete,
|
|
86
|
+
onAudioPause,
|
|
87
|
+
onAudioProgress,
|
|
88
|
+
onAudioResume,
|
|
89
|
+
onAudioStart,
|
|
90
|
+
onQueueChange
|
|
67
91
|
} from './info';
|
|
68
92
|
|
|
69
93
|
// Core data access for legacy compatibility
|
|
@@ -74,16 +98,18 @@ export {
|
|
|
74
98
|
cleanWebpackFilename,
|
|
75
99
|
createQueueSnapshot,
|
|
76
100
|
extractFileName,
|
|
77
|
-
getAudioInfoFromElement
|
|
101
|
+
getAudioInfoFromElement,
|
|
102
|
+
sanitizeForDisplay,
|
|
103
|
+
validateAudioUrl
|
|
78
104
|
} from './utils';
|
|
79
105
|
|
|
80
106
|
// TypeScript type definitions and interfaces
|
|
81
|
-
export type {
|
|
107
|
+
export type {
|
|
82
108
|
AudioCompleteCallback,
|
|
83
109
|
AudioCompleteInfo,
|
|
84
110
|
AudioErrorCallback,
|
|
85
111
|
AudioErrorInfo,
|
|
86
|
-
AudioInfo,
|
|
112
|
+
AudioInfo,
|
|
87
113
|
AudioPauseCallback,
|
|
88
114
|
AudioQueueOptions,
|
|
89
115
|
AudioResumeCallback,
|
|
@@ -96,13 +122,12 @@ export type {
|
|
|
96
122
|
ProgressCallback,
|
|
97
123
|
QueueChangeCallback,
|
|
98
124
|
QueueItem,
|
|
125
|
+
QueueManipulationResult,
|
|
99
126
|
QueueSnapshot,
|
|
100
127
|
RetryConfig,
|
|
101
|
-
VolumeConfig
|
|
128
|
+
VolumeConfig,
|
|
129
|
+
QueueConfig
|
|
102
130
|
} from './types';
|
|
103
131
|
|
|
104
|
-
// Enums
|
|
105
|
-
export {
|
|
106
|
-
EasingType,
|
|
107
|
-
FadeType
|
|
108
|
-
} from './types';
|
|
132
|
+
// Enums and constants
|
|
133
|
+
export { EasingType, FadeType, MAX_CHANNELS, TimerType, GLOBAL_PROGRESS_KEY } from './types';
|
package/src/info.ts
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
* @fileoverview Audio information and progress tracking functions for the audio-channel-queue package
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
AudioInfo,
|
|
7
|
-
QueueSnapshot,
|
|
5
|
+
import {
|
|
6
|
+
AudioInfo,
|
|
7
|
+
QueueSnapshot,
|
|
8
8
|
ProgressCallback,
|
|
9
9
|
QueueChangeCallback,
|
|
10
10
|
AudioStartCallback,
|
|
11
11
|
AudioCompleteCallback,
|
|
12
12
|
AudioPauseCallback,
|
|
13
13
|
AudioResumeCallback,
|
|
14
|
-
ExtendedAudioQueueChannel
|
|
14
|
+
ExtendedAudioQueueChannel,
|
|
15
|
+
GLOBAL_PROGRESS_KEY,
|
|
16
|
+
MAX_CHANNELS
|
|
15
17
|
} from './types';
|
|
16
18
|
import { getAudioInfoFromElement, createQueueSnapshot } from './utils';
|
|
17
19
|
import { setupProgressTracking, cleanupProgressTracking } from './events';
|
|
@@ -19,8 +21,85 @@ import { setupProgressTracking, cleanupProgressTracking } from './events';
|
|
|
19
21
|
/**
|
|
20
22
|
* Global array to store audio channels with their queues and callback management
|
|
21
23
|
* Each channel maintains its own audio queue and event callback sets
|
|
24
|
+
*
|
|
25
|
+
* Note: While you can inspect this array for debugging, direct modification is discouraged.
|
|
26
|
+
* Use the provided API functions for safe channel management.
|
|
22
27
|
*/
|
|
23
|
-
export const audioChannels: ExtendedAudioQueueChannel[] =
|
|
28
|
+
export const audioChannels: ExtendedAudioQueueChannel[] = new Proxy(
|
|
29
|
+
[] as ExtendedAudioQueueChannel[],
|
|
30
|
+
{
|
|
31
|
+
deleteProperty(target: ExtendedAudioQueueChannel[], prop: string | symbol): boolean {
|
|
32
|
+
if (typeof prop === 'string' && !isNaN(Number(prop))) {
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.warn(
|
|
35
|
+
'Warning: Direct deletion from audioChannels detected. ' +
|
|
36
|
+
'Consider using stopAllAudioInChannel() for proper cleanup.'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
delete (target as unknown as Record<string, unknown>)[prop as string];
|
|
40
|
+
return true;
|
|
41
|
+
},
|
|
42
|
+
get(target: ExtendedAudioQueueChannel[], prop: string | symbol): unknown {
|
|
43
|
+
const value = (target as unknown as Record<string, unknown>)[prop as string];
|
|
44
|
+
|
|
45
|
+
// Return channel objects with warnings on modification attempts
|
|
46
|
+
if (
|
|
47
|
+
typeof value === 'object' &&
|
|
48
|
+
value !== null &&
|
|
49
|
+
typeof prop === 'string' &&
|
|
50
|
+
!isNaN(Number(prop))
|
|
51
|
+
) {
|
|
52
|
+
return new Proxy(value as ExtendedAudioQueueChannel, {
|
|
53
|
+
set(
|
|
54
|
+
channelTarget: ExtendedAudioQueueChannel,
|
|
55
|
+
channelProp: string | symbol,
|
|
56
|
+
channelValue: unknown
|
|
57
|
+
): boolean {
|
|
58
|
+
// Allow internal modifications but warn about direct property changes
|
|
59
|
+
if (
|
|
60
|
+
typeof channelProp === 'string' &&
|
|
61
|
+
!['queue', 'volume', 'isPaused', 'isLocked', 'volumeConfig'].includes(channelProp)
|
|
62
|
+
) {
|
|
63
|
+
// eslint-disable-next-line no-console
|
|
64
|
+
console.warn(
|
|
65
|
+
`Warning: Direct modification of channel.${channelProp} detected. ` +
|
|
66
|
+
'Use API functions for safer channel management.'
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const key = typeof channelProp === 'symbol' ? channelProp.toString() : channelProp;
|
|
70
|
+
(channelTarget as unknown as Record<string, unknown>)[key] = channelValue;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return value;
|
|
77
|
+
},
|
|
78
|
+
set(target: ExtendedAudioQueueChannel[], prop: string | symbol, value: unknown): boolean {
|
|
79
|
+
// Allow normal array operations
|
|
80
|
+
const key = typeof prop === 'symbol' ? prop.toString() : prop;
|
|
81
|
+
(target as unknown as Record<string, unknown>)[key] = value;
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Validates a channel number against MAX_CHANNELS limit
|
|
89
|
+
* @param channelNumber - The channel number to validate
|
|
90
|
+
* @throws Error if the channel number is invalid
|
|
91
|
+
* @internal
|
|
92
|
+
*/
|
|
93
|
+
const validateChannelNumber = (channelNumber: number): void => {
|
|
94
|
+
if (channelNumber < 0) {
|
|
95
|
+
throw new Error('Channel number must be non-negative');
|
|
96
|
+
}
|
|
97
|
+
if (channelNumber >= MAX_CHANNELS) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Channel number ${channelNumber} exceeds maximum allowed channels (${MAX_CHANNELS})`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
24
103
|
|
|
25
104
|
/**
|
|
26
105
|
* Gets current audio information for a specific channel
|
|
@@ -60,28 +139,29 @@ export const getCurrentAudioInfo = (channelNumber: number = 0): AudioInfo | null
|
|
|
60
139
|
*/
|
|
61
140
|
export const getAllChannelsInfo = (): (AudioInfo | null)[] => {
|
|
62
141
|
const allChannelsInfo: (AudioInfo | null)[] = [];
|
|
63
|
-
|
|
64
|
-
for (let i = 0; i < audioChannels.length; i++) {
|
|
142
|
+
|
|
143
|
+
for (let i: number = 0; i < audioChannels.length; i++) {
|
|
65
144
|
allChannelsInfo.push(getCurrentAudioInfo(i));
|
|
66
145
|
}
|
|
67
|
-
|
|
146
|
+
|
|
68
147
|
return allChannelsInfo;
|
|
69
148
|
};
|
|
70
149
|
|
|
71
150
|
/**
|
|
72
151
|
* Gets a complete snapshot of the queue state for a specific channel
|
|
73
|
-
* @param channelNumber - The channel number
|
|
152
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
74
153
|
* @returns QueueSnapshot object or null if channel doesn't exist
|
|
75
154
|
* @example
|
|
76
155
|
* ```typescript
|
|
77
|
-
* const snapshot = getQueueSnapshot(
|
|
156
|
+
* const snapshot = getQueueSnapshot();
|
|
78
157
|
* if (snapshot) {
|
|
79
158
|
* console.log(`Queue has ${snapshot.totalItems} items`);
|
|
80
159
|
* console.log(`Currently playing: ${snapshot.items[0]?.fileName}`);
|
|
81
160
|
* }
|
|
161
|
+
* const channelSnapshot = getQueueSnapshot(2);
|
|
82
162
|
* ```
|
|
83
163
|
*/
|
|
84
|
-
export const getQueueSnapshot = (channelNumber: number): QueueSnapshot | null => {
|
|
164
|
+
export const getQueueSnapshot = (channelNumber: number = 0): QueueSnapshot | null => {
|
|
85
165
|
return createQueueSnapshot(channelNumber, audioChannels);
|
|
86
166
|
};
|
|
87
167
|
|
|
@@ -89,6 +169,7 @@ export const getQueueSnapshot = (channelNumber: number): QueueSnapshot | null =>
|
|
|
89
169
|
* Subscribes to real-time progress updates for a specific channel
|
|
90
170
|
* @param channelNumber - The channel number
|
|
91
171
|
* @param callback - Function to call with audio info updates
|
|
172
|
+
* @throws Error if the channel number exceeds the maximum allowed channels
|
|
92
173
|
* @example
|
|
93
174
|
* ```typescript
|
|
94
175
|
* onAudioProgress(0, (info) => {
|
|
@@ -98,8 +179,10 @@ export const getQueueSnapshot = (channelNumber: number): QueueSnapshot | null =>
|
|
|
98
179
|
* ```
|
|
99
180
|
*/
|
|
100
181
|
export const onAudioProgress = (channelNumber: number, callback: ProgressCallback): void => {
|
|
182
|
+
validateChannelNumber(channelNumber);
|
|
183
|
+
|
|
101
184
|
if (!audioChannels[channelNumber]) {
|
|
102
|
-
audioChannels[channelNumber] = {
|
|
185
|
+
audioChannels[channelNumber] = {
|
|
103
186
|
audioCompleteCallbacks: new Set(),
|
|
104
187
|
audioErrorCallbacks: new Set(),
|
|
105
188
|
audioPauseCallbacks: new Set(),
|
|
@@ -125,29 +208,30 @@ export const onAudioProgress = (channelNumber: number, callback: ProgressCallbac
|
|
|
125
208
|
channel.progressCallbacks.set(currentAudio, new Set());
|
|
126
209
|
}
|
|
127
210
|
channel.progressCallbacks.get(currentAudio)!.add(callback);
|
|
128
|
-
|
|
211
|
+
|
|
129
212
|
// Set up tracking if not already done
|
|
130
213
|
setupProgressTracking(currentAudio, channelNumber, audioChannels);
|
|
131
214
|
}
|
|
132
215
|
|
|
133
216
|
// Store callback for future audio elements in this channel
|
|
134
|
-
if (!channel.progressCallbacks.has(
|
|
135
|
-
channel.progressCallbacks.set(
|
|
217
|
+
if (!channel.progressCallbacks.has(GLOBAL_PROGRESS_KEY)) {
|
|
218
|
+
channel.progressCallbacks.set(GLOBAL_PROGRESS_KEY, new Set());
|
|
136
219
|
}
|
|
137
|
-
channel.progressCallbacks.get(
|
|
220
|
+
channel.progressCallbacks.get(GLOBAL_PROGRESS_KEY)!.add(callback);
|
|
138
221
|
};
|
|
139
222
|
|
|
140
223
|
/**
|
|
141
224
|
* Removes progress listeners for a specific channel
|
|
142
|
-
* @param channelNumber - The channel number
|
|
225
|
+
* @param channelNumber - The channel number (defaults to 0)
|
|
143
226
|
* @example
|
|
144
227
|
* ```typescript
|
|
145
|
-
* offAudioProgress(
|
|
228
|
+
* offAudioProgress();
|
|
229
|
+
* offAudioProgress(1); // Stop receiving progress updates for channel 1
|
|
146
230
|
* ```
|
|
147
231
|
*/
|
|
148
|
-
export
|
|
232
|
+
export function offAudioProgress(channelNumber: number = 0): void {
|
|
149
233
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
150
|
-
if (!channel
|
|
234
|
+
if (!channel?.progressCallbacks) return;
|
|
151
235
|
|
|
152
236
|
// Clean up event listeners for current audio if exists
|
|
153
237
|
if (channel.queue.length > 0) {
|
|
@@ -157,12 +241,13 @@ export const offAudioProgress = (channelNumber: number): void => {
|
|
|
157
241
|
|
|
158
242
|
// Clear all callbacks for this channel
|
|
159
243
|
channel.progressCallbacks.clear();
|
|
160
|
-
}
|
|
244
|
+
}
|
|
161
245
|
|
|
162
246
|
/**
|
|
163
247
|
* Subscribes to queue change events for a specific channel
|
|
164
248
|
* @param channelNumber - The channel number to monitor
|
|
165
249
|
* @param callback - Function to call when queue changes
|
|
250
|
+
* @throws Error if the channel number exceeds the maximum allowed channels
|
|
166
251
|
* @example
|
|
167
252
|
* ```typescript
|
|
168
253
|
* onQueueChange(0, (snapshot) => {
|
|
@@ -172,8 +257,10 @@ export const offAudioProgress = (channelNumber: number): void => {
|
|
|
172
257
|
* ```
|
|
173
258
|
*/
|
|
174
259
|
export const onQueueChange = (channelNumber: number, callback: QueueChangeCallback): void => {
|
|
260
|
+
validateChannelNumber(channelNumber);
|
|
261
|
+
|
|
175
262
|
if (!audioChannels[channelNumber]) {
|
|
176
|
-
audioChannels[channelNumber] = {
|
|
263
|
+
audioChannels[channelNumber] = {
|
|
177
264
|
audioCompleteCallbacks: new Set(),
|
|
178
265
|
audioErrorCallbacks: new Set(),
|
|
179
266
|
audioPauseCallbacks: new Set(),
|
|
@@ -205,7 +292,7 @@ export const onQueueChange = (channelNumber: number, callback: QueueChangeCallba
|
|
|
205
292
|
*/
|
|
206
293
|
export const offQueueChange = (channelNumber: number): void => {
|
|
207
294
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
208
|
-
if (!channel
|
|
295
|
+
if (!channel?.queueChangeCallbacks) return;
|
|
209
296
|
|
|
210
297
|
channel.queueChangeCallbacks.clear();
|
|
211
298
|
};
|
|
@@ -214,6 +301,7 @@ export const offQueueChange = (channelNumber: number): void => {
|
|
|
214
301
|
* Subscribes to audio start events for a specific channel
|
|
215
302
|
* @param channelNumber - The channel number to monitor
|
|
216
303
|
* @param callback - Function to call when audio starts playing
|
|
304
|
+
* @throws Error if the channel number exceeds the maximum allowed channels
|
|
217
305
|
* @example
|
|
218
306
|
* ```typescript
|
|
219
307
|
* onAudioStart(0, (info) => {
|
|
@@ -223,8 +311,10 @@ export const offQueueChange = (channelNumber: number): void => {
|
|
|
223
311
|
* ```
|
|
224
312
|
*/
|
|
225
313
|
export const onAudioStart = (channelNumber: number, callback: AudioStartCallback): void => {
|
|
314
|
+
validateChannelNumber(channelNumber);
|
|
315
|
+
|
|
226
316
|
if (!audioChannels[channelNumber]) {
|
|
227
|
-
audioChannels[channelNumber] = {
|
|
317
|
+
audioChannels[channelNumber] = {
|
|
228
318
|
audioCompleteCallbacks: new Set(),
|
|
229
319
|
audioErrorCallbacks: new Set(),
|
|
230
320
|
audioPauseCallbacks: new Set(),
|
|
@@ -250,6 +340,7 @@ export const onAudioStart = (channelNumber: number, callback: AudioStartCallback
|
|
|
250
340
|
* Subscribes to audio complete events for a specific channel
|
|
251
341
|
* @param channelNumber - The channel number to monitor
|
|
252
342
|
* @param callback - Function to call when audio completes
|
|
343
|
+
* @throws Error if the channel number exceeds the maximum allowed channels
|
|
253
344
|
* @example
|
|
254
345
|
* ```typescript
|
|
255
346
|
* onAudioComplete(0, (info) => {
|
|
@@ -261,8 +352,10 @@ export const onAudioStart = (channelNumber: number, callback: AudioStartCallback
|
|
|
261
352
|
* ```
|
|
262
353
|
*/
|
|
263
354
|
export const onAudioComplete = (channelNumber: number, callback: AudioCompleteCallback): void => {
|
|
355
|
+
validateChannelNumber(channelNumber);
|
|
356
|
+
|
|
264
357
|
if (!audioChannels[channelNumber]) {
|
|
265
|
-
audioChannels[channelNumber] = {
|
|
358
|
+
audioChannels[channelNumber] = {
|
|
266
359
|
audioCompleteCallbacks: new Set(),
|
|
267
360
|
audioErrorCallbacks: new Set(),
|
|
268
361
|
audioPauseCallbacks: new Set(),
|
|
@@ -288,6 +381,7 @@ export const onAudioComplete = (channelNumber: number, callback: AudioCompleteCa
|
|
|
288
381
|
* Subscribes to audio pause events for a specific channel
|
|
289
382
|
* @param channelNumber - The channel number to monitor
|
|
290
383
|
* @param callback - Function to call when audio is paused
|
|
384
|
+
* @throws Error if the channel number exceeds the maximum allowed channels
|
|
291
385
|
* @example
|
|
292
386
|
* ```typescript
|
|
293
387
|
* onAudioPause(0, (channelNumber, info) => {
|
|
@@ -297,8 +391,10 @@ export const onAudioComplete = (channelNumber: number, callback: AudioCompleteCa
|
|
|
297
391
|
* ```
|
|
298
392
|
*/
|
|
299
393
|
export const onAudioPause = (channelNumber: number, callback: AudioPauseCallback): void => {
|
|
394
|
+
validateChannelNumber(channelNumber);
|
|
395
|
+
|
|
300
396
|
if (!audioChannels[channelNumber]) {
|
|
301
|
-
audioChannels[channelNumber] = {
|
|
397
|
+
audioChannels[channelNumber] = {
|
|
302
398
|
audioCompleteCallbacks: new Set(),
|
|
303
399
|
audioErrorCallbacks: new Set(),
|
|
304
400
|
audioPauseCallbacks: new Set(),
|
|
@@ -324,6 +420,7 @@ export const onAudioPause = (channelNumber: number, callback: AudioPauseCallback
|
|
|
324
420
|
* Subscribes to audio resume events for a specific channel
|
|
325
421
|
* @param channelNumber - The channel number to monitor
|
|
326
422
|
* @param callback - Function to call when audio is resumed
|
|
423
|
+
* @throws Error if the channel number exceeds the maximum allowed channels
|
|
327
424
|
* @example
|
|
328
425
|
* ```typescript
|
|
329
426
|
* onAudioResume(0, (channelNumber, info) => {
|
|
@@ -333,8 +430,10 @@ export const onAudioPause = (channelNumber: number, callback: AudioPauseCallback
|
|
|
333
430
|
* ```
|
|
334
431
|
*/
|
|
335
432
|
export const onAudioResume = (channelNumber: number, callback: AudioResumeCallback): void => {
|
|
433
|
+
validateChannelNumber(channelNumber);
|
|
434
|
+
|
|
336
435
|
if (!audioChannels[channelNumber]) {
|
|
337
|
-
audioChannels[channelNumber] = {
|
|
436
|
+
audioChannels[channelNumber] = {
|
|
338
437
|
audioCompleteCallbacks: new Set(),
|
|
339
438
|
audioErrorCallbacks: new Set(),
|
|
340
439
|
audioPauseCallbacks: new Set(),
|
|
@@ -366,7 +465,7 @@ export const onAudioResume = (channelNumber: number, callback: AudioResumeCallba
|
|
|
366
465
|
*/
|
|
367
466
|
export const offAudioPause = (channelNumber: number): void => {
|
|
368
467
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
369
|
-
if (!channel
|
|
468
|
+
if (!channel?.audioPauseCallbacks) return;
|
|
370
469
|
|
|
371
470
|
channel.audioPauseCallbacks.clear();
|
|
372
471
|
};
|
|
@@ -381,7 +480,7 @@ export const offAudioPause = (channelNumber: number): void => {
|
|
|
381
480
|
*/
|
|
382
481
|
export const offAudioResume = (channelNumber: number): void => {
|
|
383
482
|
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
384
|
-
if (!channel
|
|
483
|
+
if (!channel?.audioResumeCallbacks) return;
|
|
385
484
|
|
|
386
485
|
channel.audioResumeCallbacks.clear();
|
|
387
|
-
};
|
|
486
|
+
};
|