@@ -43,10 +43,32 @@ class WorkletNodeEngine final : public AudioNodeEngine {
43
43
44
44
void NotifyForcedShutdown () override { ReleaseJSResources (); }
45
45
46
+
47
+
48
+
49
+
50
+
51
+
52
+ struct Channels {
53
+ Vector<JS::PersistentRooted<JSObject*>, GUESS_AUDIO_CHANNELS>
54
+ mFloat32Arrays ;
55
+ JS::PersistentRooted<JSObject*> mJSArray ;
56
+
57
+ operator JS::Handle<JSObject*>() const { return mJSArray ; }
58
+ };
59
+ struct Ports {
60
+ Vector<Channels, 1 > mPorts ;
61
+ JS::PersistentRooted<JSObject*> mJSArray ;
62
+ };
63
+
46
64
private:
47
65
void SendProcessorError ();
48
66
49
67
void ReleaseJSResources () {
68
+ mInputs .mPorts .clearAndFree ();
69
+ mOutputs .mPorts .clearAndFree ();
70
+ mInputs .mJSArray .reset ();
71
+ mOutputs .mJSArray .reset ();
50
72
mGlobal = nullptr ;
51
73
mProcessor .reset ();
52
74
}
@@ -60,6 +82,16 @@ class WorkletNodeEngine final : public AudioNodeEngine {
60
82
61
83
62
84
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+ Ports mInputs ;
93
+ Ports mOutputs ;
94
+
63
95
RefPtr<AudioWorkletGlobalScope> mGlobal ;
64
96
JS::PersistentRooted<JSObject*> mProcessor ;
65
97
};
@@ -82,25 +114,135 @@ void WorkletNodeEngine::SendProcessorError() {
82
114
void WorkletNodeEngine::ConstructProcessor (
83
115
AudioWorkletImpl* aWorkletImpl, const nsAString& aName,
84
116
NotNull<StructuredCloneHolder*> aOptionsSerialization) {
117
+ MOZ_ASSERT (mInputs .mPorts .empty () && mOutputs .mPorts .empty ());
85
118
RefPtr<AudioWorkletGlobalScope> global = aWorkletImpl->GetGlobalScope ();
86
119
MOZ_ASSERT (global);
87
120
JS::RootingContext* cx = RootingCx ();
88
121
mProcessor .init (cx);
89
- if (!global->ConstructProcessor (aName, aOptionsSerialization, &mProcessor )) {
122
+ if (!global->ConstructProcessor (aName, aOptionsSerialization, &mProcessor ) ||
123
+
124
+
125
+ NS_WARN_IF (!mInputs .mPorts .growBy(InputCount())) ||
126
+ NS_WARN_IF(!mOutputs .mPorts .growBy(OutputCount()))) {
90
127
SendProcessorError ();
91
128
return ;
92
129
}
93
130
mGlobal = std::move (global);
131
+ mInputs .mJSArray .init (cx);
132
+ mOutputs .mJSArray .init (cx);
133
+ for (auto & port : mInputs .mPorts ) {
134
+ port.mJSArray .init (cx);
135
+ }
136
+ for (auto & port : mOutputs .mPorts ) {
137
+ port.mJSArray .init (cx);
138
+ }
139
+ }
140
+
141
+
142
+
143
+ template <typename T>
144
+ static bool SetArrayElements (JSContext* aCx, const T& aElements,
145
+ JS::Handle<JSObject*> aArray) {
146
+ for (size_t i = 0 ; i < aElements.length (); ++i) {
147
+ if (!JS_DefineElement (aCx, aArray, i, aElements[i], JSPROP_ENUMERATE)) {
148
+ return false ;
149
+ }
150
+ }
151
+
152
+ return true ;
153
+ }
154
+
155
+ template <typename T>
156
+ static bool PrepareArray (JSContext* aCx, const T& aElements,
157
+ JS::MutableHandle<JSObject*> aArray) {
158
+ size_t length = aElements.length ();
159
+ if (aArray) {
160
+
161
+ uint32_t oldLength;
162
+ if (JS_GetArrayLength (aCx, aArray, &oldLength) &&
163
+ (oldLength == length || JS_SetArrayLength (aCx, aArray, length)) &&
164
+ SetArrayElements (aCx, aElements, aArray)) {
165
+ return true ;
166
+ }
167
+
168
+ JS_ClearPendingException (aCx);
169
+ }
170
+ JSObject* array = JS_NewArrayObject (aCx, length);
171
+ if (NS_WARN_IF(!array)) {
172
+ return false ;
173
+ }
174
+ aArray.set (array);
175
+ return SetArrayElements (aCx, aElements, aArray);
176
+ }
177
+
178
+ enum class ArrayElementInit { None, Zero };
179
+
180
+
181
+
182
+
183
+
184
+
185
+ static bool PrepareBufferArrays (JSContext* aCx, Span<const AudioBlock> aBlocks,
186
+ WorkletNodeEngine::Ports* aPorts,
187
+ ArrayElementInit aInit) {
188
+ for (size_t i = 0 ; i < aBlocks.Length (); ++i) {
189
+ size_t channelCount = aBlocks[i].ChannelCount ();
190
+ WorkletNodeEngine::Channels& portRef = aPorts->mPorts [i];
191
+
192
+ auto & float32ArraysRef = portRef.mFloat32Arrays ;
193
+ for (auto & channelRef : float32ArraysRef) {
194
+ uint32_t length = JS_GetTypedArrayLength (channelRef);
195
+ if (length != WEBAUDIO_BLOCK_SIZE) {
196
+
197
+ JSObject* array = JS_NewFloat32Array (aCx, WEBAUDIO_BLOCK_SIZE);
198
+ if (NS_WARN_IF(!array)) {
199
+ return false ;
200
+ }
201
+ channelRef = array;
202
+ } else if (aInit == ArrayElementInit::Zero) {
203
+
204
+ JS::AutoCheckCannotGC nogc;
205
+ bool isShared;
206
+ float * elementData =
207
+ JS_GetFloat32ArrayData (channelRef, &isShared, nogc);
208
+ MOZ_ASSERT (!isShared);
209
+ std::fill_n (elementData, WEBAUDIO_BLOCK_SIZE, 0 .0f );
210
+ }
211
+ }
212
+
213
+ if (NS_WARN_IF(!float32ArraysRef.reserve (channelCount))) {
214
+ return false ;
215
+ }
216
+ while (float32ArraysRef.length () < channelCount) {
217
+ JSObject* array = JS_NewFloat32Array (aCx, WEBAUDIO_BLOCK_SIZE);
218
+ if (NS_WARN_IF(!array)) {
219
+ return false ;
220
+ }
221
+ float32ArraysRef.infallibleEmplaceBack (aCx, array);
222
+ }
223
+
224
+ float32ArraysRef.shrinkTo (channelCount);
225
+
226
+ if (NS_WARN_IF(!PrepareArray (aCx, float32ArraysRef, &portRef.mJSArray ))) {
227
+ return false ;
228
+ }
229
+ }
230
+
231
+ return !(NS_WARN_IF(!PrepareArray (aCx, aPorts->mPorts , &aPorts->mJSArray )));
232
+ }
233
+
234
+ static void ProduceSilence (Span<AudioBlock> aOutput) {
235
+ for (AudioBlock& output : aOutput) {
236
+ output.SetNull (WEBAUDIO_BLOCK_SIZE);
237
+ }
94
238
}
95
239
96
240
void WorkletNodeEngine::ProcessBlocksOnPorts (AudioNodeStream* aStream,
97
241
Span<const AudioBlock> aInput,
98
242
Span<AudioBlock> aOutput,
99
243
bool * aFinished) {
100
244
if (!mProcessor ) {
101
- for (AudioBlock& output : aOutput) {
102
- output.SetNull (WEBAUDIO_BLOCK_SIZE);
103
- }
245
+ ProduceSilence (aOutput);
104
246
return ;
105
247
}
106
248
@@ -116,6 +258,17 @@ void WorkletNodeEngine::ProcessBlocksOnPorts(AudioNodeStream* aStream,
116
258
output.AllocateChannels (1 );
117
259
}
118
260
}
261
+
262
+ AutoEntryScript aes (mGlobal , " Worklet Process" );
263
+ JSContext* cx = aes.cx ();
264
+
265
+ if (!PrepareBufferArrays (cx, aInput, &mInputs , ArrayElementInit::None) ||
266
+ !PrepareBufferArrays (cx, aOutput, &mOutputs , ArrayElementInit::Zero)) {
267
+
268
+ SendProcessorError ();
269
+ ProduceSilence (aOutput);
270
+ return ;
271
+ }
119
272
}
120
273
121
274
AudioWorkletNode::AudioWorkletNode (AudioContext* aAudioContext,
0 commit comments