node-web-audio-api 0.14.0 → 0.15.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/CHANGELOG.md +7 -0
- package/LICENSE +1 -1
- package/README.md +35 -17
- package/index.cjs +1 -1
- package/index.mjs +2 -1
- package/js/AnalyserNode.js +135 -0
- package/js/AudioBufferSourceNode.js +105 -0
- package/js/AudioContext.js +60 -0
- package/js/AudioNode.mixin.js +121 -0
- package/js/AudioParam.js +132 -0
- package/js/AudioScheduledSourceNode.mixin.js +67 -0
- package/js/BaseAudioContext.mixin.js +140 -0
- package/js/BiquadFilterNode.js +75 -0
- package/js/ChannelMergerNode.js +51 -0
- package/js/ChannelSplitterNode.js +51 -0
- package/js/ConstantSourceNode.js +56 -0
- package/js/ConvolverNode.js +75 -0
- package/js/DelayNode.js +52 -0
- package/js/DynamicsCompressorNode.js +60 -0
- package/js/EventTarget.mixin.js +59 -0
- package/js/GainNode.js +52 -0
- package/js/IIRFilterNode.js +59 -0
- package/js/OfflineAudioContext.js +45 -0
- package/js/OscillatorNode.js +77 -0
- package/js/PannerNode.js +169 -0
- package/js/StereoPannerNode.js +52 -0
- package/js/WaveShaperNode.js +75 -0
- package/js/lib/errors.js +108 -0
- package/js/lib/utils.js +16 -0
- package/js/monkey-patch.js +67 -0
- 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 +10 -6
- package/monkey-patch.js +0 -184
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// -------------------------------------------------------------------------- //
|
|
2
|
+
// -------------------------------------------------------------------------- //
|
|
3
|
+
// //
|
|
4
|
+
// //
|
|
5
|
+
// //
|
|
6
|
+
// ██╗ ██╗ █████╗ ██████╗ ███╗ ██╗██╗███╗ ██╗ ██████╗ //
|
|
7
|
+
// ██║ ██║██╔══██╗██╔══██╗████╗ ██║██║████╗ ██║██╔════╝ //
|
|
8
|
+
// ██║ █╗ ██║███████║██████╔╝██╔██╗ ██║██║██╔██╗ ██║██║ ███╗ //
|
|
9
|
+
// ██║███╗██║██╔══██║██╔══██╗██║╚██╗██║██║██║╚██╗██║██║ ██║ //
|
|
10
|
+
// ╚███╔███╔╝██║ ██║██║ ██║██║ ╚████║██║██║ ╚████║╚██████╔╝ //
|
|
11
|
+
// ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═══╝ ╚═════╝ //
|
|
12
|
+
// //
|
|
13
|
+
// //
|
|
14
|
+
// - This file has been generated --------------------------- //
|
|
15
|
+
// //
|
|
16
|
+
// //
|
|
17
|
+
// -------------------------------------------------------------------------- //
|
|
18
|
+
// -------------------------------------------------------------------------- //
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line no-unused-vars
|
|
21
|
+
const { throwSanitizedError } = require('./lib/errors.js');
|
|
22
|
+
// eslint-disable-next-line no-unused-vars
|
|
23
|
+
const { AudioParam } = require('./AudioParam.js');
|
|
24
|
+
const EventTargetMixin = require('./EventTarget.mixin.js');
|
|
25
|
+
const AudioNodeMixin = require('./AudioNode.mixin.js');
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
module.exports = (NativeWaveShaperNode) => {
|
|
29
|
+
|
|
30
|
+
const EventTarget = EventTargetMixin(NativeWaveShaperNode);
|
|
31
|
+
const AudioNode = AudioNodeMixin(EventTarget);
|
|
32
|
+
|
|
33
|
+
class WaveShaperNode extends AudioNode {
|
|
34
|
+
constructor(context, options) {
|
|
35
|
+
super(context, options);
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// getters
|
|
40
|
+
|
|
41
|
+
get curve() {
|
|
42
|
+
return super.curve;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get oversample() {
|
|
46
|
+
return super.oversample;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// setters
|
|
50
|
+
|
|
51
|
+
set curve(value) {
|
|
52
|
+
try {
|
|
53
|
+
super.curve = value;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
throwSanitizedError(err);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set oversample(value) {
|
|
60
|
+
try {
|
|
61
|
+
super.oversample = value;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
throwSanitizedError(err);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// methods
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return WaveShaperNode;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
package/js/lib/errors.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const { EOL } = require('os');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const internalPath = path.join('node-web-audio-api', 'js');
|
|
5
|
+
const internalRe = new RegExp(internalPath);
|
|
6
|
+
|
|
7
|
+
class NotSupportedError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'NotSupportedError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class InvalidStateError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'InvalidStateError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class IndexSizeError extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'IndexSizeError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class InvalidAccessError extends Error {
|
|
29
|
+
constructor(message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = 'InvalidAccessError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.NotSupportedError = NotSupportedError;
|
|
36
|
+
exports.InvalidStateError = InvalidStateError;
|
|
37
|
+
exports.IndexSizeError = IndexSizeError;
|
|
38
|
+
|
|
39
|
+
function overrideStack(originalError, newError) {
|
|
40
|
+
// override previous error message
|
|
41
|
+
const stack = originalError.stack.replace(originalError.message, newError.message);
|
|
42
|
+
const lines = stack.split(EOL);
|
|
43
|
+
|
|
44
|
+
// remove all lines that refer to internal classes, i.e. contains `node-web-audio-api/js`
|
|
45
|
+
for (let i = lines.length - 1; i > 0; i--) {
|
|
46
|
+
const line = lines[i];
|
|
47
|
+
if (internalRe.test(line)) {
|
|
48
|
+
lines.splice(i, 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// override new stack with modified one
|
|
53
|
+
newError.stack = lines.join(EOL);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.throwSanitizedError = function throwSanitizedError(err) {
|
|
57
|
+
// We also need to handle output of `assert_ne!` as well, e.g.
|
|
58
|
+
// assertion `left != right` failed: NotSupportedError - StereoPannerNode channel count mode cannot be set to max
|
|
59
|
+
// left: Max
|
|
60
|
+
// right: Max
|
|
61
|
+
let originalMessage = err.message;
|
|
62
|
+
originalMessage = originalMessage.replace('assertion `left != right` failed: ', '');
|
|
63
|
+
originalMessage = originalMessage.split(EOL)[0]; // keep only first line
|
|
64
|
+
|
|
65
|
+
// "Native Errors"
|
|
66
|
+
if (originalMessage.startsWith('TypeError')) {
|
|
67
|
+
const msg = originalMessage.replace(/^TypeError - /, '');
|
|
68
|
+
const error = new TypeError(msg);
|
|
69
|
+
|
|
70
|
+
throw error;
|
|
71
|
+
} else if (originalMessage.startsWith('RangeError')) {
|
|
72
|
+
const msg = originalMessage.replace(/^RangeError - /, '');
|
|
73
|
+
const error = new RangeError(msg);
|
|
74
|
+
overrideStack(err, error);
|
|
75
|
+
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// "other errors"
|
|
80
|
+
if (originalMessage.startsWith('NotSupportedError')) {
|
|
81
|
+
const msg = originalMessage.replace(/^NotSupportedError - /, '');
|
|
82
|
+
const error = new NotSupportedError(msg);
|
|
83
|
+
overrideStack(err, error);
|
|
84
|
+
|
|
85
|
+
throw error;
|
|
86
|
+
} else if (originalMessage.startsWith('InvalidStateError')) {
|
|
87
|
+
const msg = originalMessage.replace(/^InvalidStateError - /, '');
|
|
88
|
+
const error = new InvalidStateError(msg);
|
|
89
|
+
overrideStack(err, error);
|
|
90
|
+
|
|
91
|
+
throw error;
|
|
92
|
+
} if (originalMessage.startsWith('IndexSizeError')) {
|
|
93
|
+
const msg = originalMessage.replace(/^IndexSizeError - /, '');
|
|
94
|
+
const error = new IndexSizeError(msg);
|
|
95
|
+
overrideStack(err, error);
|
|
96
|
+
|
|
97
|
+
throw error;
|
|
98
|
+
} if (originalMessage.startsWith('InvalidAccessError')) {
|
|
99
|
+
const msg = originalMessage.replace(/^InvalidAccessError - /, '');
|
|
100
|
+
const error = new InvalidAccessError(msg);
|
|
101
|
+
overrideStack(err, error);
|
|
102
|
+
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.warn('[lib/errors.js] Unhandled error type', err.name, err.message);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
package/js/lib/utils.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
exports.isPlainObject = function isPlainObject(obj) {
|
|
2
|
+
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
exports.isPositiveInt = function isPositiveInt(n) {
|
|
6
|
+
return Number.isSafeInteger(n) && 0 < n;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
exports.isPositiveNumber = function isPositiveNumber(n) {
|
|
10
|
+
return Number(n) === n && 0 < n;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
exports.isFunction = function isFunction(val) {
|
|
14
|
+
return Object.prototype.toString.call(val) == '[object Function]' ||
|
|
15
|
+
Object.prototype.toString.call(val) == '[object AsyncFunction]';
|
|
16
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// -------------------------------------------------------------------------- //
|
|
2
|
+
// -------------------------------------------------------------------------- //
|
|
3
|
+
// //
|
|
4
|
+
// //
|
|
5
|
+
// //
|
|
6
|
+
// ██╗ ██╗ █████╗ ██████╗ ███╗ ██╗██╗███╗ ██╗ ██████╗ //
|
|
7
|
+
// ██║ ██║██╔══██╗██╔══██╗████╗ ██║██║████╗ ██║██╔════╝ //
|
|
8
|
+
// ██║ █╗ ██║███████║██████╔╝██╔██╗ ██║██║██╔██╗ ██║██║ ███╗ //
|
|
9
|
+
// ██║███╗██║██╔══██║██╔══██╗██║╚██╗██║██║██║╚██╗██║██║ ██║ //
|
|
10
|
+
// ╚███╔███╔╝██║ ██║██║ ██║██║ ╚████║██║██║ ╚████║╚██████╔╝ //
|
|
11
|
+
// ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═══╝ ╚═════╝ //
|
|
12
|
+
// //
|
|
13
|
+
// //
|
|
14
|
+
// - This file has been generated --------------------------- //
|
|
15
|
+
// //
|
|
16
|
+
// //
|
|
17
|
+
// -------------------------------------------------------------------------- //
|
|
18
|
+
// -------------------------------------------------------------------------- //
|
|
19
|
+
|
|
20
|
+
module.exports = function monkeyPatch(nativeBinding) {
|
|
21
|
+
// --------------------------------------------------------------------------
|
|
22
|
+
// Monkey Patch Web Audio API
|
|
23
|
+
// --------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
nativeBinding.AnalyserNode = require('./AnalyserNode.js')(nativeBinding.AnalyserNode);
|
|
26
|
+
nativeBinding.AudioBufferSourceNode = require('./AudioBufferSourceNode.js')(nativeBinding.AudioBufferSourceNode);
|
|
27
|
+
nativeBinding.BiquadFilterNode = require('./BiquadFilterNode.js')(nativeBinding.BiquadFilterNode);
|
|
28
|
+
nativeBinding.ChannelMergerNode = require('./ChannelMergerNode.js')(nativeBinding.ChannelMergerNode);
|
|
29
|
+
nativeBinding.ChannelSplitterNode = require('./ChannelSplitterNode.js')(nativeBinding.ChannelSplitterNode);
|
|
30
|
+
nativeBinding.ConstantSourceNode = require('./ConstantSourceNode.js')(nativeBinding.ConstantSourceNode);
|
|
31
|
+
nativeBinding.ConvolverNode = require('./ConvolverNode.js')(nativeBinding.ConvolverNode);
|
|
32
|
+
nativeBinding.DelayNode = require('./DelayNode.js')(nativeBinding.DelayNode);
|
|
33
|
+
nativeBinding.DynamicsCompressorNode = require('./DynamicsCompressorNode.js')(nativeBinding.DynamicsCompressorNode);
|
|
34
|
+
nativeBinding.GainNode = require('./GainNode.js')(nativeBinding.GainNode);
|
|
35
|
+
nativeBinding.IIRFilterNode = require('./IIRFilterNode.js')(nativeBinding.IIRFilterNode);
|
|
36
|
+
nativeBinding.OscillatorNode = require('./OscillatorNode.js')(nativeBinding.OscillatorNode);
|
|
37
|
+
nativeBinding.PannerNode = require('./PannerNode.js')(nativeBinding.PannerNode);
|
|
38
|
+
nativeBinding.StereoPannerNode = require('./StereoPannerNode.js')(nativeBinding.StereoPannerNode);
|
|
39
|
+
nativeBinding.WaveShaperNode = require('./WaveShaperNode.js')(nativeBinding.WaveShaperNode);
|
|
40
|
+
|
|
41
|
+
nativeBinding.AudioContext = require('./AudioContext.js')(nativeBinding);
|
|
42
|
+
nativeBinding.OfflineAudioContext = require('./OfflineAudioContext.js')(nativeBinding);
|
|
43
|
+
|
|
44
|
+
// --------------------------------------------------------------------------
|
|
45
|
+
// Promisify MediaDevices API
|
|
46
|
+
// --------------------------------------------------------------------------
|
|
47
|
+
const enumerateDevicesSync = nativeBinding.mediaDevices.enumerateDevices;
|
|
48
|
+
nativeBinding.mediaDevices.enumerateDevices = async function enumerateDevices() {
|
|
49
|
+
const list = enumerateDevicesSync();
|
|
50
|
+
return Promise.resolve(list);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getUserMediaSync = nativeBinding.mediaDevices.getUserMedia;
|
|
54
|
+
nativeBinding.mediaDevices.getUserMedia = async function getUserMedia(options) {
|
|
55
|
+
if (options === undefined) {
|
|
56
|
+
throw new TypeError('Failed to execute "getUserMedia" on "MediaDevices": audio must be requested');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const stream = getUserMediaSync(options);
|
|
60
|
+
return Promise.resolve(stream);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return nativeBinding;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-web-audio-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"author": "Benjamin Matuszewski",
|
|
5
5
|
"description": "Node.js bindings for web-audio-api-rs using napi-rs",
|
|
6
6
|
"exports": {
|
|
@@ -38,10 +38,12 @@
|
|
|
38
38
|
"build:only": "napi build --platform --release",
|
|
39
39
|
"check": "cargo fmt && cargo clippy",
|
|
40
40
|
"generate": "node generator/index.mjs && cargo fmt",
|
|
41
|
-
"lint": "eslint
|
|
41
|
+
"lint": "npx eslint index.cjs index.mjs && npx eslint js/*.js && npx eslint examples/*.mjs",
|
|
42
42
|
"preversion": "yarn install && npm run generate",
|
|
43
|
-
"postversion": "cargo bump $npm_package_version && git commit -am \"v$npm_package_version\" && node
|
|
44
|
-
"test": "mocha"
|
|
43
|
+
"postversion": "cargo bump $npm_package_version && git commit -am \"v$npm_package_version\" && node .scripts/check-changelog.mjs",
|
|
44
|
+
"test": "mocha",
|
|
45
|
+
"wpt": "npm run build && node ./.scripts/wpt-harness.mjs",
|
|
46
|
+
"wpt:only": "node ./.scripts/wpt-harness.mjs"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@ircam/eslint-config": "^1.3.0",
|
|
@@ -49,8 +51,9 @@
|
|
|
49
51
|
"@sindresorhus/slugify": "^2.1.1",
|
|
50
52
|
"camelcase": "^7.0.1",
|
|
51
53
|
"chai": "^4.3.7",
|
|
52
|
-
"chalk": "^5.
|
|
54
|
+
"chalk": "^5.3.0",
|
|
53
55
|
"cli-table": "^0.3.11",
|
|
56
|
+
"commander": "^11.1.0",
|
|
54
57
|
"dotenv": "^16.0.3",
|
|
55
58
|
"eslint": "^8.32.0",
|
|
56
59
|
"mocha": "^10.2.0",
|
|
@@ -59,7 +62,8 @@
|
|
|
59
62
|
"ping": "^0.4.2",
|
|
60
63
|
"template-literal": "^1.0.4",
|
|
61
64
|
"waves-masters": "^2.3.1",
|
|
62
|
-
"webidl2": "^24.2.0"
|
|
65
|
+
"webidl2": "^24.2.0",
|
|
66
|
+
"wpt-runner": "^5.0.0"
|
|
63
67
|
},
|
|
64
68
|
"dependencies": {
|
|
65
69
|
"@napi-rs/cli": "^2.14.3",
|
package/monkey-patch.js
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
|
|
3
|
-
const isPlainObject = function(obj) {
|
|
4
|
-
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
const isPositiveInt = function(n) {
|
|
8
|
-
return Number.isSafeInteger(n) && 0 < n;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const isPositiveNumber = function(n) {
|
|
12
|
-
return Number(n) === n && 0 < n;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
class NotSupportedError extends Error {
|
|
16
|
-
constructor(message) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.name = 'NotSupportedError';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const { platform, arch } = process;
|
|
23
|
-
|
|
24
|
-
let contextIds = {
|
|
25
|
-
audioinput: 0,
|
|
26
|
-
audiooutput: 0,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
let enumerateDevicesSync = null;
|
|
30
|
-
|
|
31
|
-
function handleDefaultOptions(options, kind) {
|
|
32
|
-
// increment contextIds as they are used to keep the process awake
|
|
33
|
-
contextIds[kind] += 1;
|
|
34
|
-
|
|
35
|
-
return options;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function patchAudioContext(nativeBinding) {
|
|
39
|
-
class AudioContext extends nativeBinding.AudioContext {
|
|
40
|
-
constructor(options = {}) {
|
|
41
|
-
// special handling of options on linux, these are not spec compliant but are
|
|
42
|
-
// ment to be more user-friendly than what we have now (is subject to change)
|
|
43
|
-
options = handleDefaultOptions(options, 'audiooutput');
|
|
44
|
-
super(options);
|
|
45
|
-
// prevent garbage collection
|
|
46
|
-
const processId = `__AudioContext_${contextIds['audiooutput']}`;
|
|
47
|
-
process[processId] = this;
|
|
48
|
-
|
|
49
|
-
Object.defineProperty(this, '__processId', {
|
|
50
|
-
value: processId,
|
|
51
|
-
enumerable: false,
|
|
52
|
-
writable: false,
|
|
53
|
-
configurable: false,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// keep process awake
|
|
57
|
-
const keepAwakeId = setInterval(() => {}, 10000);
|
|
58
|
-
Object.defineProperty(this, '__keepAwakeId', {
|
|
59
|
-
value: keepAwakeId,
|
|
60
|
-
enumerable: false,
|
|
61
|
-
writable: true,
|
|
62
|
-
configurable: false,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// promisify sync APIs
|
|
67
|
-
resume() {
|
|
68
|
-
clearTimeout(this.__keepAwakeId);
|
|
69
|
-
this.__keepAwakeId = setInterval(() => {}, 2000);
|
|
70
|
-
return Promise.resolve(super.resume());
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
suspend() {
|
|
74
|
-
return Promise.resolve(super.suspend());
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
close() {
|
|
78
|
-
delete process[this.__processId];
|
|
79
|
-
clearTimeout(this.__keepAwakeId);
|
|
80
|
-
return Promise.resolve(super.close());
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
setSinkId(sinkId) {
|
|
84
|
-
try {
|
|
85
|
-
super.setSinkId(sinkId);
|
|
86
|
-
Promise.resolve(undefined);
|
|
87
|
-
} catch (err) {
|
|
88
|
-
Promise.reject(err);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
decodeAudioData(audioData) {
|
|
93
|
-
if (!audioData instanceof ArrayBuffer) {
|
|
94
|
-
throw new Error('Invalid argument, please provide an ArrayBuffer');
|
|
95
|
-
}
|
|
96
|
-
try {
|
|
97
|
-
const audioBuffer = super.decodeAudioData(audioData);
|
|
98
|
-
return Promise.resolve(audioBuffer);
|
|
99
|
-
} catch (err) {
|
|
100
|
-
return Promise.reject(err);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return AudioContext;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function patchOfflineAudioContext(nativeBinding) {
|
|
109
|
-
class OfflineAudioContext extends nativeBinding.OfflineAudioContext {
|
|
110
|
-
constructor(...args) {
|
|
111
|
-
// handle initialisation with either an options object or a sequence of parameters
|
|
112
|
-
// https://webaudio.github.io/web-audio-api/#dom-offlineaudiocontext-constructor-contextoptions-contextoptions
|
|
113
|
-
if (isPlainObject(args[0])
|
|
114
|
-
&& 'numberOfChannels' in args[0] && 'length' in args[0] && 'sampleRate' in args[0]
|
|
115
|
-
) {
|
|
116
|
-
const { numberOfChannels, length, sampleRate } = args[0];
|
|
117
|
-
args = [numberOfChannels, length, sampleRate];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const [numberOfChannels, length, sampleRate] = args;
|
|
121
|
-
|
|
122
|
-
if (!isPositiveInt(numberOfChannels)) {
|
|
123
|
-
throw new NotSupportedError(`Unsupported value for numberOfChannels: ${numberOfChannels}`);
|
|
124
|
-
} else if (!isPositiveInt(length)) {
|
|
125
|
-
throw new NotSupportedError(`Unsupported value for length: ${length}`);
|
|
126
|
-
} else if (!isPositiveNumber(sampleRate)) {
|
|
127
|
-
throw new NotSupportedError(`Unsupported value for sampleRate: ${sampleRate}`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
super(numberOfChannels, length, sampleRate);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// promisify sync APIs
|
|
134
|
-
startRendering() {
|
|
135
|
-
try {
|
|
136
|
-
const audioBuffer = super.startRendering();
|
|
137
|
-
|
|
138
|
-
clearTimeout(this.__keepAwakeId);
|
|
139
|
-
return Promise.resolve(audioBuffer);
|
|
140
|
-
} catch (err) {
|
|
141
|
-
return Promise.reject(err);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
decodeAudioData(audioData) {
|
|
146
|
-
if (!audioData instanceof ArrayBuffer) {
|
|
147
|
-
throw new Error('Invalid argument, please provide an ArrayBuffer');
|
|
148
|
-
}
|
|
149
|
-
try {
|
|
150
|
-
const audioBuffer = super.decodeAudioData(audioData);
|
|
151
|
-
return Promise.resolve(audioBuffer);
|
|
152
|
-
} catch (err) {
|
|
153
|
-
return Promise.reject(err);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return OfflineAudioContext;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
module.exports = function monkeyPatch(nativeBinding) {
|
|
162
|
-
nativeBinding.AudioContext = patchAudioContext(nativeBinding);
|
|
163
|
-
nativeBinding.OfflineAudioContext = patchOfflineAudioContext(nativeBinding);
|
|
164
|
-
|
|
165
|
-
// Promisify MediaDevices API
|
|
166
|
-
enumerateDevicesSync = nativeBinding.mediaDevices.enumerateDevices;
|
|
167
|
-
nativeBinding.mediaDevices.enumerateDevices = async function enumerateDevices(options) {
|
|
168
|
-
const list = enumerateDevicesSync();
|
|
169
|
-
return Promise.resolve(list);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const getUserMediaSync = nativeBinding.mediaDevices.getUserMedia;
|
|
173
|
-
nativeBinding.mediaDevices.getUserMedia = async function getUserMedia(options) {
|
|
174
|
-
if (options === undefined) {
|
|
175
|
-
throw new TypeError("Failed to execute 'getUserMedia' on 'MediaDevices': audio must be requested")
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
options = handleDefaultOptions(options, 'audioinput');
|
|
179
|
-
const stream = getUserMediaSync(options);
|
|
180
|
-
return Promise.resolve(stream);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return nativeBinding;
|
|
184
|
-
}
|