@ain1084/audio-worklet-stream 0.1.6 → 0.1.8

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 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 various strategies like manual, timer-based, and worker-based buffer writing.
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
- ## Confirmed Browser Support
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|![Chrome](https://img.icons8.com/color/24/000000/chrome.png)|![Chrome](https://img.icons8.com/color/24/000000/chrome.png)|![Firefox](https://img.icons8.com/color/24/000000/firefox.png)|![Safari](https://img.icons8.com/color/24/000000/safari--v2.png)|![Safari](https://img.icons8.com/color/24/000000/safari--v2.png)|![Edge](https://img.icons8.com/color/24/000000/ms-edge.png)|![Opera](https://img.icons8.com/color/24/000000/opera.png)|
30
+ |Basic Support|✅|✅|✅|✅|❓|✅|❓|
25
31
  |Manual Buffer Writing|✅|✅|✅|✅|❓|✅|❓|
26
32
  |Timer-Based Buffer Writing|✅|✅|✅|🔺|❓|✅|❓|
27
33
  |Worker-Based Stability|✅|✅|✅|✅|❓|✅|❓|
28
34
 
29
- ### Legend
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. The developer uses Nuxt3, which is compatible with Vite.
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 `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.
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
- ### Buffer Writing Methods
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
- - **Manual**: The consumer is responsible for writing to the ring buffer. If the buffer becomes empty, silence is played. This method requires active management to ensure the buffer is always filled with audio data.
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
- import { StreamNodeFactory, type OutputStreamNode } from '@ain1084/audio-worklet-stream';
156
- import worker from './worker?worker';
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
- // Create a manual buffer node
171
- async createManualNode() {
172
- if (!this.factory) throw new Error('Factory not initialized');
173
- const [node, writer] = await this.factory.createManualBufferNode({
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
- // Create a timed buffer node
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
- // Create a worker buffer node
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
- // Start the audio stream
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
- // Stop the audio stream
212
- // stop() internally calls node.disconnect(). Since inter-thread communication may take some time, it returns a Promise.
213
- stop() {
214
- if (!this.streamNode) throw new Error('Stream node not created');
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
- export default new Main();
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
- ## Documentation
188
+ ## Buffer Underrun Handling
223
189
 
224
- For more detailed documentation, visit the [API documentation](https://ain1084.github.io/audio-worklet-stream/).
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
- ## Provided Example
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 `example/README.md`.
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
- *Note: Some content overlaps with previous sections.*
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
- ## Future Plans and Known Issues
524
+ </details>
525
+
526
+ ## Future Plans
327
527
 
328
- ### Future Plans
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
- ### Known Issues
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
- We are continuously working on these areas to improve the library. Contributions and suggestions are always welcome!
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 = Math.min((sampleCount !== undefined) ? (sampleStart + sampleCount) : samples.length, samples.length);
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,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QACtH,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"}
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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"}
@@ -22,7 +22,7 @@ class PlayContext {
22
22
  node.stop(writer.totalFrames);
23
23
  }
24
24
  }
25
- catch (error) {
25
+ catch {
26
26
  this.cleanup();
27
27
  node.stop();
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"timed.js","sourceRoot":"","sources":["../../src/write-strategy/timed.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAA2B,MAAM,gCAAgC,CAAA;AAKjG;;;GAGG;AACH,MAAM,WAAW;IACP,QAAQ,GAAW,CAAC,CAAA;IAE5B;;;;;;OAMG;IACH,YAAY,IAAsB,EAAE,MAAyB,EAAE,MAAyB,EAAE,YAAoB;QAC5G,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpC,OAAM;YACR,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;gBAC/B,CAAC;YACH,CAAC;YACD,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,OAAO,EAAE,CAAA;gBACd,IAAI,CAAC,IAAI,EAAE,CAAA;YACb,CAAC;QACH,CAAC,EAAE,YAAY,CAAC,CAAA;IAClB,CAAC;IAED;;OAEG;IACI,OAAO;QACZ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC5B,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IAClB,OAAO,CAAmB;IAC1B,OAAO,CAAmB;IAC1B,SAAS,CAAQ;IACjB,mBAAmB,CAAS;IACrC,QAAQ,GAAuB,IAAI,CAAA;IAE3C;;;;OAIG;IACH,YAAY,MAA+B,EAAE,MAAyB;QACpE,IAAI,CAAC,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAA;QAC9C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,YAAY,CAAA;QACpC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC5D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAC,4BAA4B;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAsB;QAC5B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACjF,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACH,SAAS;QACP,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;IACtB,CAAC;CACF"}
1
+ {"version":3,"file":"timed.js","sourceRoot":"","sources":["../../src/write-strategy/timed.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAA2B,MAAM,gCAAgC,CAAA;AAKjG;;;GAGG;AACH,MAAM,WAAW;IACP,QAAQ,GAAW,CAAC,CAAA;IAE5B;;;;;;OAMG;IACH,YAAY,IAAsB,EAAE,MAAyB,EAAE,MAAyB,EAAE,YAAoB;QAC5G,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpC,OAAM;YACR,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;gBAC/B,CAAC;YACH,CAAC;YACD,MAAM,CAAC;gBACL,IAAI,CAAC,OAAO,EAAE,CAAA;gBACd,IAAI,CAAC,IAAI,EAAE,CAAA;YACb,CAAC;QACH,CAAC,EAAE,YAAY,CAAC,CAAA;IAClB,CAAC;IAED;;OAEG;IACI,OAAO;QACZ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC5B,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IAClB,OAAO,CAAmB;IAC1B,OAAO,CAAmB;IAC1B,SAAS,CAAQ;IACjB,mBAAmB,CAAS;IACrC,QAAQ,GAAuB,IAAI,CAAA;IAE3C;;;;OAIG;IACH,YAAY,MAA+B,EAAE,MAAyB;QACpE,IAAI,CAAC,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAA;QAC9C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,YAAY,CAAA;QACpC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC5D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAC,4BAA4B;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAsB;QAC5B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACjF,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACH,SAAS;QACP,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;IACtB,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ain1084/audio-worklet-stream",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -40,15 +40,15 @@
40
40
  "docs": "typedoc"
41
41
  },
42
42
  "devDependencies": {
43
- "@stylistic/eslint-plugin": "^2.3.0",
44
- "@types/audioworklet": "^0.0.57",
45
- "@types/node": "^20.14.10",
46
- "@typescript-eslint/parser": "^7.16.0",
47
- "eslint": "^8.57.0",
48
- "globals": "^15.8.0",
49
- "typedoc": "^0.26.4",
50
- "typescript": "^5.5.3",
51
- "typescript-eslint": "^7.16.0",
52
- "vite": "^5.3.3"
43
+ "@stylistic/eslint-plugin": "^2.9.0",
44
+ "@types/audioworklet": "^0.0.60",
45
+ "@types/node": "^22.7.5",
46
+ "@typescript-eslint/parser": "^8.8.1",
47
+ "eslint": "^9.12.0",
48
+ "globals": "^15.10.0",
49
+ "typedoc": "^0.26.8",
50
+ "typescript": "^5.6.2",
51
+ "typescript-eslint": "^8.8.1",
52
+ "vite": "^5.4.8"
53
53
  }
54
54
  }
@@ -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 = Math.min((sampleCount !== undefined) ? (sampleStart + sampleCount) : samples.length, samples.length)
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
  }
@@ -28,7 +28,7 @@ class PlayContext {
28
28
  node.stop(writer.totalFrames)
29
29
  }
30
30
  }
31
- catch (error) {
31
+ catch {
32
32
  this.cleanup()
33
33
  node.stop()
34
34
  }