/*
 * 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 "modules/webaudio/ScriptProcessorNode.h"
#include "bindings/core/v8/ExceptionState.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/ExecutionContext.h"
#include "core/dom/TaskRunnerHelper.h"
#include "modules/webaudio/AudioBuffer.h"
#include "modules/webaudio/AudioNodeInput.h"
#include "modules/webaudio/AudioNodeOutput.h"
#include "modules/webaudio/AudioProcessingEvent.h"
#include "modules/webaudio/BaseAudioContext.h"
#include "platform/CrossThreadFunctional.h"
#include "platform/WaitableEvent.h"
#include "public/platform/Platform.h"

namespace blink {

ScriptProcessorHandler::ScriptProcessorHandler(
    AudioNode& node,
    float sample_rate,
    size_t buffer_size,
    unsigned number_of_input_channels,
    unsigned number_of_output_channels)
    : AudioHandler(kNodeTypeScriptProcessor, node, sample_rate),
      double_buffer_index_(0),
      buffer_size_(buffer_size),
      buffer_read_write_index_(0),
      number_of_input_channels_(number_of_input_channels),
      number_of_output_channels_(number_of_output_channels),
      internal_input_bus_(AudioBus::Create(number_of_input_channels,
                                           AudioUtilities::kRenderQuantumFrames,
                                           false)) {
  // Regardless of the allowed buffer sizes, we still need to process at the
  // granularity of the AudioNode.
  if (buffer_size_ < AudioUtilities::kRenderQuantumFrames)
    buffer_size_ = AudioUtilities::kRenderQuantumFrames;

  DCHECK_LE(number_of_input_channels, BaseAudioContext::MaxNumberOfChannels());

  AddInput();
  AddOutput(number_of_output_channels);

  channel_count_ = number_of_input_channels;
  SetInternalChannelCountMode(kExplicit);

  Initialize();
}

RefPtr<ScriptProcessorHandler> ScriptProcessorHandler::Create(
    AudioNode& node,
    float sample_rate,
    size_t buffer_size,
    unsigned number_of_input_channels,
    unsigned number_of_output_channels) {
  return WTF::AdoptRef(new ScriptProcessorHandler(
      node, sample_rate, buffer_size, number_of_input_channels,
      number_of_output_channels));
}

ScriptProcessorHandler::~ScriptProcessorHandler() {
  Uninitialize();
}

void ScriptProcessorHandler::Initialize() {
  if (IsInitialized())
    return;

  float sample_rate = Context()->sampleRate();

  // Create double buffers on both the input and output sides.
  // These AudioBuffers will be directly accessed in the main thread by
  // JavaScript.
  for (unsigned i = 0; i < 2; ++i) {
    AudioBuffer* input_buffer =
        number_of_input_channels_
            ? AudioBuffer::Create(number_of_input_channels_, BufferSize(),
                                  sample_rate)
            : 0;
    AudioBuffer* output_buffer =
        number_of_output_channels_
            ? AudioBuffer::Create(number_of_output_channels_, BufferSize(),
                                  sample_rate)
            : 0;

    input_buffers_.push_back(input_buffer);
    output_buffers_.push_back(output_buffer);
  }

  AudioHandler::Initialize();
}

void ScriptProcessorHandler::Process(size_t frames_to_process) {
  // Discussion about inputs and outputs:
  // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
  // and output (see inputBus and outputBus below).  Additionally, there is a
  // double-buffering for input and output which is exposed directly to
  // JavaScript (see inputBuffer and outputBuffer below).  This node is the
  // producer for inputBuffer and the consumer for outputBuffer.  The JavaScript
  // code is the consumer of inputBuffer and the producer for outputBuffer.

  // Get input and output busses.
  AudioBus* input_bus = Input(0).Bus();
  AudioBus* output_bus = Output(0).Bus();

  // Get input and output buffers. We double-buffer both the input and output
  // sides.
  unsigned double_buffer_index = this->DoubleBufferIndex();
  bool is_double_buffer_index_good =
      double_buffer_index < 2 && double_buffer_index < input_buffers_.size() &&
      double_buffer_index < output_buffers_.size();
  DCHECK(is_double_buffer_index_good);
  if (!is_double_buffer_index_good)
    return;

  AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get();
  AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get();

  // Check the consistency of input and output buffers.
  unsigned number_of_input_channels = internal_input_bus_->NumberOfChannels();
  bool buffers_are_good =
      output_buffer && BufferSize() == output_buffer->length() &&
      buffer_read_write_index_ + frames_to_process <= BufferSize();

  // If the number of input channels is zero, it's ok to have inputBuffer = 0.
  if (internal_input_bus_->NumberOfChannels())
    buffers_are_good = buffers_are_good && input_buffer &&
                       BufferSize() == input_buffer->length();

  DCHECK(buffers_are_good);
  if (!buffers_are_good)
    return;

  // We assume that bufferSize() is evenly divisible by framesToProcess - should
  // always be true, but we should still check.
  bool is_frames_to_process_good = frames_to_process &&
                                   BufferSize() >= frames_to_process &&
                                   !(BufferSize() % frames_to_process);
  DCHECK(is_frames_to_process_good);
  if (!is_frames_to_process_good)
    return;

  unsigned number_of_output_channels = output_bus->NumberOfChannels();

  bool channels_are_good =
      (number_of_input_channels == number_of_input_channels_) &&
      (number_of_output_channels == number_of_output_channels_);
  DCHECK(channels_are_good);
  if (!channels_are_good)
    return;

  for (unsigned i = 0; i < number_of_input_channels; ++i)
    internal_input_bus_->SetChannelMemory(
        i,
        input_buffer->getChannelData(i).View()->Data() +
            buffer_read_write_index_,
        frames_to_process);

  if (number_of_input_channels)
    internal_input_bus_->CopyFrom(*input_bus);

  // Copy from the output buffer to the output.
  for (unsigned i = 0; i < number_of_output_channels; ++i) {
    memcpy(output_bus->Channel(i)->MutableData(),
           output_buffer->getChannelData(i).View()->Data() +
               buffer_read_write_index_,
           sizeof(float) * frames_to_process);
  }

  // Update the buffering index.
  buffer_read_write_index_ =
      (buffer_read_write_index_ + frames_to_process) % BufferSize();

  // m_bufferReadWriteIndex will wrap back around to 0 when the current input
  // and output buffers are full.
  // When this happens, fire an event and swap buffers.
  if (!buffer_read_write_index_) {
    // Avoid building up requests on the main thread to fire process events when
    // they're not being handled.  This could be a problem if the main thread is
    // very busy doing other things and is being held up handling previous
    // requests.  The audio thread can't block on this lock, so we call
    // tryLock() instead.
    MutexTryLocker try_locker(process_event_lock_);
    if (!try_locker.Locked()) {
      // We're late in handling the previous request. The main thread must be
      // very busy.  The best we can do is clear out the buffer ourself here.
      output_buffer->Zero();
    } else if (Context()->GetExecutionContext()) {
      // With the realtime context, execute the script code asynchronously
      // and do not wait.
      if (Context()->HasRealtimeConstraint()) {
        // Fire the event on the main thread with the appropriate buffer
        // index.
        TaskRunnerHelper::Get(TaskType::kMediaElementEvent,
                              Context()->GetExecutionContext())
            ->PostTask(
                BLINK_FROM_HERE,
                CrossThreadBind(&ScriptProcessorHandler::FireProcessEvent,
                                WrapRefPtr(this), double_buffer_index_));
      } else {
        // If this node is in the offline audio context, use the
        // waitable event to synchronize to the offline rendering thread.
        std::unique_ptr<WaitableEvent> waitable_event =
            WTF::MakeUnique<WaitableEvent>();

        TaskRunnerHelper::Get(TaskType::kMediaElementEvent,
                              Context()->GetExecutionContext())
            ->PostTask(
                BLINK_FROM_HERE,
                CrossThreadBind(&ScriptProcessorHandler::
                                    FireProcessEventForOfflineAudioContext,
                                WrapRefPtr(this), double_buffer_index_,
                                CrossThreadUnretained(waitable_event.get())));

        // Okay to block the offline audio rendering thread since it is
        // not the actual audio device thread.
        waitable_event->Wait();
      }
    }

    SwapBuffers();
  }
}

void ScriptProcessorHandler::FireProcessEvent(unsigned double_buffer_index) {
  DCHECK(IsMainThread());

  DCHECK_LT(double_buffer_index, 2u);
  if (double_buffer_index > 1)
    return;

  AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get();
  AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get();
  DCHECK(output_buffer);
  if (!output_buffer)
    return;

  // Avoid firing the event if the document has already gone away.
  if (GetNode() && Context() && Context()->GetExecutionContext()) {
    // This synchronizes with process().
    MutexLocker process_locker(process_event_lock_);

    // Calculate a playbackTime with the buffersize which needs to be processed
    // each time onaudioprocess is called.  The outputBuffer being passed to JS
    // will be played after exhuasting previous outputBuffer by
    // double-buffering.
    double playback_time = (Context()->CurrentSampleFrame() + buffer_size_) /
                           static_cast<double>(Context()->sampleRate());

    // Call the JavaScript event handler which will do the audio processing.
    GetNode()->DispatchEvent(AudioProcessingEvent::Create(
        input_buffer, output_buffer, playback_time));
  }
}

void ScriptProcessorHandler::FireProcessEventForOfflineAudioContext(
    unsigned double_buffer_index,
    WaitableEvent* waitable_event) {
  DCHECK(IsMainThread());

  DCHECK_LT(double_buffer_index, 2u);
  if (double_buffer_index > 1) {
    waitable_event->Signal();
    return;
  }

  AudioBuffer* input_buffer = input_buffers_[double_buffer_index].Get();
  AudioBuffer* output_buffer = output_buffers_[double_buffer_index].Get();
  DCHECK(output_buffer);
  if (!output_buffer) {
    waitable_event->Signal();
    return;
  }

  if (GetNode() && Context() && Context()->GetExecutionContext()) {
    // We do not need a process lock here because the offline render thread
    // is locked by the waitable event.
    double playback_time = (Context()->CurrentSampleFrame() + buffer_size_) /
                           static_cast<double>(Context()->sampleRate());
    GetNode()->DispatchEvent(AudioProcessingEvent::Create(
        input_buffer, output_buffer, playback_time));
  }

  waitable_event->Signal();
}

double ScriptProcessorHandler::TailTime() const {
  return std::numeric_limits<double>::infinity();
}

double ScriptProcessorHandler::LatencyTime() const {
  return std::numeric_limits<double>::infinity();
}

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

  if (channel_count != channel_count_) {
    exception_state.ThrowDOMException(
        kNotSupportedError, "channelCount cannot be changed from " +
                                String::Number(channel_count_) + " to " +
                                String::Number(channel_count));
  }
}

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

  if ((mode == "max") || (mode == "clamped-max")) {
    exception_state.ThrowDOMException(
        kNotSupportedError,
        "channelCountMode cannot be changed from 'explicit' to '" + mode + "'");
  }
}

// ----------------------------------------------------------------

ScriptProcessorNode::ScriptProcessorNode(BaseAudioContext& context,
                                         float sample_rate,
                                         size_t buffer_size,
                                         unsigned number_of_input_channels,
                                         unsigned number_of_output_channels)
    : AudioNode(context) {
  SetHandler(ScriptProcessorHandler::Create(*this, sample_rate, buffer_size,
                                            number_of_input_channels,
                                            number_of_output_channels));
}

static size_t ChooseBufferSize(size_t callback_buffer_size) {
  // Choose a buffer size based on the audio hardware buffer size. Arbitarily
  // make it a power of two that is 4 times greater than the hardware buffer
  // size.
  // FIXME: What is the best way to choose this?
  size_t buffer_size =
      1 << static_cast<unsigned>(log2(4 * callback_buffer_size) + 0.5);

  if (buffer_size < 256)
    return 256;
  if (buffer_size > 16384)
    return 16384;

  return buffer_size;
}

ScriptProcessorNode* ScriptProcessorNode::Create(
    BaseAudioContext& context,
    ExceptionState& exception_state) {
  DCHECK(IsMainThread());

  // Default buffer size is 0 (let WebAudio choose) with 2 inputs and 2
  // outputs.
  return Create(context, 0, 2, 2, exception_state);
}

ScriptProcessorNode* ScriptProcessorNode::Create(
    BaseAudioContext& context,
    size_t buffer_size,
    ExceptionState& exception_state) {
  DCHECK(IsMainThread());

  // Default is 2 inputs and 2 outputs.
  return Create(context, buffer_size, 2, 2, exception_state);
}

ScriptProcessorNode* ScriptProcessorNode::Create(
    BaseAudioContext& context,
    size_t buffer_size,
    unsigned number_of_input_channels,
    ExceptionState& exception_state) {
  DCHECK(IsMainThread());

  // Default is 2 outputs.
  return Create(context, buffer_size, number_of_input_channels, 2,
                exception_state);
}

ScriptProcessorNode* ScriptProcessorNode::Create(
    BaseAudioContext& context,
    size_t buffer_size,
    unsigned number_of_input_channels,
    unsigned number_of_output_channels,
    ExceptionState& exception_state) {
  DCHECK(IsMainThread());

  if (context.IsContextClosed()) {
    context.ThrowExceptionForClosedState(exception_state);
    return nullptr;
  }

  if (number_of_input_channels == 0 && number_of_output_channels == 0) {
    exception_state.ThrowDOMException(
        kIndexSizeError,
        "number of input channels and output channels cannot both be zero.");
    return nullptr;
  }

  if (number_of_input_channels > BaseAudioContext::MaxNumberOfChannels()) {
    exception_state.ThrowDOMException(
        kIndexSizeError,
        "number of input channels (" +
            String::Number(number_of_input_channels) + ") exceeds maximum (" +
            String::Number(BaseAudioContext::MaxNumberOfChannels()) + ").");
    return nullptr;
  }

  if (number_of_output_channels > BaseAudioContext::MaxNumberOfChannels()) {
    exception_state.ThrowDOMException(
        kIndexSizeError,
        "number of output channels (" +
            String::Number(number_of_output_channels) + ") exceeds maximum (" +
            String::Number(BaseAudioContext::MaxNumberOfChannels()) + ").");
    return nullptr;
  }

  // Check for valid buffer size.
  switch (buffer_size) {
    case 0:
      // Choose an appropriate size.  For an AudioContext, we need to
      // choose an appropriate size based on the callback buffer size.
      // For OfflineAudioContext, there's no callback buffer size, so
      // just use the minimum valid buffer size.
      buffer_size =
          context.HasRealtimeConstraint()
              ? ChooseBufferSize(context.destination()->CallbackBufferSize())
              : 256;
      break;
    case 256:
    case 512:
    case 1024:
    case 2048:
    case 4096:
    case 8192:
    case 16384:
      break;
    default:
      exception_state.ThrowDOMException(
          kIndexSizeError,
          "buffer size (" + String::Number(buffer_size) +
              ") must be 0 or a power of two between 256 and 16384.");
      return nullptr;
  }

  ScriptProcessorNode* node = new ScriptProcessorNode(
      context, context.sampleRate(), buffer_size, number_of_input_channels,
      number_of_output_channels);

  if (!node)
    return nullptr;

  // context keeps reference until we stop making javascript rendering callbacks
  context.NotifySourceNodeStartedProcessing(node);

  return node;
}

size_t ScriptProcessorNode::bufferSize() const {
  return static_cast<ScriptProcessorHandler&>(Handler()).BufferSize();
}

bool ScriptProcessorNode::HasPendingActivity() const {
  // To prevent the node from leaking after the context is closed.
  if (context()->IsContextClosed())
    return false;

  // If |onaudioprocess| event handler is defined, the node should not be
  // GCed even if it is out of scope.
  if (HasEventListeners(EventTypeNames::audioprocess))
    return true;

  return false;
}

}  // namespace blink
