OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "modules/webaudio/AudioWorkletNode.h" |
| 6 |
| 7 #include "core/dom/TaskRunnerHelper.h" |
| 8 #include "modules/webaudio/AudioBuffer.h" |
| 9 #include "modules/webaudio/AudioNodeInput.h" |
| 10 #include "modules/webaudio/AudioNodeOutput.h" |
| 11 #include "modules/webaudio/AudioParamDescriptor.h" |
| 12 #include "modules/webaudio/AudioWorkletGlobalScope.h" |
| 13 #include "modules/webaudio/AudioWorkletProcessor.h" |
| 14 #include "modules/webaudio/AudioWorkletProcessorDefinition.h" |
| 15 #include "platform/audio/AudioBus.h" |
| 16 #include "platform/audio/AudioUtilities.h" |
| 17 #include "platform/heap/Persistent.h" |
| 18 |
| 19 namespace blink { |
| 20 |
| 21 AudioWorkletHandler::AudioWorkletHandler(AudioNode& node, |
| 22 float sample_rate, |
| 23 String name) |
| 24 : AudioHandler(kNodeTypeAudioWorklet, node, sample_rate) { |
| 25 DCHECK(IsMainThread()); |
| 26 |
| 27 AddInput(); |
| 28 AddOutput(1); |
| 29 |
| 30 // Post a task for the instantiation of corresponding AudioWorkletProcessor. |
| 31 // This blocks the main thread until the construction is completed. |
| 32 WaitableEvent doneConstruction; |
| 33 Context()->GetWorkletMessagingProxy()->CreateProcessorInstance( |
| 34 name, this, &doneConstruction); |
| 35 doneConstruction.Wait(); |
| 36 |
| 37 DCHECK(processor_); |
| 38 if (processor_) { |
| 39 const AudioWorkletProcessorDefinition* definition = |
| 40 processor_->GetDefinition(); |
| 41 DCHECK(definition); |
| 42 |
| 43 HeapHashMap<String, Member<AudioParam>> audio_param_map; |
| 44 for (const auto& descriptor : definition->GetAudioParamDescriptors()) { |
| 45 // A thread-specific isolated copy is necessary since |descriptor| belongs |
| 46 // to the rendering thread and AudioParams are owned by the main thread. |
| 47 String param_name = descriptor.name().IsolatedCopy(); |
| 48 AudioParam* audio_param = AudioParam::Create(*Context(), |
| 49 kParamTypeAudioWorklet, |
| 50 descriptor.defaultValue(), |
| 51 descriptor.minValue(), |
| 52 descriptor.maxValue()); |
| 53 DCHECK(audio_param); |
| 54 audio_param_map.Set(param_name, audio_param); |
| 55 |
| 56 // We need another isolated copy of string because AudioParamHandler is |
| 57 // touched by the rendering thread. |
| 58 param_handler_map_.Set(param_name.IsolatedCopy(), |
| 59 audio_param->HandlerExperimental()); |
| 60 } |
| 61 |
| 62 static_cast<AudioWorkletNode&>(node).SetParameterMap( |
| 63 new AudioParamMap(audio_param_map)); |
| 64 |
| 65 // Initialize the handler only when the processor is valid. After this call, |
| 66 // the handler/processor will get pulled by the rendering thread. |
| 67 Initialize(); |
| 68 } |
| 69 } |
| 70 |
| 71 AudioWorkletHandler::~AudioWorkletHandler() { |
| 72 processor_->Dispose(); |
| 73 Uninitialize(); |
| 74 processor_ = nullptr; |
| 75 } |
| 76 |
| 77 PassRefPtr<AudioWorkletHandler> AudioWorkletHandler::Create(AudioNode& node, |
| 78 float sample_rate, |
| 79 String name) { |
| 80 return AdoptRef(new AudioWorkletHandler(node, sample_rate, name)); |
| 81 } |
| 82 |
| 83 void AudioWorkletHandler::Process(size_t frames_to_process) { |
| 84 AudioBus* output_bus = Output(0).Bus(); |
| 85 DCHECK(output_bus); |
| 86 |
| 87 if (!IsInitialized()) { |
| 88 output_bus->Zero(); |
| 89 return; |
| 90 } |
| 91 |
| 92 AudioBuffer* input_buffer = Input(0).IsConnected() |
| 93 ? AudioBuffer::CreateFromAudioBus(Input(0).Bus()) |
| 94 : AudioBuffer::Create(1, 128, Context()->sampleRate()); |
| 95 AudioBuffer* output_buffer = |
| 96 AudioBuffer::Create(1, 128, Context()->sampleRate()); |
| 97 |
| 98 HashMap<String, AudioFloatArray*> audio_param_data_map; |
| 99 for (const auto& param_name : param_handler_map_.Keys()) { |
| 100 AudioParamHandler* audio_param_handler = param_handler_map_.at(param_name); |
| 101 AudioFloatArray* param_values = |
| 102 new AudioFloatArray(AudioUtilities::kRenderQuantumFrames); |
| 103 if (audio_param_handler->HasSampleAccurateValues()) { |
| 104 audio_param_handler->CalculateSampleAccurateValues( |
| 105 param_values->Data(), frames_to_process); |
| 106 } else { |
| 107 std::fill(param_values->Data(), |
| 108 param_values->Data() + AudioUtilities::kRenderQuantumFrames, |
| 109 audio_param_handler->Value()); |
| 110 } |
| 111 |
| 112 audio_param_data_map.Set(param_name, param_values); |
| 113 } |
| 114 |
| 115 processor_->Process(input_buffer, output_buffer, audio_param_data_map); |
| 116 |
| 117 for (unsigned i = 0; i < 1; ++i) { |
| 118 memcpy(output_bus->Channel(i)->MutableData(), |
| 119 output_buffer->getChannelData(i).View()->Data(), |
| 120 sizeof(float) * frames_to_process); |
| 121 } |
| 122 } |
| 123 |
| 124 double AudioWorkletHandler::TailTime() const { |
| 125 return std::numeric_limits<double>::infinity(); |
| 126 } |
| 127 |
| 128 double AudioWorkletHandler::LatencyTime() const { |
| 129 return std::numeric_limits<double>::infinity(); |
| 130 } |
| 131 |
| 132 void AudioWorkletHandler::SetProcessorOnRenderingThread( |
| 133 AudioWorkletProcessor* processor) { |
| 134 DCHECK(!IsMainThread()); |
| 135 processor_ = processor; |
| 136 } |
| 137 |
| 138 // ---------------------------------------------------------------- |
| 139 |
| 140 AudioWorkletNode::AudioWorkletNode(BaseAudioContext& context, |
| 141 const String& name) |
| 142 : AudioNode(context), name_(name) { |
| 143 SetHandler(AudioWorkletHandler::Create(*this, context.sampleRate(), name)); |
| 144 |
| 145 DCHECK(parameter_map_); |
| 146 } |
| 147 |
| 148 AudioWorkletNode* AudioWorkletNode::Create(BaseAudioContext* context, |
| 149 const String& name, |
| 150 ExceptionState& exception_state) { |
| 151 DCHECK(IsMainThread()); |
| 152 |
| 153 if (context->IsContextClosed()) { |
| 154 context->ThrowExceptionForClosedState(exception_state); |
| 155 return nullptr; |
| 156 } |
| 157 |
| 158 // Create instance of node; this will set the instance of handler as well. |
| 159 // Once the handler is ready then create AudioParam objects in AudioParamMap. |
| 160 AudioWorkletNode* node = new AudioWorkletNode(*context, name); |
| 161 |
| 162 if (!node || !node->GetWorkletHandler().IsInitialized()) |
| 163 return nullptr; |
| 164 |
| 165 // Do something with node. |
| 166 // node->handleChannelOptions(options, exception_state); |
| 167 |
| 168 // context keeps reference as a source node. |
| 169 context->NotifySourceNodeStartedProcessing(node); |
| 170 |
| 171 return node; |
| 172 } |
| 173 |
| 174 bool AudioWorkletNode::HasPendingActivity() const { |
| 175 return !context()->IsContextClosed(); |
| 176 } |
| 177 |
| 178 AudioParamMap* AudioWorkletNode::parameters() const { |
| 179 return parameter_map_; |
| 180 } |
| 181 |
| 182 void AudioWorkletNode::SetParameterMap(AudioParamMap* parameter_map) { |
| 183 parameter_map_ = parameter_map; |
| 184 } |
| 185 |
| 186 AudioWorkletHandler& AudioWorkletNode::GetWorkletHandler() const { |
| 187 return static_cast<AudioWorkletHandler&>(Handler()); |
| 188 } |
| 189 |
| 190 DEFINE_TRACE(AudioWorkletNode) { |
| 191 visitor->Trace(parameter_map_); |
| 192 AudioNode::Trace(visitor); |
| 193 } |
| 194 |
| 195 } // namespace blink |
OLD | NEW |