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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..351ce67bef3b85a619b954913a96deb71c1c7bdd
--- /dev/null
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScopeTest.cpp
@@ -0,0 +1,291 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "modules/webaudio/AudioWorkletGlobalScope.h"
+
+#include "bindings/core/v8/ScriptSourceCode.h"
+#include "bindings/core/v8/ScriptState.h"
+#include "bindings/core/v8/ScriptValue.h"
+#include "bindings/core/v8/SourceLocation.h"
+#include "bindings/core/v8/ToV8.h"
+#include "bindings/core/v8/V8Binding.h"
+#include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/V8BindingMacros.h"
+#include "bindings/core/v8/V8GCController.h"
+#include "bindings/core/v8/V8ObjectConstructor.h"
+#include "bindings/core/v8/WorkerOrWorkletScriptController.h"
+#include "core/workers/WorkerBackingThread.h"
+#include "core/workers/WorkerReportingProxy.h"
+#include "core/workers/WorkerThreadStartupData.h"
+#include "modules/webaudio/AudioBuffer.h"
+#include "modules/webaudio/AudioWorkletProcessor.h"
+#include "modules/webaudio/AudioWorkletProcessorDefinition.h"
+#include "modules/webaudio/AudioWorkletThread.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+
+static const size_t kRenderQuantumFrames = 128;
+
+// This is a typical sample rate.
+static const float kTestingSampleRate = 44100;
+
+// A null WorkerReportingProxy, supplied when creating AudioWorkletThreads.
+class TestAudioWorkletReportingProxy : public WorkerReportingProxy {
+ public:
+ static std::unique_ptr<TestAudioWorkletReportingProxy> create() {
+ return WTF::wrapUnique(new TestAudioWorkletReportingProxy());
+ }
+
+ // (Empty) WorkerReportingProxy implementation:
+ void countFeature(UseCounter::Feature) override {}
+ void countDeprecation(UseCounter::Feature) override {}
+ void reportException(const String& errorMessage,
+ std::unique_ptr<SourceLocation>,
+ int exceptionId) override {}
+ void reportConsoleMessage(MessageSource,
+ MessageLevel,
+ const String& message,
+ SourceLocation*) override {}
+ void postMessageToPageInspector(const String&) override {}
+ void didEvaluateWorkerScript(bool success) override {}
+ void didCloseWorkerGlobalScope() override {}
+ void willDestroyWorkerGlobalScope() override {}
+ void didTerminateWorkerThread() override {}
+
+ private:
+ TestAudioWorkletReportingProxy() {}
+};
+
+} // namespace
+
+class AudioWorkletGlobalScopeTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ AudioWorkletThread::createSharedBackingThreadForTest();
+ m_reportingProxy = TestAudioWorkletReportingProxy::create();
+ m_securityOrigin =
+ SecurityOrigin::create(KURL(ParsedURLString, "http://fake.url/"));
+ }
+
+ void TearDown() override { AudioWorkletThread::clearSharedBackingThread(); }
+
+ std::unique_ptr<AudioWorkletThread> createAudioWorkletThread() {
+ std::unique_ptr<AudioWorkletThread> thread =
+ AudioWorkletThread::create(nullptr, *m_reportingProxy);
+ thread->start(
+ WorkerThreadStartupData::create(
+ KURL(ParsedURLString, "http://fake.url/"), "fake user agent", "",
+ nullptr, DontPauseWorkerGlobalScopeOnStart, nullptr, "",
+ m_securityOrigin.get(), nullptr, WebAddressSpaceLocal, nullptr,
+ nullptr, WorkerV8Settings::Default()),
+ ParentFrameTaskRunners::create(nullptr));
+ return thread;
+ }
+
+ void runBasicTest(WorkerThread* thread) {
+ WaitableEvent waitableEvent;
+ thread->postTask(
+ BLINK_FROM_HERE,
+ crossThreadBind(
+ &AudioWorkletGlobalScopeTest::runBasicTestOnWorkletThread,
+ crossThreadUnretained(this), crossThreadUnretained(thread),
+ crossThreadUnretained(&waitableEvent)));
+ waitableEvent.wait();
+ }
+
+ void runSimpleProcessTest(WorkerThread* thread) {
+ WaitableEvent waitableEvent;
+ thread->postTask(
+ BLINK_FROM_HERE,
+ crossThreadBind(
+ &AudioWorkletGlobalScopeTest::runSimpleProcessTestOnWorkletThread,
+ crossThreadUnretained(this), crossThreadUnretained(thread),
+ crossThreadUnretained(&waitableEvent)));
+ waitableEvent.wait();
+ }
+
+ void runParsingTest(WorkerThread* thread) {
+ WaitableEvent waitableEvent;
+ thread->postTask(
+ BLINK_FROM_HERE,
+ crossThreadBind(
+ &AudioWorkletGlobalScopeTest::runParsingTestOnWorkletThread,
+ crossThreadUnretained(this), crossThreadUnretained(thread),
+ crossThreadUnretained(&waitableEvent)));
+ waitableEvent.wait();
+ }
+
+ private:
+ // Test if AudioWorkletGlobalScope and V8 components (ScriptState, Isolate)
+ // are properly instantiated. Runs a simple processor registration and check
+ // if the class definition is correctly registered, then instantiate an
+ // AudioWorkletProcessor instance from the definition.
+ void runBasicTestOnWorkletThread(WorkerThread* thread,
+ WaitableEvent* waitEvent) {
+ EXPECT_TRUE(thread->isCurrentThread());
+
+ AudioWorkletGlobalScope* globalScope =
+ static_cast<AudioWorkletGlobalScope*>(thread->globalScope());
+ EXPECT_TRUE(globalScope);
+ EXPECT_TRUE(globalScope->isAudioWorkletGlobalScope());
+
+ ScriptState* scriptState =
+ globalScope->scriptController()->getScriptState();
+ EXPECT_TRUE(scriptState);
+
+ v8::Isolate* isolate = scriptState->isolate();
+ EXPECT_TRUE(isolate);
+
+ ScriptState::Scope scope(scriptState);
+
+ globalScope->scriptController()->evaluate(ScriptSourceCode(
+ R"JS(
+ registerProcessor('testProcessor', class {
+ constructor () {}
+ process () {}
+ });
+ )JS"));
+
+ AudioWorkletProcessorDefinition* definition =
+ globalScope->findDefinition("testProcessor");
+ EXPECT_TRUE(definition);
+ EXPECT_EQ(definition->name(), "testProcessor");
+ EXPECT_TRUE(definition->constructorLocal(isolate)->IsFunction());
+ EXPECT_TRUE(definition->processLocal(isolate)->IsFunction());
+
+ AudioWorkletProcessor* processor =
+ globalScope->createInstance("testProcessor");
+ EXPECT_TRUE(processor);
+ EXPECT_EQ(processor->name(), "testProcessor");
+ EXPECT_TRUE(processor->instanceLocal(isolate)->IsObject());
+
+ waitEvent->signal();
+ }
+
+ // Test if various class definition patterns are parsed correctly.
+ void runParsingTestOnWorkletThread(WorkerThread* thread,
+ WaitableEvent* waitEvent) {
+ EXPECT_TRUE(thread->isCurrentThread());
+
+ AudioWorkletGlobalScope* globalScope =
+ static_cast<AudioWorkletGlobalScope*>(thread->globalScope());
+ ScriptState* scriptState =
+ globalScope->scriptController()->getScriptState();
+
+ ScriptState::Scope scope(scriptState);
+
+ globalScope->scriptController()->evaluate(ScriptSourceCode(
+ R"JS(
+ var class1 = function () {};
+ class1.prototype.process = function () {};
+ registerProcessor('class1', class1);
+
+ var class2 = function () {};
+ class2.prototype = { process: function () {} };
+ registerProcessor('class2', class2);
+
+ var class3 = function () {};
+ Object.defineProperty(class3, 'prototype', {
+ get: function () {
+ return {
+ process: function () {}
+ };
+ }
+ });
+ registerProcessor('class3', class3);
+ )JS"));
+
+ EXPECT_TRUE(globalScope->findDefinition("class1"));
+ EXPECT_TRUE(globalScope->findDefinition("class2"));
+ EXPECT_FALSE(globalScope->findDefinition("class3"));
+
+ waitEvent->signal();
+ }
+
+ // Test if the invocation of process() method in AudioWorkletProcessor and
+ // AudioWorkletGlobalScope is performed correctly.
+ void runSimpleProcessTestOnWorkletThread(WorkerThread* thread,
+ WaitableEvent* waitEvent) {
+ EXPECT_TRUE(thread->isCurrentThread());
+
+ AudioWorkletGlobalScope* globalScope =
+ static_cast<AudioWorkletGlobalScope*>(thread->globalScope());
+ ScriptState* scriptState =
+ globalScope->scriptController()->getScriptState();
+
+ ScriptState::Scope scope(scriptState);
+
+ globalScope->scriptController()->evaluate(ScriptSourceCode(
+ R"JS(
+ registerProcessor('testProcessor', class {
+ constructor () {
+ this.constant = 1;
+ }
+ process (input, output) {
+ let inputChannelData = input.getChannelData(0);
+ let outputChannelData = output.getChannelData(0);
+ for (let i = 0; i < input.length; ++i) {
+ outputChannelData[i] = inputChannelData[i] + this.constant;
+ }
+ }
+ }
+ )
+ )JS"));
+
+ AudioWorkletProcessor* processor =
+ globalScope->createInstance("testProcessor");
+ EXPECT_TRUE(processor);
+
+ AudioBuffer* inputBuffer =
+ AudioBuffer::create(1, kRenderQuantumFrames, kTestingSampleRate);
+ AudioBuffer* outputBuffer =
+ AudioBuffer::create(1, kRenderQuantumFrames, kTestingSampleRate);
+ DOMFloat32Array* inputChannelData = inputBuffer->getChannelData(0);
+ float* inputArrayData = inputChannelData->data();
+ EXPECT_TRUE(inputArrayData);
+ DOMFloat32Array* outputChannelData = outputBuffer->getChannelData(0);
+ float* outputArrayData = outputChannelData->data();
+ EXPECT_TRUE(outputArrayData);
+
+ // Fill |inputBuffer| with 1 and zero out |outputBuffer|.
+ std::fill(inputArrayData, inputArrayData + inputBuffer->length(), 1);
+ outputBuffer->zero();
+
+ // Then invoke the process() method to perform JS buffer manipulation. The
+ // output buffer should contain a constant value of 2.
+ processor->process(inputBuffer, outputBuffer);
+ for (unsigned i = 0; i < outputBuffer->length(); ++i) {
+ EXPECT_EQ(outputArrayData[i], 2);
+ }
+
+ waitEvent->signal();
+ }
+
+ RefPtr<SecurityOrigin> m_securityOrigin;
+ std::unique_ptr<WorkerReportingProxy> m_reportingProxy;
+};
+
+TEST_F(AudioWorkletGlobalScopeTest, Basic) {
+ std::unique_ptr<AudioWorkletThread> thread = createAudioWorkletThread();
+ runBasicTest(thread.get());
+ thread->terminateAndWait();
+}
+
+TEST_F(AudioWorkletGlobalScopeTest, Parsing) {
+ std::unique_ptr<AudioWorkletThread> thread = createAudioWorkletThread();
+ runParsingTest(thread.get());
+ thread->terminateAndWait();
+}
+
+TEST_F(AudioWorkletGlobalScopeTest, BufferProcessing) {
+ std::unique_ptr<AudioWorkletThread> thread = createAudioWorkletThread();
+ runSimpleProcessTest(thread.get());
+ thread->terminateAndWait();
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698