Index: third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp |
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0f89d3678e5b934f65c4c4f4e9029b51151bc7bd |
--- /dev/null |
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp |
@@ -0,0 +1,195 @@ |
+// 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/AudioWorkletNode.h" |
+ |
+#include "core/dom/TaskRunnerHelper.h" |
+#include "modules/webaudio/AudioBuffer.h" |
+#include "modules/webaudio/AudioNodeInput.h" |
+#include "modules/webaudio/AudioNodeOutput.h" |
+#include "modules/webaudio/AudioParamDescriptor.h" |
+#include "modules/webaudio/AudioWorkletGlobalScope.h" |
+#include "modules/webaudio/AudioWorkletProcessor.h" |
+#include "modules/webaudio/AudioWorkletProcessorDefinition.h" |
+#include "platform/audio/AudioBus.h" |
+#include "platform/audio/AudioUtilities.h" |
+#include "platform/heap/Persistent.h" |
+ |
+namespace blink { |
+ |
+AudioWorkletHandler::AudioWorkletHandler(AudioNode& node, |
+ float sample_rate, |
+ String name) |
+ : AudioHandler(kNodeTypeAudioWorklet, node, sample_rate) { |
+ DCHECK(IsMainThread()); |
+ |
+ AddInput(); |
+ AddOutput(1); |
+ |
+ // Post a task for the instantiation of corresponding AudioWorkletProcessor. |
+ // This blocks the main thread until the construction is completed. |
+ WaitableEvent doneConstruction; |
+ Context()->GetWorkletMessagingProxy()->CreateProcessorInstance( |
+ name, this, &doneConstruction); |
+ doneConstruction.Wait(); |
+ |
+ DCHECK(processor_); |
+ if (processor_) { |
+ const AudioWorkletProcessorDefinition* definition = |
+ processor_->GetDefinition(); |
+ DCHECK(definition); |
+ |
+ HeapHashMap<String, Member<AudioParam>> audio_param_map; |
+ for (const auto& descriptor : definition->GetAudioParamDescriptors()) { |
+ // A thread-specific isolated copy is necessary since |descriptor| belongs |
+ // to the rendering thread and AudioParams are owned by the main thread. |
+ String param_name = descriptor.name().IsolatedCopy(); |
+ AudioParam* audio_param = AudioParam::Create(*Context(), |
+ kParamTypeAudioWorklet, |
+ descriptor.defaultValue(), |
+ descriptor.minValue(), |
+ descriptor.maxValue()); |
+ DCHECK(audio_param); |
+ audio_param_map.Set(param_name, audio_param); |
+ |
+ // We need another isolated copy of string because AudioParamHandler is |
+ // touched by the rendering thread. |
+ param_handler_map_.Set(param_name.IsolatedCopy(), |
+ audio_param->HandlerExperimental()); |
+ } |
+ |
+ static_cast<AudioWorkletNode&>(node).SetParameterMap( |
+ new AudioParamMap(audio_param_map)); |
+ |
+ // Initialize the handler only when the processor is valid. After this call, |
+ // the handler/processor will get pulled by the rendering thread. |
+ Initialize(); |
+ } |
+} |
+ |
+AudioWorkletHandler::~AudioWorkletHandler() { |
+ processor_->Dispose(); |
+ Uninitialize(); |
+ processor_ = nullptr; |
+} |
+ |
+PassRefPtr<AudioWorkletHandler> AudioWorkletHandler::Create(AudioNode& node, |
+ float sample_rate, |
+ String name) { |
+ return AdoptRef(new AudioWorkletHandler(node, sample_rate, name)); |
+} |
+ |
+void AudioWorkletHandler::Process(size_t frames_to_process) { |
+ AudioBus* output_bus = Output(0).Bus(); |
+ DCHECK(output_bus); |
+ |
+ if (!IsInitialized()) { |
+ output_bus->Zero(); |
+ return; |
+ } |
+ |
+ AudioBuffer* input_buffer = Input(0).IsConnected() |
+ ? AudioBuffer::CreateFromAudioBus(Input(0).Bus()) |
+ : AudioBuffer::Create(1, 128, Context()->sampleRate()); |
+ AudioBuffer* output_buffer = |
+ AudioBuffer::Create(1, 128, Context()->sampleRate()); |
+ |
+ HashMap<String, AudioFloatArray*> audio_param_data_map; |
+ for (const auto& param_name : param_handler_map_.Keys()) { |
+ AudioParamHandler* audio_param_handler = param_handler_map_.at(param_name); |
+ AudioFloatArray* param_values = |
+ new AudioFloatArray(AudioUtilities::kRenderQuantumFrames); |
+ if (audio_param_handler->HasSampleAccurateValues()) { |
+ audio_param_handler->CalculateSampleAccurateValues( |
+ param_values->Data(), frames_to_process); |
+ } else { |
+ std::fill(param_values->Data(), |
+ param_values->Data() + AudioUtilities::kRenderQuantumFrames, |
+ audio_param_handler->Value()); |
+ } |
+ |
+ audio_param_data_map.Set(param_name, param_values); |
+ } |
+ |
+ processor_->Process(input_buffer, output_buffer, audio_param_data_map); |
+ |
+ for (unsigned i = 0; i < 1; ++i) { |
+ memcpy(output_bus->Channel(i)->MutableData(), |
+ output_buffer->getChannelData(i).View()->Data(), |
+ sizeof(float) * frames_to_process); |
+ } |
+} |
+ |
+double AudioWorkletHandler::TailTime() const { |
+ return std::numeric_limits<double>::infinity(); |
+} |
+ |
+double AudioWorkletHandler::LatencyTime() const { |
+ return std::numeric_limits<double>::infinity(); |
+} |
+ |
+void AudioWorkletHandler::SetProcessorOnRenderingThread( |
+ AudioWorkletProcessor* processor) { |
+ DCHECK(!IsMainThread()); |
+ processor_ = processor; |
+} |
+ |
+// ---------------------------------------------------------------- |
+ |
+AudioWorkletNode::AudioWorkletNode(BaseAudioContext& context, |
+ const String& name) |
+ : AudioNode(context), name_(name) { |
+ SetHandler(AudioWorkletHandler::Create(*this, context.sampleRate(), name)); |
+ |
+ DCHECK(parameter_map_); |
+} |
+ |
+AudioWorkletNode* AudioWorkletNode::Create(BaseAudioContext* context, |
+ const String& name, |
+ ExceptionState& exception_state) { |
+ DCHECK(IsMainThread()); |
+ |
+ if (context->IsContextClosed()) { |
+ context->ThrowExceptionForClosedState(exception_state); |
+ return nullptr; |
+ } |
+ |
+ // Create instance of node; this will set the instance of handler as well. |
+ // Once the handler is ready then create AudioParam objects in AudioParamMap. |
+ AudioWorkletNode* node = new AudioWorkletNode(*context, name); |
+ |
+ if (!node || !node->GetWorkletHandler().IsInitialized()) |
+ return nullptr; |
+ |
+ // Do something with node. |
+ // node->handleChannelOptions(options, exception_state); |
+ |
+ // context keeps reference as a source node. |
+ context->NotifySourceNodeStartedProcessing(node); |
+ |
+ return node; |
+} |
+ |
+bool AudioWorkletNode::HasPendingActivity() const { |
+ return !context()->IsContextClosed(); |
+} |
+ |
+AudioParamMap* AudioWorkletNode::parameters() const { |
+ return parameter_map_; |
+} |
+ |
+void AudioWorkletNode::SetParameterMap(AudioParamMap* parameter_map) { |
+ parameter_map_ = parameter_map; |
+} |
+ |
+AudioWorkletHandler& AudioWorkletNode::GetWorkletHandler() const { |
+ return static_cast<AudioWorkletHandler&>(Handler()); |
+} |
+ |
+DEFINE_TRACE(AudioWorkletNode) { |
+ visitor->Trace(parameter_map_); |
+ AudioNode::Trace(visitor); |
+} |
+ |
+} // namespace blink |