node-web-audio-api 0.21.5 → 1.0.0-beta.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/Cross.toml +17 -0
- package/all-checks.sh +2 -2
- package/js/AudioRenderCapacity.js +3 -2
- package/js/AudioWorklet.js +14 -20
- package/js/AudioWorkletGlobalScope.js +4 -8
- package/js/AudioWorkletNode.js +1 -1
- package/js/OfflineAudioContext.js +4 -2
- package/load-native.cjs +18 -4
- package/node-web-audio-api.darwin-arm64.node +0 -0
- package/node-web-audio-api.darwin-x64.node +0 -0
- package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
- package/node-web-audio-api.linux-arm64-gnu.node +0 -0
- package/node-web-audio-api.linux-x64-gnu.node +0 -0
- package/node-web-audio-api.win32-arm64-msvc.node +0 -0
- package/node-web-audio-api.win32-x64-msvc.node +0 -0
- package/package.json +9 -11
package/Cross.toml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[target.aarch64-unknown-linux-gnu]
|
|
2
|
+
pre-build = [
|
|
3
|
+
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
|
4
|
+
"apt-get update && apt-get --assume-yes install libasound2-dev:$CROSS_DEB_ARCH libjack-jackd2-dev:$CROSS_DEB_ARCH"
|
|
5
|
+
]
|
|
6
|
+
|
|
7
|
+
[target.armv7-unknown-linux-gnueabihf]
|
|
8
|
+
pre-build = [
|
|
9
|
+
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
|
10
|
+
"apt-get update && apt-get --assume-yes install libasound2-dev:$CROSS_DEB_ARCH libjack-jackd2-dev:$CROSS_DEB_ARCH"
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[target.x86_64-unknown-linux-gnu]
|
|
14
|
+
pre-build = [
|
|
15
|
+
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
|
16
|
+
"apt-get update && apt-get --assume-yes install libasound2-dev:$CROSS_DEB_ARCH libjack-jackd2-dev:$CROSS_DEB_ARCH"
|
|
17
|
+
]
|
package/all-checks.sh
CHANGED
|
@@ -7,9 +7,9 @@ echo "-----------------------------------------------"
|
|
|
7
7
|
cargo fmt -- --check --color always
|
|
8
8
|
|
|
9
9
|
echo "-----------------------------------------------"
|
|
10
|
-
echo "> cargo clippy --all-targets --
|
|
10
|
+
echo "> cargo clippy --all-targets -- -D warnings"
|
|
11
11
|
echo "-----------------------------------------------"
|
|
12
|
-
cargo clippy --all-targets --
|
|
12
|
+
cargo clippy --all-targets -- -D warnings
|
|
13
13
|
|
|
14
14
|
echo "-----------------------------------------------"
|
|
15
15
|
echo "> Run js tests"
|
|
@@ -5,6 +5,7 @@ const {
|
|
|
5
5
|
kOnUpdate,
|
|
6
6
|
} = require('./lib/symbols.js');
|
|
7
7
|
const {
|
|
8
|
+
isFunction,
|
|
8
9
|
kEnumerableProperty,
|
|
9
10
|
} = require('./lib/utils.js');
|
|
10
11
|
const {
|
|
@@ -70,7 +71,7 @@ class AudioRenderCapacity extends EventTarget {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
targetOptions.updateInterval = conversions['double'](options.updateInterval, {
|
|
73
|
-
context: `Failed to execute 'start' on 'AudioRenderCapacity': Failed to read the 'updateInterval' property on 'AudioRenderCapacityOptions': The provided value ()
|
|
74
|
+
context: `Failed to execute 'start' on 'AudioRenderCapacity': Failed to read the 'updateInterval' property on 'AudioRenderCapacityOptions': The provided value ()`,
|
|
74
75
|
});
|
|
75
76
|
} else {
|
|
76
77
|
targetOptions.updateInterval = 1;
|
|
@@ -108,7 +109,7 @@ Object.defineProperties(AudioRenderCapacity.prototype, {
|
|
|
108
109
|
},
|
|
109
110
|
|
|
110
111
|
onupdate: kEnumerableProperty,
|
|
111
|
-
|
|
112
|
+
start: kEnumerableProperty,
|
|
112
113
|
stop: kEnumerableProperty,
|
|
113
114
|
});
|
|
114
115
|
|
package/js/AudioWorklet.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const {
|
|
2
|
-
resolveObjectURL
|
|
2
|
+
resolveObjectURL,
|
|
3
3
|
} = require('node:buffer');
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const {
|
|
5
|
+
existsSync,
|
|
6
|
+
} = require('node:fs');
|
|
6
7
|
const path = require('node:path');
|
|
7
8
|
const {
|
|
8
9
|
Worker,
|
|
@@ -23,7 +24,7 @@ const {
|
|
|
23
24
|
|
|
24
25
|
const caller = require('caller');
|
|
25
26
|
// cf. https://www.npmjs.com/package/node-fetch#commonjs
|
|
26
|
-
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
27
|
+
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Retrieve code with different module resolution strategies
|
|
@@ -47,11 +48,11 @@ const resolveModule = async (moduleUrl) => {
|
|
|
47
48
|
}
|
|
48
49
|
} else if (moduleUrl.startsWith('http')) {
|
|
49
50
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
const res = await fetch(moduleUrl);
|
|
52
|
+
code = await res.text();
|
|
53
|
+
} catch (err) {
|
|
54
|
+
throw new DOMException(`Failed to execute 'addModule' on 'AudioWorklet': ${err.message}`, 'AbortError');
|
|
55
|
+
}
|
|
55
56
|
} else if (moduleUrl.startsWith('blob:')) {
|
|
56
57
|
try {
|
|
57
58
|
const blob = resolveObjectURL(moduleUrl);
|
|
@@ -63,16 +64,8 @@ const resolveModule = async (moduleUrl) => {
|
|
|
63
64
|
const callerSite = caller(2);
|
|
64
65
|
|
|
65
66
|
if (callerSite.startsWith('http')) { // this branch exists for wpt where caller site is an url
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (moduleUrl.startsWith('/')) {
|
|
69
|
-
const origin = new URL(baseUrl).origin;
|
|
70
|
-
url = origin + moduleUrl;
|
|
71
|
-
} else {
|
|
72
|
-
// we know separators are '/'
|
|
73
|
-
const baseUrl = callerSite.substr(0, callerSite.lastIndexOf('/'));
|
|
74
|
-
url = baseUrl + '/' + moduleUrl;
|
|
75
|
-
}
|
|
67
|
+
const baseUrl = callerSite.substring(0, callerSite.lastIndexOf('/'));
|
|
68
|
+
const url = baseUrl + '/' + moduleUrl;
|
|
76
69
|
|
|
77
70
|
try {
|
|
78
71
|
const res = await fetch(url);
|
|
@@ -100,7 +93,7 @@ const resolveModule = async (moduleUrl) => {
|
|
|
100
93
|
}
|
|
101
94
|
|
|
102
95
|
return { absPathname, code };
|
|
103
|
-
}
|
|
96
|
+
};
|
|
104
97
|
|
|
105
98
|
class AudioWorklet {
|
|
106
99
|
#workletId = null;
|
|
@@ -200,6 +193,7 @@ class AudioWorklet {
|
|
|
200
193
|
// For OfflineAudioContext only, check that all processors have been properly
|
|
201
194
|
// created before actual `startRendering`
|
|
202
195
|
async [kCheckProcessorsCreated]() {
|
|
196
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
203
197
|
return new Promise(async resolve => {
|
|
204
198
|
while (this.#pendingCreateProcessors.size !== 0) {
|
|
205
199
|
// we need a microtask to ensure message can be received
|
|
@@ -87,7 +87,7 @@ globalThis[kWorkletRecycleBuffer1] = buffer => pool1.recycle(buffer);
|
|
|
87
87
|
globalThis[kWorkletMarkAsUntransferable] = obj => {
|
|
88
88
|
markAsUntransferable(obj);
|
|
89
89
|
return obj;
|
|
90
|
-
}
|
|
90
|
+
};
|
|
91
91
|
|
|
92
92
|
function isIterable(obj) {
|
|
93
93
|
// checks for null and undefined
|
|
@@ -114,7 +114,7 @@ function runLoop() {
|
|
|
114
114
|
runLoopImmediateId = setImmediate(runLoop);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
globalThis.currentTime = 0
|
|
117
|
+
globalThis.currentTime = 0;
|
|
118
118
|
globalThis.currentFrame = 0;
|
|
119
119
|
globalThis.sampleRate = sampleRate;
|
|
120
120
|
// @todo - implement in upstream crate
|
|
@@ -153,7 +153,7 @@ globalThis.AudioWorkletProcessor = class AudioWorkletProcessor {
|
|
|
153
153
|
this[kWorkletParamsCache][desc.name] = [
|
|
154
154
|
pool128.get(), // should be globalThis.renderQuantumSize
|
|
155
155
|
pool1.get(),
|
|
156
|
-
]
|
|
156
|
+
];
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
this.#port = port;
|
|
@@ -170,7 +170,7 @@ globalThis.AudioWorkletProcessor = class AudioWorkletProcessor {
|
|
|
170
170
|
[kWorkletQueueTask](cmd, err) {
|
|
171
171
|
this.#port.postMessage({ cmd, err });
|
|
172
172
|
}
|
|
173
|
-
}
|
|
173
|
+
};
|
|
174
174
|
|
|
175
175
|
// follow algorithm from:
|
|
176
176
|
// https://webaudio.github.io/web-audio-api/#dom-audioworkletglobalscope-registerprocessor
|
|
@@ -300,10 +300,6 @@ globalThis.registerProcessor = function registerProcessor(name, processorCtor) {
|
|
|
300
300
|
|
|
301
301
|
parentPort.on('message', async event => {
|
|
302
302
|
switch (event.cmd) {
|
|
303
|
-
case 'node-web-audio-api:worklet:init': {
|
|
304
|
-
const { workletId, processors, promiseId } = event;
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
303
|
case 'node-web-audio-api:worklet:exit': {
|
|
308
304
|
clearImmediate(runLoopImmediateId);
|
|
309
305
|
// properly exit audio worklet on rust side
|
package/js/AudioWorkletNode.js
CHANGED
|
@@ -156,7 +156,7 @@ module.exports = (jsExport, nativeBinding) => {
|
|
|
156
156
|
// if we delegate this check to Rust, this can poison a Mutex
|
|
157
157
|
// (probably the `audio_param_descriptor_channel` one)
|
|
158
158
|
if (parsedOptions.channelCount <= 0 || parsedOptions.channelCount > IMPLEMENTATION_MAX_NUMBER_OF_CHANNELS) {
|
|
159
|
-
throw new DOMException(`Failed to construct 'AudioWorkletNode': Invalid 'channelCount' property: Number of channels: ${parsedOptions.channelCount} is outside range [1, 32]`, 'NotSupportedError')
|
|
159
|
+
throw new DOMException(`Failed to construct 'AudioWorkletNode': Invalid 'channelCount' property: Number of channels: ${parsedOptions.channelCount} is outside range [1, 32]`, 'NotSupportedError');
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -138,10 +138,12 @@ module.exports = function patchOfflineAudioContext(jsExport, nativeBinding) {
|
|
|
138
138
|
// ensure all AudioWorkletProcessor have finished their instanciation
|
|
139
139
|
await this.audioWorklet[kCheckProcessorsCreated]();
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
// keep this to highlight the workaround w/ the oncomplete event
|
|
142
|
+
let _nativeAudioBuffer;
|
|
142
143
|
|
|
143
144
|
try {
|
|
144
|
-
|
|
145
|
+
// eslint-disable-next-line no-unused-vars
|
|
146
|
+
_nativeAudioBuffer = await this[kNapiObj].startRendering();
|
|
145
147
|
} catch (err) {
|
|
146
148
|
throwSanitizedError(err);
|
|
147
149
|
}
|
package/load-native.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
1
2
|
const { platform, arch } = process;
|
|
2
3
|
|
|
3
4
|
let nativeBinding = null;
|
|
@@ -21,7 +22,7 @@ switch (platform) {
|
|
|
21
22
|
}
|
|
22
23
|
break;
|
|
23
24
|
default:
|
|
24
|
-
|
|
25
|
+
loadError = new Error(`Unsupported architecture on Windows: ${arch}`);
|
|
25
26
|
}
|
|
26
27
|
break;
|
|
27
28
|
case 'darwin':
|
|
@@ -41,11 +42,15 @@ switch (platform) {
|
|
|
41
42
|
}
|
|
42
43
|
break;
|
|
43
44
|
default:
|
|
44
|
-
|
|
45
|
+
loadError = new Error(`Unsupported architecture on macOS: ${arch}`);
|
|
45
46
|
}
|
|
46
47
|
break;
|
|
48
|
+
// case 'freebsd': x64 only
|
|
47
49
|
case 'linux':
|
|
48
50
|
switch (arch) {
|
|
51
|
+
// @todo
|
|
52
|
+
// - support riscv64 arch
|
|
53
|
+
// - support musl C lib
|
|
49
54
|
case 'x64':
|
|
50
55
|
try {
|
|
51
56
|
nativeBinding = require('./node-web-audio-api.linux-x64-gnu.node');
|
|
@@ -68,11 +73,20 @@ switch (platform) {
|
|
|
68
73
|
}
|
|
69
74
|
break;
|
|
70
75
|
default:
|
|
71
|
-
|
|
76
|
+
loadError = new Error(`Unsupported architecture on Linux: ${arch}`);
|
|
72
77
|
}
|
|
73
78
|
break;
|
|
74
79
|
default:
|
|
75
|
-
|
|
80
|
+
loadError = new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// use local build if exists
|
|
84
|
+
if (fs.existsSync('node-web-audio-api.build-release.node')) {
|
|
85
|
+
nativeBinding = require('./node-web-audio-api.build-release.node');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (fs.existsSync('node-web-audio-api.build-debug.node')) {
|
|
89
|
+
nativeBinding = require('./node-web-audio-api.build-debug.node');
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
if (!nativeBinding) {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-web-audio-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
4
|
"author": "Benjamin Matuszewski",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Web Audio API implementation for Node.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
"import": "./index.mjs",
|
|
8
8
|
"require": "./index.cjs",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"music",
|
|
22
22
|
"dsp",
|
|
23
23
|
"rust",
|
|
24
|
-
"
|
|
24
|
+
"node-api"
|
|
25
25
|
],
|
|
26
26
|
"engines": {
|
|
27
27
|
"node": ">= 14"
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
|
-
"
|
|
39
|
-
"build": "npm run generate &&
|
|
40
|
-
"build:
|
|
41
|
-
"build:
|
|
42
|
-
"build:only": "napi build --platform --release",
|
|
38
|
+
"build": "npm run generate && cargo build --release && node ./.scripts/move-artifact.mjs --release",
|
|
39
|
+
"build:jack": "npm run generate && cargo build --features jack --release && node ./.scripts/move-artifact.mjs --release",
|
|
40
|
+
"build:debug": "npm run generate && cargo build && node ./.scripts/move-artifact.mjs",
|
|
41
|
+
"build:only": "cargo build --release && node ./.scripts/move-artifact.mjs --release",
|
|
43
42
|
"check": "cargo fmt && cargo clippy",
|
|
44
43
|
"generate": "node generator/index.mjs && cargo fmt",
|
|
45
44
|
"lint": "npx eslint index.cjs index.mjs && npx eslint js/*.js && npx eslint examples/*.mjs",
|
|
46
|
-
"preversion": "
|
|
45
|
+
"preversion": "npm install && npm run generate",
|
|
47
46
|
"postversion": "cargo bump $npm_package_version && git commit -am \"v$npm_package_version\" && node .scripts/check-changelog.mjs",
|
|
48
47
|
"test": "mocha tests/*.spec.mjs",
|
|
48
|
+
"test:ci": "mocha tests/*.spec.mjs -- --ci",
|
|
49
49
|
"test:only": "mocha",
|
|
50
50
|
"wpt": "npm run build && node ./.scripts/wpt-harness.mjs",
|
|
51
51
|
"wpt:only": "node ./.scripts/wpt-harness.mjs"
|
|
@@ -73,8 +73,6 @@
|
|
|
73
73
|
"wpt-runner": "^5.0.0"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@napi-rs/cli": "^2.14.3",
|
|
77
|
-
"@node-rs/helper": "^1.3.3",
|
|
78
76
|
"caller": "^1.1.0",
|
|
79
77
|
"node-fetch": "^3.3.2",
|
|
80
78
|
"webidl-conversions": "^7.0.0"
|