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

Unified Diff: third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp

Issue 2793593002: AudioWorklet prototype
Patch Set: Merge changes, AudioParam bug fix Created 3 years, 5 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/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

Powered by Google App Engine
This is Rietveld 408576698