Chromium Code Reviews| Index: third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp |
| diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp |
| index 33abafe5dd2497fded72ea08c2b587cd44bcadeb..2b8d6760387930e74243d0b6f841f5784a9f7ff2 100644 |
| --- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp |
| +++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp |
| @@ -4,6 +4,15 @@ |
| #include "modules/webaudio/AudioWorkletGlobalScope.h" |
| +#include "bindings/core/v8/ToV8.h" |
| +#include "bindings/core/v8/V8Binding.h" |
| +#include "bindings/core/v8/V8BindingMacros.h" |
| +#include "bindings/core/v8/V8ObjectConstructor.h" |
| +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" |
| +#include "core/dom/ExceptionCode.h" |
| +#include "modules/webaudio/AudioBuffer.h" |
| +#include "modules/webaudio/AudioWorkletProcessor.h" |
| +#include "modules/webaudio/AudioWorkletProcessorDefinition.h" |
| #include "platform/weborigin/SecurityOrigin.h" |
| namespace blink { |
| @@ -32,4 +41,157 @@ AudioWorkletGlobalScope::AudioWorkletGlobalScope( |
| AudioWorkletGlobalScope::~AudioWorkletGlobalScope() {} |
| +void AudioWorkletGlobalScope::dispose() { |
| + DCHECK(isContextThread()); |
| + m_processorDefinitionMap.clear(); |
| + m_processorInstances.clear(); |
| + ThreadedWorkletGlobalScope::dispose(); |
| +} |
| + |
| +void AudioWorkletGlobalScope::registerProcessor( |
| + const String& name, |
| + const ScriptValue& classDefinition, |
| + ExceptionState& exceptionState) { |
| + DCHECK(isContextThread()); |
| + |
| + if (m_processorDefinitionMap.contains(name)) { |
| + exceptionState.throwDOMException( |
| + NotSupportedError, |
| + "A class with name:'" + name + "' is already registered."); |
| + return; |
| + } |
| + |
| + if (name.isEmpty()) { |
|
Raymond Toy
2017/03/17 16:45:32
I think this isn't stated in the spec. File an is
hongchan
2017/03/20 17:03:32
Done.
|
| + exceptionState.throwTypeError("The empty string is not a valid name."); |
| + return; |
| + } |
| + |
| + v8::Isolate* isolate = scriptController()->getScriptState()->isolate(); |
| + v8::Local<v8::Context> context = |
| + scriptController()->getScriptState()->context(); |
| + |
| + DCHECK(classDefinition.v8Value()->IsFunction()); |
| + v8::Local<v8::Function> classDefinitionLocal = |
| + classDefinition.v8Value().As<v8::Function>(); |
| + |
| + // This does not work. prototypeValue is not valid after this line. |
| + // v8::Local<v8::Value> prototypeValue = constructorLocal->GetPrototype(); |
|
Raymond Toy
2017/03/17 16:45:31
Clarify what you mean by "not valid" after which l
hongchan
2017/03/20 17:03:32
I am going to remove this line since it just does
|
| + |
| + v8::Local<v8::Value> prototypeValueLocal; |
| + bool prototypeExtraced = |
|
Raymond Toy
2017/03/17 16:45:31
Did you mean "prototypeExtracted" instead of "prot
hongchan
2017/03/20 17:03:31
Typo! Done.
|
| + classDefinitionLocal->Get(context, v8String(isolate, "prototype")) |
| + .ToLocal(&prototypeValueLocal); |
| + DCHECK(prototypeExtraced); |
| + |
| + if (prototypeValueLocal->IsNullOrUndefined()) { |
|
Raymond Toy
2017/03/17 16:45:31
The spec doesn't require the distinction between n
hongchan
2017/03/20 17:03:32
Hmm. This is a good point. The class definition mu
|
| + exceptionState.throwTypeError( |
| + "The 'prototype' object on the class does not exist."); |
| + return; |
| + } |
| + |
| + if (!prototypeValueLocal->IsObject()) { |
| + exceptionState.throwTypeError( |
| + "The 'prototype' property on the class is not an object."); |
| + return; |
| + } |
| + |
| + v8::Local<v8::Object> prototypeObjectLocal = |
| + prototypeValueLocal.As<v8::Object>(); |
| + |
| + v8::Local<v8::Value> processValueLocal; |
| + bool processExtracted = |
| + prototypeObjectLocal->Get(context, v8String(isolate, "process")) |
| + .ToLocal(&processValueLocal); |
| + DCHECK(processExtracted); |
| + |
| + if (processValueLocal->IsNullOrUndefined()) { |
| + exceptionState.throwTypeError( |
| + "The 'process' function does not exist in the prototype."); |
| + return; |
| + } |
| + |
| + if (!processValueLocal->IsFunction()) { |
| + exceptionState.throwTypeError( |
| + "The 'process' property on the prototype is not a function."); |
| + return; |
| + } |
| + |
| + v8::Local<v8::Function> processFunctionLocal = |
| + processValueLocal.As<v8::Function>(); |
| + |
| + AudioWorkletProcessorDefinition* definition = |
|
Raymond Toy
2017/03/17 16:45:31
DCHECK(definition), just to be sure it was created
hongchan
2017/03/20 17:03:32
DCHECK is good enough here, I think.
|
| + AudioWorkletProcessorDefinition::create( |
| + isolate, name, classDefinitionLocal, processFunctionLocal); |
| + |
| + m_processorDefinitionMap.set(name, definition); |
| +} |
| + |
| +AudioWorkletProcessor* AudioWorkletGlobalScope::createInstance( |
| + const String& name) { |
| + DCHECK(isContextThread()); |
| + |
| + AudioWorkletProcessorDefinition* definition = findDefinition(name); |
| + if (!definition) |
| + return nullptr; |
| + |
| + // V8 object instance construction: this construction process is here to make |
| + // the AudioWorkletProcessor class a thin wrapper of V8::Object instance. |
| + v8::Isolate* isolate = scriptController()->getScriptState()->isolate(); |
| + v8::Local<v8::Object> instanceLocal; |
| + if (!V8ObjectConstructor::newInstance(isolate, |
| + definition->constructorLocal(isolate)) |
| + .ToLocal(&instanceLocal)) { |
| + return nullptr; |
| + } |
| + |
| + AudioWorkletProcessor* processor = AudioWorkletProcessor::create(this, name); |
|
Raymond Toy
2017/03/17 16:45:31
DCHECK(processor)?
hongchan
2017/03/20 17:03:32
Done.
|
| + processor->setInstance(isolate, instanceLocal); |
| + m_processorInstances.push_back(processor); |
| + |
| + return processor; |
| +} |
| + |
| +bool AudioWorkletGlobalScope::process(AudioWorkletProcessor* processor, |
| + AudioBuffer* inputBuffer, |
| + AudioBuffer* outputBuffer) { |
|
Raymond Toy
2017/03/17 16:45:31
DCHECK (or CHECK) that input pointers are not null
hongchan
2017/03/20 17:03:32
Done.
|
| + ScriptState* scriptState = scriptController()->getScriptState(); |
| + ScriptState::Scope scope(scriptState); |
| + |
| + v8::Isolate* isolate = scriptState->isolate(); |
| + AudioWorkletProcessorDefinition* definition = |
| + findDefinition(processor->name()); |
| + DCHECK(definition); |
| + |
| + v8::Local<v8::Value> argv[] = { |
| + ToV8(inputBuffer, scriptState->context()->Global(), isolate), |
| + ToV8(outputBuffer, scriptState->context()->Global(), isolate)}; |
| + |
| + v8::TryCatch block(isolate); |
| + block.SetVerbose(true); |
|
Raymond Toy
2017/03/17 16:45:31
Being unfamiliar with this v8 stuff, what does Set
hongchan
2017/03/20 17:03:32
Done.
|
| + |
| + // Perform JS function process() in AudioWorkletProcessor instance. The actual |
| + // V8 operation happens here to make the AudioWorkletProcessor class a thin |
| + // wrapper of v8::Object instance. |
| + V8ScriptRunner::callFunction( |
| + definition->processLocal(isolate), scriptState->getExecutionContext(), |
| + processor->instanceLocal(isolate), WTF_ARRAY_LENGTH(argv), argv, isolate); |
| + |
| + if (block.HasCaught()) { |
|
Raymond Toy
2017/03/17 16:45:31
Maybe replace lines 179-183 with
return !block.Ha
hongchan
2017/03/20 17:03:31
Done.
|
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +AudioWorkletProcessorDefinition* AudioWorkletGlobalScope::findDefinition( |
| + const String& name) { |
| + return m_processorDefinitionMap.at(name); |
| +} |
| + |
| +DEFINE_TRACE(AudioWorkletGlobalScope) { |
| + visitor->trace(m_processorDefinitionMap); |
| + visitor->trace(m_processorInstances); |
| + ThreadedWorkletGlobalScope::trace(visitor); |
| +} |
| + |
| } // namespace blink |