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/pause.ts ADDED
@@ -0,0 +1,190 @@
1
+ /**
2
+ * @fileoverview Pause and resume management functions for the audio-channel-queue package
3
+ */
4
+
5
+ import { ExtendedAudioQueueChannel, AudioInfo } from './types';
6
+ import { audioChannels } from './info';
7
+ import { getAudioInfoFromElement } from './utils';
8
+ import { emitAudioPause, emitAudioResume } from './events';
9
+
10
+ /**
11
+ * Pauses the currently playing audio in a specific channel
12
+ * @param channelNumber - The channel number to pause (defaults to 0)
13
+ * @returns Promise that resolves when the audio is paused
14
+ * @example
15
+ * ```typescript
16
+ * await pauseChannel(0); // Pause audio in channel 0
17
+ * await pauseChannel(); // Pause audio in default channel
18
+ * ```
19
+ */
20
+ export const pauseChannel = async (channelNumber: number = 0): Promise<void> => {
21
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
22
+
23
+ if (channel && channel.queue.length > 0) {
24
+ const currentAudio: HTMLAudioElement = channel.queue[0];
25
+
26
+ if (!currentAudio.paused && !currentAudio.ended) {
27
+ currentAudio.pause();
28
+ channel.isPaused = true;
29
+
30
+ const audioInfo: AudioInfo | null = getAudioInfoFromElement(currentAudio, channelNumber, audioChannels);
31
+ if (audioInfo) {
32
+ emitAudioPause(channelNumber, audioInfo, audioChannels);
33
+ }
34
+ }
35
+ }
36
+ };
37
+
38
+ /**
39
+ * Resumes the currently paused audio in a specific channel
40
+ * @param channelNumber - The channel number to resume (defaults to 0)
41
+ * @returns Promise that resolves when the audio starts playing
42
+ * @example
43
+ * ```typescript
44
+ * await resumeChannel(0); // Resume audio in channel 0
45
+ * await resumeChannel(); // Resume audio in default channel
46
+ * ```
47
+ */
48
+ export const resumeChannel = async (channelNumber: number = 0): Promise<void> => {
49
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
50
+
51
+ if (channel && channel.queue.length > 0) {
52
+ const currentAudio: HTMLAudioElement = channel.queue[0];
53
+
54
+ // Only resume if both the channel is marked as paused AND the audio element is actually paused AND not ended
55
+ if (channel.isPaused && currentAudio.paused && !currentAudio.ended) {
56
+ await currentAudio.play();
57
+ channel.isPaused = false;
58
+
59
+ const audioInfo: AudioInfo | null = getAudioInfoFromElement(currentAudio, channelNumber, audioChannels);
60
+ if (audioInfo) {
61
+ emitAudioResume(channelNumber, audioInfo, audioChannels);
62
+ }
63
+ }
64
+ }
65
+ };
66
+
67
+ /**
68
+ * Toggles pause/resume state for a specific channel
69
+ * @param channelNumber - The channel number to toggle (defaults to 0)
70
+ * @returns Promise that resolves when the toggle is complete
71
+ * @example
72
+ * ```typescript
73
+ * await togglePauseChannel(0); // Toggle pause state for channel 0
74
+ * ```
75
+ */
76
+ export const togglePauseChannel = async (channelNumber: number = 0): Promise<void> => {
77
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
78
+
79
+ if (channel && channel.queue.length > 0) {
80
+ const currentAudio: HTMLAudioElement = channel.queue[0];
81
+
82
+ if (currentAudio.paused) {
83
+ await resumeChannel(channelNumber);
84
+ } else {
85
+ await pauseChannel(channelNumber);
86
+ }
87
+ }
88
+ };
89
+
90
+ /**
91
+ * Pauses all currently playing audio across all channels
92
+ * @returns Promise that resolves when all audio is paused
93
+ * @example
94
+ * ```typescript
95
+ * await pauseAllChannels(); // Pause everything
96
+ * ```
97
+ */
98
+ export const pauseAllChannels = async (): Promise<void> => {
99
+ const pausePromises: Promise<void>[] = [];
100
+
101
+ audioChannels.forEach((_channel: ExtendedAudioQueueChannel, index: number) => {
102
+ pausePromises.push(pauseChannel(index));
103
+ });
104
+
105
+ await Promise.all(pausePromises);
106
+ };
107
+
108
+ /**
109
+ * Resumes all currently paused audio across all channels
110
+ * @returns Promise that resolves when all audio is resumed
111
+ * @example
112
+ * ```typescript
113
+ * await resumeAllChannels(); // Resume everything that was paused
114
+ * ```
115
+ */
116
+ export const resumeAllChannels = async (): Promise<void> => {
117
+ const resumePromises: Promise<void>[] = [];
118
+
119
+ audioChannels.forEach((_channel: ExtendedAudioQueueChannel, index: number) => {
120
+ resumePromises.push(resumeChannel(index));
121
+ });
122
+
123
+ await Promise.all(resumePromises);
124
+ };
125
+
126
+ /**
127
+ * Checks if a specific channel is currently paused
128
+ * @param channelNumber - The channel number to check (defaults to 0)
129
+ * @returns True if the channel is paused, false otherwise
130
+ * @example
131
+ * ```typescript
132
+ * const isPaused = isChannelPaused(0);
133
+ * console.log(`Channel 0 is ${isPaused ? 'paused' : 'playing'}`);
134
+ * ```
135
+ */
136
+ export const isChannelPaused = (channelNumber: number = 0): boolean => {
137
+ const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
138
+ return channel?.isPaused || false;
139
+ };
140
+
141
+ /**
142
+ * Gets the pause state of all channels
143
+ * @returns Array of boolean values indicating pause state for each channel
144
+ * @example
145
+ * ```typescript
146
+ * const pauseStates = getAllChannelsPauseState();
147
+ * pauseStates.forEach((isPaused, index) => {
148
+ * console.log(`Channel ${index}: ${isPaused ? 'paused' : 'playing'}`);
149
+ * });
150
+ * ```
151
+ */
152
+ export const getAllChannelsPauseState = (): boolean[] => {
153
+ return audioChannels.map((channel: ExtendedAudioQueueChannel) =>
154
+ channel?.isPaused || false
155
+ );
156
+ };
157
+
158
+ /**
159
+ * Toggles pause/resume state for all channels globally
160
+ * If any channels are currently playing, all channels will be paused
161
+ * If all channels are paused, all channels will be resumed
162
+ * @returns Promise that resolves when the toggle is complete
163
+ * @example
164
+ * ```typescript
165
+ * await togglePauseAllChannels(); // Pause all if any are playing, resume all if all are paused
166
+ * ```
167
+ */
168
+ export const togglePauseAllChannels = async (): Promise<void> => {
169
+ let hasPlayingChannel: boolean = false;
170
+
171
+ // Check if any channel is currently playing
172
+ for (let i = 0; i < audioChannels.length; i++) {
173
+ const channel: ExtendedAudioQueueChannel = audioChannels[i];
174
+ if (channel && channel.queue.length > 0) {
175
+ const currentAudio: HTMLAudioElement = channel.queue[0];
176
+ if (!currentAudio.paused && !currentAudio.ended) {
177
+ hasPlayingChannel = true;
178
+ break;
179
+ }
180
+ }
181
+ }
182
+
183
+ // If any channel is playing, pause all channels
184
+ // If no channels are playing, resume all channels
185
+ if (hasPlayingChannel) {
186
+ await pauseAllChannels();
187
+ } else {
188
+ await resumeAllChannels();
189
+ }
190
+ };
package/src/types.ts CHANGED
@@ -1,127 +1,236 @@
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>;
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
+ * Volume ducking configuration for channels
19
+ */
20
+ export interface VolumeConfig {
21
+ /** The channel number that should have priority */
22
+ priorityChannel: number;
23
+ /** Volume level for the priority channel (0-1) */
24
+ priorityVolume: number;
25
+ /** Volume level for all other channels when priority channel is active (0-1) */
26
+ duckingVolume: number;
27
+ /** Duration in milliseconds for volume duck transition (defaults to 250ms) */
28
+ duckTransitionDuration?: number;
29
+ /** Duration in milliseconds for volume restore transition (defaults to 500ms) */
30
+ restoreTransitionDuration?: number;
31
+ /** Easing function for volume transitions (defaults to 'ease-out') */
32
+ transitionEasing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
33
+ }
34
+
35
+ /**
36
+ * Audio file configuration for queueing
37
+ */
38
+ export interface AudioQueueOptions {
39
+ /** Whether to add the audio to the front of the queue (defaults to false) */
40
+ addToFront?: boolean;
41
+ /** Whether the audio should loop when it finishes */
42
+ loop?: boolean;
43
+ /** Whether to add the audio with priority (same as addToFront) */
44
+ priority?: boolean;
45
+ /** Volume level for this specific audio file (0-1, defaults to channel volume) */
46
+ volume?: number;
47
+ }
48
+
49
+ /**
50
+ * Comprehensive audio information interface providing metadata about currently playing audio
51
+ */
52
+ export interface AudioInfo {
53
+ /** Current playback position in milliseconds */
54
+ currentTime: number;
55
+ /** Total audio duration in milliseconds */
56
+ duration: number;
57
+ /** Extracted filename from the source URL */
58
+ fileName: string;
59
+ /** Whether the audio is set to loop */
60
+ isLooping: boolean;
61
+ /** Whether the audio is currently paused */
62
+ isPaused: boolean;
63
+ /** Whether the audio is currently playing */
64
+ isPlaying: boolean;
65
+ /** Playback progress as a decimal (0-1) */
66
+ progress: number;
67
+ /** Number of audio files remaining in the queue after current */
68
+ remainingInQueue: number;
69
+ /** Audio file source URL */
70
+ src: string;
71
+ /** Current volume level (0-1) */
72
+ volume: number;
73
+ }
74
+
75
+ /**
76
+ * Information provided when an audio file completes playback
77
+ */
78
+ export interface AudioCompleteInfo {
79
+ /** Channel number where the audio completed */
80
+ channelNumber: number;
81
+ /** Extracted filename from the source URL */
82
+ fileName: string;
83
+ /** Number of audio files remaining in the queue after completion */
84
+ remainingInQueue: number;
85
+ /** Audio file source URL */
86
+ src: string;
87
+ }
88
+
89
+ /**
90
+ * Information provided when an audio file starts playing
91
+ */
92
+ export interface AudioStartInfo {
93
+ /** Channel number where the audio is starting */
94
+ channelNumber: number;
95
+ /** Total audio duration in milliseconds */
96
+ duration: number;
97
+ /** Extracted filename from the source URL */
98
+ fileName: string;
99
+ /** Audio file source URL */
100
+ src: string;
101
+ }
102
+
103
+ /**
104
+ * Information about a single item in an audio queue
105
+ */
106
+ export interface QueueItem {
107
+ /** Total audio duration in milliseconds */
108
+ duration: number;
109
+ /** Extracted filename from the source URL */
110
+ fileName: string;
111
+ /** Whether this item is currently playing */
112
+ isCurrentlyPlaying: boolean;
113
+ /** Whether this item is set to loop */
114
+ isLooping: boolean;
115
+ /** Audio file source URL */
116
+ src: string;
117
+ /** Volume level for this item (0-1) */
118
+ volume: number;
119
+ }
120
+
121
+ /**
122
+ * Complete snapshot of a queue's current state
123
+ */
124
+ export interface QueueSnapshot {
125
+ /** Channel number this snapshot represents */
126
+ channelNumber: number;
127
+ /** Zero-based index of the currently playing item */
128
+ currentIndex: number;
129
+ /** Whether the current audio is paused */
130
+ isPaused: boolean;
131
+ /** Array of audio items in the queue with their metadata */
132
+ items: QueueItem[];
133
+ /** Total number of items in the queue */
134
+ totalItems: number;
135
+ /** Current volume level for the channel (0-1) */
136
+ volume: number;
137
+ }
138
+
139
+ /**
140
+ * Callback function type for audio progress updates
141
+ * @param info Current audio information
142
+ */
143
+ export type ProgressCallback = (info: AudioInfo) => void;
144
+
145
+ /**
146
+ * Callback function type for queue change notifications
147
+ * @param queueSnapshot Current state of the queue
148
+ */
149
+ export type QueueChangeCallback = (queueSnapshot: QueueSnapshot) => void;
150
+
151
+ /**
152
+ * Callback function type for audio start notifications
153
+ * @param audioInfo Information about the audio that started
154
+ */
155
+ export type AudioStartCallback = (audioInfo: AudioStartInfo) => void;
156
+
157
+ /**
158
+ * Callback function type for audio complete notifications
159
+ * @param audioInfo Information about the audio that completed
160
+ */
161
+ export type AudioCompleteCallback = (audioInfo: AudioCompleteInfo) => void;
162
+
163
+ /**
164
+ * Callback function type for audio pause notifications
165
+ * @param channelNumber Channel that was paused
166
+ * @param audioInfo Information about the audio that was paused
167
+ */
168
+ export type AudioPauseCallback = (channelNumber: number, audioInfo: AudioInfo) => void;
169
+
170
+ /**
171
+ * Callback function type for audio resume notifications
172
+ * @param channelNumber Channel that was resumed
173
+ * @param audioInfo Information about the audio that was resumed
174
+ */
175
+ export type AudioResumeCallback = (channelNumber: number, audioInfo: AudioInfo) => void;
176
+
177
+ /**
178
+ * Information about an audio error that occurred
179
+ */
180
+ export interface AudioErrorInfo {
181
+ channelNumber: number;
182
+ src: string;
183
+ fileName: string;
184
+ error: Error;
185
+ errorType: 'network' | 'decode' | 'unsupported' | 'permission' | 'abort' | 'timeout' | 'unknown';
186
+ timestamp: number;
187
+ retryAttempt?: number;
188
+ remainingInQueue: number;
189
+ }
190
+
191
+ /**
192
+ * Configuration for automatic retry behavior when audio fails to load or play
193
+ */
194
+ export interface RetryConfig {
195
+ enabled: boolean;
196
+ maxRetries: number;
197
+ baseDelay: number;
198
+ exponentialBackoff: boolean;
199
+ timeoutMs: number;
200
+ fallbackUrls?: string[];
201
+ skipOnFailure: boolean;
202
+ }
203
+
204
+ /**
205
+ * Configuration options for error recovery mechanisms
206
+ */
207
+ export interface ErrorRecoveryOptions {
208
+ autoRetry: boolean;
209
+ showUserFeedback: boolean;
210
+ logErrorsToAnalytics: boolean;
211
+ preserveQueueOnError: boolean;
212
+ fallbackToNextTrack: boolean;
213
+ }
214
+
215
+ /**
216
+ * Callback function type for audio error events
217
+ */
218
+ export type AudioErrorCallback = (errorInfo: AudioErrorInfo) => void;
219
+
220
+ /**
221
+ * Extended audio queue channel with error handling capabilities
222
+ */
223
+ export interface ExtendedAudioQueueChannel {
224
+ audioCompleteCallbacks: Set<AudioCompleteCallback>;
225
+ audioErrorCallbacks: Set<AudioErrorCallback>;
226
+ audioPauseCallbacks: Set<AudioPauseCallback>;
227
+ audioResumeCallbacks: Set<AudioResumeCallback>;
228
+ audioStartCallbacks: Set<AudioStartCallback>;
229
+ isPaused?: boolean;
230
+ progressCallbacks: Map<HTMLAudioElement | null, Set<ProgressCallback>>;
231
+ queue: HTMLAudioElement[];
232
+ queueChangeCallbacks: Set<QueueChangeCallback>;
233
+ retryConfig?: RetryConfig;
234
+ volume?: number;
235
+ volumeConfig?: VolumeConfig;
127
236
  }