@ain1084/audio-worklet-stream 0.1.8 → 1.0.1
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 +23 -40
- package/dist/events.d.ts +6 -6
- package/dist/events.js +8 -8
- package/dist/events.js.map +1 -1
- package/dist/frame-buffer/buffer-config.d.ts +67 -0
- package/dist/frame-buffer/buffer-config.js +64 -0
- package/dist/frame-buffer/buffer-config.js.map +1 -0
- package/dist/frame-buffer/buffer-factory.d.ts +1 -2
- package/dist/frame-buffer/buffer-factory.js +6 -3
- package/dist/frame-buffer/buffer-factory.js.map +1 -1
- package/dist/frame-buffer/buffer-reader.d.ts +30 -10
- package/dist/frame-buffer/buffer-reader.js +38 -16
- package/dist/frame-buffer/buffer-reader.js.map +1 -1
- package/dist/frame-buffer/buffer-utils.js +2 -2
- package/dist/frame-buffer/buffer-utils.js.map +1 -1
- package/dist/frame-buffer/buffer-writer.d.ts +32 -12
- package/dist/frame-buffer/buffer-writer.js +40 -18
- package/dist/frame-buffer/buffer-writer.js.map +1 -1
- package/dist/frame-buffer/buffer.d.ts +33 -22
- package/dist/frame-buffer/buffer.js +50 -40
- package/dist/frame-buffer/buffer.js.map +1 -1
- package/dist/output-message.d.ts +9 -9
- package/dist/output-stream-node.d.ts +13 -19
- package/dist/output-stream-node.js +20 -26
- package/dist/output-stream-node.js.map +1 -1
- package/dist/output-stream-processor.js +25 -18
- package/dist/output-stream-processor.js.map +1 -1
- package/dist/stream-node-factory.d.ts +10 -0
- package/dist/stream-node-factory.js +27 -12
- package/dist/stream-node-factory.js.map +1 -1
- package/dist/write-strategy/manual.d.ts +1 -1
- package/dist/write-strategy/manual.js +1 -1
- package/dist/write-strategy/manual.js.map +1 -1
- package/dist/write-strategy/timed.d.ts +1 -1
- package/dist/write-strategy/timed.js +1 -1
- package/dist/write-strategy/timed.js.map +1 -1
- package/dist/write-strategy/worker/message.d.ts +1 -1
- package/dist/write-strategy/worker/strategy.d.ts +1 -1
- package/dist/write-strategy/worker/worker.js +1 -1
- package/dist/write-strategy/worker/worker.js.map +1 -1
- package/package.json +9 -9
- package/src/events.ts +4 -4
- package/src/frame-buffer/buffer-config.ts +129 -0
- package/src/frame-buffer/buffer-reader.ts +38 -16
- package/src/frame-buffer/buffer-writer.ts +40 -18
- package/src/frame-buffer/buffer.ts +51 -40
- package/src/output-message.ts +9 -9
- package/src/output-stream-node.ts +23 -29
- package/src/output-stream-processor.ts +25 -18
- package/src/stream-node-factory.ts +33 -15
- package/src/write-strategy/manual.ts +1 -1
- package/src/write-strategy/timed.ts +1 -1
- package/src/write-strategy/worker/message.ts +1 -1
- package/src/write-strategy/worker/strategy.ts +1 -1
- package/src/write-strategy/worker/worker.ts +1 -1
- package/src/frame-buffer/buffer-factory.ts +0 -115
- package/src/frame-buffer/buffer-utils.ts +0 -48
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ This library uses modern Web APIs and is designed for contemporary browsers only
|
|
|
33
33
|
|Worker-Based Stability|✅|✅|✅|✅|❓|✅|❓|
|
|
34
34
|
|
|
35
35
|
Legend:
|
|
36
|
+
|
|
36
37
|
- ✅: Confirmed and working without issues
|
|
37
38
|
- 🔺: Confirmed with limitations (e.g., unstable in background operation)
|
|
38
39
|
- ❓: Not yet confirmed
|
|
@@ -59,9 +60,10 @@ npm install @ain1084/audio-worklet-stream
|
|
|
59
60
|
<details>
|
|
60
61
|
<summary>Click to view configuration details</summary>
|
|
61
62
|
|
|
62
|
-
You need to add `@ain1084/audio-worklet-stream` to the optimizeDeps.exclude section in `vite.config.ts`. Furthermore, include the necessary
|
|
63
|
+
You need to add `@ain1084/audio-worklet-stream` to the optimizeDeps.exclude section in `vite.config.ts`. Furthermore, include the necessary **COOP (Cross-Origin Opener Policy)** and **COEP (Cross-Origin Embedder Policy)** settings to enable the use of `SharedArrayBuffer`.
|
|
64
|
+
|
|
65
|
+
### vite.config.ts
|
|
63
66
|
|
|
64
|
-
**vite.config.ts**
|
|
65
67
|
```typescript
|
|
66
68
|
import { defineConfig } from 'vite'
|
|
67
69
|
|
|
@@ -86,7 +88,8 @@ export default defineConfig({
|
|
|
86
88
|
|
|
87
89
|
If you are using Nuxt3, add it under vite in `nuxt.config.ts`.
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
### nuxt.config.ts
|
|
92
|
+
|
|
90
93
|
```typescript
|
|
91
94
|
export default defineNuxtConfig({
|
|
92
95
|
vite: {
|
|
@@ -112,7 +115,6 @@ export default defineNuxtConfig({
|
|
|
112
115
|
},
|
|
113
116
|
routeRules: {
|
|
114
117
|
'/**': {
|
|
115
|
-
cors: true,
|
|
116
118
|
headers: {
|
|
117
119
|
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
118
120
|
'Cross-Origin-Opener-Policy': 'same-origin',
|
|
@@ -141,6 +143,7 @@ Instances of OutputStreamNode cannot be constructed directly. First, an instance
|
|
|
141
143
|
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
144
|
|
|
143
145
|
Example:
|
|
146
|
+
|
|
144
147
|
```typescript
|
|
145
148
|
let audioContext: AudioContext | null = null
|
|
146
149
|
let factory: StreamNodeFactory | null = null
|
|
@@ -200,10 +203,12 @@ As outlined in the overview, OutputStreamNode requires external audio samples. T
|
|
|
200
203
|
Understanding these parameters is crucial for optimal audio performance:
|
|
201
204
|
|
|
202
205
|
### channelCount (All strategies)
|
|
206
|
+
|
|
203
207
|
- Specifies the number of audio channels (e.g., 2 for stereo).
|
|
204
208
|
- Determines the sample composition within each frame.
|
|
205
209
|
|
|
206
210
|
### frameBufferSize (Manual strategy only)
|
|
211
|
+
|
|
207
212
|
- Defines the size of the ring buffer in frames.
|
|
208
213
|
- For continuous streaming, new frames must be supplied before buffer depletion.
|
|
209
214
|
- Larger size: Less susceptible to interruptions, but increases latency.
|
|
@@ -212,15 +217,18 @@ Understanding these parameters is crucial for optimal audio performance:
|
|
|
212
217
|
- Timed/Worker strategies: Calculated internally based on fillInterval.
|
|
213
218
|
|
|
214
219
|
### fillInterval (Timed and Worker strategies only)
|
|
220
|
+
|
|
215
221
|
- Specifies the interval for buffer refill timer.
|
|
216
222
|
- Default: 20ms.
|
|
217
223
|
|
|
218
224
|
### frameBufferChunks (Timed and Worker strategies only)
|
|
225
|
+
|
|
219
226
|
- Specifies the number of chunks in the total buffer size.
|
|
220
227
|
- Default: 5.
|
|
221
228
|
|
|
222
229
|
Example calculation:
|
|
223
230
|
For 48kHz sample rate and 20ms fillInterval:
|
|
231
|
+
|
|
224
232
|
- One chunk size = 48000 * 0.02 = 960 frames
|
|
225
233
|
- Total buffer size with default 5 chunks = 960 * 5 = 4800 frames
|
|
226
234
|
|
|
@@ -233,17 +241,17 @@ The actual values may slightly differ from the above because they are rounded up
|
|
|
233
241
|
<details>
|
|
234
242
|
<summary>Click to view example details</summary>
|
|
235
243
|
|
|
236
|
-
The example can be found at [
|
|
244
|
+
The example can be found at [example](https://github.com/ain1084/audio-worklet-stream/tree/main/example).
|
|
237
245
|
|
|
238
246
|
The provided example demonstrates how to use the library to manually write audio frames to a buffer. It includes:
|
|
239
247
|
|
|
240
|
-
- **Main Application** (
|
|
241
|
-
- **Sine Wave Filler** (
|
|
242
|
-
- **Sine Wave Generator** (
|
|
243
|
-
- **Worker** (
|
|
244
|
-
- **HTML Entry Point** (
|
|
248
|
+
- **Main Application** ([example/src/main.ts](https://github.com/ain1084/audio-worklet-stream/blob/main/example/src/main.ts)): Sets up and starts the audio stream using different buffer writing strategies.
|
|
249
|
+
- **Sine Wave Filler** ([example/src/sine-wave-frame-buffer-filler.ts](https://github.com/ain1084/audio-worklet-stream/blob/main/example/src/sine-wave-frame-buffer-filler.ts)): Implements a frame buffer filler that generates a sine wave.
|
|
250
|
+
- **Sine Wave Generator** ([example/src/sine-wave-generator.ts](https://github.com/ain1084/audio-worklet-stream/blob/main/example/src/sine-wave-generator.ts)): Generates sine wave values for the buffer filler.
|
|
251
|
+
- **Worker** ([example/src/worker.ts](https://github.com/ain1084/audio-worklet-stream/blob/main/example/src/worker.ts)): Sets up a worker to handle buffer filling tasks.
|
|
252
|
+
- **HTML Entry Point** ([example/index.html](https://github.com/ain1084/audio-worklet-stream/blob/main/example/index.html)): Provides the HTML structure and buttons to control the audio stream.
|
|
245
253
|
|
|
246
|
-
For more details, refer to the [example/README.md](https://github.com/ain1084/audio-worklet-stream/
|
|
254
|
+
For more details, refer to the [example/README.md](https://github.com/ain1084/audio-worklet-stream/blob/main/example/README.md).
|
|
247
255
|
|
|
248
256
|
</details>
|
|
249
257
|
|
|
@@ -299,30 +307,6 @@ By following these guidelines, you can ensure that your audio application runs e
|
|
|
299
307
|
|
|
300
308
|
This guide covers advanced usage scenarios and techniques for the Audio Worklet Stream Library.
|
|
301
309
|
|
|
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
310
|
### Advanced Worker Usage
|
|
327
311
|
|
|
328
312
|
For complex audio processing tasks:
|
|
@@ -415,9 +399,9 @@ If you're experiencing frequent UnderrunEvents:
|
|
|
415
399
|
1. Ensure `@ain1084/audio-worklet-stream` is properly installed.
|
|
416
400
|
2. Check your bundler configuration, especially the `optimizeDeps.exclude` setting in Vite.
|
|
417
401
|
|
|
418
|
-
####
|
|
402
|
+
#### Browser Errors
|
|
419
403
|
|
|
420
|
-
1. Verify that you've set the correct
|
|
404
|
+
1. Verify that you've set the correct **COOP (Cross-Origin Opener Policy)** and **COEP (Cross-Origin Embedder Policy)** headers as described in the installation instructions.
|
|
421
405
|
2. If using a development server, ensure it's configured to send the required headers.
|
|
422
406
|
|
|
423
407
|
### Performance Issues
|
|
@@ -451,7 +435,7 @@ When using `@ain1084/audio-worklet-stream` in a Nuxt 3 project, you may encounte
|
|
|
451
435
|
|
|
452
436
|
You can disable SSR for the component that uses the package. This can be done by using `<client-only>`:
|
|
453
437
|
|
|
454
|
-
```
|
|
438
|
+
```vue
|
|
455
439
|
<client-only>
|
|
456
440
|
<MyComponent />
|
|
457
441
|
</client-only>
|
|
@@ -507,10 +491,9 @@ export default defineNuxtConfig({
|
|
|
507
491
|
rollupConfig: {
|
|
508
492
|
external: '@ain1084/audio-worklet-stream',
|
|
509
493
|
},
|
|
510
|
-
// Ensure
|
|
494
|
+
// Ensure COEP and COOP settings for SharedArrayBuffer
|
|
511
495
|
routeRules: {
|
|
512
496
|
'/**': {
|
|
513
|
-
cors: true,
|
|
514
497
|
headers: {
|
|
515
498
|
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
516
499
|
'Cross-Origin-Opener-Policy': 'same-origin',
|
package/dist/events.d.ts
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* This event is dispatched when the audio processing stops.
|
|
4
4
|
*/
|
|
5
5
|
export declare class StopEvent extends Event {
|
|
6
|
-
readonly
|
|
6
|
+
readonly stoppedAtFrame: bigint;
|
|
7
7
|
static readonly type = "@ain1084/audio-worklet-stream/stop";
|
|
8
8
|
/**
|
|
9
9
|
* Creates an instance of StopEvent.
|
|
10
|
-
* @param
|
|
10
|
+
* @param stoppedAtFrame - The position in the audio stream where the stop occurred.
|
|
11
11
|
*/
|
|
12
|
-
constructor(
|
|
12
|
+
constructor(stoppedAtFrame: bigint);
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Represents a custom event indicating that an underrun occurred in the audio processing.
|
|
@@ -17,13 +17,13 @@ export declare class StopEvent extends Event {
|
|
|
17
17
|
* or just before the node stops.
|
|
18
18
|
*/
|
|
19
19
|
export declare class UnderrunEvent extends Event {
|
|
20
|
-
readonly
|
|
20
|
+
readonly frameCount: number;
|
|
21
21
|
static readonly type = "@ain1084/audio-worklet-stream/underrun";
|
|
22
22
|
/**
|
|
23
23
|
* Creates an instance of UnderrunEvent.
|
|
24
|
-
* @param
|
|
24
|
+
* @param frameCount - The number of frames that were not processed due to the underrun.
|
|
25
25
|
*/
|
|
26
|
-
constructor(
|
|
26
|
+
constructor(frameCount: number);
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Extends the AudioWorkletNodeEventMap interface to include the custom events.
|
package/dist/events.js
CHANGED
|
@@ -4,15 +4,15 @@ import { STOP_EVENT_TYPE, UNDERRUN_EVENT_TYPE } from './constants';
|
|
|
4
4
|
* This event is dispatched when the audio processing stops.
|
|
5
5
|
*/
|
|
6
6
|
export class StopEvent extends Event {
|
|
7
|
-
|
|
7
|
+
stoppedAtFrame;
|
|
8
8
|
static type = STOP_EVENT_TYPE;
|
|
9
9
|
/**
|
|
10
10
|
* Creates an instance of StopEvent.
|
|
11
|
-
* @param
|
|
11
|
+
* @param stoppedAtFrame - The position in the audio stream where the stop occurred.
|
|
12
12
|
*/
|
|
13
|
-
constructor(
|
|
13
|
+
constructor(stoppedAtFrame) {
|
|
14
14
|
super(StopEvent.type);
|
|
15
|
-
this.
|
|
15
|
+
this.stoppedAtFrame = stoppedAtFrame;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
@@ -21,15 +21,15 @@ export class StopEvent extends Event {
|
|
|
21
21
|
* or just before the node stops.
|
|
22
22
|
*/
|
|
23
23
|
export class UnderrunEvent extends Event {
|
|
24
|
-
|
|
24
|
+
frameCount;
|
|
25
25
|
static type = UNDERRUN_EVENT_TYPE;
|
|
26
26
|
/**
|
|
27
27
|
* Creates an instance of UnderrunEvent.
|
|
28
|
-
* @param
|
|
28
|
+
* @param frameCount - The number of frames that were not processed due to the underrun.
|
|
29
29
|
*/
|
|
30
|
-
constructor(
|
|
30
|
+
constructor(frameCount) {
|
|
31
31
|
super(UnderrunEvent.type);
|
|
32
|
-
this.
|
|
32
|
+
this.frameCount = frameCount;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
//# sourceMappingURL=events.js.map
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAElE;;;GAGG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAMN;IALrB,MAAM,CAAU,IAAI,GAAG,eAAe,CAAA;IAC7C;;;OAGG;IACH,YAA4B,
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAElE;;;GAGG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAMN;IALrB,MAAM,CAAU,IAAI,GAAG,eAAe,CAAA;IAC7C;;;OAGG;IACH,YAA4B,cAAsB;QAChD,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QADK,mBAAc,GAAd,cAAc,CAAQ;IAElD,CAAC;;AAGH;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAMV;IALrB,MAAM,CAAU,IAAI,GAAG,mBAAmB,CAAA;IACjD;;;OAGG;IACH,YAA4B,UAAkB;QAC5C,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;QADC,eAAU,GAAV,UAAU,CAAQ;IAE9C,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { FrameBufferWriter } from './buffer-writer';
|
|
2
|
+
/**
|
|
3
|
+
* Parameters for creating a FrameBuffer.
|
|
4
|
+
* @property frameBufferSize - The size of the frame buffer.
|
|
5
|
+
* @property channelCount - The number of audio channels.
|
|
6
|
+
*/
|
|
7
|
+
export type FrameBufferParams = Readonly<{
|
|
8
|
+
frameBufferSize: number;
|
|
9
|
+
channelCount: number;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Parameters for creating a FillerFrameBuffer.
|
|
13
|
+
* @property channelCount - The number of audio channels.
|
|
14
|
+
* @property fillInterval - The interval in milliseconds for filling the buffer.
|
|
15
|
+
* @property sampleRate - The sample rate of the audio context.
|
|
16
|
+
* @property frameBufferChunks - The number of chunks in the frame buffer.
|
|
17
|
+
*/
|
|
18
|
+
export type FillerFrameBufferParams = Readonly<{
|
|
19
|
+
channelCount: number;
|
|
20
|
+
fillInterval?: number;
|
|
21
|
+
sampleRate?: number;
|
|
22
|
+
frameBufferChunks?: number;
|
|
23
|
+
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for a FrameBuffer.
|
|
26
|
+
* This configuration is returned by the createFrameBufferConfig function.
|
|
27
|
+
* @property sampleBuffer - The shared buffer for audio data frames.
|
|
28
|
+
* @property samplesPerFrame - The number of samples per frame.
|
|
29
|
+
* @property usedFramesInBuffer - The usage count of the frames in the buffer.
|
|
30
|
+
* @property totalReadFrames - The total frames read from the buffer.
|
|
31
|
+
* @property totalWriteFrames - The total frames written to the buffer.
|
|
32
|
+
*/
|
|
33
|
+
export type FrameBufferConfig = Readonly<{
|
|
34
|
+
sampleBuffer: Float32Array;
|
|
35
|
+
samplesPerFrame: number;
|
|
36
|
+
usedFramesInBuffer: Uint32Array;
|
|
37
|
+
totalReadFrames: BigUint64Array;
|
|
38
|
+
totalWriteFrames: BigUint64Array;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Configuration for a FillerFrameBuffer.
|
|
42
|
+
* This configuration is returned by the createFillerFrameBufferConfig function.
|
|
43
|
+
* @property sampleRate - The sample rate of the audio context.
|
|
44
|
+
* @property fillInterval - The interval in milliseconds for filling the buffer.
|
|
45
|
+
*/
|
|
46
|
+
export type FillerFrameBufferConfig = FrameBufferConfig & Readonly<{
|
|
47
|
+
sampleRate: number;
|
|
48
|
+
fillInterval: number;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a FrameBufferWriter instance.
|
|
52
|
+
* @param config - The configuration for the FrameBuffer.
|
|
53
|
+
* @returns A new instance of FrameBufferWriter.
|
|
54
|
+
*/
|
|
55
|
+
export declare const createFrameBufferWriter: (config: FrameBufferConfig) => FrameBufferWriter;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a FrameBufferConfig instance.
|
|
58
|
+
* @param params - The parameters for the FrameBuffer.
|
|
59
|
+
* @returns A new instance of FrameBufferConfig.
|
|
60
|
+
*/
|
|
61
|
+
export declare const createFrameBufferConfig: (params: FrameBufferParams) => FrameBufferConfig;
|
|
62
|
+
/**
|
|
63
|
+
* Creates a FillerFrameBufferConfig instance.
|
|
64
|
+
* @param params - The parameters for the FillerFrameBuffer.
|
|
65
|
+
* @returns A new instance of FillerFrameBufferConfig.
|
|
66
|
+
*/
|
|
67
|
+
export declare const createFillerFrameBufferConfig: (params: FillerFrameBufferParams) => FillerFrameBufferConfig;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { FrameBuffer } from './buffer';
|
|
2
|
+
import { FrameBufferWriter } from './buffer-writer';
|
|
3
|
+
/**
|
|
4
|
+
* The default number of chunks in the frame buffer when
|
|
5
|
+
* FillerFrameBufferParams.frameBufferChunks is not provided.
|
|
6
|
+
* A frame buffer sufficient to hold fillInterval * frameBufferChunks of playback time is allocated.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_FILL_INTERVAL_MS = 20;
|
|
9
|
+
/**
|
|
10
|
+
* The default number of chunks in the frame buffer when
|
|
11
|
+
* FillerFrameBufferParams.frameBufferChunks is not provided.
|
|
12
|
+
* The total frame buffer size will be fillInterval * frameBufferChunks.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_FRAME_BUFFER_CHUNKS = 5;
|
|
15
|
+
/**
|
|
16
|
+
* The unit for rounding up the frame buffer size.
|
|
17
|
+
* This value is aligned with the audio data block size used by the AudioWorkletProcessor.
|
|
18
|
+
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletProcessor/process
|
|
19
|
+
*/
|
|
20
|
+
const AUDIO_WORKLET_BLOCK_SIZE = 128;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a FrameBufferWriter instance.
|
|
23
|
+
* @param config - The configuration for the FrameBuffer.
|
|
24
|
+
* @returns A new instance of FrameBufferWriter.
|
|
25
|
+
*/
|
|
26
|
+
export const createFrameBufferWriter = (config) => {
|
|
27
|
+
return new FrameBufferWriter(new FrameBuffer(config.sampleBuffer, config.samplesPerFrame), config.usedFramesInBuffer, config.totalWriteFrames);
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Creates a FrameBufferConfig instance.
|
|
31
|
+
* @param params - The parameters for the FrameBuffer.
|
|
32
|
+
* @returns A new instance of FrameBufferConfig.
|
|
33
|
+
*/
|
|
34
|
+
export const createFrameBufferConfig = (params) => {
|
|
35
|
+
return {
|
|
36
|
+
sampleBuffer: new Float32Array(new SharedArrayBuffer(params.frameBufferSize * params.channelCount * Float32Array.BYTES_PER_ELEMENT)),
|
|
37
|
+
samplesPerFrame: params.channelCount,
|
|
38
|
+
usedFramesInBuffer: new Uint32Array(new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT)),
|
|
39
|
+
totalReadFrames: new BigUint64Array(new SharedArrayBuffer(BigUint64Array.BYTES_PER_ELEMENT)),
|
|
40
|
+
totalWriteFrames: new BigUint64Array(new SharedArrayBuffer(BigUint64Array.BYTES_PER_ELEMENT)),
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Creates a FillerFrameBufferConfig instance.
|
|
45
|
+
* @param params - The parameters for the FillerFrameBuffer.
|
|
46
|
+
* @returns A new instance of FillerFrameBufferConfig.
|
|
47
|
+
*/
|
|
48
|
+
export const createFillerFrameBufferConfig = (params) => {
|
|
49
|
+
const sampleRate = params.sampleRate;
|
|
50
|
+
// Check if 'sampleRate' is a positive integer
|
|
51
|
+
if (sampleRate === undefined || (!Number.isInteger(sampleRate) || sampleRate <= 0)) {
|
|
52
|
+
throw new Error('Invalid sampleRate: must be a positive integer.');
|
|
53
|
+
}
|
|
54
|
+
const intervalMillisecond = params.fillInterval ?? DEFAULT_FILL_INTERVAL_MS;
|
|
55
|
+
const frameBufferSize = Math.floor(sampleRate * intervalMillisecond / 1000 + (AUDIO_WORKLET_BLOCK_SIZE - 1)) & ~(AUDIO_WORKLET_BLOCK_SIZE - 1);
|
|
56
|
+
const frameBufferChunkCount = params.frameBufferChunks ?? DEFAULT_FRAME_BUFFER_CHUNKS;
|
|
57
|
+
const config = createFrameBufferConfig({ frameBufferSize: frameBufferSize * frameBufferChunkCount, channelCount: params.channelCount });
|
|
58
|
+
return {
|
|
59
|
+
...config,
|
|
60
|
+
sampleRate,
|
|
61
|
+
fillInterval: intervalMillisecond,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=buffer-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer-config.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEnD;;;;GAIG;AACH,MAAM,wBAAwB,GAAG,EAAE,CAAA;AAEnC;;;;GAIG;AACH,MAAM,2BAA2B,GAAG,CAAC,CAAA;AAErC;;;;GAIG;AACH,MAAM,wBAAwB,GAAG,GAAG,CAAA;AAsDpC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAyB,EAAqB,EAAE;IACtF,OAAO,IAAI,iBAAiB,CAC1B,IAAI,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC,EAC5D,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,CACnD,CAAA;AACH,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAyB,EAAqB,EAAE;IACtF,OAAO;QACL,YAAY,EAAE,IAAI,YAAY,CAC5B,IAAI,iBAAiB,CAAC,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC,iBAAiB,CAAC,CACrG;QACD,eAAe,EAAE,MAAM,CAAC,YAAY;QACpC,kBAAkB,EAAE,IAAI,WAAW,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;QACzF,eAAe,EAAE,IAAI,cAAc,CAAC,IAAI,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;QAC5F,gBAAgB,EAAE,IAAI,cAAc,CAAC,IAAI,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;KAC9F,CAAA;AACH,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,MAA+B,EAA2B,EAAE;IACxG,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;IACpC,8CAA8C;IAC9C,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IACpE,CAAC;IACD,MAAM,mBAAmB,GAAG,MAAM,CAAC,YAAY,IAAI,wBAAwB,CAAA;IAC3E,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAChC,UAAU,GAAG,mBAAmB,GAAG,IAAI,GAAG,CAAC,wBAAwB,GAAG,CAAC,CAAC,CACzE,GAAG,CAAC,CAAC,wBAAwB,GAAG,CAAC,CAAC,CAAA;IACnC,MAAM,qBAAqB,GAAG,MAAM,CAAC,iBAAiB,IAAI,2BAA2B,CAAA;IACrF,MAAM,MAAM,GAAG,uBAAuB,CACpC,EAAE,eAAe,EAAE,eAAe,GAAG,qBAAqB,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;IAClG,OAAO;QACL,GAAG,MAAM;QACT,UAAU;QACV,YAAY,EAAE,mBAAmB;KAClC,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -69,9 +69,8 @@ export declare class FrameBufferFactory {
|
|
|
69
69
|
static createFrameBufferConfig(params: FrameBufferParams): FrameBufferConfig;
|
|
70
70
|
/**
|
|
71
71
|
* Creates a FillerFrameBufferConfig instance.
|
|
72
|
-
* @param defaultSampleRate - The sample rate of the audio context.
|
|
73
72
|
* @param params - The parameters for the FillerFrameBuffer.
|
|
74
73
|
* @returns A new instance of FillerFrameBufferConfig.
|
|
75
74
|
*/
|
|
76
|
-
static createFillerFrameBufferConfig(
|
|
75
|
+
static createFillerFrameBufferConfig(params: FillerFrameBufferParams): FillerFrameBufferConfig;
|
|
77
76
|
}
|
|
@@ -32,12 +32,15 @@ export class FrameBufferFactory {
|
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Creates a FillerFrameBufferConfig instance.
|
|
35
|
-
* @param defaultSampleRate - The sample rate of the audio context.
|
|
36
35
|
* @param params - The parameters for the FillerFrameBuffer.
|
|
37
36
|
* @returns A new instance of FillerFrameBufferConfig.
|
|
38
37
|
*/
|
|
39
|
-
static createFillerFrameBufferConfig(
|
|
40
|
-
const sampleRate = params.sampleRate
|
|
38
|
+
static createFillerFrameBufferConfig(params) {
|
|
39
|
+
const sampleRate = params.sampleRate;
|
|
40
|
+
// Check if 'sampleRate' is a positive integer
|
|
41
|
+
if (sampleRate === undefined || (!Number.isInteger(sampleRate) || sampleRate <= 0)) {
|
|
42
|
+
throw new Error('Invalid sampleRate: must be a positive integer.');
|
|
43
|
+
}
|
|
41
44
|
const intervalMillisecond = params.fillInterval ?? FrameBufferFactory.DEFAULT_FILL_INTERVAL_MS;
|
|
42
45
|
const frameBufferSize = Math.floor(sampleRate * intervalMillisecond / 1000 + (FrameBufferFactory.PROCESS_UNIT - 1)) & ~(FrameBufferFactory.PROCESS_UNIT - 1);
|
|
43
46
|
const frameBufferChunkCount = params.frameBufferChunks ?? FrameBufferFactory.DEFAULT_FRAME_BUFFER_CHUNKS;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buffer-factory.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAsDnD;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAyB,EAAqB,EAAE;IACtF,OAAO,IAAI,iBAAiB,CAC1B,IAAI,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC,EAC5D,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,CACnD,CAAA;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACtB,MAAM,CAAU,wBAAwB,GAAG,EAAE,CAAA;IAC7C,MAAM,CAAU,2BAA2B,GAAG,CAAC,CAAA;IAC/C,MAAM,CAAU,YAAY,GAAG,GAAG,CAAA;IAEzC;;;;OAIG;IACI,MAAM,CAAC,uBAAuB,CAAC,MAAyB;QAC7D,OAAO;YACL,YAAY,EAAE,IAAI,YAAY,CAC5B,IAAI,iBAAiB,CAAC,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC,iBAAiB,CAAC,CACrG;YACD,eAAe,EAAE,MAAM,CAAC,YAAY;YACpC,kBAAkB,EAAE,IAAI,WAAW,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;YACzF,eAAe,EAAE,IAAI,cAAc,CAAC,IAAI,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;YAC5F,gBAAgB,EAAE,IAAI,cAAc,CAAC,IAAI,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;SAC9F,CAAA;IACH,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"buffer-factory.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAsDnD;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAyB,EAAqB,EAAE;IACtF,OAAO,IAAI,iBAAiB,CAC1B,IAAI,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC,EAC5D,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,CACnD,CAAA;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACtB,MAAM,CAAU,wBAAwB,GAAG,EAAE,CAAA;IAC7C,MAAM,CAAU,2BAA2B,GAAG,CAAC,CAAA;IAC/C,MAAM,CAAU,YAAY,GAAG,GAAG,CAAA;IAEzC;;;;OAIG;IACI,MAAM,CAAC,uBAAuB,CAAC,MAAyB;QAC7D,OAAO;YACL,YAAY,EAAE,IAAI,YAAY,CAC5B,IAAI,iBAAiB,CAAC,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,YAAY,GAAG,YAAY,CAAC,iBAAiB,CAAC,CACrG;YACD,eAAe,EAAE,MAAM,CAAC,YAAY;YACpC,kBAAkB,EAAE,IAAI,WAAW,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;YACzF,eAAe,EAAE,IAAI,cAAc,CAAC,IAAI,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;YAC5F,gBAAgB,EAAE,IAAI,cAAc,CAAC,IAAI,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;SAC9F,CAAA;IACH,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,6BAA6B,CAAC,MAA+B;QACzE,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;QACpC,8CAA8C;QAC9C,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC;YACnF,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;QACD,MAAM,mBAAmB,GAAG,MAAM,CAAC,YAAY,IAAI,kBAAkB,CAAC,wBAAwB,CAAA;QAC9F,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAChC,UAAU,GAAG,mBAAmB,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,YAAY,GAAG,CAAC,CAAC,CAChF,GAAG,CAAC,CAAC,kBAAkB,CAAC,YAAY,GAAG,CAAC,CAAC,CAAA;QAC1C,MAAM,qBAAqB,GAAG,MAAM,CAAC,iBAAiB,IAAI,kBAAkB,CAAC,2BAA2B,CAAA;QACxG,MAAM,MAAM,GAAG,kBAAkB,CAAC,uBAAuB,CACvD,EAAE,eAAe,EAAE,eAAe,GAAG,qBAAqB,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAA;QAClG,OAAO;YACL,GAAG,MAAM;YACT,UAAU;YACV,YAAY,EAAE,mBAAmB;SAClC,CAAA;IACH,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type FrameCallback } from './buffer-utils';
|
|
2
1
|
import { FrameBuffer } from './buffer';
|
|
3
2
|
/**
|
|
4
3
|
* FrameBufferReader class
|
|
@@ -7,31 +6,52 @@ import { FrameBuffer } from './buffer';
|
|
|
7
6
|
*/
|
|
8
7
|
export declare class FrameBufferReader {
|
|
9
8
|
private readonly _frameBuffer;
|
|
10
|
-
private readonly
|
|
9
|
+
private readonly _usedFramesInBuffer;
|
|
11
10
|
private readonly _totalFrames;
|
|
12
11
|
private _index;
|
|
13
12
|
/**
|
|
14
13
|
* Creates an instance of FrameBufferReader.
|
|
15
14
|
* @param frameBuffer - The shared buffer to read from.
|
|
16
|
-
* @param
|
|
15
|
+
* @param usedFramesInBuffer - The Uint32Array tracking the usage of the buffer.
|
|
17
16
|
* @param totalFrames - The BigUint64Array tracking the total frames read from the buffer.
|
|
18
17
|
*/
|
|
19
|
-
constructor(frameBuffer: FrameBuffer,
|
|
18
|
+
constructor(frameBuffer: FrameBuffer, usedFramesInBuffer: Uint32Array, totalFrames: BigUint64Array);
|
|
20
19
|
/**
|
|
21
20
|
* Get the number of available frames in the buffer.
|
|
22
21
|
* @returns The number of available frames in the buffer.
|
|
23
22
|
*/
|
|
24
|
-
get
|
|
23
|
+
get availableFrames(): number;
|
|
25
24
|
/**
|
|
26
25
|
* Get the total number of frames read from the buffer.
|
|
26
|
+
*
|
|
27
27
|
* @returns The total number of frames read.
|
|
28
28
|
*/
|
|
29
29
|
get totalFrames(): bigint;
|
|
30
30
|
/**
|
|
31
|
-
* Reads audio frame data from the buffer
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* Reads audio frame data from the buffer using the provided callback.
|
|
32
|
+
* This method handles one or more readable segments within the ring buffer
|
|
33
|
+
* and invokes the callback for each segment.
|
|
34
|
+
*
|
|
35
|
+
* @param processFrameSegment - The callback function invoked for each readable segment
|
|
36
|
+
* of the ring buffer. It receives:
|
|
37
|
+
* 1. `buffer`: A Float32Array representing the readable segment of the buffer.
|
|
38
|
+
* 2. `offset`: The cumulative number of frames processed so far, used as the starting index
|
|
39
|
+
* for the current segment relative to the entire data.
|
|
40
|
+
*
|
|
41
|
+
* The callback must return the number of frames it successfully processed.
|
|
42
|
+
* If the callback processes fewer frames than available in the current segment,
|
|
43
|
+
* processing will stop early.
|
|
44
|
+
*
|
|
45
|
+
* @returns The total number of frames processed across all segments.
|
|
46
|
+
* Note: The return value is in frames, not in samples.
|
|
47
|
+
*
|
|
48
|
+
* @throws RangeError - If the processFrameSegment callback returns a processed length greater than the available frames in the current segment.
|
|
49
|
+
*
|
|
50
|
+
* @remarks The buffer is an array of samples, but it is always provided in frame-sized segments.
|
|
51
|
+
* Each frame consists of multiple samples (e.g., for stereo, a frame contains a sample for the left channel
|
|
52
|
+
* and one for the right channel). You must access and process the buffer in frame-sized chunks,
|
|
53
|
+
* based on the structure of the frames.
|
|
54
|
+
*
|
|
35
55
|
*/
|
|
36
|
-
read(
|
|
56
|
+
read(processFrameSegment: (buffer: Float32Array, offset: number) => number): number;
|
|
37
57
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { enumFrames } from './buffer-utils';
|
|
2
1
|
/**
|
|
3
2
|
* FrameBufferReader class
|
|
4
3
|
* This class reads audio frame data from a shared Float32Array buffer and processes it.
|
|
@@ -6,46 +5,69 @@ import { enumFrames } from './buffer-utils';
|
|
|
6
5
|
*/
|
|
7
6
|
export class FrameBufferReader {
|
|
8
7
|
_frameBuffer;
|
|
9
|
-
|
|
8
|
+
_usedFramesInBuffer;
|
|
10
9
|
_totalFrames;
|
|
11
10
|
_index = 0;
|
|
12
11
|
/**
|
|
13
12
|
* Creates an instance of FrameBufferReader.
|
|
14
13
|
* @param frameBuffer - The shared buffer to read from.
|
|
15
|
-
* @param
|
|
14
|
+
* @param usedFramesInBuffer - The Uint32Array tracking the usage of the buffer.
|
|
16
15
|
* @param totalFrames - The BigUint64Array tracking the total frames read from the buffer.
|
|
17
16
|
*/
|
|
18
|
-
constructor(frameBuffer,
|
|
17
|
+
constructor(frameBuffer, usedFramesInBuffer, totalFrames) {
|
|
19
18
|
this._frameBuffer = frameBuffer;
|
|
20
|
-
this.
|
|
19
|
+
this._usedFramesInBuffer = usedFramesInBuffer;
|
|
21
20
|
this._totalFrames = totalFrames;
|
|
22
21
|
}
|
|
23
22
|
/**
|
|
24
23
|
* Get the number of available frames in the buffer.
|
|
25
24
|
* @returns The number of available frames in the buffer.
|
|
26
25
|
*/
|
|
27
|
-
get
|
|
28
|
-
return Atomics.load(this.
|
|
26
|
+
get availableFrames() {
|
|
27
|
+
return Atomics.load(this._usedFramesInBuffer, 0);
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* Get the total number of frames read from the buffer.
|
|
31
|
+
*
|
|
32
32
|
* @returns The total number of frames read.
|
|
33
33
|
*/
|
|
34
34
|
get totalFrames() {
|
|
35
|
+
// This class is not used concurrently by multiple threads,
|
|
36
|
+
// so `Atomics` is not necessary when reading `totalFrames`.
|
|
35
37
|
return this._totalFrames[0];
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
|
-
* Reads audio frame data from the buffer
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
40
|
+
* Reads audio frame data from the buffer using the provided callback.
|
|
41
|
+
* This method handles one or more readable segments within the ring buffer
|
|
42
|
+
* and invokes the callback for each segment.
|
|
43
|
+
*
|
|
44
|
+
* @param processFrameSegment - The callback function invoked for each readable segment
|
|
45
|
+
* of the ring buffer. It receives:
|
|
46
|
+
* 1. `buffer`: A Float32Array representing the readable segment of the buffer.
|
|
47
|
+
* 2. `offset`: The cumulative number of frames processed so far, used as the starting index
|
|
48
|
+
* for the current segment relative to the entire data.
|
|
49
|
+
*
|
|
50
|
+
* The callback must return the number of frames it successfully processed.
|
|
51
|
+
* If the callback processes fewer frames than available in the current segment,
|
|
52
|
+
* processing will stop early.
|
|
53
|
+
*
|
|
54
|
+
* @returns The total number of frames processed across all segments.
|
|
55
|
+
* Note: The return value is in frames, not in samples.
|
|
56
|
+
*
|
|
57
|
+
* @throws RangeError - If the processFrameSegment callback returns a processed length greater than the available frames in the current segment.
|
|
58
|
+
*
|
|
59
|
+
* @remarks The buffer is an array of samples, but it is always provided in frame-sized segments.
|
|
60
|
+
* Each frame consists of multiple samples (e.g., for stereo, a frame contains a sample for the left channel
|
|
61
|
+
* and one for the right channel). You must access and process the buffer in frame-sized chunks,
|
|
62
|
+
* based on the structure of the frames.
|
|
63
|
+
*
|
|
42
64
|
*/
|
|
43
|
-
read(
|
|
44
|
-
const result =
|
|
65
|
+
read(processFrameSegment) {
|
|
66
|
+
const result = this._frameBuffer.enumFrameSegments(this._index, this.availableFrames, processFrameSegment);
|
|
45
67
|
this._index = result.nextIndex;
|
|
46
|
-
Atomics.sub(this.
|
|
47
|
-
Atomics.add(this._totalFrames, 0, BigInt(result.
|
|
48
|
-
return result.
|
|
68
|
+
Atomics.sub(this._usedFramesInBuffer, 0, result.totalProcessedFrames);
|
|
69
|
+
Atomics.add(this._totalFrames, 0, BigInt(result.totalProcessedFrames));
|
|
70
|
+
return result.totalProcessedFrames;
|
|
49
71
|
}
|
|
50
72
|
}
|
|
51
73
|
//# sourceMappingURL=buffer-reader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buffer-reader.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-reader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"buffer-reader.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-reader.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACX,YAAY,CAAa;IACzB,mBAAmB,CAAa;IAChC,YAAY,CAAgB;IACrC,MAAM,GAAW,CAAC,CAAA;IAE1B;;;;;OAKG;IACH,YAAY,WAAwB,EAAE,kBAA+B,EAAE,WAA2B;QAChG,IAAI,CAAC,YAAY,GAAG,WAAW,CAAA;QAC/B,IAAI,CAAC,mBAAmB,GAAG,kBAAkB,CAAA;QAC7C,IAAI,CAAC,YAAY,GAAG,WAAW,CAAA;IACjC,CAAC;IAED;;;OAGG;IACH,IAAW,eAAe;QACxB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAA;IAClD,CAAC;IAED;;;;OAIG;IACH,IAAW,WAAW;QACpB,2DAA2D;QAC3D,4DAA4D;QAC5D,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IAC7B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACI,IAAI,CAAC,mBAAqE;QAC/E,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAA;QAC1G,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,CAAA;QAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAA;QACrE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAA;QACtE,OAAO,MAAM,CAAC,oBAAoB,CAAA;IACpC,CAAC;CACF"}
|
|
@@ -16,7 +16,7 @@ export const enumFrames = (buffer, startIndex, availableFrames, frameCallback) =
|
|
|
16
16
|
let totalFrames = 0;
|
|
17
17
|
while (totalFrames < availableFrames) {
|
|
18
18
|
// Determine the length of the current section to process
|
|
19
|
-
const sectionFrames = Math.min(buffer.
|
|
19
|
+
const sectionFrames = Math.min(buffer.frameCount - startIndex, availableFrames - totalFrames);
|
|
20
20
|
// Process the current section using the frameCallback function
|
|
21
21
|
const processedFrames = frameCallback({ buffer, index: startIndex, frames: sectionFrames }, totalFrames);
|
|
22
22
|
// Ensure the processed length does not exceed the section length
|
|
@@ -24,7 +24,7 @@ export const enumFrames = (buffer, startIndex, availableFrames, frameCallback) =
|
|
|
24
24
|
throw new RangeError(`Processed frames (${processedFrames}) exceeds section frames (${sectionFrames})`);
|
|
25
25
|
}
|
|
26
26
|
totalFrames += processedFrames;
|
|
27
|
-
startIndex = (startIndex + processedFrames) % buffer.
|
|
27
|
+
startIndex = (startIndex + processedFrames) % buffer.frameCount;
|
|
28
28
|
if (processedFrames < sectionFrames) {
|
|
29
29
|
break;
|
|
30
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buffer-utils.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-utils.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAmB,EAAE,UAAkB,EAAE,eAAuB,EAAE,aAA4B,EACnF,EAAE;IACtC,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,OAAO,WAAW,GAAG,eAAe,EAAE,CAAC;QACrC,yDAAyD;QACzD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"buffer-utils.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-utils.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAmB,EAAE,UAAkB,EAAE,eAAuB,EAAE,aAA4B,EACnF,EAAE;IACtC,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,OAAO,WAAW,GAAG,eAAe,EAAE,CAAC;QACrC,yDAAyD;QACzD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,UAAU,EAAE,eAAe,GAAG,WAAW,CAAC,CAAA;QAC7F,+DAA+D;QAC/D,MAAM,eAAe,GAAG,aAAa,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,WAAW,CAAC,CAAA;QACxG,iEAAiE;QACjE,IAAI,eAAe,GAAG,aAAa,EAAE,CAAC;YACpC,MAAM,IAAI,UAAU,CAAC,qBAAqB,eAAe,6BAA6B,aAAa,GAAG,CAAC,CAAA;QACzG,CAAC;QACD,WAAW,IAAI,eAAe,CAAA;QAC9B,UAAU,GAAG,CAAC,UAAU,GAAG,eAAe,CAAC,GAAG,MAAM,CAAC,UAAU,CAAA;QAC/D,IAAI,eAAe,GAAG,aAAa,EAAE,CAAC;YACpC,MAAK;QACP,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;AACvD,CAAC,CAAA"}
|