@ain1084/audio-worklet-stream 1.0.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/filler-frame-buffer-context.d.ts +30 -0
- package/dist/{frame-buffer/buffer-config.js → filler-frame-buffer-context.js} +5 -21
- package/dist/filler-frame-buffer-context.js.map +1 -0
- package/dist/{frame-buffer/buffer-filler.d.ts → frame-buffer-filler.d.ts} +2 -2
- package/dist/frame-buffer-filler.js +2 -0
- package/dist/frame-buffer-filler.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/output-stream-node.d.ts +4 -4
- package/dist/output-stream-node.js +9 -9
- package/dist/output-stream-node.js.map +1 -1
- package/dist/output-stream-processor.js +4 -4
- package/dist/output-stream-processor.js.map +1 -1
- package/dist/stream-node-factory.d.ts +4 -4
- package/dist/stream-node-factory.js +9 -8
- package/dist/stream-node-factory.js.map +1 -1
- package/dist/write-strategy/manual-strategy.d.ts +3 -4
- package/dist/write-strategy/manual-strategy.js +4 -4
- package/dist/write-strategy/manual-strategy.js.map +1 -1
- package/dist/write-strategy/timed-strategy.d.ts +4 -4
- package/dist/write-strategy/timed-strategy.js +5 -5
- package/dist/write-strategy/timed-strategy.js.map +1 -1
- package/dist/write-strategy/worker/message.d.ts +3 -3
- package/dist/write-strategy/worker/worker.d.ts +2 -2
- package/dist/write-strategy/worker/worker.js +8 -8
- package/dist/write-strategy/worker/worker.js.map +1 -1
- package/dist/write-strategy/worker-strategy.d.ts +3 -3
- package/dist/write-strategy/worker-strategy.js +6 -6
- package/dist/write-strategy/worker-strategy.js.map +1 -1
- package/package.json +11 -12
- package/src/{frame-buffer/buffer-config.ts → filler-frame-buffer-context.ts} +6 -50
- package/src/{frame-buffer/buffer-filler.ts → frame-buffer-filler.ts} +2 -2
- package/src/index.ts +2 -2
- package/src/output-stream-node.ts +10 -10
- package/src/output-stream-processor.ts +5 -6
- package/src/stream-node-factory.ts +12 -12
- package/src/write-strategy/manual-strategy.ts +4 -5
- package/src/write-strategy/timed-strategy.ts +7 -7
- package/src/write-strategy/worker/message.ts +3 -3
- package/src/write-strategy/worker/worker.ts +10 -10
- package/src/write-strategy/worker-strategy.ts +9 -9
- package/dist/frame-buffer/buffer-config.d.ts +0 -60
- package/dist/frame-buffer/buffer-config.js.map +0 -1
- package/dist/frame-buffer/buffer-factory.d.ts +0 -76
- package/dist/frame-buffer/buffer-factory.js +0 -55
- package/dist/frame-buffer/buffer-factory.js.map +0 -1
- package/dist/frame-buffer/buffer-filler.js +0 -2
- package/dist/frame-buffer/buffer-filler.js.map +0 -1
- package/dist/frame-buffer/buffer-reader.d.ts +0 -60
- package/dist/frame-buffer/buffer-reader.js +0 -77
- package/dist/frame-buffer/buffer-reader.js.map +0 -1
- package/dist/frame-buffer/buffer-utils.d.ts +0 -34
- package/dist/frame-buffer/buffer-utils.js +0 -34
- package/dist/frame-buffer/buffer-utils.js.map +0 -1
- package/dist/frame-buffer/buffer-writer.d.ts +0 -60
- package/dist/frame-buffer/buffer-writer.js +0 -77
- package/dist/frame-buffer/buffer-writer.js.map +0 -1
- package/dist/frame-buffer/buffer.d.ts +0 -51
- package/dist/frame-buffer/buffer.js +0 -75
- package/dist/frame-buffer/buffer.js.map +0 -1
- package/dist/write-strategy/manual.d.ts +0 -36
- package/dist/write-strategy/manual.js +0 -43
- package/dist/write-strategy/manual.js.map +0 -1
- package/dist/write-strategy/timed.d.ts +0 -36
- package/dist/write-strategy/timed.js +0 -92
- package/dist/write-strategy/timed.js.map +0 -1
- package/dist/write-strategy/worker/strategy.d.ts +0 -34
- package/dist/write-strategy/worker/strategy.js +0 -125
- package/dist/write-strategy/worker/strategy.js.map +0 -1
- package/dist/write-strategy/worker/worker-strategy.d.ts +0 -34
- package/dist/write-strategy/worker/worker-strategy.js +0 -125
- package/dist/write-strategy/worker/worker-strategy.js.map +0 -1
- package/src/frame-buffer/buffer-reader.ts +0 -82
- package/src/frame-buffer/buffer-writer.ts +0 -82
- package/src/frame-buffer/buffer.ts +0 -79
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-strategy.js","sourceRoot":"","sources":["../../src/write-strategy/worker-strategy.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,MAAM,OAAO;IACM,KAAK,CAAkB;IACvB,
|
|
1
|
+
{"version":3,"file":"worker-strategy.js","sourceRoot":"","sources":["../../src/write-strategy/worker-strategy.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ain1084/audio-worklet-stream",
|
|
3
|
-
"version": "
|
|
4
|
-
"main": "dist/index.js",
|
|
3
|
+
"version": "2.0.0",
|
|
5
4
|
"module": "dist/index.js",
|
|
6
5
|
"types": "dist/index.d.ts",
|
|
7
6
|
"files": [
|
|
@@ -31,7 +30,7 @@
|
|
|
31
30
|
"bugs": {
|
|
32
31
|
"url": "https://github.com/ain1084/audio-worklet-stream/issues"
|
|
33
32
|
},
|
|
34
|
-
"homepage": "https://github.
|
|
33
|
+
"homepage": "https://ain1084.github.io/audio-worklet-stream/",
|
|
35
34
|
"scripts": {
|
|
36
35
|
"build": "tsc",
|
|
37
36
|
"watch": "tsc --watch",
|
|
@@ -40,18 +39,18 @@
|
|
|
40
39
|
"docs": "typedoc"
|
|
41
40
|
},
|
|
42
41
|
"devDependencies": {
|
|
43
|
-
"@stylistic/eslint-plugin": "^2.
|
|
44
|
-
"@types/audioworklet": "^0.0.
|
|
45
|
-
"@types/node": "^22.
|
|
46
|
-
"@typescript-eslint/parser": "^8.
|
|
47
|
-
"eslint": "^9.
|
|
48
|
-
"globals": "^15.
|
|
49
|
-
"typedoc": "^0.26.
|
|
42
|
+
"@stylistic/eslint-plugin": "^2.10.1",
|
|
43
|
+
"@types/audioworklet": "^0.0.64",
|
|
44
|
+
"@types/node": "^22.9.0",
|
|
45
|
+
"@typescript-eslint/parser": "^8.13.0",
|
|
46
|
+
"eslint": "^9.14.0",
|
|
47
|
+
"globals": "^15.12.0",
|
|
48
|
+
"typedoc": "^0.26.11",
|
|
50
49
|
"typescript": "^5.6.3",
|
|
51
|
-
"typescript-eslint": "^8.
|
|
50
|
+
"typescript-eslint": "^8.13.0",
|
|
52
51
|
"vite": "^5.4.10"
|
|
53
52
|
},
|
|
54
53
|
"dependencies": {
|
|
55
|
-
"@ain1084/
|
|
54
|
+
"@ain1084/audio-frame-buffer": "^0.2.0"
|
|
56
55
|
}
|
|
57
56
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type FrameBufferContext, createFrameBufferContext } from '@ain1084/audio-frame-buffer'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The default number of chunks in the frame buffer when
|
|
@@ -21,16 +21,6 @@ const DEFAULT_FRAME_BUFFER_CHUNKS = 5
|
|
|
21
21
|
*/
|
|
22
22
|
const AUDIO_WORKLET_BLOCK_SIZE = 128
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Parameters for creating a FrameBuffer.
|
|
26
|
-
* @property frameBufferSize - The size of the frame buffer.
|
|
27
|
-
* @property channelCount - The number of audio channels.
|
|
28
|
-
*/
|
|
29
|
-
export type FrameBufferParams = Readonly<{
|
|
30
|
-
frameBufferSize: number
|
|
31
|
-
channelCount: number
|
|
32
|
-
}>
|
|
33
|
-
|
|
34
24
|
/**
|
|
35
25
|
* Parameters for creating a FillerFrameBuffer.
|
|
36
26
|
* @property channelCount - The number of audio channels.
|
|
@@ -45,69 +35,35 @@ export type FillerFrameBufferParams = Readonly<{
|
|
|
45
35
|
frameBufferChunks?: number
|
|
46
36
|
}>
|
|
47
37
|
|
|
48
|
-
/**
|
|
49
|
-
* Configuration for a FrameBuffer.
|
|
50
|
-
* This configuration is returned by the createFrameBufferConfig function.
|
|
51
|
-
* @property sampleBuffer - The shared buffer for audio data frames.
|
|
52
|
-
* @property samplesPerFrame - The number of samples per frame.
|
|
53
|
-
* @property usedFramesInBuffer - The usage count of the frames in the buffer.
|
|
54
|
-
* @property totalReadFrames - The total frames read from the buffer.
|
|
55
|
-
* @property totalWriteFrames - The total frames written to the buffer.
|
|
56
|
-
*/
|
|
57
|
-
export type FrameBufferConfig = Readonly<{
|
|
58
|
-
sampleBuffer: Float32Array
|
|
59
|
-
samplesPerFrame: number
|
|
60
|
-
usedFramesInBuffer: Uint32Array
|
|
61
|
-
totalReadFrames: BigUint64Array
|
|
62
|
-
totalWriteFrames: BigUint64Array
|
|
63
|
-
}>
|
|
64
|
-
|
|
65
38
|
/**
|
|
66
39
|
* Configuration for a FillerFrameBuffer.
|
|
67
40
|
* This configuration is returned by the createFillerFrameBufferConfig function.
|
|
68
41
|
* @property sampleRate - The sample rate of the audio context.
|
|
69
42
|
* @property fillInterval - The interval in milliseconds for filling the buffer.
|
|
70
43
|
*/
|
|
71
|
-
export type
|
|
44
|
+
export type FillerFrameBufferContext = FrameBufferContext & Readonly<{
|
|
72
45
|
sampleRate: number
|
|
73
46
|
fillInterval: number
|
|
74
47
|
}>
|
|
75
48
|
|
|
76
|
-
/**
|
|
77
|
-
* Creates a FrameBufferConfig instance.
|
|
78
|
-
* @param params - The parameters for the FrameBuffer.
|
|
79
|
-
* @returns A new instance of FrameBufferConfig.
|
|
80
|
-
*/
|
|
81
|
-
export const createFrameBufferConfig = (params: FrameBufferParams): FrameBufferConfig => {
|
|
82
|
-
return {
|
|
83
|
-
...createArrayBufferViews(SharedArrayBuffer, {
|
|
84
|
-
sampleBuffer: [Float32Array, params.frameBufferSize * params.channelCount],
|
|
85
|
-
usedFramesInBuffer: [Uint32Array, 1],
|
|
86
|
-
totalReadFrames: [BigUint64Array, 1],
|
|
87
|
-
totalWriteFrames: [BigUint64Array, 1],
|
|
88
|
-
}),
|
|
89
|
-
samplesPerFrame: params.channelCount,
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
49
|
/**
|
|
94
50
|
* Creates a FillerFrameBufferConfig instance.
|
|
95
51
|
* @param params - The parameters for the FillerFrameBuffer.
|
|
96
52
|
* @returns A new instance of FillerFrameBufferConfig.
|
|
97
53
|
*/
|
|
98
|
-
export const
|
|
54
|
+
export const createFillerFrameBufferContext = (params: FillerFrameBufferParams): FillerFrameBufferContext => {
|
|
99
55
|
const sampleRate = params.sampleRate
|
|
100
56
|
// Check if 'sampleRate' is a positive integer
|
|
101
57
|
if (sampleRate === undefined || (!Number.isInteger(sampleRate) || sampleRate <= 0)) {
|
|
102
58
|
throw new Error('Invalid sampleRate: must be a positive integer.')
|
|
103
59
|
}
|
|
104
60
|
const intervalMillisecond = params.fillInterval ?? DEFAULT_FILL_INTERVAL_MS
|
|
105
|
-
const
|
|
61
|
+
const frameCount = Math.floor(
|
|
106
62
|
sampleRate * intervalMillisecond / 1000 + (AUDIO_WORKLET_BLOCK_SIZE - 1),
|
|
107
63
|
) & ~(AUDIO_WORKLET_BLOCK_SIZE - 1)
|
|
108
64
|
const frameBufferChunkCount = params.frameBufferChunks ?? DEFAULT_FRAME_BUFFER_CHUNKS
|
|
109
|
-
const config =
|
|
110
|
-
{
|
|
65
|
+
const config = createFrameBufferContext(
|
|
66
|
+
{ frameCount: frameCount * frameBufferChunkCount, channelCount: params.channelCount })
|
|
111
67
|
return {
|
|
112
68
|
...config,
|
|
113
69
|
sampleRate,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FrameBufferWriter } from '
|
|
1
|
+
import type { FrameBufferWriter } from '@ain1084/audio-frame-buffer'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* FrameBufferFiller interface
|
|
@@ -7,7 +7,7 @@ import type { FrameBufferWriter } from './buffer-writer'
|
|
|
7
7
|
export interface FrameBufferFiller {
|
|
8
8
|
/**
|
|
9
9
|
* Fill the buffer with audio frames using the provided writer.
|
|
10
|
-
* @param writer - An instance of FrameBufferWriter used to write audio frames to the buffer.
|
|
10
|
+
* @param writer - An instance of {@link https://ain1084.github.io/audio-frame-buffer/classes/FrameBufferWriter.html | FrameBufferWriter} used to write audio frames to the buffer.
|
|
11
11
|
* @returns A boolean indicating whether to continue playback.
|
|
12
12
|
*/
|
|
13
13
|
fill(writer: FrameBufferWriter): boolean
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { StopEvent, UnderrunEvent } from './events'
|
|
2
2
|
export type { OutputStreamNode } from './output-stream-node'
|
|
3
|
-
export type { FrameBufferWriter } from '
|
|
4
|
-
export type { FrameBufferFiller } from './frame-buffer
|
|
3
|
+
export type { FrameBufferWriter } from '@ain1084/audio-frame-buffer'
|
|
4
|
+
export type { FrameBufferFiller } from './frame-buffer-filler'
|
|
5
5
|
export { StreamNodeFactory,
|
|
6
6
|
type ManualBufferNodeParams,
|
|
7
7
|
type TimedBufferNodeParams,
|
|
@@ -2,7 +2,7 @@ import type { MessageToProcessor, MessageToAudioNode } from './output-message'
|
|
|
2
2
|
import { PROCESSOR_NAME } from './constants'
|
|
3
3
|
import { StopEvent, UnderrunEvent } from './events'
|
|
4
4
|
import { BufferWriteStrategy } from './write-strategy/strategy'
|
|
5
|
-
import {
|
|
5
|
+
import { FrameBufferContext } from '@ain1084/audio-frame-buffer'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Stream state
|
|
@@ -32,21 +32,21 @@ export class OutputStreamNode extends AudioWorkletNode {
|
|
|
32
32
|
/**
|
|
33
33
|
* Creates an instance of OutputStreamNode.
|
|
34
34
|
* @param baseAudioContext - The audio context to use.
|
|
35
|
-
* @param
|
|
35
|
+
* @param bufferContext - The context for the audio frame buffer.
|
|
36
36
|
* @param strategy - The strategy for writing to the buffer.
|
|
37
37
|
*/
|
|
38
38
|
private constructor(
|
|
39
39
|
baseAudioContext: BaseAudioContext,
|
|
40
|
-
|
|
40
|
+
bufferContext: FrameBufferContext,
|
|
41
41
|
strategy: BufferWriteStrategy,
|
|
42
42
|
) {
|
|
43
43
|
super(baseAudioContext, PROCESSOR_NAME, {
|
|
44
|
-
outputChannelCount: [
|
|
45
|
-
processorOptions:
|
|
44
|
+
outputChannelCount: [bufferContext.samplesPerFrame],
|
|
45
|
+
processorOptions: bufferContext,
|
|
46
46
|
})
|
|
47
47
|
this._strategy = strategy
|
|
48
|
-
this._totalWriteFrames =
|
|
49
|
-
this._totalReadFrames =
|
|
48
|
+
this._totalWriteFrames = bufferContext.totalWriteFrames
|
|
49
|
+
this._totalReadFrames = bufferContext.totalReadFrames
|
|
50
50
|
this.port.onmessage = this.handleMessage.bind(this)
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -54,12 +54,12 @@ export class OutputStreamNode extends AudioWorkletNode {
|
|
|
54
54
|
* @internal
|
|
55
55
|
* Creates an instance of OutputStreamNode.
|
|
56
56
|
* @param audioContext - The audio context to use.
|
|
57
|
-
* @param
|
|
57
|
+
* @param context - The context for the audio frame buffer.
|
|
58
58
|
* @param strategy - The strategy for writing to the buffer.
|
|
59
59
|
* @returns A promise that resolves to an instance of OutputStreamNode.
|
|
60
60
|
*/
|
|
61
|
-
public static async create(audioContext: BaseAudioContext,
|
|
62
|
-
const node = new OutputStreamNode(audioContext,
|
|
61
|
+
public static async create(audioContext: BaseAudioContext, context: FrameBufferContext, strategy: BufferWriteStrategy): Promise<OutputStreamNode> {
|
|
62
|
+
const node = new OutputStreamNode(audioContext, context, strategy)
|
|
63
63
|
if (!(await strategy.onInit(node))) {
|
|
64
64
|
throw new Error('Failed to onInit.')
|
|
65
65
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { FrameBufferReader } from '
|
|
1
|
+
import { FrameBufferReader, type FrameBufferContext } from '@ain1084/audio-frame-buffer'
|
|
2
2
|
import { PROCESSOR_NAME } from './constants'
|
|
3
3
|
import type { MessageToAudioNode, MessageToProcessor } from './output-message'
|
|
4
|
-
import type { FrameBufferConfig } from './frame-buffer/buffer-config'
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* OutputStreamProcessor class
|
|
@@ -20,7 +19,7 @@ class OutputStreamProcessor extends AudioWorkletProcessor {
|
|
|
20
19
|
*/
|
|
21
20
|
constructor(options: AudioWorkletNodeOptions) {
|
|
22
21
|
super()
|
|
23
|
-
this._frameReader = new FrameBufferReader(options.processorOptions as
|
|
22
|
+
this._frameReader = new FrameBufferReader(options.processorOptions as FrameBufferContext)
|
|
24
23
|
this.port.onmessage = this.handleMessage.bind(this)
|
|
25
24
|
}
|
|
26
25
|
|
|
@@ -79,13 +78,13 @@ class OutputStreamProcessor extends AudioWorkletProcessor {
|
|
|
79
78
|
process(_inputs: Float32Array[][], outputs: Float32Array[][]): boolean {
|
|
80
79
|
const output = outputs[0]
|
|
81
80
|
const samplesPerFrame = output.length
|
|
82
|
-
const readFrames = this._frameReader.read((
|
|
83
|
-
const bufferFrameCount =
|
|
81
|
+
const readFrames = this._frameReader.read((segment, offset) => {
|
|
82
|
+
const bufferFrameCount = segment.frameCount
|
|
84
83
|
const frameCount = Math.min(bufferFrameCount, output[0].length - offset)
|
|
85
84
|
// Deinterleaves interleaved audio frame data and writes it to the output.
|
|
86
85
|
output.forEach((outputChannel, channelIndex) => {
|
|
87
86
|
for (let i = channelIndex, j = 0; j < frameCount; i += samplesPerFrame, ++j) {
|
|
88
|
-
outputChannel[offset + j] =
|
|
87
|
+
outputChannel[offset + j] = segment.samples[i]
|
|
89
88
|
}
|
|
90
89
|
})
|
|
91
90
|
return frameCount
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import processor from './output-stream-processor?worker&url'
|
|
2
2
|
import { ManualBufferWriteStrategy } from './write-strategy/manual-strategy'
|
|
3
|
-
import {
|
|
3
|
+
import { createFillerFrameBufferContext } from './filler-frame-buffer-context'
|
|
4
4
|
import type { OutputStreamNode } from './output-stream-node'
|
|
5
5
|
import { TimedBufferWriteStrategy } from './write-strategy/timed-strategy'
|
|
6
|
-
import type { FrameBufferFiller } from './frame-buffer
|
|
7
|
-
import { FrameBufferWriter } from '
|
|
6
|
+
import type { FrameBufferFiller } from './frame-buffer-filler'
|
|
7
|
+
import { FrameBufferWriter, createFrameBufferContext } from '@ain1084/audio-frame-buffer'
|
|
8
8
|
import { WorkerBufferWriteStrategy } from './write-strategy/worker-strategy'
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -14,8 +14,8 @@ import { WorkerBufferWriteStrategy } from './write-strategy/worker-strategy'
|
|
|
14
14
|
export type ManualBufferNodeParams = {
|
|
15
15
|
/** The number of audio channels. */
|
|
16
16
|
readonly channelCount: number
|
|
17
|
-
/** The
|
|
18
|
-
readonly
|
|
17
|
+
/** The count of the frame buffer in frames. */
|
|
18
|
+
readonly frameCount: number
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -97,12 +97,12 @@ export class StreamNodeFactory {
|
|
|
97
97
|
if (params.channelCount <= 0 || !Number.isInteger(params.channelCount)) {
|
|
98
98
|
throw new Error('Invalid channelCount: must be a positive integer.')
|
|
99
99
|
}
|
|
100
|
-
if (params.
|
|
101
|
-
throw new Error('Invalid
|
|
100
|
+
if (params.frameCount <= 0 || !Number.isInteger(params.frameCount)) {
|
|
101
|
+
throw new Error('Invalid frameCount: must be a positive integer.')
|
|
102
102
|
}
|
|
103
|
-
const
|
|
104
|
-
const strategy = new ManualBufferWriteStrategy(
|
|
105
|
-
return [await this._outputStreamNodeFactory.create(this.audioContext,
|
|
103
|
+
const context = createFrameBufferContext({ ...params })
|
|
104
|
+
const strategy = new ManualBufferWriteStrategy(context)
|
|
105
|
+
return [await this._outputStreamNodeFactory.create(this.audioContext, context, strategy), strategy.writer]
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
@@ -119,7 +119,7 @@ export class StreamNodeFactory {
|
|
|
119
119
|
}
|
|
120
120
|
StreamNodeFactory.validateTimedBufferNodeParams(params)
|
|
121
121
|
const paramsWithSampleRate = StreamNodeFactory.applySampleRateToParams(params, this._audioContext.sampleRate)
|
|
122
|
-
const config =
|
|
122
|
+
const config = createFillerFrameBufferContext(paramsWithSampleRate)
|
|
123
123
|
return this._outputStreamNodeFactory.create(this.audioContext, config,
|
|
124
124
|
new TimedBufferWriteStrategy(config, frameFiller))
|
|
125
125
|
}
|
|
@@ -135,7 +135,7 @@ export class StreamNodeFactory {
|
|
|
135
135
|
): Promise<OutputStreamNode> {
|
|
136
136
|
StreamNodeFactory.validateTimedBufferNodeParams(params)
|
|
137
137
|
const paramsWithSampleRate = StreamNodeFactory.applySampleRateToParams(params, this._audioContext.sampleRate)
|
|
138
|
-
const config =
|
|
138
|
+
const config = createFillerFrameBufferContext(paramsWithSampleRate)
|
|
139
139
|
return this._outputStreamNodeFactory.create(this._audioContext, config,
|
|
140
140
|
new WorkerBufferWriteStrategy<FillerParams>(config, worker, params.fillerParams))
|
|
141
141
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { BufferWriteStrategy } from './strategy'
|
|
2
|
-
import type
|
|
3
|
-
import { FrameBufferWriter } from '../frame-buffer/buffer-writer'
|
|
2
|
+
import { type FrameBufferContext, FrameBufferWriter } from '@ain1084/audio-frame-buffer'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* ManualBufferWriteStrategy class
|
|
@@ -11,10 +10,10 @@ export class ManualBufferWriteStrategy implements BufferWriteStrategy {
|
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Creates an instance of ManualBufferWriteStrategy.
|
|
14
|
-
* @param
|
|
13
|
+
* @param bufferContext - The configuration for the frame buffer.
|
|
15
14
|
*/
|
|
16
|
-
constructor(
|
|
17
|
-
this._writer = new FrameBufferWriter(
|
|
15
|
+
constructor(bufferContext: FrameBufferContext) {
|
|
16
|
+
this._writer = new FrameBufferWriter(bufferContext)
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BufferWriteStrategy } from './strategy'
|
|
2
|
-
import type {
|
|
3
|
-
import { FrameBufferWriter } from '
|
|
4
|
-
import type { FrameBufferFiller } from '../frame-buffer
|
|
2
|
+
import type { FillerFrameBufferContext } from '../filler-frame-buffer-context'
|
|
3
|
+
import { FrameBufferWriter } from '@ain1084/audio-frame-buffer'
|
|
4
|
+
import type { FrameBufferFiller } from '../frame-buffer-filler'
|
|
5
5
|
import type { OutputStreamNode } from '../output-stream-node'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -59,13 +59,13 @@ export class TimedBufferWriteStrategy implements BufferWriteStrategy {
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Creates an instance of TimedBufferWriteStrategy.
|
|
62
|
-
* @param
|
|
62
|
+
* @param bufferContext - The configuration for the filler frame buffer.
|
|
63
63
|
* @param filler - The FrameBufferFiller instance.
|
|
64
64
|
*/
|
|
65
|
-
constructor(
|
|
66
|
-
this._writer = new FrameBufferWriter(
|
|
65
|
+
constructor(bufferContext: FillerFrameBufferContext, filler: FrameBufferFiller) {
|
|
66
|
+
this._writer = new FrameBufferWriter(bufferContext)
|
|
67
67
|
this._filler = filler
|
|
68
|
-
this._interval =
|
|
68
|
+
this._interval = bufferContext.fillInterval
|
|
69
69
|
this._isContinuePlayback = this._filler.fill(this._writer)
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FillerFrameBufferContext } from '../../filler-frame-buffer-context'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Message sent from the main thread to the worker.
|
|
@@ -6,7 +6,7 @@ import type { FillerFrameBufferConfig } from '../../frame-buffer/buffer-config'
|
|
|
6
6
|
* @typeParam FillerParams - The type of the parameters for the FrameBufferFiller.
|
|
7
7
|
*
|
|
8
8
|
* For 'init' messages:
|
|
9
|
-
* @property
|
|
9
|
+
* @property context - The context for the filler frame buffer.
|
|
10
10
|
* @property fillerParams - The parameters for the FrameBufferFiller.
|
|
11
11
|
*
|
|
12
12
|
* For 'start' messages:
|
|
@@ -23,7 +23,7 @@ import type { FillerFrameBufferConfig } from '../../frame-buffer/buffer-config'
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
export type MessageToWorker<FillerParams> =
|
|
26
|
-
| { type: 'init', config:
|
|
26
|
+
| { type: 'init', config: FillerFrameBufferContext, fillerParams: FillerParams }
|
|
27
27
|
| { type: 'start' }
|
|
28
28
|
| { type: 'stop' }
|
|
29
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { FrameBufferFiller } from '../../frame-buffer
|
|
3
|
-
import { FrameBufferWriter } from '
|
|
1
|
+
import type { FillerFrameBufferContext } from '../../filler-frame-buffer-context'
|
|
2
|
+
import type { FrameBufferFiller } from '../../frame-buffer-filler'
|
|
3
|
+
import { FrameBufferWriter } from '@ain1084/audio-frame-buffer'
|
|
4
4
|
import { MessageToStrategy, MessageToWorker } from './message'
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -16,13 +16,13 @@ class Context {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Creates an instance ofContext.
|
|
19
|
-
* @param
|
|
19
|
+
* @param context - The configuration for the filler frame buffer.
|
|
20
20
|
* @param frameBufferFiller - The FrameBufferFiller instance.
|
|
21
21
|
*/
|
|
22
|
-
constructor(
|
|
23
|
-
this._frameBufferWriter = new FrameBufferWriter(
|
|
22
|
+
constructor(context: FillerFrameBufferContext, frameBufferFiller: FrameBufferFiller) {
|
|
23
|
+
this._frameBufferWriter = new FrameBufferWriter(context)
|
|
24
24
|
this._frameBufferFiller = frameBufferFiller
|
|
25
|
-
this._fillInterval =
|
|
25
|
+
this._fillInterval = context.fillInterval
|
|
26
26
|
this._isContinuePlayback = this.fillBuffer()
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -117,15 +117,15 @@ export class BufferFillWorker<FillerParams> {
|
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
119
|
* Initializes the worker context.
|
|
120
|
-
* @param
|
|
120
|
+
* @param bufferContext - The configuration for the filler frame buffer.
|
|
121
121
|
* @param params - The parameters for the FrameBufferFiller.
|
|
122
122
|
*/
|
|
123
|
-
private async init(
|
|
123
|
+
private async init(bufferContext: FillerFrameBufferContext, params: FillerParams) {
|
|
124
124
|
if (this._context) {
|
|
125
125
|
throw new Error('Error: Context is already created.')
|
|
126
126
|
}
|
|
127
127
|
await this._init?.()
|
|
128
|
-
this._context = new Context(
|
|
128
|
+
this._context = new Context(bufferContext, new this._frameBufferFillerGenerator(params))
|
|
129
129
|
self.postMessage({ type: 'init-done' } as MessageToStrategy)
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { BufferWriteStrategy } from './strategy'
|
|
2
|
-
import type {
|
|
2
|
+
import type { FillerFrameBufferContext } from '../filler-frame-buffer-context'
|
|
3
3
|
import type { MessageToStrategy, MessageToWorker } from './worker/message'
|
|
4
4
|
import type { OutputStreamNode } from '../output-stream-node'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Parameters for creating a PlayContext.
|
|
8
8
|
* @property node - The OutputStreamNode instance.
|
|
9
|
-
* @property
|
|
9
|
+
* @property context - The FillerFrameBufferContext instance.
|
|
10
10
|
* @property workerConstructor - The constructor for the Worker.
|
|
11
11
|
* @property fillerParam - The parameters for the FrameBufferFiller.
|
|
12
12
|
*/
|
|
13
13
|
type PlayerContextParams<FillerParams> = Readonly<{
|
|
14
14
|
node: OutputStreamNode
|
|
15
|
-
|
|
15
|
+
context: FillerFrameBufferContext
|
|
16
16
|
workerConstructor: new () => Worker
|
|
17
17
|
fillerParam: FillerParams
|
|
18
18
|
}>
|
|
@@ -23,7 +23,7 @@ type PlayerContextParams<FillerParams> = Readonly<{
|
|
|
23
23
|
*/
|
|
24
24
|
class Context<FillerParams> {
|
|
25
25
|
private readonly _node: OutputStreamNode
|
|
26
|
-
private readonly
|
|
26
|
+
private readonly _bufferContext: FillerFrameBufferContext
|
|
27
27
|
private readonly _fillerParam: FillerParams
|
|
28
28
|
private readonly _worker: Worker
|
|
29
29
|
|
|
@@ -33,7 +33,7 @@ class Context<FillerParams> {
|
|
|
33
33
|
*/
|
|
34
34
|
private constructor(params: PlayerContextParams<FillerParams>) {
|
|
35
35
|
this._node = params.node
|
|
36
|
-
this.
|
|
36
|
+
this._bufferContext = params.context
|
|
37
37
|
this._worker = new params.workerConstructor()
|
|
38
38
|
this._fillerParam = params.fillerParam
|
|
39
39
|
this._worker.onmessage = this.handleWorkerMessage.bind(this)
|
|
@@ -68,7 +68,7 @@ class Context<FillerParams> {
|
|
|
68
68
|
return new Promise<void>((resolve) => {
|
|
69
69
|
const message: MessageToWorker<FillerParams> = {
|
|
70
70
|
type: 'init',
|
|
71
|
-
config: this.
|
|
71
|
+
config: this._bufferContext,
|
|
72
72
|
fillerParams: this._fillerParam,
|
|
73
73
|
}
|
|
74
74
|
this._worker.postMessage(message)
|
|
@@ -111,12 +111,12 @@ export class WorkerBufferWriteStrategy<FillerParam> implements BufferWriteStrate
|
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* Creates an instance of WorkerBufferWriteStrategy.
|
|
114
|
-
* @param
|
|
114
|
+
* @param bufferContext - The context for the filler frame buffer.
|
|
115
115
|
* @param workerConstructor - The constructor for the Worker.
|
|
116
116
|
* @param fillerParam - The parameters for the FrameBufferFiller.
|
|
117
117
|
*/
|
|
118
|
-
constructor(
|
|
119
|
-
this._createPlayContext = (node: OutputStreamNode) => Context.create<FillerParam>({ node,
|
|
118
|
+
constructor(bufferContext: FillerFrameBufferContext, workerConstructor: new () => Worker, fillerParam: FillerParam) {
|
|
119
|
+
this._createPlayContext = (node: OutputStreamNode) => Context.create<FillerParam>({ node, context: bufferContext, workerConstructor, fillerParam })
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/**
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parameters for creating a FrameBuffer.
|
|
3
|
-
* @property frameBufferSize - The size of the frame buffer.
|
|
4
|
-
* @property channelCount - The number of audio channels.
|
|
5
|
-
*/
|
|
6
|
-
export type FrameBufferParams = Readonly<{
|
|
7
|
-
frameBufferSize: number;
|
|
8
|
-
channelCount: number;
|
|
9
|
-
}>;
|
|
10
|
-
/**
|
|
11
|
-
* Parameters for creating a FillerFrameBuffer.
|
|
12
|
-
* @property channelCount - The number of audio channels.
|
|
13
|
-
* @property fillInterval - The interval in milliseconds for filling the buffer.
|
|
14
|
-
* @property sampleRate - The sample rate of the audio context.
|
|
15
|
-
* @property frameBufferChunks - The number of chunks in the frame buffer.
|
|
16
|
-
*/
|
|
17
|
-
export type FillerFrameBufferParams = Readonly<{
|
|
18
|
-
channelCount: number;
|
|
19
|
-
fillInterval?: number;
|
|
20
|
-
sampleRate?: number;
|
|
21
|
-
frameBufferChunks?: number;
|
|
22
|
-
}>;
|
|
23
|
-
/**
|
|
24
|
-
* Configuration for a FrameBuffer.
|
|
25
|
-
* This configuration is returned by the createFrameBufferConfig function.
|
|
26
|
-
* @property sampleBuffer - The shared buffer for audio data frames.
|
|
27
|
-
* @property samplesPerFrame - The number of samples per frame.
|
|
28
|
-
* @property usedFramesInBuffer - The usage count of the frames in the buffer.
|
|
29
|
-
* @property totalReadFrames - The total frames read from the buffer.
|
|
30
|
-
* @property totalWriteFrames - The total frames written to the buffer.
|
|
31
|
-
*/
|
|
32
|
-
export type FrameBufferConfig = Readonly<{
|
|
33
|
-
sampleBuffer: Float32Array;
|
|
34
|
-
samplesPerFrame: number;
|
|
35
|
-
usedFramesInBuffer: Uint32Array;
|
|
36
|
-
totalReadFrames: BigUint64Array;
|
|
37
|
-
totalWriteFrames: BigUint64Array;
|
|
38
|
-
}>;
|
|
39
|
-
/**
|
|
40
|
-
* Configuration for a FillerFrameBuffer.
|
|
41
|
-
* This configuration is returned by the createFillerFrameBufferConfig function.
|
|
42
|
-
* @property sampleRate - The sample rate of the audio context.
|
|
43
|
-
* @property fillInterval - The interval in milliseconds for filling the buffer.
|
|
44
|
-
*/
|
|
45
|
-
export type FillerFrameBufferConfig = FrameBufferConfig & Readonly<{
|
|
46
|
-
sampleRate: number;
|
|
47
|
-
fillInterval: number;
|
|
48
|
-
}>;
|
|
49
|
-
/**
|
|
50
|
-
* Creates a FrameBufferConfig instance.
|
|
51
|
-
* @param params - The parameters for the FrameBuffer.
|
|
52
|
-
* @returns A new instance of FrameBufferConfig.
|
|
53
|
-
*/
|
|
54
|
-
export declare const createFrameBufferConfig: (params: FrameBufferParams) => FrameBufferConfig;
|
|
55
|
-
/**
|
|
56
|
-
* Creates a FillerFrameBufferConfig instance.
|
|
57
|
-
* @param params - The parameters for the FillerFrameBuffer.
|
|
58
|
-
* @returns A new instance of FillerFrameBufferConfig.
|
|
59
|
-
*/
|
|
60
|
-
export declare const createFillerFrameBufferConfig: (params: FillerFrameBufferParams) => FillerFrameBufferConfig;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"buffer-config.js","sourceRoot":"","sources":["../../src/frame-buffer/buffer-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAE1E;;;;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;QACL,GAAG,sBAAsB,CAAC,iBAAiB,EAAE;YAC3C,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,YAAY,CAAC;YAC1E,kBAAkB,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YACpC,eAAe,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;YACpC,gBAAgB,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;SACtC,CAAC;QACF,eAAe,EAAE,MAAM,CAAC,YAAY;KACrC,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"}
|