/*
 * Copyright (C) 2010, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include "third_party/blink/renderer/modules/webaudio/audio_node.h"

#include "base/trace_event/trace_event.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_audio_node_options.h"
#include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_input.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
#include "third_party/blink/renderer/modules/webaudio/audio_node_wiring.h"
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"

#if DEBUG_AUDIONODE_REFERENCES
#include <stdio.h>
#endif

namespace blink {

AudioHandler::AudioHandler(NodeType node_type,
                           AudioNode& node,
                           float sample_rate)
    : last_processing_time_(-1),
      last_non_silent_time_(0),
      is_initialized_(false),
      node_type_(kNodeTypeUnknown),
      node_(&node),
      context_(node.context()),
      deferred_task_handler_(&context_->GetDeferredTaskHandler()),
      connection_ref_count_(0),
      is_disabled_(false),
      channel_count_(2) {
  SetNodeType(node_type);
  SetInternalChannelCountMode(kMax);
  SetInternalChannelInterpretation(AudioBus::kSpeakers);

#if DEBUG_AUDIONODE_REFERENCES
  if (!is_node_count_initialized_) {
    is_node_count_initialized_ = true;
    atexit(AudioHandler::PrintNodeCounts);
  }
#endif
  InstanceCounters::IncrementCounter(InstanceCounters::kAudioHandlerCounter);

#if DEBUG_AUDIONODE_REFERENCES
  fprintf(
      stderr,
      "[%16p]: %16p: %2d: AudioHandler::AudioHandler() %d [%d] total: %u\n",
      Context(), this, GetNodeType(), connection_ref_count_,
      node_count_[GetNodeType()],
      InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter));
#endif
  node.context()->WarnIfContextClosed(this);
}

AudioHandler::~AudioHandler() {
  DCHECK(IsMainThread());
  InstanceCounters::DecrementCounter(InstanceCounters::kAudioHandlerCounter);
#if DEBUG_AUDIONODE_REFERENCES
  --node_count_[GetNodeType()];
  fprintf(
      stderr,
      "[%16p]: %16p: %2d: AudioHandler::~AudioHandler() %d [%d] remaining: "
      "%u\n",
      Context(), this, GetNodeType(), connection_ref_count_,
      node_count_[GetNodeType()],
      InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter));
#endif
}

void AudioHandler::Initialize() {
  DCHECK_EQ(new_channel_count_mode_, channel_count_mode_);
  DCHECK_EQ(new_channel_interpretation_, channel_interpretation_);

  is_initialized_ = true;
}

void AudioHandler::Uninitialize() {
  is_initialized_ = false;
}

void AudioHandler::Dispose() {
  DCHECK(IsMainThread());
  deferred_task_handler_->AssertGraphOwner();

  deferred_task_handler_->RemoveChangedChannelCountMode(this);
  deferred_task_handler_->RemoveChangedChannelInterpretation(this);
  deferred_task_handler_->RemoveAutomaticPullNode(this);
  for (auto& output : outputs_)
    output->Dispose();
}

AudioNode* AudioHandler::GetNode() const {
  DCHECK(IsMainThread());
  return node_;
}

BaseAudioContext* AudioHandler::Context() const {
  return context_;
}

String AudioHandler::NodeTypeName() const {
  switch (node_type_) {
    case kNodeTypeDestination:
      return "AudioDestinationNode";
    case kNodeTypeOscillator:
      return "OscillatorNode";
    case kNodeTypeAudioBufferSource:
      return "AudioBufferSourceNode";
    case kNodeTypeMediaElementAudioSource:
      return "MediaElementAudioSourceNode";
    case kNodeTypeMediaStreamAudioDestination:
      return "MediaStreamAudioDestinationNode";
    case kNodeTypeMediaStreamAudioSource:
      return "MediaStreamAudioSourceNode";
    case kNodeTypeScriptProcessor:
      return "ScriptProcessorNode";
    case kNodeTypeBiquadFilter:
      return "BiquadFilterNode";
    case kNodeTypePanner:
      return "PannerNode";
    case kNodeTypeStereoPanner:
      return "StereoPannerNode";
    case kNodeTypeConvolver:
      return "ConvolverNode";
    case kNodeTypeDelay:
      return "DelayNode";
    case kNodeTypeGain:
      return "GainNode";
    case kNodeTypeChannelSplitter:
      return "ChannelSplitterNode";
    case kNodeTypeChannelMerger:
      return "ChannelMergerNode";
    case kNodeTypeAnalyser:
      return "AnalyserNode";
    case kNodeTypeDynamicsCompressor:
      return "DynamicsCompressorNode";
    case kNodeTypeWaveShaper:
      return "WaveShaperNode";
    case kNodeTypeIIRFilter:
      return "IIRFilterNode";
    case kNodeTypeConstantSource:
      return "ConstantSourceNode";
    case kNodeTypeAudioWorklet:
      return "AudioWorkletNode";
    case kNodeTypeUnknown:
    case kNodeTypeEnd:
    default:
      NOTREACHED();
      return "UnknownNode";
  }
}

void AudioHandler::SetNodeType(NodeType type) {
  // Don't allow the node type to be changed to a different node type, after
  // it's already been set.  And the new type can't be unknown or end.
  DCHECK_EQ(node_type_, kNodeTypeUnknown);
  DCHECK_NE(type, kNodeTypeUnknown);
  DCHECK_NE(type, kNodeTypeEnd);

  node_type_ = type;

#if DEBUG_AUDIONODE_REFERENCES
  ++node_count_[type];
  fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::AudioHandler [%3d]\n",
          Context(), this, GetNodeType(), node_count_[GetNodeType()]);
#endif
}

void AudioHandler::AddInput() {
  inputs_.push_back(std::make_unique<AudioNodeInput>(*this));
}

void AudioHandler::AddOutput(unsigned number_of_channels) {
  DCHECK(IsMainThread());
  outputs_.push_back(
      std::make_unique<AudioNodeOutput>(this, number_of_channels));
  GetNode()->DidAddOutput(NumberOfOutputs());
}

AudioNodeInput& AudioHandler::Input(unsigned i) {
  return *inputs_[i];
}

AudioNodeOutput& AudioHandler::Output(unsigned i) {
  return *outputs_[i];
}

const AudioNodeOutput& AudioHandler::Output(unsigned i) const {
  return *outputs_[i];
}

unsigned AudioHandler::ChannelCount() {
  return channel_count_;
}

void AudioHandler::SetInternalChannelCountMode(ChannelCountMode mode) {
  channel_count_mode_ = mode;
  new_channel_count_mode_ = mode;
}

void AudioHandler::SetInternalChannelInterpretation(
    AudioBus::ChannelInterpretation interpretation) {
  channel_interpretation_ = interpretation;
  new_channel_interpretation_ = interpretation;
}

void AudioHandler::SetChannelCount(unsigned channel_count,
                                   ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(Context());

  if (channel_count > 0 &&
      channel_count <= BaseAudioContext::MaxNumberOfChannels()) {
    if (channel_count_ != channel_count) {
      channel_count_ = channel_count;
      if (channel_count_mode_ != kMax)
        UpdateChannelsForInputs();
    }
  } else {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kNotSupportedError,
        ExceptionMessages::IndexOutsideRange<uint32_t>(
            "channel count", channel_count, 1,
            ExceptionMessages::kInclusiveBound,
            BaseAudioContext::MaxNumberOfChannels(),
            ExceptionMessages::kInclusiveBound));
  }
}

String AudioHandler::GetChannelCountMode() {
  // Because we delay the actual setting of the mode to the pre or post
  // rendering phase, we want to return the value that was set, not the actual
  // current mode.
  switch (new_channel_count_mode_) {
    case kMax:
      return "max";
    case kClampedMax:
      return "clamped-max";
    case kExplicit:
      return "explicit";
  }
  NOTREACHED();
  return "";
}

void AudioHandler::SetChannelCountMode(const String& mode,
                                       ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(Context());

  ChannelCountMode old_mode = channel_count_mode_;

  if (mode == "max") {
    new_channel_count_mode_ = kMax;
  } else if (mode == "clamped-max") {
    new_channel_count_mode_ = kClampedMax;
  } else if (mode == "explicit") {
    new_channel_count_mode_ = kExplicit;
  } else {
    NOTREACHED();
  }

  if (new_channel_count_mode_ != old_mode)
    Context()->GetDeferredTaskHandler().AddChangedChannelCountMode(this);
}

String AudioHandler::ChannelInterpretation() {
  // Because we delay the actual setting of the interpreation to the pre or
  // post rendering phase, we want to return the value that was set, not the
  // actual current interpretation.
  switch (new_channel_interpretation_) {
    case AudioBus::kSpeakers:
      return "speakers";
    case AudioBus::kDiscrete:
      return "discrete";
  }
  NOTREACHED();
  return "";
}

void AudioHandler::SetChannelInterpretation(const String& interpretation,
                                            ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(Context());

  AudioBus::ChannelInterpretation old_mode = channel_interpretation_;

  if (interpretation == "speakers") {
    new_channel_interpretation_ = AudioBus::kSpeakers;
  } else if (interpretation == "discrete") {
    new_channel_interpretation_ = AudioBus::kDiscrete;
  } else {
    NOTREACHED();
  }

  if (new_channel_interpretation_ != old_mode)
    Context()->GetDeferredTaskHandler().AddChangedChannelInterpretation(this);
}

void AudioHandler::UpdateChannelsForInputs() {
  for (auto& input : inputs_)
    input->ChangedOutputs();
}

void AudioHandler::ProcessIfNecessary(uint32_t frames_to_process) {
  DCHECK(Context()->IsAudioThread());

  if (!IsInitialized())
    return;

  TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
               "AudioHandler::ProcessIfNecessary", "this",
               static_cast<void*>(this), "node type", NodeTypeName().Ascii());

  // Ensure that we only process once per rendering quantum.
  // This handles the "fanout" problem where an output is connected to multiple
  // inputs.  The first time we're called during this time slice we process, but
  // after that we don't want to re-process, instead our output(s) will already
  // have the results cached in their bus;
  double current_time = Context()->currentTime();
  if (last_processing_time_ != current_time) {
    // important to first update this time because of feedback loops in the
    // rendering graph.
    last_processing_time_ = current_time;

    PullInputs(frames_to_process);

    bool silent_inputs = InputsAreSilent();
    if (silent_inputs && PropagatesSilence()) {
      SilenceOutputs();
      // AudioParams still need to be processed so that the value can be updated
      // if there are automations or so that the upstream nodes get pulled if
      // any are connected to the AudioParam.
      ProcessOnlyAudioParams(frames_to_process);
    } else {
      // Unsilence the outputs first because the processing of the node may
      // cause the outputs to go silent and we want to propagate that hint to
      // the downstream nodes.  (For example, a Gain node with a gain of 0 will
      // want to silence its output.)
      UnsilenceOutputs();
      Process(frames_to_process);
    }

    if (!silent_inputs) {
      // Update |last_non_silent_time| AFTER processing this block.
      // Doing it before causes |PropagateSilence()| to be one render
      // quantum longer than necessary.
      last_non_silent_time_ =
          (Context()->CurrentSampleFrame() + frames_to_process) /
          static_cast<double>(Context()->sampleRate());
    }
  }
}

void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) {
  DCHECK(Context()->IsAudioThread());
  deferred_task_handler_->AssertGraphOwner();

  DCHECK(inputs_.Contains(input));

  input->UpdateInternalBus();
}

bool AudioHandler::PropagatesSilence() const {
  return last_non_silent_time_ + LatencyTime() + TailTime() <
         Context()->currentTime();
}

void AudioHandler::PullInputs(uint32_t frames_to_process) {
  DCHECK(Context()->IsAudioThread());

  // Process all of the AudioNodes connected to our inputs.
  for (auto& input : inputs_)
    input->Pull(nullptr, frames_to_process);
}

bool AudioHandler::InputsAreSilent() {
  for (auto& input : inputs_) {
    if (!input->Bus()->IsSilent())
      return false;
  }
  return true;
}

void AudioHandler::SilenceOutputs() {
  for (auto& output : outputs_)
    output->Bus()->Zero();
}

void AudioHandler::UnsilenceOutputs() {
  for (auto& output : outputs_)
    output->Bus()->ClearSilentFlag();
}

void AudioHandler::EnableOutputsIfNecessary() {
  DCHECK(IsMainThread());
  deferred_task_handler_->AssertGraphOwner();

  // We're enabling outputs for this handler.  Remove this from the tail
  // processing list (if it's there) so that we don't inadvertently disable the
  // outputs later on when the tail processing time has elapsed.
  Context()->GetDeferredTaskHandler().RemoveTailProcessingHandler(this, false);

#if DEBUG_AUDIONODE_REFERENCES > 1
  fprintf(stderr,
          "[%16p]: %16p: %2d: EnableOutputsIfNecessary: is_disabled %d count "
          "%d output size %u\n",
          Context(), this, GetNodeType(), is_disabled_, connection_ref_count_,
          outputs_.size());
#endif

  if (is_disabled_ && connection_ref_count_ > 0) {
    is_disabled_ = false;
    for (auto& output : outputs_)
      output->Enable();
  }
}

void AudioHandler::DisableOutputsIfNecessary() {
  // This function calls other functions that require graph ownership,
  // so assert that this needs graph ownership too.
  deferred_task_handler_->AssertGraphOwner();

#if DEBUG_AUDIONODE_REFERENCES > 1
  fprintf(stderr,
          "[%16p]: %16p: %2d: DisableOutputsIfNecessary is_disabled %d count %d"
          " tail %d\n",
          Context(), this, GetNodeType(), is_disabled_, connection_ref_count_,
          RequiresTailProcessing());
#endif

  // Disable outputs if appropriate. We do this if the number of connections is
  // 0 or 1. The case of 0 is from deref() where there are no connections left.
  // The case of 1 is from AudioNodeInput::disable() where we want to disable
  // outputs when there's only one connection left because we're ready to go
  // away, but can't quite yet.
  if (connection_ref_count_ <= 1 && !is_disabled_) {
    // Still may have JavaScript references, but no more "active" connection
    // references, so put all of our outputs in a "dormant" disabled state.
    // Garbage collection may take a very long time after this time, so the
    // "dormant" disabled nodes should not bog down the rendering...

    // As far as JavaScript is concerned, our outputs must still appear to be
    // connected.  But internally our outputs should be disabled from the inputs
    // they're connected to.  disable() can recursively deref connections (and
    // call disable()) down a whole chain of connected nodes.

    // If a node requires tail processing, we defer the disabling of
    // the outputs so that the tail for the node can be output.
    // Otherwise, we can disable the outputs right away.
    if (RequiresTailProcessing()) {
      if (deferred_task_handler_->AcceptsTailProcessing())
        deferred_task_handler_->AddTailProcessingHandler(this);
    } else {
      DisableOutputs();
    }
  }
}

void AudioHandler::DisableOutputs() {
  is_disabled_ = true;
  for (auto& output : outputs_)
    output->Disable();
}

void AudioHandler::MakeConnection() {
  deferred_task_handler_->AssertGraphOwner();
  connection_ref_count_++;

#if DEBUG_AUDIONODE_REFERENCES
  fprintf(
      stderr,
      "[%16p]: %16p: %2d: AudioHandler::MakeConnection   %3d [%3d] @%.15g\n",
      Context(), this, GetNodeType(), connection_ref_count_,
      node_count_[GetNodeType()], Context()->currentTime());
#endif

  // See the disabling code in disableOutputsIfNecessary(). This handles
  // the case where a node is being re-connected after being used at least
  // once and disconnected. In this case, we need to re-enable.
  EnableOutputsIfNecessary();
}

void AudioHandler::BreakConnectionWithLock() {
  deferred_task_handler_->AssertGraphOwner();
  connection_ref_count_--;

#if DEBUG_AUDIONODE_REFERENCES
  fprintf(stderr,
          "[%16p]: %16p: %2d: AudioHandler::BreakConnectionWitLock %3d [%3d] "
          "@%.15g\n",
          Context(), this, GetNodeType(), connection_ref_count_,
          node_count_[GetNodeType()], Context()->currentTime());
#endif

  if (!connection_ref_count_)
    DisableOutputsIfNecessary();
}

#if DEBUG_AUDIONODE_REFERENCES

bool AudioHandler::is_node_count_initialized_ = false;
int AudioHandler::node_count_[kNodeTypeEnd];

void AudioHandler::PrintNodeCounts() {
  fprintf(stderr, "\n\n");
  fprintf(stderr, "===========================\n");
  fprintf(stderr, "AudioNode: reference counts\n");
  fprintf(stderr, "===========================\n");

  for (unsigned i = 0; i < kNodeTypeEnd; ++i)
    fprintf(stderr, "%2d: %d\n", i, node_count_[i]);

  fprintf(stderr, "===========================\n\n\n");
}

#endif  // DEBUG_AUDIONODE_REFERENCES

#if DEBUG_AUDIONODE_REFERENCES > 1
void AudioHandler::TailProcessingDebug(const char* note, bool flag) {
  fprintf(stderr, "[%16p]: %16p: %2d: %s %d @%.15g flag=%d", Context(), this,
          GetNodeType(), note, connection_ref_count_, Context()->currentTime(),
          flag);

  // If we're on the audio thread, we can print out the tail and
  // latency times (because these methods can only be called from the
  // audio thread.)
  if (Context()->IsAudioThread()) {
    fprintf(stderr, ", tail=%.15g + %.15g, last=%.15g\n", TailTime(),
            LatencyTime(), last_non_silent_time_);
  }

  fprintf(stderr, "\n");
}

void AudioHandler::AddTailProcessingDebug() {
  TailProcessingDebug("addTail", false);
}

void AudioHandler::RemoveTailProcessingDebug(bool disable_outputs) {
  TailProcessingDebug("remTail", disable_outputs);
}
#endif  // DEBUG_AUDIONODE_REFERENCES > 1

void AudioHandler::UpdateChannelCountMode() {
  channel_count_mode_ = new_channel_count_mode_;
  UpdateChannelsForInputs();
}

void AudioHandler::UpdateChannelInterpretation() {
  channel_interpretation_ = new_channel_interpretation_;
}

unsigned AudioHandler::NumberOfOutputChannels() const {
  // This should only be called for ScriptProcessorNodes which are the only
  // nodes where you can have an output with 0 channels.  All other nodes have
  // have at least one output channel, so there's no reason other nodes should
  // ever call this function.
  DCHECK(0) << "numberOfOutputChannels() not valid for node type "
            << GetNodeType();
  return 1;
}
// ----------------------------------------------------------------

AudioNode::AudioNode(BaseAudioContext& context)
    : InspectorHelperMixin(context.GraphTracer(), context.Uuid()),
      context_(context),
      deferred_task_handler_(&context.GetDeferredTaskHandler()),
      handler_(nullptr) {}

AudioNode::~AudioNode() {
  // The graph lock is required to destroy the handler. And we can't use
  // |context_| to touch it, since that object may also be a dead heap object.
  {
    DeferredTaskHandler::GraphAutoLocker locker(*deferred_task_handler_);
    handler_ = nullptr;
  }
}

void AudioNode::Dispose() {
  DCHECK(IsMainThread());
#if DEBUG_AUDIONODE_REFERENCES
  fprintf(stderr, "[%16p]: %16p: %2d: AudioNode::dispose %16p @%g\n", context(),
          this, Handler().GetNodeType(), handler_.get(),
          context()->currentTime());
#endif
  BaseAudioContext::GraphAutoLocker locker(context());
  Handler().Dispose();

  // Add the handler to the orphan list.  This keeps the handler alive until it
  // can be deleted at a safe point (in pre/post handler task).  If the graph is
  // being processed, the handler must be added.  If the context is suspended,
  // the handler still needs to be added in case the context is resumed.
  DCHECK(context());
  if (context()->IsPullingAudioGraph() ||
      context()->ContextState() == BaseAudioContext::kSuspended) {
    context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
        std::move(handler_));
  }

  // Notify the inspector that this node is going away. The actual clean up
  // will be done in the subclass implementation.
  ReportWillBeDestroyed();
}

void AudioNode::SetHandler(scoped_refptr<AudioHandler> handler) {
  DCHECK(handler);
  handler_ = std::move(handler);

  // Unless the node is an AudioDestinationNode, notify the inspector that the
  // construction is completed. The actual report will be done in the subclass
  // implementation. (A destination node is owned by the context and will be
  // reported by it.)
  if (handler_->GetNodeType() != AudioHandler::NodeType::kNodeTypeDestination)
    ReportDidCreate();

#if DEBUG_AUDIONODE_REFERENCES
  fprintf(stderr, "[%16p]: %16p: %2d: AudioNode::AudioNode %16p\n", context(),
          this, handler_->GetNodeType(), handler_.get());
#endif
}

bool AudioNode::ContainsHandler() const {
  return handler_.get();
}

AudioHandler& AudioNode::Handler() const {
  return *handler_;
}

void AudioNode::Trace(Visitor* visitor) const {
  visitor->Trace(context_);
  visitor->Trace(connected_nodes_);
  visitor->Trace(connected_params_);
  InspectorHelperMixin::Trace(visitor);
  EventTargetWithInlineData::Trace(visitor);
}

void AudioNode::HandleChannelOptions(const AudioNodeOptions* options,
                                     ExceptionState& exception_state) {
  DCHECK(IsMainThread());

  if (options->hasChannelCount())
    setChannelCount(options->channelCount(), exception_state);
  if (options->hasChannelCountMode())
    setChannelCountMode(options->channelCountMode(), exception_state);
  if (options->hasChannelInterpretation())
    setChannelInterpretation(options->channelInterpretation(), exception_state);
}

BaseAudioContext* AudioNode::context() const {
  return context_;
}

AudioNode* AudioNode::connect(AudioNode* destination,
                              unsigned output_index,
                              unsigned input_index,
                              ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  context()->WarnForConnectionIfContextClosed();

  if (!destination) {
    exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
                                      "invalid destination node.");
    return nullptr;
  }

  // Sanity check input and output indices.
  if (output_index >= numberOfOutputs()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        "output index (" + String::Number(output_index) +
            ") exceeds number of outputs (" +
            String::Number(numberOfOutputs()) + ").");
    return nullptr;
  }

  if (destination && input_index >= destination->numberOfInputs()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        "input index (" + String::Number(input_index) +
            ") exceeds number of inputs (" +
            String::Number(destination->numberOfInputs()) + ").");
    return nullptr;
  }

  if (context() != destination->context()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidAccessError,
        "cannot connect to a destination "
        "belonging to a different audio context.");
    return nullptr;
  }

  // ScriptProcessorNodes with 0 output channels can't be connected to any
  // destination.  If there are no output channels, what would the destination
  // receive?  Just disallow this.
  if (Handler().GetNodeType() == AudioHandler::kNodeTypeScriptProcessor &&
      Handler().NumberOfOutputChannels() == 0) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
                                      "cannot connect a ScriptProcessorNode "
                                      "with 0 output channels to any "
                                      "destination node.");
    return nullptr;
  }

  AudioNodeWiring::Connect(Handler().Output(output_index),
                           destination->Handler().Input(input_index));
  if (!connected_nodes_[output_index]) {
    connected_nodes_[output_index] =
        MakeGarbageCollected<HeapHashSet<Member<AudioNode>>>();
  }
  connected_nodes_[output_index]->insert(destination);

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidConnectNodes(this, destination, output_index, input_index);

  return destination;
}

void AudioNode::connect(AudioParam* param,
                        unsigned output_index,
                        ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  context()->WarnForConnectionIfContextClosed();

  if (!param) {
    exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
                                      "invalid AudioParam.");
    return;
  }

  if (output_index >= numberOfOutputs()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        "output index (" + String::Number(output_index) +
            ") exceeds number of outputs (" +
            String::Number(numberOfOutputs()) + ").");
    return;
  }

  if (context() != param->Context()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kSyntaxError,
        "cannot connect to an AudioParam "
        "belonging to a different audio context.");
    return;
  }

  AudioNodeWiring::Connect(Handler().Output(output_index), param->Handler());
  if (!connected_params_[output_index]) {
    connected_params_[output_index] =
        MakeGarbageCollected<HeapHashSet<Member<AudioParam>>>();
  }
  connected_params_[output_index]->insert(param);

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidConnectNodeParam(this, param, output_index);
}

void AudioNode::DisconnectAllFromOutput(unsigned output_index) {
  Handler().Output(output_index).DisconnectAll();
  connected_nodes_[output_index] = nullptr;
  connected_params_[output_index] = nullptr;
}

bool AudioNode::DisconnectFromOutputIfConnected(
    unsigned output_index,
    AudioNode& destination,
    unsigned input_index_of_destination) {
  AudioNodeOutput& output = Handler().Output(output_index);
  AudioNodeInput& input =
      destination.Handler().Input(input_index_of_destination);
  if (!AudioNodeWiring::IsConnected(output, input))
    return false;
  AudioNodeWiring::Disconnect(output, input);
  connected_nodes_[output_index]->erase(&destination);
  return true;
}

bool AudioNode::DisconnectFromOutputIfConnected(unsigned output_index,
                                                AudioParam& param) {
  AudioNodeOutput& output = Handler().Output(output_index);
  if (!AudioNodeWiring::IsConnected(output, param.Handler()))
    return false;
  AudioNodeWiring::Disconnect(output, param.Handler());
  connected_params_[output_index]->erase(&param);
  return true;
}

void AudioNode::disconnect() {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  // Disconnect all outgoing connections.
  for (unsigned i = 0; i < numberOfOutputs(); ++i)
    DisconnectAllFromOutput(i);

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodes(this);
}

void AudioNode::disconnect(unsigned output_index,
                           ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  // Sanity check on the output index.
  if (output_index >= numberOfOutputs()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        ExceptionMessages::IndexOutsideRange(
            "output index", output_index, 0u,
            ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
            ExceptionMessages::kInclusiveBound));
    return;
  }
  // Disconnect all outgoing connections from the given output.
  DisconnectAllFromOutput(output_index);

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodes(this, nullptr, output_index);
}

void AudioNode::disconnect(AudioNode* destination,
                           ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  unsigned number_of_disconnections = 0;

  // FIXME: Can this be optimized? ChannelSplitter and ChannelMerger can have
  // 32 ports and that requires 1024 iterations to validate entire connections.
  for (unsigned output_index = 0; output_index < numberOfOutputs();
       ++output_index) {
    for (unsigned input_index = 0;
         input_index < destination->Handler().NumberOfInputs(); ++input_index) {
      if (DisconnectFromOutputIfConnected(output_index, *destination,
                                          input_index))
        number_of_disconnections++;
    }
  }

  // If there is no connection to the destination, throw an exception.
  if (number_of_disconnections == 0) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidAccessError,
        "the given destination is not connected.");
    return;
  }

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodes(this, destination);
}

void AudioNode::disconnect(AudioNode* destination,
                           unsigned output_index,
                           ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  if (output_index >= numberOfOutputs()) {
    // The output index is out of range. Throw an exception.
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        ExceptionMessages::IndexOutsideRange(
            "output index", output_index, 0u,
            ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
            ExceptionMessages::kInclusiveBound));
    return;
  }

  // If the output index is valid, proceed to disconnect.
  unsigned number_of_disconnections = 0;
  // Sanity check on destination inputs and disconnect when possible.
  for (unsigned input_index = 0; input_index < destination->numberOfInputs();
       ++input_index) {
    if (DisconnectFromOutputIfConnected(output_index, *destination,
                                        input_index))
      number_of_disconnections++;
  }

  // If there is no connection to the destination, throw an exception.
  if (number_of_disconnections == 0) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidAccessError,
        "output (" + String::Number(output_index) +
            ") is not connected to the given destination.");
  }

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodes(this, destination, output_index);
}

void AudioNode::disconnect(AudioNode* destination,
                           unsigned output_index,
                           unsigned input_index,
                           ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  if (output_index >= numberOfOutputs()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        ExceptionMessages::IndexOutsideRange(
            "output index", output_index, 0u,
            ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
            ExceptionMessages::kInclusiveBound));
    return;
  }

  if (input_index >= destination->Handler().NumberOfInputs()) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        ExceptionMessages::IndexOutsideRange(
            "input index", input_index, 0u, ExceptionMessages::kInclusiveBound,
            destination->numberOfInputs() - 1,
            ExceptionMessages::kInclusiveBound));
    return;
  }

  // If both indices are valid, proceed to disconnect.
  if (!DisconnectFromOutputIfConnected(output_index, *destination,
                                       input_index)) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidAccessError,
        "output (" + String::Number(output_index) +
            ") is not connected to the input (" + String::Number(input_index) +
            ") of the destination.");
    return;
  }

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodes(
      this, destination, output_index, input_index);
}

void AudioNode::disconnect(AudioParam* destination_param,
                           ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  // The number of disconnection made.
  unsigned number_of_disconnections = 0;

  // Check if the node output is connected the destination AudioParam.
  // Disconnect if connected and increase |numberOfDisconnectios| by 1.
  for (unsigned output_index = 0; output_index < Handler().NumberOfOutputs();
       ++output_index) {
    if (DisconnectFromOutputIfConnected(output_index, *destination_param))
      number_of_disconnections++;
  }

  // Throw an exception when there is no valid connection to the destination.
  if (number_of_disconnections == 0) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
                                      "the given AudioParam is not connected.");
    return;
  }

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodeParam(this, destination_param);
}

void AudioNode::disconnect(AudioParam* destination_param,
                           unsigned output_index,
                           ExceptionState& exception_state) {
  DCHECK(IsMainThread());
  BaseAudioContext::GraphAutoLocker locker(context());

  if (output_index >= Handler().NumberOfOutputs()) {
    // The output index is out of range. Throw an exception.
    exception_state.ThrowDOMException(
        DOMExceptionCode::kIndexSizeError,
        ExceptionMessages::IndexOutsideRange(
            "output index", output_index, 0u,
            ExceptionMessages::kInclusiveBound, numberOfOutputs() - 1,
            ExceptionMessages::kInclusiveBound));
    return;
  }

  // If the output index is valid, proceed to disconnect.
  if (!DisconnectFromOutputIfConnected(output_index, *destination_param)) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidAccessError,
        "specified destination AudioParam and node output (" +
            String::Number(output_index) + ") are not connected.");
    return;
  }

  Handler().UpdatePullStatusIfNeeded();

  GraphTracer().DidDisconnectNodeParam(this, destination_param, output_index);
}

unsigned AudioNode::numberOfInputs() const {
  return Handler().NumberOfInputs();
}

unsigned AudioNode::numberOfOutputs() const {
  return Handler().NumberOfOutputs();
}

unsigned AudioNode::channelCount() const {
  return Handler().ChannelCount();
}

void AudioNode::setChannelCount(unsigned count,
                                ExceptionState& exception_state) {
  Handler().SetChannelCount(count, exception_state);
}

String AudioNode::channelCountMode() const {
  return Handler().GetChannelCountMode();
}

void AudioNode::setChannelCountMode(const String& mode,
                                    ExceptionState& exception_state) {
  Handler().SetChannelCountMode(mode, exception_state);
}

String AudioNode::channelInterpretation() const {
  return Handler().ChannelInterpretation();
}

void AudioNode::setChannelInterpretation(const String& interpretation,
                                         ExceptionState& exception_state) {
  Handler().SetChannelInterpretation(interpretation, exception_state);
}

const AtomicString& AudioNode::InterfaceName() const {
  return event_target_names::kAudioNode;
}

ExecutionContext* AudioNode::GetExecutionContext() const {
  return context()->GetExecutionContext();
}

void AudioNode::DidAddOutput(unsigned number_of_outputs) {
  connected_nodes_.push_back(nullptr);
  DCHECK_EQ(number_of_outputs, connected_nodes_.size());
  connected_params_.push_back(nullptr);
  DCHECK_EQ(number_of_outputs, connected_params_.size());
}

}  // namespace blink
