| 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
|
|
|