audio-channel-queue 1.6.0 → 1.8.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/dist/core.js +53 -34
- package/dist/errors.d.ts +137 -0
- package/dist/errors.js +461 -0
- package/dist/index.d.ts +10 -25
- package/dist/index.js +36 -32
- package/dist/info.d.ts +2 -1
- package/dist/info.js +8 -1
- package/dist/pause.d.ts +71 -0
- package/dist/pause.js +205 -2
- package/dist/types.d.ts +93 -20
- package/dist/types.js +20 -0
- package/dist/volume.d.ts +28 -3
- package/dist/volume.js +52 -9
- package/package.json +1 -1
- package/src/core.ts +55 -35
- package/src/errors.ts +480 -0
- package/src/index.ts +87 -83
- package/src/info.ts +8 -1
- package/src/pause.ts +411 -189
- package/src/types.ts +99 -18
- package/src/volume.ts +375 -327
package/src/info.ts
CHANGED
|
@@ -17,7 +17,8 @@ import { getAudioInfoFromElement, createQueueSnapshot } from './utils';
|
|
|
17
17
|
import { setupProgressTracking, cleanupProgressTracking } from './events';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Global array
|
|
20
|
+
* Global array to store audio channels with their queues and callback management
|
|
21
|
+
* Each channel maintains its own audio queue and event callback sets
|
|
21
22
|
*/
|
|
22
23
|
export const audioChannels: ExtendedAudioQueueChannel[] = [];
|
|
23
24
|
|
|
@@ -100,6 +101,7 @@ export const onAudioProgress = (channelNumber: number, callback: ProgressCallbac
|
|
|
100
101
|
if (!audioChannels[channelNumber]) {
|
|
101
102
|
audioChannels[channelNumber] = {
|
|
102
103
|
audioCompleteCallbacks: new Set(),
|
|
104
|
+
audioErrorCallbacks: new Set(),
|
|
103
105
|
audioPauseCallbacks: new Set(),
|
|
104
106
|
audioResumeCallbacks: new Set(),
|
|
105
107
|
audioStartCallbacks: new Set(),
|
|
@@ -173,6 +175,7 @@ export const onQueueChange = (channelNumber: number, callback: QueueChangeCallba
|
|
|
173
175
|
if (!audioChannels[channelNumber]) {
|
|
174
176
|
audioChannels[channelNumber] = {
|
|
175
177
|
audioCompleteCallbacks: new Set(),
|
|
178
|
+
audioErrorCallbacks: new Set(),
|
|
176
179
|
audioPauseCallbacks: new Set(),
|
|
177
180
|
audioResumeCallbacks: new Set(),
|
|
178
181
|
audioStartCallbacks: new Set(),
|
|
@@ -223,6 +226,7 @@ export const onAudioStart = (channelNumber: number, callback: AudioStartCallback
|
|
|
223
226
|
if (!audioChannels[channelNumber]) {
|
|
224
227
|
audioChannels[channelNumber] = {
|
|
225
228
|
audioCompleteCallbacks: new Set(),
|
|
229
|
+
audioErrorCallbacks: new Set(),
|
|
226
230
|
audioPauseCallbacks: new Set(),
|
|
227
231
|
audioResumeCallbacks: new Set(),
|
|
228
232
|
audioStartCallbacks: new Set(),
|
|
@@ -260,6 +264,7 @@ export const onAudioComplete = (channelNumber: number, callback: AudioCompleteCa
|
|
|
260
264
|
if (!audioChannels[channelNumber]) {
|
|
261
265
|
audioChannels[channelNumber] = {
|
|
262
266
|
audioCompleteCallbacks: new Set(),
|
|
267
|
+
audioErrorCallbacks: new Set(),
|
|
263
268
|
audioPauseCallbacks: new Set(),
|
|
264
269
|
audioResumeCallbacks: new Set(),
|
|
265
270
|
audioStartCallbacks: new Set(),
|
|
@@ -295,6 +300,7 @@ export const onAudioPause = (channelNumber: number, callback: AudioPauseCallback
|
|
|
295
300
|
if (!audioChannels[channelNumber]) {
|
|
296
301
|
audioChannels[channelNumber] = {
|
|
297
302
|
audioCompleteCallbacks: new Set(),
|
|
303
|
+
audioErrorCallbacks: new Set(),
|
|
298
304
|
audioPauseCallbacks: new Set(),
|
|
299
305
|
audioResumeCallbacks: new Set(),
|
|
300
306
|
audioStartCallbacks: new Set(),
|
|
@@ -330,6 +336,7 @@ export const onAudioResume = (channelNumber: number, callback: AudioResumeCallba
|
|
|
330
336
|
if (!audioChannels[channelNumber]) {
|
|
331
337
|
audioChannels[channelNumber] = {
|
|
332
338
|
audioCompleteCallbacks: new Set(),
|
|
339
|
+
audioErrorCallbacks: new Set(),
|
|
333
340
|
audioPauseCallbacks: new Set(),
|
|
334
341
|
audioResumeCallbacks: new Set(),
|
|
335
342
|
audioStartCallbacks: new Set(),
|
package/src/pause.ts
CHANGED
|
@@ -1,190 +1,412 @@
|
|
|
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
|
-
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* @returns Promise that resolves when
|
|
163
|
-
* @example
|
|
164
|
-
* ```typescript
|
|
165
|
-
* await
|
|
166
|
-
* ```
|
|
167
|
-
*/
|
|
168
|
-
export const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pause and resume management functions for the audio-channel-queue package
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ExtendedAudioQueueChannel, AudioInfo, FadeType, FadeConfig, ChannelFadeState, EasingType } from './types';
|
|
6
|
+
import { audioChannels } from './info';
|
|
7
|
+
import { getAudioInfoFromElement } from './utils';
|
|
8
|
+
import { emitAudioPause, emitAudioResume } from './events';
|
|
9
|
+
import { transitionVolume } from './volume';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Predefined fade configurations for different transition types
|
|
13
|
+
*/
|
|
14
|
+
const FADE_CONFIGS: Record<FadeType, FadeConfig> = {
|
|
15
|
+
[FadeType.Linear]: { duration: 800, pauseCurve: EasingType.Linear, resumeCurve: EasingType.Linear },
|
|
16
|
+
[FadeType.Gentle]: { duration: 800, pauseCurve: EasingType.EaseOut, resumeCurve: EasingType.EaseIn },
|
|
17
|
+
[FadeType.Dramatic]: { duration: 800, pauseCurve: EasingType.EaseIn, resumeCurve: EasingType.EaseOut }
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets the current volume for a channel, accounting for synchronous state
|
|
22
|
+
* @param channelNumber - The channel number
|
|
23
|
+
* @returns Current volume level (0-1)
|
|
24
|
+
*/
|
|
25
|
+
const getChannelVolumeSync = (channelNumber: number): number => {
|
|
26
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
27
|
+
return channel?.volume || 1.0;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Sets the channel volume synchronously in internal state
|
|
32
|
+
* @param channelNumber - The channel number
|
|
33
|
+
* @param volume - Volume level (0-1)
|
|
34
|
+
*/
|
|
35
|
+
const setChannelVolumeSync = (channelNumber: number, volume: number): void => {
|
|
36
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
37
|
+
if (channel) {
|
|
38
|
+
channel.volume = volume;
|
|
39
|
+
if (channel.queue.length > 0) {
|
|
40
|
+
channel.queue[0].volume = volume;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Pauses the currently playing audio in a specific channel with smooth volume fade
|
|
47
|
+
* @param fadeType - Type of fade transition to apply
|
|
48
|
+
* @param channelNumber - The channel number to pause (defaults to 0)
|
|
49
|
+
* @returns Promise that resolves when the pause and fade are complete
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* await pauseWithFade(FadeType.Gentle, 0); // Pause with gentle fade out over 800ms
|
|
53
|
+
* await pauseWithFade(FadeType.Dramatic, 1); // Pause with dramatic fade out over 800ms
|
|
54
|
+
* await pauseWithFade(FadeType.Linear, 2); // Linear pause with 800ms fade
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export const pauseWithFade = async (fadeType: FadeType = FadeType.Gentle, channelNumber: number = 0): Promise<void> => {
|
|
58
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
59
|
+
|
|
60
|
+
if (!channel || channel.queue.length === 0) return;
|
|
61
|
+
|
|
62
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
63
|
+
|
|
64
|
+
// Don't pause if already paused or ended
|
|
65
|
+
if (currentAudio.paused || currentAudio.ended) return;
|
|
66
|
+
|
|
67
|
+
const config: FadeConfig = FADE_CONFIGS[fadeType];
|
|
68
|
+
const originalVolume: number = getChannelVolumeSync(channelNumber);
|
|
69
|
+
|
|
70
|
+
// Store fade state for resumeWithFade to use
|
|
71
|
+
channel.fadeState = {
|
|
72
|
+
originalVolume,
|
|
73
|
+
fadeType,
|
|
74
|
+
isPaused: true
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
if (config.duration === 0) {
|
|
78
|
+
// Instant pause
|
|
79
|
+
await pauseChannel(channelNumber);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Fade to 0 with pause curve, then pause
|
|
84
|
+
await transitionVolume(channelNumber, 0, config.duration, config.pauseCurve);
|
|
85
|
+
await pauseChannel(channelNumber);
|
|
86
|
+
|
|
87
|
+
// Reset volume to original for resume (synchronously to avoid state issues)
|
|
88
|
+
setChannelVolumeSync(channelNumber, originalVolume);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Resumes the currently paused audio in a specific channel with smooth volume fade
|
|
93
|
+
* Uses the complementary fade curve automatically based on the pause fade type, or allows override
|
|
94
|
+
* @param fadeType - Optional fade type to override the stored fade type from pause
|
|
95
|
+
* @param channelNumber - The channel number to resume (defaults to 0)
|
|
96
|
+
* @returns Promise that resolves when the resume and fade are complete
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* await resumeWithFade(); // Resume with automatically paired fade curve from pause
|
|
100
|
+
* await resumeWithFade(FadeType.Dramatic, 0); // Override with dramatic fade
|
|
101
|
+
* await resumeWithFade(FadeType.Linear); // Override with linear fade on default channel
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export const resumeWithFade = async (fadeType?: FadeType, channelNumber: number = 0): Promise<void> => {
|
|
105
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
106
|
+
|
|
107
|
+
if (!channel || channel.queue.length === 0) return;
|
|
108
|
+
|
|
109
|
+
const fadeState: ChannelFadeState | undefined = channel.fadeState;
|
|
110
|
+
if (!fadeState || !fadeState.isPaused) {
|
|
111
|
+
// Fall back to regular resume if no fade state
|
|
112
|
+
await resumeChannel(channelNumber);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Use provided fadeType or fall back to stored fadeType from pause
|
|
117
|
+
const effectiveFadeType: FadeType = fadeType || fadeState.fadeType;
|
|
118
|
+
const config: FadeConfig = FADE_CONFIGS[effectiveFadeType];
|
|
119
|
+
|
|
120
|
+
if (config.duration === 0) {
|
|
121
|
+
// Instant resume
|
|
122
|
+
await resumeChannel(channelNumber);
|
|
123
|
+
fadeState.isPaused = false;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Set volume to 0, resume, then fade to original with resume curve
|
|
128
|
+
setChannelVolumeSync(channelNumber, 0);
|
|
129
|
+
await resumeChannel(channelNumber);
|
|
130
|
+
await transitionVolume(channelNumber, fadeState.originalVolume, config.duration, config.resumeCurve);
|
|
131
|
+
|
|
132
|
+
fadeState.isPaused = false;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Toggles pause/resume state for a specific channel with integrated fade
|
|
137
|
+
* @param fadeType - Type of fade transition to apply when pausing
|
|
138
|
+
* @param channelNumber - The channel number to toggle (defaults to 0)
|
|
139
|
+
* @returns Promise that resolves when the toggle and fade are complete
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* await togglePauseWithFade(FadeType.Gentle, 0); // Toggle with gentle fade
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export const togglePauseWithFade = async (fadeType: FadeType = FadeType.Gentle, channelNumber: number = 0): Promise<void> => {
|
|
146
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
147
|
+
|
|
148
|
+
if (!channel || channel.queue.length === 0) return;
|
|
149
|
+
|
|
150
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
151
|
+
|
|
152
|
+
if (currentAudio.paused) {
|
|
153
|
+
await resumeWithFade(undefined, channelNumber);
|
|
154
|
+
} else {
|
|
155
|
+
await pauseWithFade(fadeType, channelNumber);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Pauses all currently playing audio across all channels with smooth volume fade
|
|
161
|
+
* @param fadeType - Type of fade transition to apply to all channels
|
|
162
|
+
* @returns Promise that resolves when all channels are paused and faded
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* await pauseAllWithFade('dramatic'); // Pause everything with dramatic fade
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export const pauseAllWithFade = async (fadeType: FadeType = FadeType.Gentle): Promise<void> => {
|
|
169
|
+
const pausePromises: Promise<void>[] = [];
|
|
170
|
+
|
|
171
|
+
audioChannels.forEach((_channel: ExtendedAudioQueueChannel, index: number) => {
|
|
172
|
+
pausePromises.push(pauseWithFade(fadeType, index));
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await Promise.all(pausePromises);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Resumes all currently paused audio across all channels with smooth volume fade
|
|
180
|
+
* Uses automatically paired fade curves based on each channel's pause fade type
|
|
181
|
+
* @returns Promise that resolves when all channels are resumed and faded
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* await resumeAllWithFade(); // Resume everything with paired fade curves
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export const resumeAllWithFade = async (): Promise<void> => {
|
|
188
|
+
const resumePromises: Promise<void>[] = [];
|
|
189
|
+
|
|
190
|
+
audioChannels.forEach((_channel: ExtendedAudioQueueChannel, index: number) => {
|
|
191
|
+
resumePromises.push(resumeWithFade(undefined, index));
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
await Promise.all(resumePromises);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Toggles pause/resume state for all channels with integrated fade
|
|
199
|
+
* If any channels are playing, all will be paused with fade
|
|
200
|
+
* If all channels are paused, all will be resumed with fade
|
|
201
|
+
* @param fadeType - Type of fade transition to apply when pausing
|
|
202
|
+
* @returns Promise that resolves when all toggles and fades are complete
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* await togglePauseAllWithFade('gentle'); // Global toggle with gentle fade
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export const togglePauseAllWithFade = async (fadeType: FadeType = FadeType.Gentle): Promise<void> => {
|
|
209
|
+
let hasPlayingChannel: boolean = false;
|
|
210
|
+
|
|
211
|
+
// Check if any channel is currently playing
|
|
212
|
+
for (let i = 0; i < audioChannels.length; i++) {
|
|
213
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[i];
|
|
214
|
+
if (channel && channel.queue.length > 0) {
|
|
215
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
216
|
+
if (!currentAudio.paused && !currentAudio.ended) {
|
|
217
|
+
hasPlayingChannel = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// If any channel is playing, pause all with fade
|
|
224
|
+
// If no channels are playing, resume all with fade
|
|
225
|
+
if (hasPlayingChannel) {
|
|
226
|
+
await pauseAllWithFade(fadeType);
|
|
227
|
+
} else {
|
|
228
|
+
await resumeAllWithFade();
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Pauses the currently playing audio in a specific channel
|
|
234
|
+
* @param channelNumber - The channel number to pause (defaults to 0)
|
|
235
|
+
* @returns Promise that resolves when the audio is paused
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* await pauseChannel(0); // Pause audio in channel 0
|
|
239
|
+
* await pauseChannel(); // Pause audio in default channel
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
export const pauseChannel = async (channelNumber: number = 0): Promise<void> => {
|
|
243
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
244
|
+
|
|
245
|
+
if (channel && channel.queue.length > 0) {
|
|
246
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
247
|
+
|
|
248
|
+
if (!currentAudio.paused && !currentAudio.ended) {
|
|
249
|
+
currentAudio.pause();
|
|
250
|
+
channel.isPaused = true;
|
|
251
|
+
|
|
252
|
+
const audioInfo: AudioInfo | null = getAudioInfoFromElement(currentAudio, channelNumber, audioChannels);
|
|
253
|
+
if (audioInfo) {
|
|
254
|
+
emitAudioPause(channelNumber, audioInfo, audioChannels);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Resumes the currently paused audio in a specific channel
|
|
262
|
+
* @param channelNumber - The channel number to resume (defaults to 0)
|
|
263
|
+
* @returns Promise that resolves when the audio starts playing
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* await resumeChannel(0); // Resume audio in channel 0
|
|
267
|
+
* await resumeChannel(); // Resume audio in default channel
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
export const resumeChannel = async (channelNumber: number = 0): Promise<void> => {
|
|
271
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
272
|
+
|
|
273
|
+
if (channel && channel.queue.length > 0) {
|
|
274
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
275
|
+
|
|
276
|
+
// Only resume if both the channel is marked as paused AND the audio element is actually paused AND not ended
|
|
277
|
+
if (channel.isPaused && currentAudio.paused && !currentAudio.ended) {
|
|
278
|
+
await currentAudio.play();
|
|
279
|
+
channel.isPaused = false;
|
|
280
|
+
|
|
281
|
+
const audioInfo: AudioInfo | null = getAudioInfoFromElement(currentAudio, channelNumber, audioChannels);
|
|
282
|
+
if (audioInfo) {
|
|
283
|
+
emitAudioResume(channelNumber, audioInfo, audioChannels);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Toggles pause/resume state for a specific channel
|
|
291
|
+
* @param channelNumber - The channel number to toggle (defaults to 0)
|
|
292
|
+
* @returns Promise that resolves when the toggle is complete
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* await togglePauseChannel(0); // Toggle pause state for channel 0
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export const togglePauseChannel = async (channelNumber: number = 0): Promise<void> => {
|
|
299
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
300
|
+
|
|
301
|
+
if (channel && channel.queue.length > 0) {
|
|
302
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
303
|
+
|
|
304
|
+
if (currentAudio.paused) {
|
|
305
|
+
await resumeChannel(channelNumber);
|
|
306
|
+
} else {
|
|
307
|
+
await pauseChannel(channelNumber);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Pauses all currently playing audio across all channels
|
|
314
|
+
* @returns Promise that resolves when all audio is paused
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* await pauseAllChannels(); // Pause everything
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export const pauseAllChannels = async (): Promise<void> => {
|
|
321
|
+
const pausePromises: Promise<void>[] = [];
|
|
322
|
+
|
|
323
|
+
audioChannels.forEach((_channel: ExtendedAudioQueueChannel, index: number) => {
|
|
324
|
+
pausePromises.push(pauseChannel(index));
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
await Promise.all(pausePromises);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Resumes all currently paused audio across all channels
|
|
332
|
+
* @returns Promise that resolves when all audio is resumed
|
|
333
|
+
* @example
|
|
334
|
+
* ```typescript
|
|
335
|
+
* await resumeAllChannels(); // Resume everything that was paused
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
export const resumeAllChannels = async (): Promise<void> => {
|
|
339
|
+
const resumePromises: Promise<void>[] = [];
|
|
340
|
+
|
|
341
|
+
audioChannels.forEach((_channel: ExtendedAudioQueueChannel, index: number) => {
|
|
342
|
+
resumePromises.push(resumeChannel(index));
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
await Promise.all(resumePromises);
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Checks if a specific channel is currently paused
|
|
350
|
+
* @param channelNumber - The channel number to check (defaults to 0)
|
|
351
|
+
* @returns True if the channel is paused, false otherwise
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* const isPaused = isChannelPaused(0);
|
|
355
|
+
* console.log(`Channel 0 is ${isPaused ? 'paused' : 'playing'}`);
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
export const isChannelPaused = (channelNumber: number = 0): boolean => {
|
|
359
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[channelNumber];
|
|
360
|
+
return channel?.isPaused || false;
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Gets the pause state of all channels
|
|
365
|
+
* @returns Array of boolean values indicating pause state for each channel
|
|
366
|
+
* @example
|
|
367
|
+
* ```typescript
|
|
368
|
+
* const pauseStates = getAllChannelsPauseState();
|
|
369
|
+
* pauseStates.forEach((isPaused, index) => {
|
|
370
|
+
* console.log(`Channel ${index}: ${isPaused ? 'paused' : 'playing'}`);
|
|
371
|
+
* });
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
export const getAllChannelsPauseState = (): boolean[] => {
|
|
375
|
+
return audioChannels.map((channel: ExtendedAudioQueueChannel) =>
|
|
376
|
+
channel?.isPaused || false
|
|
377
|
+
);
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Toggles pause/resume state for all channels globally
|
|
382
|
+
* If any channels are currently playing, all channels will be paused
|
|
383
|
+
* If all channels are paused, all channels will be resumed
|
|
384
|
+
* @returns Promise that resolves when the toggle is complete
|
|
385
|
+
* @example
|
|
386
|
+
* ```typescript
|
|
387
|
+
* await togglePauseAllChannels(); // Pause all if any are playing, resume all if all are paused
|
|
388
|
+
* ```
|
|
389
|
+
*/
|
|
390
|
+
export const togglePauseAllChannels = async (): Promise<void> => {
|
|
391
|
+
let hasPlayingChannel: boolean = false;
|
|
392
|
+
|
|
393
|
+
// Check if any channel is currently playing
|
|
394
|
+
for (let i = 0; i < audioChannels.length; i++) {
|
|
395
|
+
const channel: ExtendedAudioQueueChannel = audioChannels[i];
|
|
396
|
+
if (channel && channel.queue.length > 0) {
|
|
397
|
+
const currentAudio: HTMLAudioElement = channel.queue[0];
|
|
398
|
+
if (!currentAudio.paused && !currentAudio.ended) {
|
|
399
|
+
hasPlayingChannel = true;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// If any channel is playing, pause all channels
|
|
406
|
+
// If no channels are playing, resume all channels
|
|
407
|
+
if (hasPlayingChannel) {
|
|
408
|
+
await pauseAllChannels();
|
|
409
|
+
} else {
|
|
410
|
+
await resumeAllChannels();
|
|
411
|
+
}
|
|
190
412
|
};
|