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/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Audio Channel Queue
|
|
2
2
|
The purpose of this package is to help manage the playback of audio files.
|
|
3
3
|
|
|
4
|
+
π΅ [Demo](https://tonycarpenter21.github.io/audio-queue-demo/queue-management)
|
|
5
|
+
|
|
6
|
+
π [Docs](https://tonycarpenter21.github.io/audio-queue-docs/)
|
|
7
|
+
|
|
4
8
|
## π Key Features
|
|
5
9
|
|
|
6
10
|
- β
**Multi-channel queue management** - Independent audio queues for concurrent playback
|
|
@@ -22,6 +26,8 @@ NPM package can be found [here](https://www.npmjs.com/package/audio-channel-queu
|
|
|
22
26
|
|
|
23
27
|
GitHub Repo can be found [here](https://github.com/tonycarpenter21/audio-channel-queue).
|
|
24
28
|
|
|
29
|
+
Documentation can be found [here](https://tonycarpenter21.github.io/audio-queue-docs/)
|
|
30
|
+
|
|
25
31
|
## π Browser Compatibility
|
|
26
32
|
|
|
27
33
|
This package is designed for **browser environments** and uses the Web Audio API (`HTMLAudioElement`). It is **not** intended for Node.js server-side use.
|
|
@@ -66,111 +72,206 @@ Install this package by running either of these commands (typescript packages ar
|
|
|
66
72
|
## Basic Queue Management Functions:
|
|
67
73
|
|
|
68
74
|
### Queue Audio
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
```typescript
|
|
76
|
+
// Add an audio file to the queue and start playing it automatically.
|
|
77
|
+
queueAudio(audioUrl, channelNumber?, options?);
|
|
78
|
+
queueAudio('hello.mp3'); // Add to default channel 0
|
|
79
|
+
queueAudio('laser.mp3', 1, { loop: true, volume: 0.8 }); // Add to channel 1 with options
|
|
80
|
+
```
|
|
81
|
+
|
|
74
82
|
|
|
75
83
|
### Queue Audio with Priority
|
|
76
|
-
```
|
|
77
|
-
|
|
84
|
+
```typescript
|
|
85
|
+
// Add a file to the front of the queue (plays after current audio finishes).
|
|
86
|
+
queueAudioPriority(audioUrl, channelNumber?, options?);
|
|
87
|
+
queueAudioPriority('urgent.mp3'); // Add to front of default channel 0
|
|
88
|
+
queueAudioPriority('announcement.mp3', 1, { volume: 1.0 }); // Add to front of channel 1
|
|
89
|
+
```
|
|
90
|
+
|
|
78
91
|
|
|
79
92
|
### Stop Current Audio
|
|
80
|
-
```
|
|
81
|
-
|
|
93
|
+
```typescript
|
|
94
|
+
// Stop the current audio and automatically start playing the next one in queue.
|
|
95
|
+
stopCurrentAudioInChannel(channelNumber?);
|
|
96
|
+
stopCurrentAudioInChannel(); // Stop current audio in default channel (0)
|
|
97
|
+
stopCurrentAudioInChannel(2); // Stop current audio in channel 2
|
|
98
|
+
```
|
|
99
|
+
|
|
82
100
|
|
|
83
101
|
### Stop All Audio in Channel
|
|
84
|
-
```
|
|
85
|
-
|
|
102
|
+
```typescript
|
|
103
|
+
// Stop all audio in a channel and remove all enqueued files.
|
|
104
|
+
stopAllAudioInChannel(channelNumber?);
|
|
105
|
+
stopAllAudioInChannel(); // Stop and clear all audio in default channel (0)
|
|
106
|
+
stopAllAudioInChannel(1); // Stop and clear all audio in channel 1
|
|
107
|
+
```
|
|
86
108
|
|
|
87
109
|
### Stop All Audio
|
|
88
|
-
```
|
|
89
|
-
|
|
110
|
+
```typescript
|
|
111
|
+
// Stop all audio in all channels and remove all enqueued files.
|
|
112
|
+
stopAllAudio();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## π Advanced Queue Manipulation:
|
|
116
|
+
|
|
117
|
+
### Remove Queued Item
|
|
118
|
+
```typescript
|
|
119
|
+
// Remove a specific item from the queue by its position (cannot remove currently playing item at index 0).
|
|
120
|
+
removeQueuedItem(queuedSlotNumber, channelNumber?);
|
|
121
|
+
const result = removeQueuedItem(2); // Remove item at index 2 from default channel (0)
|
|
122
|
+
const result = removeQueuedItem(1, 1); // Remove item at index 1 from channel 1
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Reorder Queue Items
|
|
126
|
+
```typescript
|
|
127
|
+
// Move a queue item from one position to another (cannot move currently playing item at index 0).
|
|
128
|
+
reorderQueue(currentQueuedSlotNumber, newQueuedSlotNumber, channelNumber?);
|
|
129
|
+
const result = reorderQueue(3, 1); // Move item from index 3 to index 1 in default channel (0)
|
|
130
|
+
const result = reorderQueue(2, 4, 1); // Move item from index 2 to index 4 in channel 1
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Clear Queue After Current
|
|
134
|
+
```typescript
|
|
135
|
+
// Remove all items from the queue except the currently playing audio.
|
|
136
|
+
clearQueueAfterCurrent(channelNumber?);
|
|
137
|
+
const result = clearQueueAfterCurrent(); // Clear queue after current in default channel (0)
|
|
138
|
+
const result = clearQueueAfterCurrent(2); // Clear queue after current in channel 2
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Swap Queue Items
|
|
142
|
+
```typescript
|
|
143
|
+
// Swap the positions of two items in the queue (cannot involve currently playing item at index 0).
|
|
144
|
+
swapQueueItems(firstQueuedSlotNumber, secondQueuedSlotNumber, channelNumber?);
|
|
145
|
+
const result = swapQueueItems(1, 3); // Swap items at index 1 and 3 in default channel (0)
|
|
146
|
+
const result = swapQueueItems(2, 4, 1); // Swap items at index 2 and 4 in channel 1
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Get Queue Item Info
|
|
150
|
+
```typescript
|
|
151
|
+
// Get information about a specific item in the queue.
|
|
152
|
+
getQueueItemInfo(queuedSlotNumber, channelNumber?);
|
|
153
|
+
const itemInfo = getQueueItemInfo(1); // Get info for item at index 1 in default channel (0)
|
|
154
|
+
const info = getQueueItemInfo(2, 1); // Get info for item at index 2 in channel 1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Get Queue Length
|
|
158
|
+
```typescript
|
|
159
|
+
// Get the total number of items in a channel's queue.
|
|
160
|
+
getQueueLength(channelNumber?);
|
|
161
|
+
const length = getQueueLength(); // Get queue length for default channel (0)
|
|
162
|
+
const count = getQueueLength(2); // Get queue length for channel 2
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// All queue manipulation functions return a QueueManipulationResult:
|
|
167
|
+
interface QueueManipulationResult {
|
|
168
|
+
success: boolean; // Whether the operation was successful
|
|
169
|
+
error?: string; // Error message if operation failed
|
|
170
|
+
updatedQueue?: QueueSnapshot; // The queue snapshot after the operation (if successful)
|
|
171
|
+
}
|
|
172
|
+
```
|
|
90
173
|
|
|
91
174
|
## ποΈ Volume Control Functions:
|
|
92
175
|
|
|
93
176
|
### Set Channel Volume
|
|
94
|
-
```setChannelVolume(channelNumber, volume);```
|
|
95
|
-
Set the volume for a specific channel (0-1 range).
|
|
96
177
|
```typescript
|
|
178
|
+
// Set the volume for a specific channel (0-1 range).
|
|
179
|
+
setChannelVolume(channelNumber, volume);
|
|
97
180
|
setChannelVolume(0, 0.5); // Set channel 0 to 50% volume
|
|
98
181
|
setChannelVolume(1, 0.8); // Set channel 1 to 80% volume
|
|
99
182
|
```
|
|
100
183
|
|
|
101
184
|
### Get Channel Volume
|
|
102
|
-
```getChannelVolume(channelNumber);```
|
|
103
|
-
Get the current volume level for a specific channel.
|
|
104
185
|
```typescript
|
|
105
|
-
|
|
106
|
-
|
|
186
|
+
// Get the current volume level for a specific channel.
|
|
187
|
+
getChannelVolume(channelNumber?);
|
|
188
|
+
const volume = getChannelVolume(); // Get default channel (0) volume
|
|
189
|
+
console.log(`Channel volume: ${(getChannelVolume(2) * 100).toFixed(0)}%`); // Get channel 2 volume
|
|
107
190
|
```
|
|
108
191
|
|
|
109
192
|
### Set All Channels Volume
|
|
110
|
-
```setAllChannelsVolume(volume);```
|
|
111
|
-
Set the same volume level for all channels.
|
|
112
193
|
```typescript
|
|
194
|
+
// Set the same volume level for all channels.
|
|
195
|
+
setAllChannelsVolume(volume);
|
|
113
196
|
setAllChannelsVolume(0.6); // Set all channels to 60% volume
|
|
197
|
+
setAllChannelsVolume(0.0); // Mute all channels
|
|
114
198
|
```
|
|
115
199
|
|
|
116
200
|
### Volume Ducking (Background Audio Reduction)
|
|
117
|
-
```setVolumeDucking(config);```
|
|
118
|
-
Automatically reduce other channels' volume when priority audio plays - perfect for voice announcements over background music!
|
|
119
201
|
```typescript
|
|
120
|
-
//
|
|
202
|
+
// Automatically reduce other channels' volume when priority audio plays.
|
|
203
|
+
setVolumeDucking(config);
|
|
204
|
+
setVolumeDucking({ priorityChannel: 1, duckingVolume: 0.2 }); // Simple ducking
|
|
121
205
|
setVolumeDucking({
|
|
122
206
|
priorityChannel: 1,
|
|
123
207
|
priorityVolume: 1.0,
|
|
124
|
-
duckingVolume: 0.2
|
|
125
|
-
|
|
208
|
+
duckingVolume: 0.2,
|
|
209
|
+
transitionDuration: 500
|
|
210
|
+
}); // Full configuration
|
|
126
211
|
```
|
|
127
212
|
|
|
128
|
-
```
|
|
129
|
-
Remove volume ducking configuration from all channels.
|
|
213
|
+
```typescript
|
|
214
|
+
// Remove volume ducking configuration from all channels.
|
|
215
|
+
clearVolumeDucking();
|
|
216
|
+
```
|
|
130
217
|
|
|
131
218
|
## β―οΈ Pause/Resume Functions:
|
|
132
219
|
|
|
133
220
|
### Pause Channel
|
|
134
|
-
```pauseChannel(channelNumber);```
|
|
135
|
-
Pause audio playback in a specific channel.
|
|
136
221
|
```typescript
|
|
137
|
-
|
|
138
|
-
|
|
222
|
+
// Pause audio playback in a specific channel.
|
|
223
|
+
pauseChannel(channelNumber?);
|
|
224
|
+
await pauseChannel(); // Pause audio in default channel (0)
|
|
225
|
+
await pauseChannel(1); // Pause audio in channel 1
|
|
139
226
|
```
|
|
140
227
|
|
|
141
228
|
### Resume Channel
|
|
142
|
-
```resumeChannel(channelNumber);```
|
|
143
|
-
Resume audio playback in a specific channel.
|
|
144
229
|
```typescript
|
|
145
|
-
|
|
230
|
+
// Resume audio playback in a specific channel.
|
|
231
|
+
resumeChannel(channelNumber?);
|
|
232
|
+
await resumeChannel(); // Resume audio in default channel (0)
|
|
233
|
+
await resumeChannel(1); // Resume audio in channel 1
|
|
146
234
|
```
|
|
147
235
|
|
|
148
236
|
### Toggle Pause
|
|
149
|
-
```togglePauseChannel(channelNumber);```
|
|
150
|
-
Toggle between pause and resume states.
|
|
151
237
|
```typescript
|
|
152
|
-
|
|
238
|
+
// Toggle between pause and resume states.
|
|
239
|
+
togglePauseChannel(channelNumber?);
|
|
240
|
+
await togglePauseChannel(); // Toggle default channel (0)
|
|
241
|
+
await togglePauseChannel(1); // Toggle channel 1
|
|
153
242
|
```
|
|
154
243
|
|
|
155
244
|
### Pause/Resume All Channels
|
|
156
|
-
```pauseAllChannels();``` and ```resumeAllChannels();```
|
|
157
|
-
Control all channels simultaneously.
|
|
158
245
|
```typescript
|
|
159
|
-
|
|
160
|
-
|
|
246
|
+
// Pause all channels simultaneously.
|
|
247
|
+
pauseAllChannels();
|
|
248
|
+
await pauseAllChannels();
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
// Resume all channels that were paused.
|
|
253
|
+
resumeAllChannels();
|
|
254
|
+
await resumeAllChannels();
|
|
161
255
|
```
|
|
162
256
|
|
|
163
257
|
### Global Toggle Pause/Resume
|
|
164
|
-
```togglePauseAllChannels();```
|
|
165
|
-
Smart toggle that pauses all channels if any are playing, or resumes all if all are paused.
|
|
166
258
|
```typescript
|
|
167
|
-
|
|
259
|
+
// Smart toggle that pauses all channels if any are playing, or resumes all if all are paused.
|
|
260
|
+
togglePauseAllChannels();
|
|
261
|
+
await togglePauseAllChannels();
|
|
168
262
|
```
|
|
169
263
|
|
|
170
264
|
### Check Pause State
|
|
171
|
-
```isChannelPaused(channelNumber);``` and ```getAllChannelsPauseState();```
|
|
172
265
|
```typescript
|
|
173
|
-
|
|
266
|
+
// Check if a specific channel is paused.
|
|
267
|
+
isChannelPaused(channelNumber?);
|
|
268
|
+
const isPaused = isChannelPaused(); // Check if default channel (0) is paused
|
|
269
|
+
const channelPaused = isChannelPaused(2); // Check if channel 2 is paused
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Get pause state for all channels.
|
|
274
|
+
getAllChannelsPauseState();
|
|
174
275
|
const allPauseStates = getAllChannelsPauseState();
|
|
175
276
|
```
|
|
176
277
|
|
|
@@ -193,16 +294,27 @@ interface AudioInfo {
|
|
|
193
294
|
```
|
|
194
295
|
|
|
195
296
|
### Get Current Audio Info
|
|
196
|
-
```
|
|
197
|
-
Get information about the currently playing audio in a specific channel.
|
|
297
|
+
```typescript
|
|
298
|
+
// Get information about the currently playing audio in a specific channel.
|
|
299
|
+
getCurrentAudioInfo(channelNumber?);
|
|
300
|
+
const audioInfo = getCurrentAudioInfo(); // Get current audio info for default channel (0)
|
|
301
|
+
const info = getCurrentAudioInfo(1); // Get info for channel 1 - returns AudioInfo | null
|
|
302
|
+
```
|
|
198
303
|
|
|
199
304
|
### Get All Channels Info
|
|
200
|
-
```
|
|
201
|
-
Get audio information for all channels.
|
|
305
|
+
```typescript
|
|
306
|
+
// Get audio information for all channels.
|
|
307
|
+
getAllChannelsInfo();
|
|
308
|
+
const allChannelsInfo = getAllChannelsInfo();
|
|
309
|
+
```
|
|
202
310
|
|
|
203
311
|
### Queue State Management
|
|
204
|
-
```
|
|
205
|
-
Get a complete snapshot of the queue state for a specific channel.
|
|
312
|
+
```typescript
|
|
313
|
+
// Get a complete snapshot of the queue state for a specific channel.
|
|
314
|
+
getQueueSnapshot(channelNumber?);
|
|
315
|
+
const queueSnapshot = getQueueSnapshot(); // Get snapshot for default channel (0)
|
|
316
|
+
const snapshot = getQueueSnapshot(2); // Get snapshot for channel 2 - returns QueueSnapshot | null
|
|
317
|
+
```
|
|
206
318
|
|
|
207
319
|
```typescript
|
|
208
320
|
interface QueueSnapshot {
|
|
@@ -223,247 +335,50 @@ interface QueueSnapshot {
|
|
|
223
335
|
```
|
|
224
336
|
|
|
225
337
|
### Real-time Progress Tracking
|
|
226
|
-
```
|
|
227
|
-
Subscribe to real-time progress updates for a specific channel.
|
|
338
|
+
```typescript
|
|
339
|
+
// Subscribe to real-time progress updates for a specific channel.
|
|
340
|
+
onAudioProgress(channelNumber, callback);
|
|
341
|
+
onAudioProgress(0, (info) => console.log(info.progress)); // Simple progress logging
|
|
342
|
+
onAudioProgress(1, (info) => updateProgressBar(info.currentTime, info.duration)); // Complex UI update
|
|
343
|
+
```
|
|
228
344
|
|
|
229
|
-
```
|
|
230
|
-
Remove all progress listeners for a specific channel.
|
|
345
|
+
```typescript
|
|
346
|
+
// Remove all progress listeners for a specific channel.
|
|
347
|
+
offAudioProgress(channelNumber?);
|
|
348
|
+
offAudioProgress(); // Remove all progress listeners in default channel (0)
|
|
349
|
+
offAudioProgress(1); // Remove all progress listeners in channel 1
|
|
350
|
+
```
|
|
231
351
|
|
|
232
352
|
### Enhanced Event System
|
|
233
|
-
```
|
|
234
|
-
Subscribe to queue change events for visual updates.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
Subscribe to audio start events.
|
|
238
|
-
|
|
239
|
-
```onAudioComplete(channelNumber, callback);```
|
|
240
|
-
Subscribe to audio completion events.
|
|
241
|
-
|
|
242
|
-
```onAudioPause(channelNumber, callback);```
|
|
243
|
-
Subscribe to audio pause events.
|
|
244
|
-
|
|
245
|
-
```onAudioResume(channelNumber, callback);```
|
|
246
|
-
Subscribe to audio resume events.
|
|
247
|
-
|
|
248
|
-
### Example Usage with All New Features:
|
|
249
|
-
|
|
250
|
-
`App.tsx`
|
|
251
|
-
```typescript
|
|
252
|
-
import backgroundMusic from './audio/background.mp3';
|
|
253
|
-
import announcement from './audio/announcement.wav';
|
|
254
|
-
import {
|
|
255
|
-
queueAudio,
|
|
256
|
-
queueAudioPriority,
|
|
257
|
-
getCurrentAudioInfo,
|
|
258
|
-
pauseChannel,
|
|
259
|
-
resumeChannel,
|
|
260
|
-
togglePauseAllChannels,
|
|
261
|
-
setChannelVolume,
|
|
262
|
-
setVolumeDucking,
|
|
263
|
-
onAudioProgress,
|
|
264
|
-
onAudioPause,
|
|
265
|
-
onAudioResume,
|
|
266
|
-
onQueueChange,
|
|
267
|
-
AudioInfo,
|
|
268
|
-
QueueSnapshot
|
|
269
|
-
} from 'audio-channel-queue';
|
|
270
|
-
import { useState, useEffect } from 'react';
|
|
271
|
-
|
|
272
|
-
function App(): JSX.Element {
|
|
273
|
-
const [currentInfo, setCurrentInfo] = useState<AudioInfo | null>(null);
|
|
274
|
-
const [queueSnapshot, setQueueSnapshot] = useState<QueueSnapshot | null>(null);
|
|
275
|
-
const [isPaused, setIsPaused] = useState(false);
|
|
276
|
-
|
|
277
|
-
useEffect(() => {
|
|
278
|
-
// Set up background music with looping
|
|
279
|
-
const setupBackgroundMusic = async () => {
|
|
280
|
-
await queueAudio(backgroundMusic, 0, {
|
|
281
|
-
loop: true,
|
|
282
|
-
volume: 0.3
|
|
283
|
-
});
|
|
284
|
-
setChannelVolume(0, 0.3); // 30% volume for background
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// Configure volume ducking for announcements
|
|
288
|
-
setVolumeDucking({
|
|
289
|
-
priorityChannel: 1, // Announcements on channel 1
|
|
290
|
-
priorityVolume: 1.0, // Full volume for announcements
|
|
291
|
-
duckingVolume: 0.1 // Reduce background to 10% during announcements
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// Set up event listeners
|
|
295
|
-
onAudioProgress(0, (info: AudioInfo) => {
|
|
296
|
-
setCurrentInfo(info);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
onQueueChange(0, (snapshot: QueueSnapshot) => {
|
|
300
|
-
setQueueSnapshot(snapshot);
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
onAudioPause(0, (channelNumber, info) => {
|
|
304
|
-
setIsPaused(true);
|
|
305
|
-
console.log(`Channel ${channelNumber} paused: ${info.fileName}`);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
onAudioResume(0, (channelNumber, info) => {
|
|
309
|
-
setIsPaused(false);
|
|
310
|
-
console.log(`Channel ${channelNumber} resumed: ${info.fileName}`);
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
setupBackgroundMusic();
|
|
314
|
-
}, []);
|
|
315
|
-
|
|
316
|
-
const playAnnouncement = async () => {
|
|
317
|
-
// Priority queue - plays next, automatically ducks background music
|
|
318
|
-
await queueAudioPriority(announcement, 1);
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
const toggleBackgroundMusic = async () => {
|
|
322
|
-
if (isPaused) {
|
|
323
|
-
await resumeChannel(0);
|
|
324
|
-
} else {
|
|
325
|
-
await pauseChannel(0);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
const adjustBackgroundVolume = (volume: number) => {
|
|
330
|
-
setChannelVolume(0, volume);
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
const emergencyToggleAll = async () => {
|
|
334
|
-
await togglePauseAllChannels(); // Smart toggle - pause all if any playing, resume all if all paused
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
return (
|
|
338
|
-
<div className="App">
|
|
339
|
-
<h2>Audio Control Center</h2>
|
|
340
|
-
|
|
341
|
-
{/* Background Music Controls */}
|
|
342
|
-
<div className="background-controls">
|
|
343
|
-
<h3>Background Music</h3>
|
|
344
|
-
<button onClick={toggleBackgroundMusic}>
|
|
345
|
-
{isPaused ? 'βΆοΈ Resume' : 'βΈοΈ Pause'}
|
|
346
|
-
</button>
|
|
347
|
-
<label>
|
|
348
|
-
Volume:
|
|
349
|
-
<input
|
|
350
|
-
type="range"
|
|
351
|
-
min="0"
|
|
352
|
-
max="1"
|
|
353
|
-
step="0.1"
|
|
354
|
-
onChange={(e) => adjustBackgroundVolume(Number(e.target.value))}
|
|
355
|
-
/>
|
|
356
|
-
</label>
|
|
357
|
-
</div>
|
|
358
|
-
|
|
359
|
-
{/* Announcement Controls */}
|
|
360
|
-
<div className="announcement-controls">
|
|
361
|
-
<h3>Announcements</h3>
|
|
362
|
-
<button onClick={playAnnouncement}>
|
|
363
|
-
π’ Play Announcement (Auto-ducks background)
|
|
364
|
-
</button>
|
|
365
|
-
</div>
|
|
366
|
-
|
|
367
|
-
{/* Emergency Controls */}
|
|
368
|
-
<div className="emergency-controls">
|
|
369
|
-
<h3>Emergency Controls</h3>
|
|
370
|
-
<button onClick={emergencyToggleAll}>
|
|
371
|
-
π¨ Toggle All Audio (Smart Pause/Resume)
|
|
372
|
-
</button>
|
|
373
|
-
</div>
|
|
374
|
-
|
|
375
|
-
{/* Current Audio Info */}
|
|
376
|
-
{currentInfo && (
|
|
377
|
-
<div className="current-info">
|
|
378
|
-
<h3>Now Playing:</h3>
|
|
379
|
-
<p>π΅ {currentInfo.fileName}</p>
|
|
380
|
-
<p>β±οΈ {(currentInfo.currentTime / 1000).toFixed(1)}s / {(currentInfo.duration / 1000).toFixed(1)}s</p>
|
|
381
|
-
<p>π Progress: {(currentInfo.progress * 100).toFixed(1)}%</p>
|
|
382
|
-
<p>π Volume: {(currentInfo.volume * 100).toFixed(0)}%</p>
|
|
383
|
-
<p>π Looping: {currentInfo.isLooping ? 'Yes' : 'No'}</p>
|
|
384
|
-
<p>βΈοΈ Paused: {currentInfo.isPaused ? 'Yes' : 'No'}</p>
|
|
385
|
-
|
|
386
|
-
{/* Progress Bar */}
|
|
387
|
-
<div className="progress-bar">
|
|
388
|
-
<div
|
|
389
|
-
className="progress-fill"
|
|
390
|
-
style={{ width: `${currentInfo.progress * 100}%` }}
|
|
391
|
-
/>
|
|
392
|
-
</div>
|
|
393
|
-
</div>
|
|
394
|
-
)}
|
|
395
|
-
|
|
396
|
-
{/* Queue Status */}
|
|
397
|
-
{queueSnapshot && (
|
|
398
|
-
<div className="queue-status">
|
|
399
|
-
<h3>Queue Status (Channel {queueSnapshot.channelNumber}):</h3>
|
|
400
|
-
<p>π Total Items: {queueSnapshot.totalItems}</p>
|
|
401
|
-
<p>π Channel Volume: {(queueSnapshot.volume * 100).toFixed(0)}%</p>
|
|
402
|
-
<p>βΈοΈ Channel Paused: {queueSnapshot.isPaused ? 'Yes' : 'No'}</p>
|
|
403
|
-
|
|
404
|
-
<h4>Queue Items:</h4>
|
|
405
|
-
<ul>
|
|
406
|
-
{queueSnapshot.items.map((item, index) => (
|
|
407
|
-
<li key={index} style={{
|
|
408
|
-
fontWeight: item.isCurrentlyPlaying ? 'bold' : 'normal',
|
|
409
|
-
color: item.isCurrentlyPlaying ? '#007bff' : 'inherit'
|
|
410
|
-
}}>
|
|
411
|
-
{item.fileName} ({(item.duration / 1000).toFixed(1)}s)
|
|
412
|
-
{item.isCurrentlyPlaying && ' βΆοΈ PLAYING'}
|
|
413
|
-
{item.isLooping && ' π LOOP'}
|
|
414
|
-
</li>
|
|
415
|
-
))}
|
|
416
|
-
</ul>
|
|
417
|
-
</div>
|
|
418
|
-
)}
|
|
419
|
-
</div>
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export default App;
|
|
353
|
+
```typescript
|
|
354
|
+
// Subscribe to queue change events for visual updates.
|
|
355
|
+
onQueueChange(channelNumber, callback);
|
|
356
|
+
onQueueChange(0, (snapshot) => updateQueueDisplay(snapshot)); // Update UI on queue changes
|
|
424
357
|
```
|
|
425
358
|
|
|
426
|
-
### Advanced Usage Examples:
|
|
427
|
-
|
|
428
|
-
#### Gaming Audio System
|
|
429
359
|
```typescript
|
|
430
|
-
//
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
// Sound effects (channel 1)
|
|
434
|
-
await queueAudio('./sfx/explosion.wav', 1);
|
|
435
|
-
|
|
436
|
-
// Voice chat (channel 2) - ducks other audio
|
|
437
|
-
setVolumeDucking({
|
|
438
|
-
priorityChannel: 2,
|
|
439
|
-
priorityVolume: 1.0,
|
|
440
|
-
duckingVolume: 0.2
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
// Critical game announcements (priority)
|
|
444
|
-
await queueAudioPriority('./voice/game-over.wav', 2);
|
|
360
|
+
// Subscribe to audio start events.
|
|
361
|
+
onAudioStart(channelNumber, callback);
|
|
362
|
+
onAudioStart(0, (info) => console.log(`Started: ${info.fileName}`)); // Log audio starts
|
|
445
363
|
```
|
|
446
364
|
|
|
447
|
-
#### Podcast/Radio App
|
|
448
365
|
```typescript
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
await queueAudioPriority('./ads/sponsor.mp3', 0);
|
|
454
|
-
|
|
455
|
-
// Background ambient (channel 2)
|
|
456
|
-
await queueAudio('./ambient/coffee-shop.mp3', 2, {
|
|
457
|
-
loop: true,
|
|
458
|
-
volume: 0.1
|
|
459
|
-
});
|
|
366
|
+
// Subscribe to audio completion events.
|
|
367
|
+
onAudioComplete(channelNumber, callback);
|
|
368
|
+
onAudioComplete(0, (info) => logPlayHistory(info)); // Track completed audio
|
|
369
|
+
```
|
|
460
370
|
|
|
461
|
-
|
|
462
|
-
|
|
371
|
+
```typescript
|
|
372
|
+
// Subscribe to audio pause events.
|
|
373
|
+
onAudioPause(channelNumber, callback);
|
|
374
|
+
onAudioPause(0, (info) => showPauseIcon(info)); // Show pause state in UI
|
|
463
375
|
```
|
|
464
376
|
|
|
465
|
-
|
|
466
|
-
|
|
377
|
+
```typescript
|
|
378
|
+
// Subscribe to audio resume events.
|
|
379
|
+
onAudioResume(channelNumber, callback);
|
|
380
|
+
onAudioResume(0, (info) => showPlayIcon(info)); // Show play state in UI
|
|
381
|
+
```
|
|
467
382
|
|
|
468
383
|
### TypeScript Support
|
|
469
384
|
If you cannot import audio files into your app, you may need a `custom.d.ts` file in the root directory. An example of one is shown here:
|
|
@@ -476,39 +391,10 @@ declare module '*.mp3' {
|
|
|
476
391
|
}
|
|
477
392
|
```
|
|
478
393
|
|
|
479
|
-
## Features:
|
|
480
|
-
- β
Queue management across multiple channels
|
|
481
|
-
- β
Pause and resume functionality for individual channels and all channels
|
|
482
|
-
- β
Volume control with per-channel precision (0-1 range)
|
|
483
|
-
- β
Volume ducking for priority audio (automatic background reduction)
|
|
484
|
-
- β
Audio looping capabilities for background music and ambient sounds
|
|
485
|
-
- β
Priority queueing system for urgent audio playback
|
|
486
|
-
- β
Real-time audio progress tracking with enhanced metadata
|
|
487
|
-
- β
Comprehensive event system (start, complete, pause, resume, queue changes)
|
|
488
|
-
- β
Audio duration and metadata extraction with loop and volume info
|
|
489
|
-
- β
Automatic filename extraction from URLs
|
|
490
|
-
- β
Queue state snapshots with pause and volume information
|
|
491
|
-
- β
TypeScript support with full type definitions
|
|
492
|
-
- β
Modular architecture with clean separation of concerns
|
|
493
|
-
- β
Comprehensive JSDoc documentation with examples
|
|
494
|
-
- β
Zero dependencies
|
|
495
|
-
- β
Backward compatible with existing implementations
|
|
496
|
-
- β
Comprehensive error handling with graceful degradation
|
|
497
|
-
|
|
498
394
|
## Development & Contributing π οΈ
|
|
499
395
|
|
|
500
396
|
The package uses a modular TypeScript architecture that makes it easy to contribute and extend:
|
|
501
397
|
|
|
502
|
-
### File Structure:
|
|
503
|
-
- **`src/types.ts`** - Interface definitions and type exports
|
|
504
|
-
- **`src/core.ts`** - Main queue management logic and priority queueing
|
|
505
|
-
- **`src/pause.ts`** - Pause and resume functionality
|
|
506
|
-
- **`src/volume.ts`** - Volume control and ducking management
|
|
507
|
-
- **`src/info.ts`** - Audio information and progress tracking
|
|
508
|
-
- **`src/events.ts`** - Event system and callback management
|
|
509
|
-
- **`src/utils.ts`** - Helper functions and utilities
|
|
510
|
-
- **`src/index.ts`** - Public API exports
|
|
511
|
-
|
|
512
398
|
### Testing:
|
|
513
399
|
The package includes a comprehensive test suite with 74+ tests covering all functionality:
|
|
514
400
|
|
|
@@ -522,5 +408,3 @@ npm run test:watch
|
|
|
522
408
|
# Run tests with coverage report
|
|
523
409
|
npm run test:coverage
|
|
524
410
|
```
|
|
525
|
-
|
|
526
|
-
**Test Coverage**: 85%+ code coverage across all modules with realistic HTMLAudioElement mocking using jsdom.
|