1 /*
2  * Copyright (C) 2010, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
23  * DAMAGE.
24  */
25 
26 #include "third_party/blink/renderer/modules/webaudio/audio_node.h"
27 
28 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_node_options.h"
29 #include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
30 #include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
31 #include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
32 #include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
33 #include "third_party/blink/renderer/modules/webaudio/audio_param.h"
34 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
35 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
36 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
37 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
38 
39 #if DEBUG_AUDIONODE_REFERENCES
40 #include <stdio.h>
41 #endif
42 
43 namespace blink {
44 
AudioHandler(NodeType node_type,AudioNode & node,float sample_rate)45 AudioHandler::AudioHandler(NodeType node_type,
46                            AudioNode& node,
47                            float sample_rate)
48     : last_processing_time_(-1),
49       last_non_silent_time_(0),
50       is_initialized_(false),
51       node_type_(kNodeTypeUnknown),
52       node_(&node),
53       context_(node.context()),
54       deferred_task_handler_(&context_->GetDeferredTaskHandler()),
55       connection_ref_count_(0),
56       is_disabled_(false),
57       channel_count_(2) {
58   SetNodeType(node_type);
59   SetInternalChannelCountMode(kMax);
60   SetInternalChannelInterpretation(AudioBus::kSpeakers);
61 
62 #if DEBUG_AUDIONODE_REFERENCES
63   if (!is_node_count_initialized_) {
64     is_node_count_initialized_ = true;
65     atexit(AudioHandler::PrintNodeCounts);
66   }
67 #endif
68   InstanceCounters::IncrementCounter(InstanceCounters::kAudioHandlerCounter);
69 
70 #if DEBUG_AUDIONODE_REFERENCES
71   fprintf(
72       stderr,
73       "[%16p]: %16p: %2d: AudioHandler::AudioHandler() %d [%d] total: %u\n",
74       Context(), this, GetNodeType(), connection_ref_count_,
75       node_count_[GetNodeType()],
76       InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter));
77 #endif
78   node.context()->WarnIfContextClosed(this);
79 }
80 
~AudioHandler()81 AudioHandler::~AudioHandler() {
82   DCHECK(IsMainThread());
83   InstanceCounters::DecrementCounter(InstanceCounters::kAudioHandlerCounter);
84 #if DEBUG_AUDIONODE_REFERENCES
85   --node_count_[GetNodeType()];
86   fprintf(
87       stderr,
88       "[%16p]: %16p: %2d: AudioHandler::~AudioHandler() %d [%d] remaining: "
89       "%u\n",
90       Context(), this, GetNodeType(), connection_ref_count_,
91       node_count_[GetNodeType()],
92       InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter));
93 #endif
94 }
95 
Initialize()96 void AudioHandler::Initialize() {
97   DCHECK_EQ(new_channel_count_mode_, channel_count_mode_);
98   DCHECK_EQ(new_channel_interpretation_, channel_interpretation_);
99 
100   is_initialized_ = true;
101 }
102 
Uninitialize()103 void AudioHandler::Uninitialize() {
104   is_initialized_ = false;
105 }
106 
Dispose()107 void AudioHandler::Dispose() {
108   DCHECK(IsMainThread());
109   deferred_task_handler_->AssertGraphOwner();
110 
111   deferred_task_handler_->RemoveChangedChannelCountMode(this);
112   deferred_task_handler_->RemoveChangedChannelInterpretation(this);
113   deferred_task_handler_->RemoveAutomaticPullNode(this);
114   for (auto& output : outputs_)
115     output->Dispose();
116 }
117 
GetNode() const118 AudioNode* AudioHandler::GetNode() const {
119   DCHECK(IsMainThread());
120   return node_;
121 }
122 
Context() const123 BaseAudioContext* AudioHandler::Context() const {
124   return context_;
125 }
126 
NodeTypeName() const127 String AudioHandler::NodeTypeName() const {
128   switch (node_type_) {
129     case kNodeTypeDestination:
130       return "AudioDestinationNode";
131     case kNodeTypeOscillator:
132       return "OscillatorNode";
133     case kNodeTypeAudioBufferSource:
134       return "AudioBufferSourceNode";
135     case kNodeTypeMediaElementAudioSource:
136       return "MediaElementAudioSourceNode";
137     case kNodeTypeMediaStreamAudioDestination:
138       return "MediaStreamAudioDestinationNode";
139     case kNodeTypeMediaStreamAudioSource:
140       return "MediaStreamAudioSourceNode";
141     case kNodeTypeScriptProcessor:
142       return "ScriptProcessorNode";
143     case kNodeTypeBiquadFilter:
144       return "BiquadFilterNode";
145     case kNodeTypePanner:
146       return "PannerNode";
147     case kNodeTypeStereoPanner:
148       return "StereoPannerNode";
149     case kNodeTypeConvolver:
150       return "ConvolverNode";
151     case kNodeTypeDelay:
152       return "DelayNode";
153     case kNodeTypeGain:
154       return "GainNode";
155     case kNodeTypeChannelSplitter:
156       return "ChannelSplitterNode";
157     case kNodeTypeChannelMerger:
158       return "ChannelMergerNode";
159     case kNodeTypeAnalyser:
160       return "AnalyserNode";
161     case kNodeTypeDynamicsCompressor:
162       return "DynamicsCompressorNode";
163     case kNodeTypeWaveShaper:
164       return "WaveShaperNode";
165     case kNodeTypeIIRFilter:
166       return "IIRFilterNode";
167     case kNodeTypeConstantSource:
168       return "ConstantSourceNode";
169     case kNodeTypeAudioWorklet:
170       return "AudioWorkletNode";
171     case kNodeTypeUnknown:
172     case kNodeTypeEnd:
173     default:
174       NOTREACHED();
175       return "UnknownNode";
176   }
177 }
178 
SetNodeType(NodeType type)179 void AudioHandler::SetNodeType(NodeType type) {
180   // Don't allow the node type to be changed to a different node type, after
181   // it's already been set.  And the new type can't be unknown or end.
182   DCHECK_EQ(node_type_, kNodeTypeUnknown);
183   DCHECK_NE(type, kNodeTypeUnknown);
184   DCHECK_NE(type, kNodeTypeEnd);
185 
186   node_type_ = type;
187 
188 #if DEBUG_AUDIONODE_REFERENCES
189   ++node_count_[type];
190   fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::AudioHandler [%3d]\n",
191           Context(), this, GetNodeType(), node_count_[GetNodeType()]);
192 #endif
193 }
194 
AddInput()195 void AudioHandler::AddInput() {
196   inputs_.push_back(std::make_unique<AudioNodeInput>(*this));
197 }
198 
AddOutput(unsigned number_of_channels)199 void AudioHandler::AddOutput(unsigned number_of_channels) {
200   DCHECK(IsMainThread());
201   outputs_.push_back(
202       std::make_unique<AudioNodeOutput>(this, number_of_channels));
203   GetNode()->DidAddOutput(NumberOfOutputs());
204 }
205 
Input(unsigned i)206 AudioNodeInput& AudioHandler::Input(unsigned i) {
207   return *inputs_[i];
208 }
209 
Output(unsigned i)210 AudioNodeOutput& AudioHandler::Output(unsigned i) {
211   return *outputs_[i];
212 }
213 
Output(unsigned i) const214 const AudioNodeOutput& AudioHandler::Output(unsigned i) const {
215   return *outputs_[i];
216 }
217 
ChannelCount()218 unsigned AudioHandler::ChannelCount() {
219   return channel_count_;
220 }
221 
SetInternalChannelCountMode(ChannelCountMode mode)222 void AudioHandler::SetInternalChannelCountMode(ChannelCountMode mode) {
223   channel_count_mode_ = mode;
224   new_channel_count_mode_ = mode;
225 }
226 
SetInternalChannelInterpretation(AudioBus::ChannelInterpretation interpretation)227 void AudioHandler::SetInternalChannelInterpretation(
228     AudioBus::ChannelInterpretation interpretation) {
229   channel_interpretation_ = interpretation;
230   new_channel_interpretation_ = interpretation;
231 }
232 
SetChannelCount(unsigned channel_count,ExceptionState & exception_state)233 void AudioHandler::SetChannelCount(unsigned channel_count,
234                                    ExceptionState& exception_state) {
235   DCHECK(IsMainThread());
236   BaseAudioContext::GraphAutoLocker locker(Context());
237 
238   if (channel_count > 0 &&
239       channel_count <= BaseAudioContext::MaxNumberOfChannels()) {
240     if (channel_count_ != channel_count) {
241       channel_count_ = channel_count;
242       if (channel_count_mode_ != kMax)
243         UpdateChannelsForInputs();
244     }
245   } else {
246     exception_state.ThrowDOMException(
247         DOMExceptionCode::kNotSupportedError,
248         ExceptionMessages::IndexOutsideRange<uint32_t>(
249             "channel count", channel_count, 1,
250             ExceptionMessages::kInclusiveBound,
251             BaseAudioContext::MaxNumberOfChannels(),
252             ExceptionMessages::kInclusiveBound));
253   }
254 }
255 
GetChannelCountMode()256 String AudioHandler::GetChannelCountMode() {
257   // Because we delay the actual setting of the mode to the pre or post
258   // rendering phase, we want to return the value that was set, not the actual
259   // current mode.
260   switch (new_channel_count_mode_) {
261     case kMax:
262       return "max";
263     case kClampedMax:
264       return "clamped-max";
265     case kExplicit:
266       return "explicit";
267   }
268   NOTREACHED();
269   return "";
270 }
271 
SetChannelCountMode(const String & mode,ExceptionState & exception_state)272 void AudioHandler::SetChannelCountMode(const String& mode,
273                                        ExceptionState& exception_state) {
274   DCHECK(IsMainThread());
275   BaseAudioContext::GraphAutoLocker locker(Context());
276 
277   ChannelCountMode old_mode = channel_count_mode_;
278 
279   if (mode == "max") {
280     new_channel_count_mode_ = kMax;
281   } else if (mode == "clamped-max") {
282     new_channel_count_mode_ = kClampedMax;
283   } else if (mode == "explicit") {
284     new_channel_count_mode_ = kExplicit;
285   } else {
286     NOTREACHED();
287   }
288 
289   if (new_channel_count_mode_ != old_mode)
290     Context()->GetDeferredTaskHandler().AddChangedChannelCountMode(this);
291 }
292 
ChannelInterpretation()293 String AudioHandler::ChannelInterpretation() {
294   // Because we delay the actual setting of the interpreation to the pre or
295   // post rendering phase, we want to return the value that was set, not the
296   // actual current interpretation.
297   switch (new_channel_interpretation_) {
298     case AudioBus::kSpeakers:
299       return "speakers";
300     case AudioBus::kDiscrete:
301       return "discrete";
302   }
303   NOTREACHED();
304   return "";
305 }
306 
SetChannelInterpretation(const String & interpretation,ExceptionState & exception_state)307 void AudioHandler::SetChannelInterpretation(const String& interpretation,
308                                             ExceptionState& exception_state) {
309   DCHECK(IsMainThread());
310   BaseAudioContext::GraphAutoLocker locker(Context());
311 
312   AudioBus::ChannelInterpretation old_mode = channel_interpretation_;
313 
314   if (interpretation == "speakers") {
315     new_channel_interpretation_ = AudioBus::kSpeakers;
316   } else if (interpretation == "discrete") {
317     new_channel_interpretation_ = AudioBus::kDiscrete;
318   } else {
319     NOTREACHED();
320   }
321 
322   if (new_channel_interpretation_ != old_mode)
323     Context()->GetDeferredTaskHandler().AddChangedChannelInterpretation(this);
324 }
325 
UpdateChannelsForInputs()326 void AudioHandler::UpdateChannelsForInputs() {
327   for (auto& input : inputs_)
328     input->ChangedOutputs();
329 }
330 
ProcessIfNecessary(uint32_t frames_to_process)331 void AudioHandler::ProcessIfNecessary(uint32_t frames_to_process) {
332   DCHECK(Context()->IsAudioThread());
333 
334   if (!IsInitialized())
335     return;
336 
337   // Ensure that we only process once per rendering quantum.
338   // This handles the "fanout" problem where an output is connected to multiple
339   // inputs.  The first time we're called during this time slice we process, but
340   // after that we don't want to re-process, instead our output(s) will already
341   // have the results cached in their bus;
342   double current_time = Context()->currentTime();
343   if (last_processing_time_ != current_time) {
344     // important to first update this time because of feedback loops in the
345     // rendering graph.
346     last_processing_time_ = current_time;
347 
348     PullInputs(frames_to_process);
349 
350     bool silent_inputs = InputsAreSilent();
351     if (silent_inputs && PropagatesSilence()) {
352       SilenceOutputs();
353       // AudioParams still need to be processed so that the value can be updated
354       // if there are automations or so that the upstream nodes get pulled if
355       // any are connected to the AudioParam.
356       ProcessOnlyAudioParams(frames_to_process);
357     } else {
358       // Unsilence the outputs first because the processing of the node may
359       // cause the outputs to go silent and we want to propagate that hint to
360       // the downstream nodes.  (For example, a Gain node with a gain of 0 will
361       // want to silence its output.)
362       UnsilenceOutputs();
363       Process(frames_to_process);
364     }
365 
366     if (!silent_inputs) {
367       // Update |last_non_silent_time| AFTER processing this block.
368       // Doing it before causes |PropagateSilence()| to be one render
369       // quantum longer than necessary.
370       last_non_silent_time_ =
371           (Context()->CurrentSampleFrame() + frames_to_process) /
372           static_cast<double>(Context()->sampleRate());
373     }
374   }
375 }
376 
CheckNumberOfChannelsForInput(AudioNodeInput * input)377 void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) {
378   DCHECK(Context()->IsAudioThread());
379   deferred_task_handler_->AssertGraphOwner();
380 
381   DCHECK(inputs_.Contains(input));
382 
383   input->UpdateInternalBus();
384 }
385 
PropagatesSilence() const386 bool AudioHandler::PropagatesSilence() const {
387   return last_non_silent_time_ + LatencyTime() + TailTime() <
388          Context()->currentTime();
389 }
390 
PullInputs(uint32_t frames_to_process)391 void AudioHandler::PullInputs(uint32_t frames_to_process) {
392   DCHECK(Context()->IsAudioThread());
393 
394   // Process all of the AudioNodes connected to our inputs.
395   for (auto& input : inputs_)
396     input->Pull(nullptr, frames_to_process);
397 }
398 
InputsAreSilent()399 bool AudioHandler::InputsAreSilent() {
400   for (auto& input : inputs_) {
401     if (!input->Bus()->IsSilent())
402       return false;
403   }
404   return true;
405 }
406 
SilenceOutputs()407 void AudioHandler::SilenceOutputs() {
408   for (auto& output : outputs_)
409     output->Bus()->Zero();
410 }
411 
UnsilenceOutputs()412 void AudioHandler::UnsilenceOutputs() {
413   for (auto& output : outputs_)
414     output->Bus()->ClearSilentFlag();
415 }
416 
EnableOutputsIfNecessary()417 void AudioHandler::EnableOutputsIfNecessary() {
418   DCHECK(IsMainThread());
419   deferred_task_handler_->AssertGraphOwner();
420 
421   // We're enabling outputs for this handler.  Remove this from the tail
422   // processing list (if it's there) so that we don't inadvertently disable the
423   // outputs later on when the tail processing time has elapsed.
424   Context()->GetDeferredTaskHandler().RemoveTailProcessingHandler(this, false);
425 
426 #if DEBUG_AUDIONODE_REFERENCES > 1
427   fprintf(stderr,
428           "[%16p]: %16p: %2d: EnableOutputsIfNecessary: is_disabled %d count "
429           "%d output size %u\n",
430           Context(), this, GetNodeType(), is_disabled_, connection_ref_count_,
431           outputs_.size());
432 #endif
433 
434   if (is_disabled_ && connection_ref_count_ > 0) {
435     is_disabled_ = false;
436     for (auto& output : outputs_)
437       output->Enable();
438   }
439 }
440 
DisableOutputsIfNecessary()441 void AudioHandler::DisableOutputsIfNecessary() {
442   // This function calls other functions that require graph ownership,
443   // so assert that this needs graph ownership too.
444   deferred_task_handler_->AssertGraphOwner();
445 
446 #if DEBUG_AUDIONODE_REFERENCES > 1
447   fprintf(stderr,
448           "[%16p]: %16p: %2d: DisableOutputsIfNecessary is_disabled %d count %d"
449           " tail %d\n",
450           Context(), this, GetNodeType(), is_disabled_, connection_ref_count_,
451           RequiresTailProcessing());
452 #endif
453 
454   // Disable outputs if appropriate. We do this if the number of connections is
455   // 0 or 1. The case of 0 is from deref() where there are no connections left.
456   // The case of 1 is from AudioNodeInput::disable() where we want to disable
457   // outputs when there's only one connection left because we're ready to go
458   // away, but can't quite yet.
459   if (connection_ref_count_ <= 1 && !is_disabled_) {
460     // Still may have JavaScript references, but no more "active" connection
461     // references, so put all of our outputs in a "dormant" disabled state.
462     // Garbage collection may take a very long time after this time, so the
463     // "dormant" disabled nodes should not bog down the rendering...
464 
465     // As far as JavaScript is concerned, our outputs must still appear to be
466     // connected.  But internally our outputs should be disabled from the inputs
467     // they're connected to.  disable() can recursively deref connections (and
468     // call disable()) down a whole chain of connected nodes.
469 
470     // If a node requires tail processing, we defer the disabling of
471     // the outputs so that the tail for the node can be output.
472     // Otherwise, we can disable the outputs right away.
473     if (RequiresTailProcessing()) {
474       if (deferred_task_handler_->AcceptsTailProcessing())
475         deferred_task_handler_->AddTailProcessingHandler(this);
476     } else {
477       DisableOutputs();
478     }
479   }
480 }
481 
DisableOutputs()482 void AudioHandler::DisableOutputs() {
483   is_disabled_ = true;
484   for (auto& output : outputs_)
485     output->Disable();
486 }
487 
MakeConnection()488 void AudioHandler::MakeConnection() {
489   deferred_task_handler_->AssertGraphOwner();
490   connection_ref_count_++;
491 
492 #if DEBUG_AUDIONODE_REFERENCES
493   fprintf(
494       stderr,
495       "[%16p]: %16p: %2d: AudioHandler::MakeConnection   %3d [%3d] @%.15g\n",
496       Context(), this, GetNodeType(), connection_ref_count_,
497       node_count_[GetNodeType()], Context()->currentTime());
498 #endif
499 
500   // See the disabling code in disableOutputsIfNecessary(). This handles
501   // the case where a node is being re-connected after being used at least
502   // once and disconnected. In this case, we need to re-enable.
503   EnableOutputsIfNecessary();
504 }
505 
BreakConnectionWithLock()506 void AudioHandler::BreakConnectionWithLock() {
507   deferred_task_handler_->AssertGraphOwner();
508   connection_ref_count_--;
509 
510 #if DEBUG_AUDIONODE_REFERENCES
511   fprintf(stderr,
512           "[%16p]: %16p: %2d: AudioHandler::BreakConnectionWitLock %3d [%3d] "
513           "@%.15g\n",
514           Context(), this, GetNodeType(), connection_ref_count_,
515           node_count_[GetNodeType()], Context()->currentTime());
516 #endif
517 
518   if (!connection_ref_count_)
519     DisableOutputsIfNecessary();
520 }
521 
522 #if DEBUG_AUDIONODE_REFERENCES
523 
524 bool AudioHandler::is_node_count_initialized_ = false;
525 int AudioHandler::node_count_[kNodeTypeEnd];
526 
PrintNodeCounts()527 void AudioHandler::PrintNodeCounts() {
528   fprintf(stderr, "\n\n");
529   fprintf(stderr, "===========================\n");
530   fprintf(stderr, "AudioNode: reference counts\n");
531   fprintf(stderr, "===========================\n");
532 
533   for (unsigned i = 0; i < kNodeTypeEnd; ++i)
534     fprintf(stderr, "%2d: %d\n", i, node_count_[i]);
535 
536   fprintf(stderr, "===========================\n\n\n");
537 }
538 
539 #endif  // DEBUG_AUDIONODE_REFERENCES
540 
541 #if DEBUG_AUDIONODE_REFERENCES > 1
TailProcessingDebug(const char * note,bool flag)542 void AudioHandler::TailProcessingDebug(const char* note, bool flag) {
543   fprintf(stderr, "[%16p]: %16p: %2d: %s %d @%.15g flag=%d", Context(), this,
544           GetNodeType(), note, connection_ref_count_, Context()->currentTime(),
545           flag);
546 
547   // If we're on the audio thread, we can print out the tail and
548   // latency times (because these methods can only be called from the
549   // audio thread.)
550   if (Context()->IsAudioThread()) {
551     fprintf(stderr, ", tail=%.15g + %.15g, last=%.15g\n", TailTime(),
552             LatencyTime(), last_non_silent_time_);
553   }
554 
555   fprintf(stderr, "\n");
556 }
557 
AddTailProcessingDebug()558 void AudioHandler::AddTailProcessingDebug() {
559   TailProcessingDebug("addTail", false);
560 }
561 
RemoveTailProcessingDebug(bool disable_outputs)562 void AudioHandler::RemoveTailProcessingDebug(bool disable_outputs) {
563   TailProcessingDebug("remTail", disable_outputs);
564 }
565 #endif  // DEBUG_AUDIONODE_REFERENCES > 1
566 
UpdateChannelCountMode()567 void AudioHandler::UpdateChannelCountMode() {
568   channel_count_mode_ = new_channel_count_mode_;
569   UpdateChannelsForInputs();
570 }
571 
UpdateChannelInterpretation()572 void AudioHandler::UpdateChannelInterpretation() {
573   channel_interpretation_ = new_channel_interpretation_;
574 }
575 
NumberOfOutputChannels() const576 unsigned AudioHandler::NumberOfOutputChannels() const {
577   // This should only be called for ScriptProcessorNodes which are the only
578   // nodes where you can have an output with 0 channels.  All other nodes have
579   // have at least one output channel, so there's no reason other nodes should
580   // ever call this function.
581   DCHECK(0) << "numberOfOutputChannels() not valid for node type "
582             << GetNodeType();
583   return 1;
584 }
585 // ----------------------------------------------------------------
586 
AudioNode(BaseAudioContext & context)587 AudioNode::AudioNode(BaseAudioContext& context)
588     : InspectorHelperMixin(context.GraphTracer(), context.Uuid()),
589       context_(context),
590       deferred_task_handler_(&context.GetDeferredTaskHandler()),
591       handler_(nullptr) {}
592 
~AudioNode()593 AudioNode::~AudioNode() {
594   // The graph lock is required to destroy the handler. And we can't use
595   // |context_| to touch it, since that object may also be a dead heap object.
596   {
597     DeferredTaskHandler::GraphAutoLocker locker(*deferred_task_handler_);
598     handler_ = nullptr;
599   }
600 }
601 
Dispose()602 void AudioNode::Dispose() {
603   DCHECK(IsMainThread());
604 #if DEBUG_AUDIONODE_REFERENCES
605   fprintf(stderr, "[%16p]: %16p: %2d: AudioNode::dispose %16p @%g\n", context(),
606           this, Handler().GetNodeType(), handler_.get(),
607           context()->currentTime());
608 #endif
609   BaseAudioContext::GraphAutoLocker locker(context());
610   Handler().Dispose();
611 
612   // Add the handler to the orphan list if the context is pulling on the audio
613   // graph.  This keeps the handler alive until it can be deleted at a safe
614   // point (in pre/post handler task).  If graph isn't being pulled, we can
615   // delete the handler now since nothing on the audio thread will be touching
616   // it.
617   DCHECK(context());
618   if (context()->IsPullingAudioGraph()) {
619     context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
620         std::move(handler_));
621   }
622 
623   // Notify the inspector that this node is going away. The actual clean up
624   // will be done in the subclass implementation.
625   ReportWillBeDestroyed();
626 }
627 
SetHandler(scoped_refptr<AudioHandler> handler)628 void AudioNode::SetHandler(scoped_refptr<AudioHandler> handler) {
629   DCHECK(handler);
630   handler_ = std::move(handler);
631 
632   // Unless the node is an AudioDestinationNode, notify the inspector that the
633   // construction is completed. The actual report will be done in the subclass
634   // implementation. (A destination node is owned by the context and will be
635   // reported by it.)
636   if (handler_->GetNodeType() != AudioHandler::NodeType::kNodeTypeDestination)
637     ReportDidCreate();
638 
639 #if DEBUG_AUDIONODE_REFERENCES
640   fprintf(stderr, "[%16p]: %16p: %2d: AudioNode::AudioNode %16p\n", context(),
641           this, handler_->GetNodeType(), handler_.get());
642 #endif
643 }
644 
ContainsHandler() const645 bool AudioNode::ContainsHandler() const {
646   return handler_.get();
647 }
648 
Handler() const649 AudioHandler& AudioNode::Handler() const {
650   return *handler_;
651 }
652 
Trace(Visitor * visitor) const653 void AudioNode::Trace(Visitor* visitor) const {
654   visitor->Trace(context_);
655   visitor->Trace(connected_nodes_);
656   visitor->Trace(connected_params_);
657   InspectorHelperMixin::Trace(visitor);
658   EventTargetWithInlineData::Trace(visitor);
659 }
660 
HandleChannelOptions(const AudioNodeOptions * options,ExceptionState & exception_state)661 void AudioNode::HandleChannelOptions(const AudioNodeOptions* options,
662                                      ExceptionState& exception_state) {
663   DCHECK(IsMainThread());
664 
665   if (options->hasChannelCount())
666     setChannelCount(options->channelCount(), exception_state);
667   if (options->hasChannelCountMode())
668     setChannelCountMode(options->channelCountMode(), exception_state);
669   if (options->hasChannelInterpretation())
670     setChannelInterpretation(options->channelInterpretation(), exception_state);
671 }
672 
context() const673 BaseAudioContext* AudioNode::context() const {
674   return context_;
675 }
676 
connect(AudioNode * destination,unsigned output_index,unsigned input_index,ExceptionState & exception_state)677 AudioNode* AudioNode::connect(AudioNode* destination,
678                               unsigned output_index,
679                               unsigned input_index,
680                               ExceptionState& exception_state) {
681   DCHECK(IsMainThread());
682   BaseAudioContext::GraphAutoLocker locker(context());
683 
684   context()->WarnForConnectionIfContextClosed();
685 
686   if (!destination) {
687     exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
688                                       "invalid destination node.");
689     return nullptr;
690   }
691 
692   // Sanity check input and output indices.
693   if (output_index >= numberOfOutputs()) {
694     exception_state.ThrowDOMException(
695         DOMExceptionCode::kIndexSizeError,
696         "output index (" + String::Number(output_index) +
697             ") exceeds number of outputs (" +
698             String::Number(numberOfOutputs()) + ").");
699     return nullptr;
700   }
701 
702   if (destination && input_index >= destination->numberOfInputs()) {
703     exception_state.ThrowDOMException(
704         DOMExceptionCode::kIndexSizeError,
705         "input index (" + String::Number(input_index) +
706             ") exceeds number of inputs (" +
707             String::Number(destination->numberOfInputs()) + ").");
708     return nullptr;
709   }
710 
711   if (context() != destination->context()) {
712     exception_state.ThrowDOMException(
713         DOMExceptionCode::kInvalidAccessError,
714         "cannot connect to a destination "
715         "belonging to a different audio context.");
716     return nullptr;
717   }
718 
719   // ScriptProcessorNodes with 0 output channels can't be connected to any
720   // destination.  If there are no output channels, what would the destination
721   // receive?  Just disallow this.
722   if (Handler().GetNodeType() == AudioHandler::kNodeTypeScriptProcessor &&
723       Handler().NumberOfOutputChannels() == 0) {
724     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
725                                       "cannot connect a ScriptProcessorNode "
726                                       "with 0 output channels to any "
727                                       "destination node.");
728     return nullptr;
729   }
730 
731   AudioNodeWiring::Connect(Handler().Output(output_index),
732                            destination->Handler().Input(input_index));
733   if (!connected_nodes_[output_index]) {
734     connected_nodes_[output_index] =
735         MakeGarbageCollected<HeapHashSet<Member<AudioNode>>>();
736   }
737   connected_nodes_[output_index]->insert(destination);
738 
739   Handler().UpdatePullStatusIfNeeded();
740 
741   GraphTracer().DidConnectNodes(this, destination, output_index, input_index);
742 
743   return destination;
744 }
745 
connect(AudioParam * param,unsigned output_index,ExceptionState & exception_state)746 void AudioNode::connect(AudioParam* param,
747                         unsigned output_index,
748                         ExceptionState& exception_state) {
749   DCHECK(IsMainThread());
750   BaseAudioContext::GraphAutoLocker locker(context());
751 
752   context()->WarnForConnectionIfContextClosed();
753 
754   if (!param) {
755     exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
756                                       "invalid AudioParam.");
757     return;
758   }
759 
760   if (output_index >= numberOfOutputs()) {
761     exception_state.ThrowDOMException(
762         DOMExceptionCode::kIndexSizeError,
763         "output index (" + String::Number(output_index) +
764             ") exceeds number of outputs (" +
765             String::Number(numberOfOutputs()) + ").");
766     return;
767   }
768 
769   if (context() != param->Context()) {
770     exception_state.ThrowDOMException(
771         DOMExceptionCode::kSyntaxError,
772         "cannot connect to an AudioParam "
773         "belonging to a different audio context.");
774     return;
775   }
776 
777   AudioNodeWiring::Connect(Handler().Output(output_index), param->Handler());
778   if (!connected_params_[output_index]) {
779     connected_params_[output_index] =
780         MakeGarbageCollected<HeapHashSet<Member<AudioParam>>>();
781   }
782   connected_params_[output_index]->insert(param);
783 
784   Handler().UpdatePullStatusIfNeeded();
785 
786   GraphTracer().DidConnectNodeParam(this, param, output_index);
787 }
788 
DisconnectAllFromOutput(unsigned output_index)789 void AudioNode::DisconnectAllFromOutput(unsigned output_index) {
790   Handler().Output(output_index).DisconnectAll();
791   connected_nodes_[output_index] = nullptr;
792   connected_params_[output_index] = nullptr;
793 }
794 
DisconnectFromOutputIfConnected(unsigned output_index,AudioNode & destination,unsigned input_index_of_destination)795 bool AudioNode::DisconnectFromOutputIfConnected(
796     unsigned output_index,
797     AudioNode& destination,
798     unsigned input_index_of_destination) {
799   AudioNodeOutput& output = Handler().Output(output_index);
800   AudioNodeInput& input =
801       destination.Handler().Input(input_index_of_destination);
802   if (!AudioNodeWiring::IsConnected(output, input))
803     return false;
804   AudioNodeWiring::Disconnect(output, input);
805   connected_nodes_[output_index]->erase(&destination);
806   return true;
807 }
808 
DisconnectFromOutputIfConnected(unsigned output_index,AudioParam & param)809 bool AudioNode::DisconnectFromOutputIfConnected(unsigned output_index,
810                                                 AudioParam& param) {
811   AudioNodeOutput& output = Handler().Output(output_index);
812   if (!AudioNodeWiring::IsConnected(output, param.Handler()))
813     return false;
814   AudioNodeWiring::Disconnect(output, param.Handler());
815   connected_params_[output_index]->erase(&param);
816   return true;
817 }
818 
disconnect()819 void AudioNode::disconnect() {
820   DCHECK(IsMainThread());
821   BaseAudioContext::GraphAutoLocker locker(context());
822 
823   // Disconnect all outgoing connections.
824   for (unsigned i = 0; i < numberOfOutputs(); ++i)
825     DisconnectAllFromOutput(i);
826 
827   Handler().UpdatePullStatusIfNeeded();
828 
829   GraphTracer().DidDisconnectNodes(this);
830 }
831 
disconnect(unsigned output_index,ExceptionState & exception_state)832 void AudioNode::disconnect(unsigned output_index,
833                            ExceptionState& exception_state) {
834   DCHECK(IsMainThread());
835   BaseAudioContext::GraphAutoLocker locker(context());
836 
837   // Sanity check on the output index.
838   if (output_index >= numberOfOutputs()) {
839     exception_state.ThrowDOMException(
840         DOMExceptionCode::kIndexSizeError,
841         ExceptionMessages::IndexOutsideRange(
842             "output index", output_index, 0u,
843             ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
844             ExceptionMessages::kInclusiveBound));
845     return;
846   }
847   // Disconnect all outgoing connections from the given output.
848   DisconnectAllFromOutput(output_index);
849 
850   Handler().UpdatePullStatusIfNeeded();
851 
852   GraphTracer().DidDisconnectNodes(this, nullptr, output_index);
853 }
854 
disconnect(AudioNode * destination,ExceptionState & exception_state)855 void AudioNode::disconnect(AudioNode* destination,
856                            ExceptionState& exception_state) {
857   DCHECK(IsMainThread());
858   BaseAudioContext::GraphAutoLocker locker(context());
859 
860   unsigned number_of_disconnections = 0;
861 
862   // FIXME: Can this be optimized? ChannelSplitter and ChannelMerger can have
863   // 32 ports and that requires 1024 iterations to validate entire connections.
864   for (unsigned output_index = 0; output_index < numberOfOutputs();
865        ++output_index) {
866     for (unsigned input_index = 0;
867          input_index < destination->Handler().NumberOfInputs(); ++input_index) {
868       if (DisconnectFromOutputIfConnected(output_index, *destination,
869                                           input_index))
870         number_of_disconnections++;
871     }
872   }
873 
874   // If there is no connection to the destination, throw an exception.
875   if (number_of_disconnections == 0) {
876     exception_state.ThrowDOMException(
877         DOMExceptionCode::kInvalidAccessError,
878         "the given destination is not connected.");
879     return;
880   }
881 
882   Handler().UpdatePullStatusIfNeeded();
883 
884   GraphTracer().DidDisconnectNodes(this, destination);
885 }
886 
disconnect(AudioNode * destination,unsigned output_index,ExceptionState & exception_state)887 void AudioNode::disconnect(AudioNode* destination,
888                            unsigned output_index,
889                            ExceptionState& exception_state) {
890   DCHECK(IsMainThread());
891   BaseAudioContext::GraphAutoLocker locker(context());
892 
893   if (output_index >= numberOfOutputs()) {
894     // The output index is out of range. Throw an exception.
895     exception_state.ThrowDOMException(
896         DOMExceptionCode::kIndexSizeError,
897         ExceptionMessages::IndexOutsideRange(
898             "output index", output_index, 0u,
899             ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
900             ExceptionMessages::kInclusiveBound));
901     return;
902   }
903 
904   // If the output index is valid, proceed to disconnect.
905   unsigned number_of_disconnections = 0;
906   // Sanity check on destination inputs and disconnect when possible.
907   for (unsigned input_index = 0; input_index < destination->numberOfInputs();
908        ++input_index) {
909     if (DisconnectFromOutputIfConnected(output_index, *destination,
910                                         input_index))
911       number_of_disconnections++;
912   }
913 
914   // If there is no connection to the destination, throw an exception.
915   if (number_of_disconnections == 0) {
916     exception_state.ThrowDOMException(
917         DOMExceptionCode::kInvalidAccessError,
918         "output (" + String::Number(output_index) +
919             ") is not connected to the given destination.");
920   }
921 
922   Handler().UpdatePullStatusIfNeeded();
923 
924   GraphTracer().DidDisconnectNodes(this, destination, output_index);
925 }
926 
disconnect(AudioNode * destination,unsigned output_index,unsigned input_index,ExceptionState & exception_state)927 void AudioNode::disconnect(AudioNode* destination,
928                            unsigned output_index,
929                            unsigned input_index,
930                            ExceptionState& exception_state) {
931   DCHECK(IsMainThread());
932   BaseAudioContext::GraphAutoLocker locker(context());
933 
934   if (output_index >= numberOfOutputs()) {
935     exception_state.ThrowDOMException(
936         DOMExceptionCode::kIndexSizeError,
937         ExceptionMessages::IndexOutsideRange(
938             "output index", output_index, 0u,
939             ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
940             ExceptionMessages::kInclusiveBound));
941     return;
942   }
943 
944   if (input_index >= destination->Handler().NumberOfInputs()) {
945     exception_state.ThrowDOMException(
946         DOMExceptionCode::kIndexSizeError,
947         ExceptionMessages::IndexOutsideRange(
948             "input index", input_index, 0u, ExceptionMessages::kInclusiveBound,
949             destination->numberOfInputs() - 1,
950             ExceptionMessages::kInclusiveBound));
951     return;
952   }
953 
954   // If both indices are valid, proceed to disconnect.
955   if (!DisconnectFromOutputIfConnected(output_index, *destination,
956                                        input_index)) {
957     exception_state.ThrowDOMException(
958         DOMExceptionCode::kInvalidAccessError,
959         "output (" + String::Number(output_index) +
960             ") is not connected to the input (" + String::Number(input_index) +
961             ") of the destination.");
962     return;
963   }
964 
965   Handler().UpdatePullStatusIfNeeded();
966 
967   GraphTracer().DidDisconnectNodes(
968       this, destination, output_index, input_index);
969 }
970 
disconnect(AudioParam * destination_param,ExceptionState & exception_state)971 void AudioNode::disconnect(AudioParam* destination_param,
972                            ExceptionState& exception_state) {
973   DCHECK(IsMainThread());
974   BaseAudioContext::GraphAutoLocker locker(context());
975 
976   // The number of disconnection made.
977   unsigned number_of_disconnections = 0;
978 
979   // Check if the node output is connected the destination AudioParam.
980   // Disconnect if connected and increase |numberOfDisconnectios| by 1.
981   for (unsigned output_index = 0; output_index < Handler().NumberOfOutputs();
982        ++output_index) {
983     if (DisconnectFromOutputIfConnected(output_index, *destination_param))
984       number_of_disconnections++;
985   }
986 
987   // Throw an exception when there is no valid connection to the destination.
988   if (number_of_disconnections == 0) {
989     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
990                                       "the given AudioParam is not connected.");
991     return;
992   }
993 
994   Handler().UpdatePullStatusIfNeeded();
995 
996   GraphTracer().DidDisconnectNodeParam(this, destination_param);
997 }
998 
disconnect(AudioParam * destination_param,unsigned output_index,ExceptionState & exception_state)999 void AudioNode::disconnect(AudioParam* destination_param,
1000                            unsigned output_index,
1001                            ExceptionState& exception_state) {
1002   DCHECK(IsMainThread());
1003   BaseAudioContext::GraphAutoLocker locker(context());
1004 
1005   if (output_index >= Handler().NumberOfOutputs()) {
1006     // The output index is out of range. Throw an exception.
1007     exception_state.ThrowDOMException(
1008         DOMExceptionCode::kIndexSizeError,
1009         ExceptionMessages::IndexOutsideRange(
1010             "output index", output_index, 0u,
1011             ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
1012             ExceptionMessages::kInclusiveBound));
1013     return;
1014   }
1015 
1016   // If the output index is valid, proceed to disconnect.
1017   if (!DisconnectFromOutputIfConnected(output_index, *destination_param)) {
1018     exception_state.ThrowDOMException(
1019         DOMExceptionCode::kInvalidAccessError,
1020         "specified destination AudioParam and node output (" +
1021             String::Number(output_index) + ") are not connected.");
1022     return;
1023   }
1024 
1025   Handler().UpdatePullStatusIfNeeded();
1026 
1027   GraphTracer().DidDisconnectNodeParam(this, destination_param, output_index);
1028 }
1029 
numberOfInputs() const1030 unsigned AudioNode::numberOfInputs() const {
1031   return Handler().NumberOfInputs();
1032 }
1033 
numberOfOutputs() const1034 unsigned AudioNode::numberOfOutputs() const {
1035   return Handler().NumberOfOutputs();
1036 }
1037 
channelCount() const1038 unsigned AudioNode::channelCount() const {
1039   return Handler().ChannelCount();
1040 }
1041 
setChannelCount(unsigned count,ExceptionState & exception_state)1042 void AudioNode::setChannelCount(unsigned count,
1043                                 ExceptionState& exception_state) {
1044   Handler().SetChannelCount(count, exception_state);
1045 }
1046 
channelCountMode() const1047 String AudioNode::channelCountMode() const {
1048   return Handler().GetChannelCountMode();
1049 }
1050 
setChannelCountMode(const String & mode,ExceptionState & exception_state)1051 void AudioNode::setChannelCountMode(const String& mode,
1052                                     ExceptionState& exception_state) {
1053   Handler().SetChannelCountMode(mode, exception_state);
1054 }
1055 
channelInterpretation() const1056 String AudioNode::channelInterpretation() const {
1057   return Handler().ChannelInterpretation();
1058 }
1059 
setChannelInterpretation(const String & interpretation,ExceptionState & exception_state)1060 void AudioNode::setChannelInterpretation(const String& interpretation,
1061                                          ExceptionState& exception_state) {
1062   Handler().SetChannelInterpretation(interpretation, exception_state);
1063 }
1064 
InterfaceName() const1065 const AtomicString& AudioNode::InterfaceName() const {
1066   return event_target_names::kAudioNode;
1067 }
1068 
GetExecutionContext() const1069 ExecutionContext* AudioNode::GetExecutionContext() const {
1070   return context()->GetExecutionContext();
1071 }
1072 
DidAddOutput(unsigned number_of_outputs)1073 void AudioNode::DidAddOutput(unsigned number_of_outputs) {
1074   connected_nodes_.push_back(nullptr);
1075   DCHECK_EQ(number_of_outputs, connected_nodes_.size());
1076   connected_params_.push_back(nullptr);
1077   DCHECK_EQ(number_of_outputs, connected_params_.size());
1078 }
1079 
1080 }  // namespace blink
1081