@ain1084/audio-worklet-stream 0.1.6 → 0.1.7
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 +310 -116
- package/dist/frame-buffer/buffer.js +1 -1
- package/dist/frame-buffer/buffer.js.map +1 -1
- package/dist/output-stream-node.js +4 -0
- package/dist/output-stream-node.js.map +1 -1
- package/package.json +1 -1
- package/src/frame-buffer/buffer.ts +1 -1
- package/src/output-stream-node.ts +4 -0
package/README.md
CHANGED
|
@@ -12,29 +12,41 @@ This library was created for use in my project [fbdplay_wasm](https://github.com
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
14
|
- **Manual Buffer Writing**: Provides the ability to manually write audio frames to a buffer.
|
|
15
|
-
- **Multiple Buffer Writing Strategies**: Includes support for
|
|
16
|
-
- **Worker-Based Stability**: Utilizes Workers to ensure stable and consistent audio playback.
|
|
15
|
+
- **Multiple Buffer Writing Strategies**: Includes support for manual, timer-based, and worker-based buffer writing.
|
|
16
|
+
- **Worker-Based Stability**: Utilizes Workers to ensure stable and consistent audio playback, reducing the impact of UI thread throttling.
|
|
17
17
|
- **Vite Integration**: Leverages Vite for easy worker loading and configuration without complex setup.
|
|
18
18
|
- **Audio Worklet Integration**: Seamlessly integrates with the Web Audio API's Audio Worklet for real-time audio processing.
|
|
19
|
+
- **Optimized Performance**: Designed for efficient real-time audio processing with batch frame handling.
|
|
19
20
|
|
|
20
|
-
##
|
|
21
|
+
## Browser Compatibility
|
|
22
|
+
|
|
23
|
+
<details>
|
|
24
|
+
<summary>Click to expand browser compatibility details</summary>
|
|
25
|
+
|
|
26
|
+
This library uses modern Web APIs and is designed for contemporary browsers only. Tested and confirmed working on:
|
|
21
27
|
|
|
22
28
|
|Feature|Chrome|Chrome (Android)|Firefox|Safari (macOS)|Safari (iOS)|Edge|Opera|
|
|
23
29
|
|:--|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|
|
24
|
-
|Basic Support
|
|
30
|
+
|Basic Support|✅|✅|✅|✅|❓|✅|❓|
|
|
25
31
|
|Manual Buffer Writing|✅|✅|✅|✅|❓|✅|❓|
|
|
26
32
|
|Timer-Based Buffer Writing|✅|✅|✅|🔺|❓|✅|❓|
|
|
27
33
|
|Worker-Based Stability|✅|✅|✅|✅|❓|✅|❓|
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
Legend:
|
|
30
36
|
- ✅: Confirmed and working without issues
|
|
31
37
|
- 🔺: Confirmed with limitations (e.g., unstable in background operation)
|
|
32
38
|
- ❓: Not yet confirmed
|
|
33
39
|
|
|
40
|
+
Note: Compatibility with Safari on iOS has not been confirmed due to lack of test devices.
|
|
41
|
+
|
|
42
|
+
To check compatibility in your environment, please run the demo in the example directory.
|
|
43
|
+
|
|
44
|
+
</details>
|
|
45
|
+
|
|
34
46
|
## Prerequisites
|
|
35
47
|
|
|
36
48
|
- **Node.js** and **npm**: Make sure you have Node.js (version 20 or higher) and npm installed. This library hasn't been tested on versions below 20.
|
|
37
|
-
- **Vite**: This library uses Vite as the bundler for its simplicity in loading and configuring workers.
|
|
49
|
+
- **Vite**: This library uses Vite as the bundler for its simplicity in loading and configuring workers.
|
|
38
50
|
|
|
39
51
|
## Installation
|
|
40
52
|
|
|
@@ -44,6 +56,9 @@ To install the library, run:
|
|
|
44
56
|
npm install @ain1084/audio-worklet-stream
|
|
45
57
|
```
|
|
46
58
|
|
|
59
|
+
<details>
|
|
60
|
+
<summary>Click to view configuration details</summary>
|
|
61
|
+
|
|
47
62
|
You need to add `@ain1084/audio-worklet-stream` to the optimizeDeps.exclude section in `vite.config.ts`. Furthermore, include the necessary CORS settings to enable the use of `SharedArrayBuffer`.
|
|
48
63
|
|
|
49
64
|
**vite.config.ts**
|
|
@@ -91,14 +106,6 @@ export default defineNuxtConfig({
|
|
|
91
106
|
},
|
|
92
107
|
],
|
|
93
108
|
},
|
|
94
|
-
})
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Additionally, add the Nitro configuration (needed when running `npm run build`).
|
|
98
|
-
|
|
99
|
-
**nuxt.config.ts**
|
|
100
|
-
```typescript
|
|
101
|
-
export default defineNuxtConfig({
|
|
102
109
|
nitro: {
|
|
103
110
|
rollupConfig: {
|
|
104
111
|
external: '@ain1084/audio-worklet-stream',
|
|
@@ -116,114 +123,117 @@ export default defineNuxtConfig({
|
|
|
116
123
|
})
|
|
117
124
|
```
|
|
118
125
|
|
|
126
|
+
</details>
|
|
127
|
+
|
|
119
128
|
## Usage
|
|
120
129
|
|
|
130
|
+
<details>
|
|
131
|
+
<summary>Click to expand usage details</summary>
|
|
132
|
+
|
|
121
133
|
### Overview
|
|
122
134
|
|
|
123
|
-
This library continuously plays audio sample frames using
|
|
135
|
+
This library continuously plays audio sample frames using AudioWorkletNode. The audio sample frames need to be supplied externally via a ring buffer. The library provides functionality to retrieve the number of written and read (played) frames and allows stopping playback at a specified frame.
|
|
124
136
|
|
|
125
|
-
|
|
137
|
+
The output-only AudioNode is implemented by the OutputStreamNode class, which inherits from AudioWorkletNode. This class adds functionalities such as stream playback, stopping, and retrieving playback position to the AudioWorkletNode.
|
|
126
138
|
|
|
127
|
-
|
|
128
|
-
- *Example*:
|
|
129
|
-
```typescript
|
|
130
|
-
const writer = await main.createManualNode();
|
|
131
|
-
// Write arbitrary audio frames
|
|
132
|
-
writer.write(...);
|
|
133
|
-
main.start();
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
- **Timed**: Uses a UI thread timer to periodically write to the buffer. Frames to be written to the buffer are requested through `FrameBufferFiller`.
|
|
137
|
-
- *Example*:
|
|
138
|
-
```typescript
|
|
139
|
-
await main.createTimedNode();
|
|
140
|
-
main.start();
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
- **Worker**: Similar to Timed but uses a timer in a Worker instead of the UI thread. This approach provides more stable playback by avoiding UI thread throttling. See the [MDN Web Docs on setInterval delay restrictions](https://developer.mozilla.org/en-US/docs/Web/API/setInterval#delay_restrictions) for more details.
|
|
144
|
-
- *Example*:
|
|
145
|
-
```typescript
|
|
146
|
-
await main.createWorkerNode();
|
|
147
|
-
main.start();
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Below is a reference implementation of `main` used in the examples.
|
|
151
|
-
|
|
152
|
-
Note: The imported `sine-wave-frame-buffer-filler` and `worker` can be found in the `example/src/` directory.
|
|
139
|
+
Instances of OutputStreamNode cannot be constructed directly. First, an instance of StreamNodeFactory needs to be created. The StreamNodeFactory is instantiated by calling its static create method with a BaseAudioContext as an argument. This method internally loads the necessary modules. Then, through the returned instance, the construction of OutputStreamNode becomes possible.
|
|
153
140
|
|
|
141
|
+
The library does not handle the construction or destruction of AudioContext. When constructing AudioContext, be sure to do so in response to a user interaction, such as a UI event (e.g., button press).
|
|
142
|
+
|
|
143
|
+
Example:
|
|
154
144
|
```typescript
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
import type { FillerParameters } from './sine-wave-frame-buffer-filler';
|
|
158
|
-
import { SineWaveFrameBufferFiller } from './sine-wave-frame-buffer-filler';
|
|
159
|
-
|
|
160
|
-
class Main {
|
|
161
|
-
private factory: StreamNodeFactory | null = null;
|
|
162
|
-
private streamNode: OutputStreamNode | null = null;
|
|
163
|
-
|
|
164
|
-
// Initialize the AudioContext and StreamNodeFactory
|
|
165
|
-
async init() {
|
|
166
|
-
const audioContext = new AudioContext();
|
|
167
|
-
this.factory = await StreamNodeFactory.create(audioContext);
|
|
168
|
-
}
|
|
145
|
+
let audioContext: AudioContext | null = null
|
|
146
|
+
let factory: StreamNodeFactory | null = null
|
|
169
147
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
channelCount: 2,
|
|
175
|
-
frameBufferSize: 4096,
|
|
176
|
-
});
|
|
177
|
-
this.streamNode = node;
|
|
178
|
-
return writer;
|
|
148
|
+
const clicked = async () => {
|
|
149
|
+
if (!audioContext) {
|
|
150
|
+
audioContext = new AudioContext()
|
|
151
|
+
factory = await StreamNodeFactory.create(audioContext)
|
|
179
152
|
}
|
|
153
|
+
const node = await factory.createManualBufferNode( { channelCount: 2, frameBufferSize: 4096 })
|
|
154
|
+
}
|
|
155
|
+
```
|
|
180
156
|
|
|
181
|
-
|
|
182
|
-
async createTimedNode() {
|
|
183
|
-
if (!this.factory) throw new Error('Factory not initialized');
|
|
184
|
-
const filler = new SineWaveFrameBufferFiller({ frequency: 440, sampleRate: 44100 });
|
|
185
|
-
this.streamNode = await this.factory.createTimedBufferNode(filler, {
|
|
186
|
-
channelCount: 2,
|
|
187
|
-
fillInterval: 20,
|
|
188
|
-
sampleRate: 44100,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
157
|
+
### Buffer Writing Methods
|
|
191
158
|
|
|
192
|
-
|
|
193
|
-
async createWorkerNode() {
|
|
194
|
-
if (!this.factory) throw new Error('Factory not initialized');
|
|
195
|
-
this.streamNode = await this.factory.createWorkerBufferNode<FillerParameters>(worker, {
|
|
196
|
-
channelCount: 2,
|
|
197
|
-
fillInterval: 20,
|
|
198
|
-
sampleRate: 44100,
|
|
199
|
-
fillerParams: { frequency: 440, sampleRate: 44100 },
|
|
200
|
-
});
|
|
201
|
-
}
|
|
159
|
+
As outlined in the overview, OutputStreamNode requires external audio samples. These samples must be written to a ring buffer, and there are several methods to achieve this.
|
|
202
160
|
|
|
203
|
-
|
|
204
|
-
// Node’s streaming process (such as timer activation) does not start until start() is called.
|
|
205
|
-
start() {
|
|
206
|
-
if (!this.streamNode) throw new Error('Stream node not created');
|
|
207
|
-
this.streamNode.connect(this.streamNode.context.destination);
|
|
208
|
-
this.streamNode.start();
|
|
209
|
-
}
|
|
161
|
+
#### Manual
|
|
210
162
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return this.streamNode.stop();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
163
|
+
- This method involves manually writing to the ring buffer. Use the `OutputStreamFactory.createManualBufferNode` method, specifying the number of channels and frames.
|
|
164
|
+
- When the OutputStreamNode is first constructed, the ring buffer is empty. Typically, you need to write to the ring buffer before starting playback. While the node is playing, you must continue writing to the ring buffer to prevent audio frame depletion.
|
|
165
|
+
- If the audio frames run out, the stream playback continues with the node outputting silence.
|
|
166
|
+
- To stop the stream playback, call the `stop()` method of OutputStreamNode. You can specify the frame at which to stop playback. If you want to play all the written frames, you can specify the total number of written frames, which can be obtained via the FrameBufferWriter.
|
|
218
167
|
|
|
219
|
-
|
|
220
|
-
|
|
168
|
+
#### Timed
|
|
169
|
+
|
|
170
|
+
- This method writes to the ring buffer using a timer initiated on the UI thread. Create it using the `OutputStreamFactory.createTimedBufferNode()` method, specifying the number of channels, timer interval, and the FrameBufferFiller that supplies samples to the buffer.
|
|
171
|
+
- Writing to the ring buffer is handled by the FrameBufferFiller. The timer periodically calls the `fill` method of the FrameBufferFiller, which supplies audio frames via the FrameBufferWriter.
|
|
172
|
+
- If the audio frames run out, the stream playback continues with the node outputting silence.
|
|
173
|
+
- If the `fill` method of the FrameBufferFiller returns false, it indicates the end of the audio frame supply. Once OutputStreamNode outputs all the written frames, the stream automatically stops and disconnects.
|
|
174
|
+
- Like the Manual method, you can also stop playback at any time using the `stop()` method.
|
|
175
|
+
|
|
176
|
+
#### Worker
|
|
177
|
+
|
|
178
|
+
- Similar to the Timed method, this method uses a timer to write to the ring buffer, but the timer runs within a Worker. This approach reduces the impact of UI thread throttling, providing more stable playback.
|
|
179
|
+
- Create it using the `OutputStreamFactory.createWorkerBufferNode()` method.
|
|
180
|
+
- Writing to the ring buffer occurs within the Worker.
|
|
181
|
+
- While the ring buffer writing is still managed by the FrameBufferFiller, the instance must be created and used within the Worker.
|
|
182
|
+
- The instantiation of the FrameBufferFiller implementation class is done within the Worker.
|
|
183
|
+
- You need to create a custom Worker, but helper implementations are available, simplifying this process. Essentially, you only need to specify the FrameBufferFiller implementation class within the Worker.
|
|
184
|
+
- Depending on how you implement the FrameBufferFiller class, you can use the same implementation as the Timed method.
|
|
185
|
+
|
|
186
|
+
</details>
|
|
221
187
|
|
|
222
|
-
##
|
|
188
|
+
## Buffer Underrun Handling
|
|
223
189
|
|
|
224
|
-
|
|
190
|
+
- When the buffer becomes empty, silent audio is output instead of throwing an error.
|
|
191
|
+
- The AudioNode continues to operate and consume CPU resources even during silent output.
|
|
192
|
+
- Normal audio output resumes automatically when new audio data is supplied.
|
|
193
|
+
- An UnderrunEvent is emitted upon recovery from an underrun, reporting the duration of silence (note: this is a post-event notification).
|
|
225
194
|
|
|
226
|
-
##
|
|
195
|
+
## Details of Configuration Parameters
|
|
196
|
+
|
|
197
|
+
<details>
|
|
198
|
+
<summary>Click to view details about configuration parameters</summary>
|
|
199
|
+
|
|
200
|
+
Understanding these parameters is crucial for optimal audio performance:
|
|
201
|
+
|
|
202
|
+
### channelCount (All strategies)
|
|
203
|
+
- Specifies the number of audio channels (e.g., 2 for stereo).
|
|
204
|
+
- Determines the sample composition within each frame.
|
|
205
|
+
|
|
206
|
+
### frameBufferSize (Manual strategy only)
|
|
207
|
+
- Defines the size of the ring buffer in frames.
|
|
208
|
+
- For continuous streaming, new frames must be supplied before buffer depletion.
|
|
209
|
+
- Larger size: Less susceptible to interruptions, but increases latency.
|
|
210
|
+
- Smaller size: Requires more frequent writes, potentially increasing CPU load.
|
|
211
|
+
- Manual strategy: Must be specified.
|
|
212
|
+
- Timed/Worker strategies: Calculated internally based on fillInterval.
|
|
213
|
+
|
|
214
|
+
### fillInterval (Timed and Worker strategies only)
|
|
215
|
+
- Specifies the interval for buffer refill timer.
|
|
216
|
+
- Default: 20ms.
|
|
217
|
+
|
|
218
|
+
### frameBufferChunks (Timed and Worker strategies only)
|
|
219
|
+
- Specifies the number of chunks in the total buffer size.
|
|
220
|
+
- Default: 5.
|
|
221
|
+
|
|
222
|
+
Example calculation:
|
|
223
|
+
For 48kHz sample rate and 20ms fillInterval:
|
|
224
|
+
- One chunk size = 48000 * 0.02 = 960 frames
|
|
225
|
+
- Total buffer size with default 5 chunks = 960 * 5 = 4800 frames
|
|
226
|
+
|
|
227
|
+
The actual values may slightly differ from the above because they are rounded up to 128 sample units.
|
|
228
|
+
|
|
229
|
+
</details>
|
|
230
|
+
|
|
231
|
+
## Example
|
|
232
|
+
|
|
233
|
+
<details>
|
|
234
|
+
<summary>Click to view example details</summary>
|
|
235
|
+
|
|
236
|
+
The example can be found at [https://github.com/ain1084/audio-worklet-stream/tree/main/example](https://github.com/ain1084/audio-worklet-stream/tree/main/example).
|
|
227
237
|
|
|
228
238
|
The provided example demonstrates how to use the library to manually write audio frames to a buffer. It includes:
|
|
229
239
|
|
|
@@ -233,11 +243,199 @@ The provided example demonstrates how to use the library to manually write audio
|
|
|
233
243
|
- **Worker** (`example/src/worker.ts`): Sets up a worker to handle buffer filling tasks.
|
|
234
244
|
- **HTML Entry Point** (`example/index.html`): Provides the HTML structure and buttons to control the audio stream.
|
|
235
245
|
|
|
236
|
-
For more details, refer to the
|
|
246
|
+
For more details, refer to the [example/README.md](https://github.com/ain1084/audio-worklet-stream/tree/main/example/README.md).
|
|
247
|
+
|
|
248
|
+
</details>
|
|
249
|
+
|
|
250
|
+
## Performance Optimization Guide
|
|
251
|
+
|
|
252
|
+
<details>
|
|
253
|
+
<summary>Click to expand performance optimization details</summary>
|
|
254
|
+
|
|
255
|
+
This guide provides tips and best practices for optimizing the performance of your audio application using the Audio Worklet Stream Library.
|
|
256
|
+
|
|
257
|
+
### Batch Processing
|
|
258
|
+
|
|
259
|
+
Our library is optimized for processing audio frames in large batches. To maximize performance:
|
|
260
|
+
|
|
261
|
+
1. When implementing your own audio generation or processing logic, work with larger chunks of audio data whenever possible.
|
|
262
|
+
2. Utilize the library's ability to handle multiple frames at once in your buffer filling strategies.
|
|
263
|
+
|
|
264
|
+
### Buffer Size Considerations
|
|
265
|
+
|
|
266
|
+
- Larger buffer sizes can improve performance but may increase latency.
|
|
267
|
+
- Experiment with different buffer sizes to find the optimal balance between performance and latency for your specific use case.
|
|
268
|
+
|
|
269
|
+
### Worker-Based Strategy
|
|
270
|
+
|
|
271
|
+
For the most stable playback, especially in scenarios where the main thread might be busy:
|
|
272
|
+
|
|
273
|
+
1. Use the Worker-based buffer writing strategy.
|
|
274
|
+
2. Implement computationally intensive tasks within the Worker to avoid impacting the main thread.
|
|
275
|
+
|
|
276
|
+
### Memory Management
|
|
277
|
+
|
|
278
|
+
- When working with multiple audio streams, be mindful of memory usage.
|
|
279
|
+
- For scenarios requiring numerous concurrent audio streams, pay attention to the creation and resource management of each stream. Consider properly releasing unused streams when necessary.
|
|
280
|
+
|
|
281
|
+
### Avoid Frequent AudioContext Creation
|
|
282
|
+
|
|
283
|
+
- Creating new AudioContext instances is expensive. Reuse existing contexts when possible.
|
|
284
|
+
- If your application requires multiple audio streams, try to use a single AudioContext for all of them.
|
|
285
|
+
|
|
286
|
+
### Profiling and Monitoring
|
|
287
|
+
|
|
288
|
+
- Use browser developer tools to profile your application and identify performance bottlenecks.
|
|
289
|
+
- Monitor CPU usage and audio underruns to ensure smooth playback.
|
|
290
|
+
|
|
291
|
+
By following these guidelines, you can ensure that your audio application runs efficiently and provides a smooth user experience.
|
|
292
|
+
|
|
293
|
+
</details>
|
|
294
|
+
|
|
295
|
+
## Advanced Usage Guide
|
|
296
|
+
|
|
297
|
+
<details>
|
|
298
|
+
<summary>Click to expand advanced usage details</summary>
|
|
299
|
+
|
|
300
|
+
This guide covers advanced usage scenarios and techniques for the Audio Worklet Stream Library.
|
|
301
|
+
|
|
302
|
+
### Custom Buffer Filling Strategies
|
|
303
|
+
|
|
304
|
+
While the library provides manual, timed, and worker-based strategies, you can create custom strategies:
|
|
305
|
+
|
|
306
|
+
1. Implement the `BufferWriteStrategy` interface.
|
|
307
|
+
2. Override the `onInit`, `onStart`, and `onStopped` methods to define your custom behavior.
|
|
308
|
+
|
|
309
|
+
Example:
|
|
310
|
+
```typescript
|
|
311
|
+
class CustomStrategy implements BufferWriteStrategy {
|
|
312
|
+
async onInit(node: OutputStreamNode): Promise<boolean> {
|
|
313
|
+
// Custom initialization logic
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
onStart(node: OutputStreamNode): boolean {
|
|
317
|
+
// Custom start logic
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
onStopped(): void {
|
|
321
|
+
// Custom stop logic
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Advanced Worker Usage
|
|
327
|
+
|
|
328
|
+
For complex audio processing tasks:
|
|
329
|
+
|
|
330
|
+
1. Create a custom Worker that extends `BufferFillWorker`.
|
|
331
|
+
2. Implement advanced audio processing algorithms within the Worker.
|
|
332
|
+
3. Use `SharedArrayBuffer` for efficient data sharing between the main thread and the Worker.
|
|
333
|
+
|
|
334
|
+
### Handling Multiple Audio Streams
|
|
335
|
+
|
|
336
|
+
When working with multiple audio streams:
|
|
337
|
+
|
|
338
|
+
1. Create separate `OutputStreamNode` instances for each stream.
|
|
339
|
+
2. Manage their lifecycle and synchronization carefully.
|
|
340
|
+
3. Consider implementing a mixer if you need to combine multiple streams.
|
|
341
|
+
|
|
342
|
+
### Integrating with Other Web Audio API Features
|
|
343
|
+
|
|
344
|
+
You can combine this library with other Web Audio API features:
|
|
345
|
+
|
|
346
|
+
1. Connect the `OutputStreamNode` to other AudioNodes for additional processing.
|
|
347
|
+
2. Use AnalyserNode for visualizations.
|
|
348
|
+
3. Implement spatial audio using PannerNode.
|
|
349
|
+
|
|
350
|
+
### Error Handling and Debugging
|
|
351
|
+
|
|
352
|
+
For robust applications:
|
|
353
|
+
|
|
354
|
+
1. Implement comprehensive error handling, especially for Worker-based strategies.
|
|
355
|
+
2. Use the UnderrunEvent to detect and handle buffer underruns.
|
|
356
|
+
3. Implement logging or metrics collection for performance monitoring.
|
|
357
|
+
|
|
358
|
+
These advanced techniques will help you leverage the full power of the Audio Worklet Stream Library in complex audio applications.
|
|
359
|
+
|
|
360
|
+
</details>
|
|
361
|
+
|
|
362
|
+
## Troubleshooting Guide
|
|
363
|
+
|
|
364
|
+
<details>
|
|
365
|
+
<summary>Click to expand troubleshooting details</summary>
|
|
366
|
+
|
|
367
|
+
This guide helps you troubleshoot common issues when using the Audio Worklet Stream Library.
|
|
368
|
+
|
|
369
|
+
### Audio Playback Issues
|
|
370
|
+
|
|
371
|
+
#### No Sound
|
|
372
|
+
|
|
373
|
+
1. Check if your AudioContext is in the 'running' state. It may need to be resumed after user interaction.
|
|
374
|
+
2. Ensure your OutputStreamNode is properly connected to the AudioContext destination.
|
|
375
|
+
3. Verify that you're writing audio data to the buffer correctly.
|
|
376
|
+
|
|
377
|
+
#### Choppy or Glitchy Playback
|
|
378
|
+
|
|
379
|
+
1. Increase your buffer size to reduce the chance of underruns.
|
|
380
|
+
2. If using the Timed strategy, consider switching to the Worker strategy for more stable playback.
|
|
381
|
+
3. Check your system's CPU usage. High CPU usage can cause audio glitches.
|
|
382
|
+
|
|
383
|
+
### Buffer Underruns
|
|
384
|
+
|
|
385
|
+
If you're experiencing frequent UnderrunEvents:
|
|
386
|
+
|
|
387
|
+
1. Increase your buffer size.
|
|
388
|
+
2. Optimize your audio data generation/loading process.
|
|
389
|
+
3. If using the Manual strategy, ensure you're writing to the buffer frequently enough.
|
|
390
|
+
|
|
391
|
+
### Worker-Related Issues
|
|
392
|
+
|
|
393
|
+
#### Worker Not Starting
|
|
394
|
+
|
|
395
|
+
1. Ensure your Worker file is in the correct location and properly bundled.
|
|
396
|
+
2. Check for any console errors related to Worker initialization.
|
|
397
|
+
|
|
398
|
+
#### Data Not Being Processed in Worker
|
|
399
|
+
|
|
400
|
+
1. Verify that your FrameBufferFiller implementation in the Worker is correct.
|
|
401
|
+
2. Check the message passing between the main thread and the Worker.
|
|
402
|
+
|
|
403
|
+
### Browser Compatibility Issues
|
|
404
|
+
|
|
405
|
+
#### Feature Not Working in Specific Browsers
|
|
406
|
+
|
|
407
|
+
1. Refer to the Browser Compatibility table in the README.
|
|
408
|
+
2. Ensure you're using the latest version of the browser.
|
|
409
|
+
3. Check if the required features (like SharedArrayBuffer) are enabled in the browser.
|
|
410
|
+
|
|
411
|
+
### Build and Integration Issues
|
|
412
|
+
|
|
413
|
+
#### Module Not Found Errors
|
|
414
|
+
|
|
415
|
+
1. Ensure `@ain1084/audio-worklet-stream` is properly installed.
|
|
416
|
+
2. Check your bundler configuration, especially the `optimizeDeps.exclude` setting in Vite.
|
|
417
|
+
|
|
418
|
+
#### CORS Errors
|
|
419
|
+
|
|
420
|
+
1. Verify that you've set the correct CORS headers as described in the installation instructions.
|
|
421
|
+
2. If using a development server, ensure it's configured to send the required headers.
|
|
422
|
+
|
|
423
|
+
### Performance Issues
|
|
424
|
+
|
|
425
|
+
If you're experiencing poor performance:
|
|
426
|
+
|
|
427
|
+
1. Profile your application using browser developer tools.
|
|
428
|
+
2. Consider using the Worker strategy for computationally intensive tasks.
|
|
429
|
+
3. Optimize your audio processing algorithms.
|
|
430
|
+
|
|
431
|
+
If you're still facing issues after trying these solutions, please open an issue on our GitHub repository with a detailed description of the problem and steps to reproduce it.
|
|
432
|
+
|
|
433
|
+
</details>
|
|
237
434
|
|
|
238
435
|
## Known Issues and Workarounds
|
|
239
436
|
|
|
240
|
-
|
|
437
|
+
<details>
|
|
438
|
+
<summary>Click to view known issues and workarounds</summary>
|
|
241
439
|
|
|
242
440
|
### SSR and Import Errors with ESM Modules
|
|
243
441
|
|
|
@@ -323,18 +521,15 @@ export default defineNuxtConfig({
|
|
|
323
521
|
})
|
|
324
522
|
```
|
|
325
523
|
|
|
326
|
-
|
|
524
|
+
</details>
|
|
525
|
+
|
|
526
|
+
## Future Plans
|
|
327
527
|
|
|
328
|
-
|
|
329
|
-
1. **Enhanced Documentation**: Improve the documentation with more examples and detailed explanations.
|
|
528
|
+
We are considering potential enhancements for future releases, including:
|
|
330
529
|
|
|
331
|
-
|
|
332
|
-
1. **Buffer Underruns**: Occasional buffer underruns under heavy CPU load.
|
|
333
|
-
2. **Limited Worker Support**: Advanced features in workers might not be fully supported across all browsers.
|
|
334
|
-
3. **Overhead at the Start of Playback**: The ring buffer is being generated each time.
|
|
335
|
-
4. **Overhead during Worker Playback**: It seems that the Worker is being loaded every time playback starts (although it hits the cache).
|
|
530
|
+
- Buffer management optimization: We are considering ways to improve memory efficiency and initialization time, especially when dealing with multiple audio streams.
|
|
336
531
|
|
|
337
|
-
|
|
532
|
+
Please note that these are just considerations and may or may not be implemented in future versions. We always aim to balance new features with maintaining the library's stability and simplicity.
|
|
338
533
|
|
|
339
534
|
## Notes
|
|
340
535
|
|
|
@@ -342,7 +537,6 @@ We are continuously working on these areas to improve the library. Contributions
|
|
|
342
537
|
|
|
343
538
|
- **Security Requirements**: Since this library uses `SharedArrayBuffer`, ensuring browser compatibility requires meeting specific security requirements. For more details, refer to the [MDN Web Docs on SharedArrayBuffer Security Requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements).
|
|
344
539
|
|
|
345
|
-
|
|
346
540
|
## Contribution
|
|
347
541
|
|
|
348
542
|
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
|
|
@@ -27,7 +27,7 @@ export class FrameBuffer {
|
|
|
27
27
|
*/
|
|
28
28
|
setFrames(index, samples, sampleStart = 0, sampleCount) {
|
|
29
29
|
index *= this._samplesPerFrame;
|
|
30
|
-
const sampleEnd =
|
|
30
|
+
const sampleEnd = (sampleCount !== undefined) ? Math.min(sampleStart + sampleCount, samples.length) : samples.length;
|
|
31
31
|
const frames = (sampleEnd - sampleStart) / this._samplesPerFrame;
|
|
32
32
|
if (!Number.isInteger(frames)) {
|
|
33
33
|
throw new Error(`Error: The number of samples per frame does not match the specified number of samples. Expected samples per frame: ${this._samplesPerFrame}, but got: ${sampleEnd - sampleStart}.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,WAAW;IACL,OAAO,CAAc;IACrB,gBAAgB,CAAQ;IACxB,OAAO,CAAQ;IAEhC;;;;OAIG;IACH,YAAmB,MAAoB,EAAE,eAAuB;QAC9D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAA;QACvC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,eAAe,CAAC,CAAA;IAC5D,CAAC;IAED;;;;;;;;OAQG;IACI,SAAS,CAAC,KAAa,EAAE,OAAqB,EAAE,cAAsB,CAAC,EAAE,WAAoB;QAClG,KAAK,IAAI,IAAI,CAAC,gBAAgB,CAAA;QAC9B,MAAM,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,WAAW;IACL,OAAO,CAAc;IACrB,gBAAgB,CAAQ;IACxB,OAAO,CAAQ;IAEhC;;;;OAIG;IACH,YAAmB,MAAoB,EAAE,eAAuB;QAC9D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAA;QACvC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,eAAe,CAAC,CAAA;IAC5D,CAAC;IAED;;;;;;;;OAQG;IACI,SAAS,CAAC,KAAa,EAAE,OAAqB,EAAE,cAAsB,CAAC,EAAE,WAAoB;QAClG,KAAK,IAAI,IAAI,CAAC,gBAAgB,CAAA;QAC9B,MAAM,SAAS,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAA;QACpH,MAAM,MAAM,GAAG,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAA;QAChE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,sHAAsH,IAAI,CAAC,gBAAgB,cAAc,SAAS,GAAG,WAAW,GAAG,CAAC,CAAA;QACtM,CAAC;QACD,KAAK,IAAI,WAAW,GAAG,WAAW,EAAE,WAAW,GAAG,SAAS,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC;YACpF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;QAC5C,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;;;;;OAQG;IACI,eAAe,CAAC,UAAkB,EAAE,MAAc,EAAE,MAAsB,EAAE,YAAoB;QACrG,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAA;QAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,aAAa,EAAE,EAAE;YAC9C,KAAK,IAAI,CAAC,GAAG,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC;gBACzE,aAAa,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;YAChE,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACH,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;CACF"}
|
|
@@ -77,6 +77,10 @@ export class OutputStreamNode extends AudioWorkletNode {
|
|
|
77
77
|
case 'ready':
|
|
78
78
|
this.handleStopped();
|
|
79
79
|
break;
|
|
80
|
+
case 'stopped':
|
|
81
|
+
break;
|
|
82
|
+
case 'stopping':
|
|
83
|
+
break;
|
|
80
84
|
default:
|
|
81
85
|
throw new Error(`Cannot stop playback. Current state: ${this._state}`);
|
|
82
86
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-stream-node.js","sourceRoot":"","sources":["../src/output-stream-node.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"output-stream-node.js","sourceRoot":"","sources":["../src/output-stream-node.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@ export class FrameBuffer {
|
|
|
29
29
|
*/
|
|
30
30
|
public setFrames(index: number, samples: Float32Array, sampleStart: number = 0, sampleCount?: number): number {
|
|
31
31
|
index *= this._samplesPerFrame
|
|
32
|
-
const sampleEnd =
|
|
32
|
+
const sampleEnd = (sampleCount !== undefined) ? Math.min(sampleStart + sampleCount, samples.length) : samples.length
|
|
33
33
|
const frames = (sampleEnd - sampleStart) / this._samplesPerFrame
|
|
34
34
|
if (!Number.isInteger(frames)) {
|
|
35
35
|
throw new Error(`Error: The number of samples per frame does not match the specified number of samples. Expected samples per frame: ${this._samplesPerFrame}, but got: ${sampleEnd - sampleStart}.`)
|
|
@@ -103,6 +103,10 @@ export class OutputStreamNode extends AudioWorkletNode {
|
|
|
103
103
|
case 'ready':
|
|
104
104
|
this.handleStopped()
|
|
105
105
|
break
|
|
106
|
+
case 'stopped':
|
|
107
|
+
break
|
|
108
|
+
case 'stopping':
|
|
109
|
+
break
|
|
106
110
|
default:
|
|
107
111
|
throw new Error(`Cannot stop playback. Current state: ${this._state}`)
|
|
108
112
|
}
|