node-web-audio-api 0.18.0 → 0.19.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/TODOS.md +140 -12
  3. package/index.mjs +10 -5
  4. package/js/AnalyserNode.js +262 -48
  5. package/js/AudioBuffer.js +244 -0
  6. package/js/AudioBufferSourceNode.js +265 -41
  7. package/js/AudioContext.js +271 -28
  8. package/js/AudioDestinationNode.js +42 -100
  9. package/js/AudioListener.js +219 -0
  10. package/js/AudioNode.js +323 -0
  11. package/js/AudioParam.js +252 -39
  12. package/js/AudioScheduledSourceNode.js +105 -0
  13. package/js/BaseAudioContext.js +419 -0
  14. package/js/BiquadFilterNode.js +221 -29
  15. package/js/ChannelMergerNode.js +96 -22
  16. package/js/ChannelSplitterNode.js +96 -22
  17. package/js/ConstantSourceNode.js +92 -26
  18. package/js/ConvolverNode.js +161 -29
  19. package/js/DelayNode.js +115 -21
  20. package/js/DynamicsCompressorNode.js +198 -27
  21. package/js/GainNode.js +107 -21
  22. package/js/IIRFilterNode.js +139 -23
  23. package/js/MediaStreamAudioSourceNode.js +83 -24
  24. package/js/OfflineAudioContext.js +182 -34
  25. package/js/OscillatorNode.js +195 -32
  26. package/js/PannerNode.js +461 -56
  27. package/js/PeriodicWave.js +67 -3
  28. package/js/StereoPannerNode.js +107 -21
  29. package/js/WaveShaperNode.js +147 -29
  30. package/js/lib/cast.js +19 -0
  31. package/js/lib/errors.js +10 -55
  32. package/js/lib/events.js +20 -0
  33. package/js/lib/symbols.js +5 -0
  34. package/js/lib/utils.js +12 -12
  35. package/js/monkey-patch.js +32 -30
  36. package/node-web-audio-api.darwin-arm64.node +0 -0
  37. package/node-web-audio-api.darwin-x64.node +0 -0
  38. package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
  39. package/node-web-audio-api.linux-arm64-gnu.node +0 -0
  40. package/node-web-audio-api.linux-x64-gnu.node +0 -0
  41. package/node-web-audio-api.win32-arm64-msvc.node +0 -0
  42. package/node-web-audio-api.win32-x64-msvc.node +0 -0
  43. package/package.json +7 -4
  44. package/run-wpt.md +27 -0
  45. package/run-wpt.sh +5 -0
  46. package/js/AudioNode.mixin.js +0 -132
  47. package/js/AudioScheduledSourceNode.mixin.js +0 -67
  48. package/js/BaseAudioContext.mixin.js +0 -154
  49. package/js/EventTarget.mixin.js +0 -60
@@ -17,38 +17,135 @@
17
17
  // -------------------------------------------------------------------------- //
18
18
  // -------------------------------------------------------------------------- //
19
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');
20
+ /* eslint-disable no-unused-vars */
21
+ const conversions = require('webidl-conversions');
22
+ const {
23
+ toSanitizedSequence,
24
+ } = require('./lib/cast.js');
25
+ const {
26
+ isFunction,
27
+ kEnumerableProperty,
28
+ } = require('./lib/utils.js');
29
+ const {
30
+ throwSanitizedError,
31
+ } = require('./lib/errors.js');
32
+ const {
33
+ kNapiObj,
34
+ kAudioBuffer,
35
+ } = require('./lib/symbols.js');
36
+ const {
37
+ bridgeEventTarget,
38
+ } = require('./lib/events.js');
39
+ /* eslint-enable no-unused-vars */
26
40
 
41
+ const AudioNode = require('./AudioNode.js');
27
42
 
28
- module.exports = (NativeIIRFilterNode) => {
29
-
30
- const EventTarget = EventTargetMixin(NativeIIRFilterNode);
31
- const AudioNode = AudioNodeMixin(EventTarget);
32
-
43
+ module.exports = (jsExport, nativeBinding) => {
33
44
  class IIRFilterNode extends AudioNode {
45
+
34
46
  constructor(context, options) {
35
- if (options !== undefined && typeof options !== 'object') {
36
- throw new TypeError("Failed to construct 'IIRFilterNode': argument 2 is not of type 'IIRFilterOptions'")
47
+
48
+ if (arguments.length < 2) {
49
+ throw new TypeError(`Failed to construct 'IIRFilterNode': 2 argument required, but only ${arguments.length} present`);
50
+ }
51
+
52
+ if (!(context instanceof jsExport.BaseAudioContext)) {
53
+ throw new TypeError(`Failed to construct 'IIRFilterNode': argument 1 is not of type BaseAudioContext`);
54
+ }
55
+
56
+ // parsed version of the option to be passed to NAPI
57
+ const parsedOptions = {};
58
+
59
+ if (options && typeof options !== 'object') {
60
+ throw new TypeError('Failed to construct \'IIRFilterNode\': argument 2 is not of type \'IIRFilterOptions\'');
61
+ }
62
+
63
+ // required options
64
+ if (typeof options !== 'object' || (options && options.feedforward === undefined)) {
65
+ throw new TypeError('Failed to construct \'IIRFilterNode\': Failed to read the \'feedforward\' property from IIRFilterOptions: Required member is undefined');
66
+ }
67
+
68
+ if (options && options.feedforward !== undefined) {
69
+ try {
70
+ parsedOptions.feedforward = toSanitizedSequence(options.feedforward, Float64Array);
71
+ } catch (err) {
72
+ throw new TypeError(`Failed to construct 'IIRFilterNode': Failed to read the 'feedforward' property from IIRFilterOptions: The provided value ${err.message}`);
73
+ }
74
+ } else {
75
+ parsedOptions.feedforward = null;
76
+ }
77
+
78
+ // required options
79
+ if (typeof options !== 'object' || (options && options.feedback === undefined)) {
80
+ throw new TypeError('Failed to construct \'IIRFilterNode\': Failed to read the \'feedback\' property from IIRFilterOptions: Required member is undefined');
81
+ }
82
+
83
+ if (options && options.feedback !== undefined) {
84
+ try {
85
+ parsedOptions.feedback = toSanitizedSequence(options.feedback, Float64Array);
86
+ } catch (err) {
87
+ throw new TypeError(`Failed to construct 'IIRFilterNode': Failed to read the 'feedback' property from IIRFilterOptions: The provided value ${err.message}`);
88
+ }
89
+ } else {
90
+ parsedOptions.feedback = null;
91
+ }
92
+
93
+ if (options && options.channelCount !== undefined) {
94
+ parsedOptions.channelCount = conversions['unsigned long'](options.channelCount, {
95
+ enforceRange: true,
96
+ context: `Failed to construct 'IIRFilterNode': Failed to read the 'channelCount' property from IIRFilterOptions: The provided value '${options.channelCount}'`,
97
+ });
98
+ }
99
+
100
+ if (options && options.channelCountMode !== undefined) {
101
+ parsedOptions.channelCountMode = conversions['DOMString'](options.channelCountMode, {
102
+ context: `Failed to construct 'IIRFilterNode': Failed to read the 'channelCount' property from IIRFilterOptions: The provided value '${options.channelCountMode}'`,
103
+ });
37
104
  }
38
105
 
39
- super(context, options);
106
+ if (options && options.channelInterpretation !== undefined) {
107
+ parsedOptions.channelInterpretation = conversions['DOMString'](options.channelInterpretation, {
108
+ context: `Failed to construct 'IIRFilterNode': Failed to read the 'channelInterpretation' property from IIRFilterOptions: The provided value '${options.channelInterpretation}'`,
109
+ });
110
+ }
111
+
112
+ let napiObj;
113
+
114
+ try {
115
+ napiObj = new nativeBinding.IIRFilterNode(context[kNapiObj], parsedOptions);
116
+ } catch (err) {
117
+ throwSanitizedError(err);
118
+ }
119
+
120
+ super(context, {
121
+ [kNapiObj]: napiObj,
122
+ });
40
123
 
41
124
  }
42
125
 
43
- // getters
126
+ getFrequencyResponse(frequencyHz, magResponse, phaseResponse) {
127
+ if (!(this instanceof IIRFilterNode)) {
128
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'IIRFilterNode\'');
129
+ }
44
130
 
45
- // setters
131
+ if (arguments.length < 3) {
132
+ throw new TypeError(`Failed to execute 'getFrequencyResponse' on 'IIRFilterNode': 3 argument required, but only ${arguments.length} present`);
133
+ }
134
+
135
+ if (!(frequencyHz instanceof Float32Array)) {
136
+ throw new TypeError(`Failed to execute 'getFrequencyResponse' on 'IIRFilterNode': Parameter 1 is not of type 'Float32Array'`);
137
+ }
138
+
139
+ if (!(magResponse instanceof Float32Array)) {
140
+ throw new TypeError(`Failed to execute 'getFrequencyResponse' on 'IIRFilterNode': Parameter 2 is not of type 'Float32Array'`);
141
+ }
142
+
143
+ if (!(phaseResponse instanceof Float32Array)) {
144
+ throw new TypeError(`Failed to execute 'getFrequencyResponse' on 'IIRFilterNode': Parameter 3 is not of type 'Float32Array'`);
145
+ }
46
146
 
47
- // methods
48
-
49
- getFrequencyResponse(...args) {
50
147
  try {
51
- return super.getFrequencyResponse(...args);
148
+ return this[kNapiObj].getFrequencyResponse(frequencyHz, magResponse, phaseResponse);
52
149
  } catch (err) {
53
150
  throwSanitizedError(err);
54
151
  }
@@ -56,8 +153,27 @@ module.exports = (NativeIIRFilterNode) => {
56
153
 
57
154
  }
58
155
 
59
- return IIRFilterNode;
60
- };
156
+ Object.defineProperties(IIRFilterNode, {
157
+ length: {
158
+ __proto__: null,
159
+ writable: false,
160
+ enumerable: false,
161
+ configurable: true,
162
+ value: 2,
163
+ },
164
+ });
165
+
166
+ Object.defineProperties(IIRFilterNode.prototype, {
167
+ [Symbol.toStringTag]: {
168
+ __proto__: null,
169
+ writable: false,
170
+ enumerable: false,
171
+ configurable: true,
172
+ value: 'IIRFilterNode',
173
+ },
61
174
 
175
+ getFrequencyResponse: kEnumerableProperty,
176
+ });
62
177
 
63
-
178
+ return IIRFilterNode;
179
+ };
@@ -17,43 +17,102 @@
17
17
  // -------------------------------------------------------------------------- //
18
18
  // -------------------------------------------------------------------------- //
19
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');
20
+ /* eslint-disable no-unused-vars */
21
+ const conversions = require('webidl-conversions');
22
+ const {
23
+ toSanitizedSequence,
24
+ } = require('./lib/cast.js');
25
+ const {
26
+ isFunction,
27
+ kEnumerableProperty,
28
+ } = require('./lib/utils.js');
29
+ const {
30
+ throwSanitizedError,
31
+ } = require('./lib/errors.js');
32
+ const {
33
+ kNapiObj,
34
+ kAudioBuffer,
35
+ } = require('./lib/symbols.js');
36
+ const {
37
+ bridgeEventTarget,
38
+ } = require('./lib/events.js');
39
+ /* eslint-enable no-unused-vars */
26
40
 
41
+ const AudioNode = require('./AudioNode.js');
27
42
 
28
- module.exports = (NativeMediaStreamAudioSourceNode) => {
29
-
30
- const EventTarget = EventTargetMixin(NativeMediaStreamAudioSourceNode);
31
- const AudioNode = AudioNodeMixin(EventTarget);
32
-
43
+ module.exports = (jsExport, nativeBinding) => {
33
44
  class MediaStreamAudioSourceNode extends AudioNode {
45
+
34
46
  constructor(context, options) {
35
- if (options !== undefined && typeof options !== 'object') {
36
- throw new TypeError("Failed to construct 'MediaStreamAudioSourceNode': argument 2 is not of type 'MediaStreamAudioSourceOptions'")
47
+
48
+ if (arguments.length < 2) {
49
+ throw new TypeError(`Failed to construct 'MediaStreamAudioSourceNode': 2 argument required, but only ${arguments.length} present`);
37
50
  }
38
51
 
39
- super(context, options);
52
+ if (!(context instanceof jsExport.AudioContext)) {
53
+ throw new TypeError(`Failed to construct 'MediaStreamAudioSourceNode': argument 1 is not of type AudioContext`);
54
+ }
40
55
 
41
- }
56
+ // parsed version of the option to be passed to NAPI
57
+ const parsedOptions = {};
42
58
 
43
- // getters
59
+ if (options && typeof options !== 'object') {
60
+ throw new TypeError('Failed to construct \'MediaStreamAudioSourceNode\': argument 2 is not of type \'MediaStreamAudioSourceOptions\'');
61
+ }
62
+
63
+ // required options
64
+ if (typeof options !== 'object' || (options && options.mediaStream === undefined)) {
65
+ throw new TypeError('Failed to construct \'MediaStreamAudioSourceNode\': Failed to read the \'mediaStream\' property from MediaStreamAudioSourceOptions: Required member is undefined');
66
+ }
67
+
68
+ parsedOptions.mediaStream = options.mediaStream;
69
+
70
+ let napiObj;
71
+
72
+ try {
73
+ napiObj = new nativeBinding.MediaStreamAudioSourceNode(context[kNapiObj], parsedOptions);
74
+ } catch (err) {
75
+ throwSanitizedError(err);
76
+ }
77
+
78
+ super(context, {
79
+ [kNapiObj]: napiObj,
80
+ });
44
81
 
45
- get mediaStream() {
46
- return super.mediaStream;
47
82
  }
48
83
 
49
- // setters
84
+ get mediaStream() {
85
+ if (!(this instanceof MediaStreamAudioSourceNode)) {
86
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'MediaStreamAudioSourceNode\'');
87
+ }
88
+
89
+ return this[kNapiObj].mediaStream;
90
+ }
50
91
 
51
- // methods
52
-
53
92
  }
54
93
 
55
- return MediaStreamAudioSourceNode;
56
- };
94
+ Object.defineProperties(MediaStreamAudioSourceNode, {
95
+ length: {
96
+ __proto__: null,
97
+ writable: false,
98
+ enumerable: false,
99
+ configurable: true,
100
+ value: 2,
101
+ },
102
+ });
103
+
104
+ Object.defineProperties(MediaStreamAudioSourceNode.prototype, {
105
+ [Symbol.toStringTag]: {
106
+ __proto__: null,
107
+ writable: false,
108
+ enumerable: false,
109
+ configurable: true,
110
+ value: 'MediaStreamAudioSourceNode',
111
+ },
57
112
 
113
+ mediaStream: kEnumerableProperty,
58
114
 
59
-
115
+ });
116
+
117
+ return MediaStreamAudioSourceNode;
118
+ };
@@ -1,57 +1,205 @@
1
- const { nameCodeMap, DOMException } = require('./lib/errors.js');
2
- const { isPlainObject, isPositiveInt, isPositiveNumber } = require('./lib/utils.js');
1
+ const conversions = require('webidl-conversions');
3
2
 
4
- module.exports = function patchOfflineAudioContext(bindings) {
5
- // @todo - EventTarget
6
- // - https://github.com/orottier/web-audio-api-rs/issues/411
7
- // - https://github.com/orottier/web-audio-api-rs/issues/416
3
+ const {
4
+ bridgeEventTarget,
5
+ } = require('./lib/events.js');
6
+ const {
7
+ throwSanitizedError,
8
+ } = require('./lib/errors.js');
9
+ const {
10
+ isFunction,
11
+ kEnumerableProperty,
12
+ } = require('./lib/utils.js');
13
+ const {
14
+ kNapiObj
15
+ } = require('./lib/symbols.js');
8
16
 
9
- const EventTarget = require('./EventTarget.mixin.js')(bindings.OfflineAudioContext, ['statechange']);
10
- const BaseAudioContext = require('./BaseAudioContext.mixin.js')(EventTarget, bindings);
17
+ // constructor(OfflineAudioContextOptions contextOptions);
18
+ // constructor(unsigned long numberOfChannels, unsigned long length, float sampleRate);
19
+ // Promise<AudioBuffer> startRendering();
20
+ // Promise<undefined> resume();
21
+ // Promise<undefined> suspend(double suspendTime);
22
+ // readonly attribute unsigned long length;
23
+ // attribute EventHandler oncomplete;
11
24
 
12
- class OfflineAudioContext extends BaseAudioContext {
25
+ module.exports = function patchOfflineAudioContext(jsExport, nativeBinding) {
26
+ class OfflineAudioContext extends jsExport.BaseAudioContext {
13
27
  constructor(...args) {
14
- // handle initialisation with either an options object or a sequence of parameters
28
+ if (arguments.length < 1) {
29
+ throw new TypeError(`Failed to construct 'OfflineAudioContext': 1 argument required, but only ${arguments.length} present`);
30
+ }
31
+
15
32
  // https://webaudio.github.io/web-audio-api/#dom-offlineaudiocontext-constructor-contextoptions-contextoptions
16
- if (isPlainObject(args[0]) && 'length' in args[0] && 'sampleRate' in args[0]
17
- ) {
18
- let { numberOfChannels, length, sampleRate } = args[0];
19
- if (numberOfChannels === undefined) {
20
- numberOfChannels = 1;
33
+ if (arguments.length === 1) {
34
+ const options = args[0];
35
+
36
+ if (typeof options !== 'object') {
37
+ throw new TypeError(`Failed to construct 'OfflineAudioContext': argument 1 is not of type 'OfflineAudioContextOptions'`);
38
+ }
39
+
40
+ if (options.length === undefined) {
41
+ throw new TypeError(`Failed to construct 'OfflineAudioContext': Failed to read the 'length' property from 'OfflineAudioContextOptions': Required member is undefined.`);
42
+ }
43
+
44
+ if (options.sampleRate === undefined) {
45
+ throw new TypeError(`Failed to construct 'OfflineAudioContext': Failed to read the 'sampleRate' property from 'OfflineAudioContextOptions': Required member is undefined.`);
21
46
  }
22
- args = [numberOfChannels, length, sampleRate];
47
+
48
+ if (options.numberOfChannels === undefined) {
49
+ options.numberOfChannels = 1;
50
+ }
51
+
52
+ args = [
53
+ options.numberOfChannels,
54
+ options.length,
55
+ options.sampleRate
56
+ ];
57
+ }
58
+
59
+ let [numberOfChannels, length, sampleRate] = args;
60
+
61
+ numberOfChannels = conversions['unsigned long'](numberOfChannels, {
62
+ enforceRange: true,
63
+ context: `Failed to construct 'OfflineAudioContext': Failed to read the 'numberOfChannels' property from OfflineContextOptions; The provided value (${numberOfChannels})`
64
+ });
65
+
66
+ length = conversions['unsigned long'](length, {
67
+ enforceRange: true,
68
+ context: `Failed to construct 'OfflineAudioContext': Failed to read the 'length' property from OfflineContextOptions; The provided value (${length})`
69
+ });
70
+
71
+ sampleRate = conversions['float'](sampleRate, {
72
+ context: `Failed to construct 'OfflineAudioContext': Failed to read the 'sampleRate' property from OfflineContextOptions; The provided value (${sampleRate})`
73
+ });
74
+
75
+ let napiObj;
76
+
77
+ try {
78
+ napiObj = new nativeBinding.OfflineAudioContext(numberOfChannels, length, sampleRate);
79
+ } catch (err) {
80
+ throwSanitizedError(err);
23
81
  }
24
82
 
25
- const [numberOfChannels, length, sampleRate] = args;
83
+ super({ [kNapiObj]: napiObj });
84
+ }
26
85
 
27
- if (!isPositiveInt(numberOfChannels)) {
28
- throw new TypeError(`Invalid value for numberOfChannels: ${numberOfChannels}`);
29
- } else if (!isPositiveInt(length)) {
30
- throw new TypeError(`Invalid value for length: ${length}`);
31
- } else if (!isPositiveNumber(sampleRate)) {
32
- throw new TypeError(`Invalid value for sampleRate: ${sampleRate}`);
86
+ get length() {
87
+ if (!(this instanceof OfflineAudioContext)) {
88
+ throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'OfflineAudioContext'");
33
89
  }
34
90
 
35
- super(numberOfChannels, length, sampleRate);
91
+ return this[kNapiObj].length;
92
+ }
36
93
 
37
- // EventTargetMixin has been called so EventTargetMixin[kDispatchEvent] is
38
- // bound to this, then we can safely finalize event target initialization
39
- super.__initEventTarget__();
94
+ get oncomplete() {
95
+ if (!(this instanceof OfflineAudioContext)) {
96
+ throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'OfflineAudioContext'");
97
+ }
98
+
99
+ return this._complete || null;
100
+ }
101
+
102
+ set oncomplete(value) {
103
+ if (!(this instanceof OfflineAudioContext)) {
104
+ throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'OfflineAudioContext'");
105
+ }
106
+
107
+ if (isFunction(value) || value === null) {
108
+ this._complete = value;
109
+ }
40
110
  }
41
111
 
42
112
  async startRendering() {
43
- const renderedBuffer = await super.startRendering();
113
+ if (!(this instanceof OfflineAudioContext)) {
114
+ throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'OfflineAudioContext'");
115
+ }
116
+
117
+ // Lazily register event callback on rust side
118
+ bridgeEventTarget(this);
44
119
 
45
- // We do this here, so that we can just share the same audioBuffer instance.
46
- // This also simplifies code on the rust side as we don't need to deal
47
- // with the OfflineAudioCompletionEvent.
120
+ let nativeAudioBuffer;
121
+
122
+ try {
123
+ nativeAudioBuffer = await this[kNapiObj].startRendering();
124
+ } catch (err) {
125
+ throwSanitizedError(err);
126
+ }
127
+
128
+ const audioBuffer = new jsExport.AudioBuffer({ [kNapiObj]: nativeAudioBuffer });
129
+
130
+ // We dispatch the complete event manually to simplify the sharing of the
131
+ // `AudioBuffer` instance. This also simplifies code on the rust side as
132
+ // we don't need to deal with the `OfflineAudioCompletionEvent` type.
48
133
  const event = new Event('complete');
49
- event.renderedBuffer = renderedBuffer;
50
- this.dispatchEvent(event)
134
+ event.renderedBuffer = audioBuffer;
51
135
 
52
- return renderedBuffer;
136
+ if (isFunction(this[`oncomplete`])) {
137
+ this[`oncomplete`](event);
138
+ }
139
+
140
+ this.dispatchEvent(event);
141
+
142
+ return audioBuffer;
143
+ }
144
+
145
+ async resume() {
146
+ if (!(this instanceof OfflineAudioContext)) {
147
+ throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'OfflineAudioContext'");
148
+ }
149
+
150
+ try {
151
+ await this[kNapiObj].resume();
152
+ } catch (err) {
153
+ throwSanitizedError(err);
154
+ }
155
+ }
156
+
157
+ async suspend(suspendTime) {
158
+ if (!(this instanceof OfflineAudioContext)) {
159
+ throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'OfflineAudioContext'");
160
+ }
161
+
162
+ if (arguments.length < 1) {
163
+ throw new TypeError(`Failed to execute 'suspend' on 'OfflineAudioContext': 1 argument required, but only ${arguments.length} present`);
164
+ }
165
+
166
+ suspendTime = conversions['double'](suspendTime, {
167
+ context: `Failed to execute 'suspend' on 'OfflineAudioContext': argument 1`,
168
+ });
169
+
170
+ try {
171
+ await this[kNapiObj].suspend(suspendTime);
172
+ } catch (err) {
173
+ throwSanitizedError(err);
174
+ }
53
175
  }
54
176
  }
55
177
 
178
+ Object.defineProperties(OfflineAudioContext, {
179
+ length: {
180
+ __proto__: null,
181
+ writable: false,
182
+ enumerable: false,
183
+ configurable: true,
184
+ value: 1,
185
+ },
186
+ });
187
+
188
+ Object.defineProperties(OfflineAudioContext.prototype, {
189
+ [Symbol.toStringTag]: {
190
+ __proto__: null,
191
+ writable: false,
192
+ enumerable: false,
193
+ configurable: true,
194
+ value: 'OfflineAudioContext',
195
+ },
196
+
197
+ length: kEnumerableProperty,
198
+ oncomplete: kEnumerableProperty,
199
+ startRendering: kEnumerableProperty,
200
+ resume: kEnumerableProperty,
201
+ suspend: kEnumerableProperty,
202
+ });
203
+
56
204
  return OfflineAudioContext;
57
205
  };