Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(423)

Side by Side Diff: third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp

Issue 2727733002: Implement AudioWorkletProcessor interface (Closed)
Patch Set: Addressing feedback from rtoy@ Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "modules/webaudio/AudioWorkletGlobalScope.h"
6
7 #include "bindings/core/v8/ScriptSourceCode.h"
8 #include "bindings/core/v8/ScriptState.h"
9 #include "bindings/core/v8/ScriptValue.h"
10 #include "bindings/core/v8/SourceLocation.h"
11 #include "bindings/core/v8/ToV8.h"
12 #include "bindings/core/v8/V8Binding.h"
13 #include "bindings/core/v8/V8BindingForTesting.h"
14 #include "bindings/core/v8/V8BindingMacros.h"
15 #include "bindings/core/v8/V8GCController.h"
16 #include "bindings/core/v8/V8ObjectConstructor.h"
17 #include "bindings/core/v8/WorkerOrWorkletScriptController.h"
18 #include "core/workers/WorkerBackingThread.h"
19 #include "core/workers/WorkerReportingProxy.h"
20 #include "core/workers/WorkerThreadStartupData.h"
21 #include "modules/webaudio/AudioBuffer.h"
22 #include "modules/webaudio/AudioWorkletProcessor.h"
23 #include "modules/webaudio/AudioWorkletProcessorDefinition.h"
24 #include "modules/webaudio/AudioWorkletThread.h"
25 #include "platform/weborigin/SecurityOrigin.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace blink {
29
30 namespace {
31
32 static const size_t kRenderQuantumFrames = 128;
33
34 // This is a typical sample rate.
35 static const float kTestingSampleRate = 44100;
36
37 // A null WorkerReportingProxy, supplied when creating AudioWorkletThreads.
38 class TestAudioWorkletReportingProxy : public WorkerReportingProxy {
39 public:
40 static std::unique_ptr<TestAudioWorkletReportingProxy> create() {
41 return WTF::wrapUnique(new TestAudioWorkletReportingProxy());
42 }
43
44 // (Empty) WorkerReportingProxy implementation:
45 void countFeature(UseCounter::Feature) override {}
46 void countDeprecation(UseCounter::Feature) override {}
47 void reportException(const String& errorMessage,
48 std::unique_ptr<SourceLocation>,
49 int exceptionId) override {}
50 void reportConsoleMessage(MessageSource,
51 MessageLevel,
52 const String& message,
53 SourceLocation*) override {}
54 void postMessageToPageInspector(const String&) override {}
55 void didEvaluateWorkerScript(bool success) override {}
56 void didCloseWorkerGlobalScope() override {}
57 void willDestroyWorkerGlobalScope() override {}
58 void didTerminateWorkerThread() override {}
59
60 private:
61 TestAudioWorkletReportingProxy() {}
62 };
63
64 } // namespace
65
66 class AudioWorkletGlobalScopeTest : public ::testing::Test {
67 public:
68 void SetUp() override {
69 AudioWorkletThread::createSharedBackingThreadForTest();
70 m_reportingProxy = TestAudioWorkletReportingProxy::create();
71 m_securityOrigin =
72 SecurityOrigin::create(KURL(ParsedURLString, "http://fake.url/"));
73 }
74
75 void TearDown() override { AudioWorkletThread::clearSharedBackingThread(); }
76
77 std::unique_ptr<AudioWorkletThread> createAudioWorkletThread() {
78 std::unique_ptr<AudioWorkletThread> thread =
79 AudioWorkletThread::create(nullptr, *m_reportingProxy);
80 thread->start(
81 WorkerThreadStartupData::create(
82 KURL(ParsedURLString, "http://fake.url/"), "fake user agent", "",
83 nullptr, DontPauseWorkerGlobalScopeOnStart, nullptr, "",
84 m_securityOrigin.get(), nullptr, WebAddressSpaceLocal, nullptr,
85 nullptr, WorkerV8Settings::Default()),
86 ParentFrameTaskRunners::create(nullptr));
87 return thread;
88 }
89
90 void runBasicTest(WorkerThread* thread) {
91 WaitableEvent waitableEvent;
92 thread->postTask(
93 BLINK_FROM_HERE,
94 crossThreadBind(
95 &AudioWorkletGlobalScopeTest::runBasicTestOnWorkletThread,
96 crossThreadUnretained(this), crossThreadUnretained(thread),
97 crossThreadUnretained(&waitableEvent)));
98 waitableEvent.wait();
99 }
100
101 void runSimpleProcessTest(WorkerThread* thread) {
102 WaitableEvent waitableEvent;
103 thread->postTask(
104 BLINK_FROM_HERE,
105 crossThreadBind(
106 &AudioWorkletGlobalScopeTest::runSimpleProcessTestOnWorkletThread,
107 crossThreadUnretained(this), crossThreadUnretained(thread),
108 crossThreadUnretained(&waitableEvent)));
109 waitableEvent.wait();
110 }
111
112 void runParsingTest(WorkerThread* thread) {
113 WaitableEvent waitableEvent;
114 thread->postTask(
115 BLINK_FROM_HERE,
116 crossThreadBind(
117 &AudioWorkletGlobalScopeTest::runParsingTestOnWorkletThread,
118 crossThreadUnretained(this), crossThreadUnretained(thread),
119 crossThreadUnretained(&waitableEvent)));
120 waitableEvent.wait();
121 }
122
123 private:
124 // Test if AudioWorkletGlobalScope and V8 components (ScriptState, Isolate)
125 // are properly instantiated. Runs a simple processor registration and check
126 // if the class definition is correctly registered, then instantiate an
127 // AudioWorkletProcessor instance from the definition.
128 void runBasicTestOnWorkletThread(WorkerThread* thread,
129 WaitableEvent* waitEvent) {
130 EXPECT_TRUE(thread->isCurrentThread());
131
132 AudioWorkletGlobalScope* globalScope =
133 static_cast<AudioWorkletGlobalScope*>(thread->globalScope());
134 EXPECT_TRUE(globalScope);
135 EXPECT_TRUE(globalScope->isAudioWorkletGlobalScope());
136
137 ScriptState* scriptState =
138 globalScope->scriptController()->getScriptState();
139 EXPECT_TRUE(scriptState);
140
141 v8::Isolate* isolate = scriptState->isolate();
142 EXPECT_TRUE(isolate);
143
144 ScriptState::Scope scope(scriptState);
145
146 globalScope->scriptController()->evaluate(ScriptSourceCode(
147 R"JS(
148 registerProcessor('testProcessor', class {
149 constructor () {}
150 process () {}
151 });
152 )JS"));
153
154 AudioWorkletProcessorDefinition* definition =
155 globalScope->findDefinition("testProcessor");
156 EXPECT_TRUE(definition);
157 EXPECT_EQ(definition->name(), "testProcessor");
158 EXPECT_TRUE(definition->constructorLocal(isolate)->IsFunction());
159 EXPECT_TRUE(definition->processLocal(isolate)->IsFunction());
160
161 AudioWorkletProcessor* processor =
162 globalScope->createInstance("testProcessor");
163 EXPECT_TRUE(processor);
164 EXPECT_EQ(processor->name(), "testProcessor");
165 EXPECT_TRUE(processor->instanceLocal(isolate)->IsObject());
166
167 waitEvent->signal();
168 }
169
170 // Test if various class definition patterns are parsed correctly.
171 void runParsingTestOnWorkletThread(WorkerThread* thread,
172 WaitableEvent* waitEvent) {
173 EXPECT_TRUE(thread->isCurrentThread());
174
175 AudioWorkletGlobalScope* globalScope =
176 static_cast<AudioWorkletGlobalScope*>(thread->globalScope());
177 ScriptState* scriptState =
178 globalScope->scriptController()->getScriptState();
179
180 ScriptState::Scope scope(scriptState);
181
182 globalScope->scriptController()->evaluate(ScriptSourceCode(
183 R"JS(
184 var class1 = function () {};
185 class1.prototype.process = function () {};
186 registerProcessor('class1', class1);
187
188 var class2 = function () {};
189 class2.prototype = { process: function () {} };
190 registerProcessor('class2', class2);
191
192 var class3 = function () {};
193 Object.defineProperty(class3, 'prototype', {
194 get: function () {
195 return {
196 process: function () {}
197 };
198 }
199 });
200 registerProcessor('class3', class3);
201 )JS"));
202
203 EXPECT_TRUE(globalScope->findDefinition("class1"));
204 EXPECT_TRUE(globalScope->findDefinition("class2"));
205 EXPECT_FALSE(globalScope->findDefinition("class3"));
206
207 waitEvent->signal();
208 }
209
210 // Test if the invocation of process() method in AudioWorkletProcessor and
211 // AudioWorkletGlobalScope is performed correctly.
212 void runSimpleProcessTestOnWorkletThread(WorkerThread* thread,
213 WaitableEvent* waitEvent) {
214 EXPECT_TRUE(thread->isCurrentThread());
215
216 AudioWorkletGlobalScope* globalScope =
217 static_cast<AudioWorkletGlobalScope*>(thread->globalScope());
218 ScriptState* scriptState =
219 globalScope->scriptController()->getScriptState();
220
221 ScriptState::Scope scope(scriptState);
222
223 globalScope->scriptController()->evaluate(ScriptSourceCode(
224 R"JS(
225 registerProcessor('testProcessor', class {
226 constructor () {
227 this.constant = 1;
228 }
229 process (input, output) {
230 let inputChannelData = input.getChannelData(0);
231 let outputChannelData = output.getChannelData(0);
232 for (let i = 0; i < input.length; ++i) {
233 outputChannelData[i] = inputChannelData[i] + this.constant;
234 }
235 }
236 }
237 )
238 )JS"));
239
240 AudioWorkletProcessor* processor =
241 globalScope->createInstance("testProcessor");
242 EXPECT_TRUE(processor);
243
244 AudioBuffer* inputBuffer =
245 AudioBuffer::create(1, kRenderQuantumFrames, kTestingSampleRate);
246 AudioBuffer* outputBuffer =
247 AudioBuffer::create(1, kRenderQuantumFrames, kTestingSampleRate);
248 DOMFloat32Array* inputChannelData = inputBuffer->getChannelData(0);
249 float* inputArrayData = inputChannelData->data();
250 EXPECT_TRUE(inputArrayData);
251 DOMFloat32Array* outputChannelData = outputBuffer->getChannelData(0);
252 float* outputArrayData = outputChannelData->data();
253 EXPECT_TRUE(outputArrayData);
254
255 // Fill |inputBuffer| with 1 and zero out |outputBuffer|.
256 std::fill(inputArrayData, inputArrayData + inputBuffer->length(), 1);
257 outputBuffer->zero();
258
259 // Then invoke the process() method to perform JS buffer manipulation. The
260 // output buffer should contain a constant value of 2.
261 processor->process(inputBuffer, outputBuffer);
262 for (unsigned i = 0; i < outputBuffer->length(); ++i) {
263 EXPECT_EQ(outputArrayData[i], 2);
264 }
265
266 waitEvent->signal();
267 }
268
269 RefPtr<SecurityOrigin> m_securityOrigin;
270 std::unique_ptr<WorkerReportingProxy> m_reportingProxy;
271 };
272
273 TEST_F(AudioWorkletGlobalScopeTest, Basic) {
274 std::unique_ptr<AudioWorkletThread> thread = createAudioWorkletThread();
275 runBasicTest(thread.get());
276 thread->terminateAndWait();
277 }
278
279 TEST_F(AudioWorkletGlobalScopeTest, Parsing) {
280 std::unique_ptr<AudioWorkletThread> thread = createAudioWorkletThread();
281 runParsingTest(thread.get());
282 thread->terminateAndWait();
283 }
284
285 TEST_F(AudioWorkletGlobalScopeTest, BufferProcessing) {
286 std::unique_ptr<AudioWorkletThread> thread = createAudioWorkletThread();
287 runSimpleProcessTest(thread.get());
288 thread->terminateAndWait();
289 }
290
291 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698