audio-channel-queue 1.5.0 → 1.6.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 +323 -96
- package/dist/core.d.ts +27 -9
- package/dist/core.js +108 -24
- package/dist/events.d.ts +23 -1
- package/dist/events.js +50 -2
- package/dist/index.d.ts +11 -5
- package/dist/index.js +34 -4
- package/dist/info.d.ts +45 -1
- package/dist/info.js +118 -6
- package/dist/pause.d.ts +87 -0
- package/dist/pause.js +186 -0
- package/dist/types.d.ts +69 -1
- package/dist/utils.d.ts +7 -1
- package/dist/utils.js +24 -4
- package/dist/volume.d.ts +98 -0
- package/dist/volume.js +302 -0
- package/package.json +4 -1
- package/src/core.ts +119 -22
- package/src/events.ts +242 -188
- package/src/index.ts +103 -65
- package/src/info.ts +379 -261
- package/src/pause.ts +190 -0
- package/src/types.ts +198 -126
- package/src/utils.ts +133 -108
- package/src/volume.ts +328 -0
package/README.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Audio Channel Queue
|
|
2
|
-
The purpose of this package is to help
|
|
2
|
+
The purpose of this package is to help manage the playback of audio files.
|
|
3
|
+
|
|
4
|
+
## 🌟 Key Features
|
|
5
|
+
|
|
6
|
+
- ✅ **Multi-channel queue management** - Independent audio queues for concurrent playback
|
|
7
|
+
- ✅ **Pause/Resume functionality** - Full playback control for individual channels or all channels
|
|
8
|
+
- ✅ **Volume control with ducking** - Dynamic volume management and automatic background audio reduction
|
|
9
|
+
- ✅ **Loop support** - Seamless audio looping for background music and ambient sounds
|
|
10
|
+
- ✅ **Priority queueing** - Add urgent audio to the front of any queue
|
|
11
|
+
- ✅ **Real-time progress tracking** - Comprehensive playback monitoring and metadata
|
|
12
|
+
- ✅ **Event-driven architecture** - Extensive callback system for UI integration
|
|
13
|
+
- ✅ **TypeScript support** - Full type definitions and IntelliSense support
|
|
14
|
+
- ✅ **Zero dependencies** - Lightweight and self-contained
|
|
15
|
+
- ✅ **Backward compatible** - All existing APIs continue to work
|
|
3
16
|
|
|
4
17
|
This package offers TypeScript support 📘, boasts zero dependencies 🚫, and is released under the MIT license 📜. As an added bonus, it's NON-GMO 🌱 and 100% Free Range Organic 🐓.
|
|
5
18
|
|
|
@@ -9,6 +22,26 @@ NPM package can be found [here](https://www.npmjs.com/package/audio-channel-queu
|
|
|
9
22
|
|
|
10
23
|
GitHub Repo can be found [here](https://github.com/tonycarpenter21/audio-channel-queue).
|
|
11
24
|
|
|
25
|
+
## 🌐 Browser Compatibility
|
|
26
|
+
|
|
27
|
+
This package is designed for **browser environments** and uses the Web Audio API (`HTMLAudioElement`). It is **not** intended for Node.js server-side use.
|
|
28
|
+
|
|
29
|
+
### ✅ **Supported Browsers:**
|
|
30
|
+
- **Chrome 51+** (June 2016)
|
|
31
|
+
- **Firefox 54+** (June 2017)
|
|
32
|
+
- **Safari 10+** (September 2016)
|
|
33
|
+
- **Edge 15+** (April 2017)
|
|
34
|
+
- **Mobile browsers** with HTML5 audio support
|
|
35
|
+
|
|
36
|
+
### 🛠️ **Development Requirements:**
|
|
37
|
+
- **Node.js 14+** (for building and testing only)
|
|
38
|
+
- **TypeScript 4.5+** (included in devDependencies)
|
|
39
|
+
|
|
40
|
+
### ⚠️ **Not Supported:**
|
|
41
|
+
- Node.js server environments (no HTMLAudioElement)
|
|
42
|
+
- Internet Explorer (lacks ES6 support)
|
|
43
|
+
- Web Workers (no DOM access)
|
|
44
|
+
|
|
12
45
|
## Architecture & Code Organization 🏗️
|
|
13
46
|
|
|
14
47
|
Modular architecture for maintainability and extensibility:
|
|
@@ -18,6 +51,8 @@ src/
|
|
|
18
51
|
├── index.ts # Main entry point with organized exports
|
|
19
52
|
├── types.ts # TypeScript interfaces and type definitions
|
|
20
53
|
├── core.ts # Core queue management functions
|
|
54
|
+
├── pause.ts # Pause and resume functionality
|
|
55
|
+
├── volume.ts # Volume control and ducking management
|
|
21
56
|
├── info.ts # Audio information and progress tracking
|
|
22
57
|
├── events.ts # Event handling and emission logic
|
|
23
58
|
└── utils.ts # Helper functions and utilities
|
|
@@ -31,51 +66,139 @@ Install this package by running either of these commands (typescript packages ar
|
|
|
31
66
|
## Basic Queue Management Functions:
|
|
32
67
|
|
|
33
68
|
### Queue Audio
|
|
34
|
-
```queueAudio(audioFileGoesHere, channelNumber);```
|
|
35
|
-
Use the `queueAudio()` function to add a file to the queue and start playing it automatically. It takes
|
|
69
|
+
```queueAudio(audioFileGoesHere, channelNumber, options);```
|
|
70
|
+
Use the `queueAudio()` function to add a file to the queue and start playing it automatically. It takes three arguments:
|
|
36
71
|
- The first argument is an imported sound file.
|
|
37
|
-
- The second argument is optional and it allows you to choose a different queue channel.
|
|
72
|
+
- The second argument is optional and it allows you to choose a different queue channel.
|
|
73
|
+
- The third argument is optional configuration for loop, volume, and priority.
|
|
74
|
+
|
|
75
|
+
### Queue Audio with Priority
|
|
76
|
+
```queueAudioPriority(audioFileGoesHere, channelNumber, options);```
|
|
77
|
+
Use the `queueAudioPriority()` function to add a file to the front of the queue (plays after current audio finishes). Perfect for urgent announcements!
|
|
38
78
|
|
|
39
79
|
### Stop Current Audio
|
|
40
80
|
```stopCurrentAudioInChannel(queueChannelNumberGoesHere);```
|
|
41
|
-
Use the `stopCurrentAudioInChannel()` function to stop the current playback of a file in a queue and start playing the next one automatically.
|
|
42
|
-
- The first argument is optional and it allows you to choose a different queue channel. If you are only using the default channel, just use `stopCurrentAudioInChannel()`.
|
|
81
|
+
Use the `stopCurrentAudioInChannel()` function to stop the current playback of a file in a queue and start playing the next one automatically.
|
|
43
82
|
|
|
44
83
|
### Stop All Audio in Channel
|
|
45
84
|
```stopAllAudioInChannel(queueChannelNumberGoesHere);```
|
|
46
|
-
Use the `stopAllAudioInChannel()` function to stop the current playback of all files in a queue and removes all enqueued files.
|
|
47
|
-
- The first argument is optional and it allows you to choose a different queue channel. If you are only using the default channel, just use `stopAllAudioInChannel()`.
|
|
85
|
+
Use the `stopAllAudioInChannel()` function to stop the current playback of all files in a queue and removes all enqueued files.
|
|
48
86
|
|
|
49
87
|
### Stop All Audio
|
|
50
88
|
```stopAllAudio();```
|
|
51
89
|
Use the `stopAllAudio()` function to stop the current playback of all files in all queues. It takes no arguments.
|
|
52
90
|
|
|
91
|
+
## 🎛️ Volume Control Functions:
|
|
92
|
+
|
|
93
|
+
### Set Channel Volume
|
|
94
|
+
```setChannelVolume(channelNumber, volume);```
|
|
95
|
+
Set the volume for a specific channel (0-1 range).
|
|
96
|
+
```typescript
|
|
97
|
+
setChannelVolume(0, 0.5); // Set channel 0 to 50% volume
|
|
98
|
+
setChannelVolume(1, 0.8); // Set channel 1 to 80% volume
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Get Channel Volume
|
|
102
|
+
```getChannelVolume(channelNumber);```
|
|
103
|
+
Get the current volume level for a specific channel.
|
|
104
|
+
```typescript
|
|
105
|
+
const volume = getChannelVolume(0);
|
|
106
|
+
console.log(`Channel 0 volume: ${volume * 100}%`);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Set All Channels Volume
|
|
110
|
+
```setAllChannelsVolume(volume);```
|
|
111
|
+
Set the same volume level for all channels.
|
|
112
|
+
```typescript
|
|
113
|
+
setAllChannelsVolume(0.6); // Set all channels to 60% volume
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 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
|
+
```typescript
|
|
120
|
+
// When channel 1 plays, reduce all other channels to 20% volume
|
|
121
|
+
setVolumeDucking({
|
|
122
|
+
priorityChannel: 1,
|
|
123
|
+
priorityVolume: 1.0,
|
|
124
|
+
duckingVolume: 0.2
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```clearVolumeDucking();```
|
|
129
|
+
Remove volume ducking configuration from all channels.
|
|
130
|
+
|
|
131
|
+
## ⏯️ Pause/Resume Functions:
|
|
132
|
+
|
|
133
|
+
### Pause Channel
|
|
134
|
+
```pauseChannel(channelNumber);```
|
|
135
|
+
Pause audio playback in a specific channel.
|
|
136
|
+
```typescript
|
|
137
|
+
await pauseChannel(0); // Pause audio in channel 0
|
|
138
|
+
await pauseChannel(); // Pause audio in default channel
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Resume Channel
|
|
142
|
+
```resumeChannel(channelNumber);```
|
|
143
|
+
Resume audio playback in a specific channel.
|
|
144
|
+
```typescript
|
|
145
|
+
await resumeChannel(0); // Resume audio in channel 0
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Toggle Pause
|
|
149
|
+
```togglePauseChannel(channelNumber);```
|
|
150
|
+
Toggle between pause and resume states.
|
|
151
|
+
```typescript
|
|
152
|
+
await togglePauseChannel(0); // Pause if playing, resume if paused
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Pause/Resume All Channels
|
|
156
|
+
```pauseAllChannels();``` and ```resumeAllChannels();```
|
|
157
|
+
Control all channels simultaneously.
|
|
158
|
+
```typescript
|
|
159
|
+
await pauseAllChannels(); // Emergency pause - everything stops
|
|
160
|
+
await resumeAllChannels(); // Resume everything that was paused
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 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
|
+
```typescript
|
|
167
|
+
await togglePauseAllChannels(); // Pause all if any playing, resume all if all paused
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Check Pause State
|
|
171
|
+
```isChannelPaused(channelNumber);``` and ```getAllChannelsPauseState();```
|
|
172
|
+
```typescript
|
|
173
|
+
const isPaused = isChannelPaused(0);
|
|
174
|
+
const allPauseStates = getAllChannelsPauseState();
|
|
175
|
+
```
|
|
176
|
+
|
|
53
177
|
## Audio Information and Progress Tracking:
|
|
54
178
|
|
|
55
179
|
### AudioInfo Interface
|
|
56
|
-
The package
|
|
180
|
+
The package provides detailed information about audio playback through the enhanced `AudioInfo` interface:
|
|
57
181
|
```typescript
|
|
58
182
|
interface AudioInfo {
|
|
59
183
|
currentTime: number; // Current position in milliseconds
|
|
60
184
|
duration: number; // Total duration in milliseconds
|
|
61
185
|
fileName: string; // Extracted filename from URL
|
|
186
|
+
isLooping: boolean; // Whether audio is set to loop
|
|
187
|
+
isPaused: boolean; // Whether audio is currently paused
|
|
62
188
|
isPlaying: boolean; // Whether audio is currently playing
|
|
63
189
|
progress: number; // Progress as percentage (0-1)
|
|
64
190
|
src: string; // Audio file source URL
|
|
191
|
+
volume: number; // Current volume level (0-1)
|
|
65
192
|
}
|
|
66
193
|
```
|
|
67
194
|
|
|
68
195
|
### Get Current Audio Info
|
|
69
196
|
```getCurrentAudioInfo(channelNumber);```
|
|
70
197
|
Get information about the currently playing audio in a specific channel. Returns `AudioInfo | null`.
|
|
71
|
-
- `channelNumber` (optional): The channel number (defaults to 0)
|
|
72
|
-
- Returns `null` if no audio is currently playing in the channel
|
|
73
198
|
|
|
74
199
|
### Get All Channels Info
|
|
75
200
|
```getAllChannelsInfo();```
|
|
76
201
|
Get audio information for all channels. Returns an array of `AudioInfo | null` objects.
|
|
77
|
-
- Returns an array where each index corresponds to a channel number
|
|
78
|
-
- `null` values indicate channels with no currently playing audio
|
|
79
202
|
|
|
80
203
|
### Queue State Management
|
|
81
204
|
```getQueueSnapshot(channelNumber);```
|
|
@@ -84,61 +207,63 @@ Get a complete snapshot of the queue state for a specific channel. Returns `Queu
|
|
|
84
207
|
```typescript
|
|
85
208
|
interface QueueSnapshot {
|
|
86
209
|
channelNumber: number; // Channel this snapshot represents
|
|
87
|
-
totalItems: number; // Total items in queue
|
|
88
210
|
currentIndex: number; // Index of currently playing item
|
|
211
|
+
isPaused: boolean; // Whether current audio is paused
|
|
89
212
|
items: Array<{ // Array of queue items with metadata
|
|
90
|
-
src: string;
|
|
91
|
-
fileName: string;
|
|
92
213
|
duration: number;
|
|
214
|
+
fileName: string;
|
|
93
215
|
isCurrentlyPlaying: boolean;
|
|
216
|
+
isLooping: boolean;
|
|
217
|
+
src: string;
|
|
218
|
+
volume: number;
|
|
94
219
|
}>;
|
|
220
|
+
totalItems: number; // Total items in queue
|
|
221
|
+
volume: number; // Current channel volume (0-1)
|
|
95
222
|
}
|
|
96
223
|
```
|
|
97
224
|
|
|
98
225
|
### Real-time Progress Tracking
|
|
99
226
|
```onAudioProgress(channelNumber, callback);```
|
|
100
227
|
Subscribe to real-time progress updates for a specific channel.
|
|
101
|
-
- `channelNumber`: The channel number to monitor
|
|
102
|
-
- `callback`: Function that receives `AudioInfo` updates
|
|
103
228
|
|
|
104
229
|
```offAudioProgress(channelNumber);```
|
|
105
230
|
Remove all progress listeners for a specific channel.
|
|
106
|
-
- `channelNumber`: The channel number to stop monitoring
|
|
107
231
|
|
|
108
|
-
###
|
|
232
|
+
### Enhanced Event System
|
|
109
233
|
```onQueueChange(channelNumber, callback);```
|
|
110
234
|
Subscribe to queue change events for visual updates.
|
|
111
|
-
- Triggered when items are added, removed, or when playback moves to next item
|
|
112
|
-
- Perfect for updating UI queue displays
|
|
113
235
|
|
|
114
|
-
```offQueueChange(channelNumber);```
|
|
115
|
-
Remove queue change listeners for a specific channel.
|
|
116
|
-
|
|
117
|
-
### Audio Lifecycle Events
|
|
118
236
|
```onAudioStart(channelNumber, callback);```
|
|
119
237
|
Subscribe to audio start events.
|
|
120
|
-
- Triggered when audio begins playing (after metadata loads)
|
|
121
|
-
- Provides duration, filename, and source information
|
|
122
238
|
|
|
123
239
|
```onAudioComplete(channelNumber, callback);```
|
|
124
240
|
Subscribe to audio completion events.
|
|
125
|
-
- Triggered when audio finishes or is stopped
|
|
126
|
-
- Includes remaining queue count information
|
|
127
241
|
|
|
128
|
-
|
|
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:
|
|
129
249
|
|
|
130
250
|
`App.tsx`
|
|
131
251
|
```typescript
|
|
132
|
-
import
|
|
252
|
+
import backgroundMusic from './audio/background.mp3';
|
|
253
|
+
import announcement from './audio/announcement.wav';
|
|
133
254
|
import {
|
|
134
255
|
queueAudio,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
256
|
+
queueAudioPriority,
|
|
257
|
+
getCurrentAudioInfo,
|
|
258
|
+
pauseChannel,
|
|
259
|
+
resumeChannel,
|
|
260
|
+
togglePauseAllChannels,
|
|
261
|
+
setChannelVolume,
|
|
262
|
+
setVolumeDucking,
|
|
263
|
+
onAudioProgress,
|
|
264
|
+
onAudioPause,
|
|
265
|
+
onAudioResume,
|
|
138
266
|
onQueueChange,
|
|
139
|
-
onAudioStart,
|
|
140
|
-
onAudioComplete,
|
|
141
|
-
getQueueSnapshot,
|
|
142
267
|
AudioInfo,
|
|
143
268
|
QueueSnapshot
|
|
144
269
|
} from 'audio-channel-queue';
|
|
@@ -147,89 +272,145 @@ import { useState, useEffect } from 'react';
|
|
|
147
272
|
function App(): JSX.Element {
|
|
148
273
|
const [currentInfo, setCurrentInfo] = useState<AudioInfo | null>(null);
|
|
149
274
|
const [queueSnapshot, setQueueSnapshot] = useState<QueueSnapshot | null>(null);
|
|
150
|
-
const [
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
+
});
|
|
161
293
|
|
|
162
|
-
|
|
163
|
-
setIsTracking(true);
|
|
164
|
-
|
|
165
|
-
// Track real-time progress
|
|
294
|
+
// Set up event listeners
|
|
166
295
|
onAudioProgress(0, (info: AudioInfo) => {
|
|
167
296
|
setCurrentInfo(info);
|
|
168
|
-
console.log(`Progress: ${(info.progress * 100).toFixed(1)}%`);
|
|
169
297
|
});
|
|
170
298
|
|
|
171
|
-
// Track queue changes
|
|
172
299
|
onQueueChange(0, (snapshot: QueueSnapshot) => {
|
|
173
300
|
setQueueSnapshot(snapshot);
|
|
174
|
-
console.log(`Queue updated: ${snapshot.totalItems} items`);
|
|
175
301
|
});
|
|
176
302
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
console.log(`
|
|
303
|
+
onAudioPause(0, (channelNumber, info) => {
|
|
304
|
+
setIsPaused(true);
|
|
305
|
+
console.log(`Channel ${channelNumber} paused: ${info.fileName}`);
|
|
180
306
|
});
|
|
181
307
|
|
|
182
|
-
|
|
183
|
-
|
|
308
|
+
onAudioResume(0, (channelNumber, info) => {
|
|
309
|
+
setIsPaused(false);
|
|
310
|
+
console.log(`Channel ${channelNumber} resumed: ${info.fileName}`);
|
|
184
311
|
});
|
|
312
|
+
|
|
313
|
+
setupBackgroundMusic();
|
|
314
|
+
}, []);
|
|
315
|
+
|
|
316
|
+
const playAnnouncement = async () => {
|
|
317
|
+
// Priority queue - plays next, automatically ducks background music
|
|
318
|
+
await queueAudioPriority(announcement, 1);
|
|
185
319
|
};
|
|
186
320
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
321
|
+
const toggleBackgroundMusic = async () => {
|
|
322
|
+
if (isPaused) {
|
|
323
|
+
await resumeChannel(0);
|
|
324
|
+
} else {
|
|
325
|
+
await pauseChannel(0);
|
|
326
|
+
}
|
|
191
327
|
};
|
|
192
328
|
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
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
|
|
196
335
|
};
|
|
197
336
|
|
|
198
337
|
return (
|
|
199
338
|
<div className="App">
|
|
200
|
-
<
|
|
201
|
-
<button onClick={addMoreAudio}>Add More to Queue</button>
|
|
202
|
-
<button onClick={startTracking} disabled={isTracking}>
|
|
203
|
-
Start Progress Tracking
|
|
204
|
-
</button>
|
|
205
|
-
<button onClick={stopTracking} disabled={!isTracking}>
|
|
206
|
-
Stop Progress Tracking
|
|
207
|
-
</button>
|
|
339
|
+
<h2>Audio Control Center</h2>
|
|
208
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 */}
|
|
209
376
|
{currentInfo && (
|
|
210
|
-
<div>
|
|
377
|
+
<div className="current-info">
|
|
211
378
|
<h3>Now Playing:</h3>
|
|
212
|
-
<p
|
|
213
|
-
<p
|
|
214
|
-
<p
|
|
215
|
-
<p
|
|
216
|
-
<p
|
|
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>
|
|
217
393
|
</div>
|
|
218
394
|
)}
|
|
219
395
|
|
|
396
|
+
{/* Queue Status */}
|
|
220
397
|
{queueSnapshot && (
|
|
221
|
-
<div>
|
|
222
|
-
<h3>Queue Status:</h3>
|
|
223
|
-
<p
|
|
224
|
-
<p
|
|
225
|
-
<p
|
|
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>
|
|
226
405
|
<ul>
|
|
227
406
|
{queueSnapshot.items.map((item, index) => (
|
|
228
407
|
<li key={index} style={{
|
|
229
|
-
fontWeight: item.isCurrentlyPlaying ? 'bold' : 'normal'
|
|
408
|
+
fontWeight: item.isCurrentlyPlaying ? 'bold' : 'normal',
|
|
409
|
+
color: item.isCurrentlyPlaying ? '#007bff' : 'inherit'
|
|
230
410
|
}}>
|
|
231
411
|
{item.fileName} ({(item.duration / 1000).toFixed(1)}s)
|
|
232
|
-
{item.isCurrentlyPlaying && ' ▶️'}
|
|
412
|
+
{item.isCurrentlyPlaying && ' ▶️ PLAYING'}
|
|
413
|
+
{item.isLooping && ' 🔄 LOOP'}
|
|
233
414
|
</li>
|
|
234
415
|
))}
|
|
235
416
|
</ul>
|
|
@@ -242,6 +423,45 @@ function App(): JSX.Element {
|
|
|
242
423
|
export default App;
|
|
243
424
|
```
|
|
244
425
|
|
|
426
|
+
### Advanced Usage Examples:
|
|
427
|
+
|
|
428
|
+
#### Gaming Audio System
|
|
429
|
+
```typescript
|
|
430
|
+
// Background music (channel 0)
|
|
431
|
+
await queueAudio('./music/background.mp3', 0, { loop: true, volume: 0.4 });
|
|
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);
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### Podcast/Radio App
|
|
448
|
+
```typescript
|
|
449
|
+
// Main content (channel 0)
|
|
450
|
+
await queueAudio('./podcast/episode1.mp3', 0);
|
|
451
|
+
|
|
452
|
+
// Jingles and ads (channel 1) - interrupt at natural breaks
|
|
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
|
+
});
|
|
460
|
+
|
|
461
|
+
// Pause everything for phone calls
|
|
462
|
+
onPhoneCall(() => pauseAllChannels());
|
|
463
|
+
```
|
|
464
|
+
|
|
245
465
|
### Legacy Access
|
|
246
466
|
If you need to expose the queue array for logging or other purposes, it is available to you as well: `audioChannels`.
|
|
247
467
|
|
|
@@ -258,17 +478,22 @@ declare module '*.mp3' {
|
|
|
258
478
|
|
|
259
479
|
## Features:
|
|
260
480
|
- ✅ Queue management across multiple channels
|
|
261
|
-
- ✅
|
|
262
|
-
- ✅
|
|
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
|
|
263
489
|
- ✅ Automatic filename extraction from URLs
|
|
264
|
-
- ✅ Queue state snapshots and
|
|
265
|
-
- ✅ Audio lifecycle events (start/complete)
|
|
490
|
+
- ✅ Queue state snapshots with pause and volume information
|
|
266
491
|
- ✅ TypeScript support with full type definitions
|
|
267
492
|
- ✅ Modular architecture with clean separation of concerns
|
|
268
493
|
- ✅ Comprehensive JSDoc documentation with examples
|
|
269
494
|
- ✅ Zero dependencies
|
|
270
495
|
- ✅ Backward compatible with existing implementations
|
|
271
|
-
- ✅ Comprehensive error handling
|
|
496
|
+
- ✅ Comprehensive error handling with graceful degradation
|
|
272
497
|
|
|
273
498
|
## Development & Contributing 🛠️
|
|
274
499
|
|
|
@@ -276,14 +501,16 @@ The package uses a modular TypeScript architecture that makes it easy to contrib
|
|
|
276
501
|
|
|
277
502
|
### File Structure:
|
|
278
503
|
- **`src/types.ts`** - Interface definitions and type exports
|
|
279
|
-
- **`src/core.ts`** - Main queue management logic
|
|
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
|
|
280
507
|
- **`src/info.ts`** - Audio information and progress tracking
|
|
281
508
|
- **`src/events.ts`** - Event system and callback management
|
|
282
509
|
- **`src/utils.ts`** - Helper functions and utilities
|
|
283
510
|
- **`src/index.ts`** - Public API exports
|
|
284
511
|
|
|
285
512
|
### Testing:
|
|
286
|
-
The package includes a comprehensive test suite with
|
|
513
|
+
The package includes a comprehensive test suite with 74+ tests covering all functionality:
|
|
287
514
|
|
|
288
515
|
```bash
|
|
289
516
|
# Run tests once
|
package/dist/core.d.ts
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Core queue management functions for the audio-channel-queue package
|
|
3
3
|
*/
|
|
4
|
+
import { AudioQueueOptions } from './types';
|
|
4
5
|
/**
|
|
5
6
|
* Queues an audio file to a specific channel and starts playing if it's the first in queue
|
|
6
7
|
* @param audioUrl - The URL of the audio file to queue
|
|
7
8
|
* @param channelNumber - The channel number to queue the audio to (defaults to 0)
|
|
9
|
+
* @param options - Optional configuration for the audio file
|
|
8
10
|
* @returns Promise that resolves when the audio is queued and starts playing (if first in queue)
|
|
9
11
|
* @example
|
|
10
12
|
* ```typescript
|
|
11
13
|
* await queueAudio('https://example.com/song.mp3', 0);
|
|
12
14
|
* await queueAudio('./sounds/notification.wav'); // Uses default channel 0
|
|
15
|
+
* await queueAudio('./music/loop.mp3', 1, { loop: true }); // Loop the audio
|
|
16
|
+
* await queueAudio('./urgent.wav', 0, { addToFront: true }); // Add to front of queue
|
|
13
17
|
* ```
|
|
14
18
|
*/
|
|
15
|
-
export declare const queueAudio: (audioUrl: string, channelNumber?: number) => Promise<void>;
|
|
19
|
+
export declare const queueAudio: (audioUrl: string, channelNumber?: number, options?: AudioQueueOptions) => Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Adds an audio file to the front of the queue in a specific channel
|
|
22
|
+
* This is a convenience function that places the audio right after the currently playing track
|
|
23
|
+
* @param audioUrl - The URL of the audio file to queue
|
|
24
|
+
* @param channelNumber - The channel number to queue the audio to (defaults to 0)
|
|
25
|
+
* @param options - Optional configuration for the audio file
|
|
26
|
+
* @returns Promise that resolves when the audio is queued
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* await queueAudioPriority('./urgent-announcement.wav', 0);
|
|
30
|
+
* await queueAudioPriority('./priority-sound.mp3', 1, { loop: true });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare const queueAudioPriority: (audioUrl: string, channelNumber?: number, options?: AudioQueueOptions) => Promise<void>;
|
|
16
34
|
/**
|
|
17
35
|
* Plays the audio queue for a specific channel
|
|
18
36
|
* @param channelNumber - The channel number to play
|
|
@@ -28,26 +46,26 @@ export declare const playAudioQueue: (channelNumber: number) => Promise<void>;
|
|
|
28
46
|
* @param channelNumber - The channel number (defaults to 0)
|
|
29
47
|
* @example
|
|
30
48
|
* ```typescript
|
|
31
|
-
* stopCurrentAudioInChannel(
|
|
32
|
-
* stopCurrentAudioInChannel(); // Stop current audio in
|
|
49
|
+
* await stopCurrentAudioInChannel(); // Stop current audio in default channel (0)
|
|
50
|
+
* await stopCurrentAudioInChannel(1); // Stop current audio in channel 1
|
|
33
51
|
* ```
|
|
34
52
|
*/
|
|
35
|
-
export declare const stopCurrentAudioInChannel: (channelNumber?: number) => void
|
|
53
|
+
export declare const stopCurrentAudioInChannel: (channelNumber?: number) => Promise<void>;
|
|
36
54
|
/**
|
|
37
55
|
* Stops all audio in a specific channel and clears the entire queue
|
|
38
56
|
* @param channelNumber - The channel number (defaults to 0)
|
|
39
57
|
* @example
|
|
40
58
|
* ```typescript
|
|
41
|
-
* stopAllAudioInChannel(
|
|
42
|
-
* stopAllAudioInChannel(); // Clear all audio in
|
|
59
|
+
* await stopAllAudioInChannel(); // Clear all audio in default channel (0)
|
|
60
|
+
* await stopAllAudioInChannel(1); // Clear all audio in channel 1
|
|
43
61
|
* ```
|
|
44
62
|
*/
|
|
45
|
-
export declare const stopAllAudioInChannel: (channelNumber?: number) => void
|
|
63
|
+
export declare const stopAllAudioInChannel: (channelNumber?: number) => Promise<void>;
|
|
46
64
|
/**
|
|
47
65
|
* Stops all audio across all channels and clears all queues
|
|
48
66
|
* @example
|
|
49
67
|
* ```typescript
|
|
50
|
-
* stopAllAudio(); // Emergency stop - clears everything
|
|
68
|
+
* await stopAllAudio(); // Emergency stop - clears everything
|
|
51
69
|
* ```
|
|
52
70
|
*/
|
|
53
|
-
export declare const stopAllAudio: () => void
|
|
71
|
+
export declare const stopAllAudio: () => Promise<void>;
|