// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/renderer/media/html_audio_element_capturer_source.h"

#include "base/threading/thread_task_runner_handle.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_sink.h"
#include "media/blink/webaudiosourceprovider_impl.h"
#include "media/blink/webmediaplayer_impl.h"
#include "third_party/WebKit/public/platform/WebMediaPlayer.h"

namespace content {

//static
HtmlAudioElementCapturerSource*
HtmlAudioElementCapturerSource::CreateFromWebMediaPlayerImpl(
    blink::WebMediaPlayer* player) {
  DCHECK(player);
  return new HtmlAudioElementCapturerSource(
      static_cast<media::WebAudioSourceProviderImpl*>(
          player->getAudioSourceProvider()));
}

HtmlAudioElementCapturerSource::HtmlAudioElementCapturerSource(
    media::WebAudioSourceProviderImpl* audio_source)
    : MediaStreamAudioSource(true /* is_local_source */),
      audio_source_(audio_source),
      is_started_(false),
      last_sample_rate_(0),
      last_num_channels_(0),
      last_bus_frames_(0) {
  DCHECK(audio_source_);
}

HtmlAudioElementCapturerSource::~HtmlAudioElementCapturerSource() {
  DCHECK(thread_checker_.CalledOnValidThread());
  EnsureSourceIsStopped();
}

bool HtmlAudioElementCapturerSource::EnsureSourceIsStarted() {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (audio_source_ && !is_started_) {
    // base:Unretained() is safe here since EnsureSourceIsStopped() guarantees
    // no more calls to OnAudioBus().
    audio_source_->SetCopyAudioCallback(base::Bind(
        &HtmlAudioElementCapturerSource::OnAudioBus, base::Unretained(this)));
    is_started_ = true;
  }
  return is_started_;
}

void HtmlAudioElementCapturerSource::EnsureSourceIsStopped() {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!is_started_)
    return;

  if (audio_source_) {
    audio_source_->ClearCopyAudioCallback();
    audio_source_ = nullptr;
  }
  is_started_ = false;
}

void HtmlAudioElementCapturerSource::OnAudioBus(
    std::unique_ptr<media::AudioBus> audio_bus,
    uint32_t frames_delayed,
    int sample_rate) {
  const base::TimeTicks capture_time =
      base::TimeTicks::Now() -
      base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond *
                                        frames_delayed / sample_rate);

  if (sample_rate != last_sample_rate_ ||
      audio_bus->channels() != last_num_channels_ ||
      audio_bus->frames() != last_bus_frames_) {
    MediaStreamAudioSource::SetFormat(
        media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                               media::GuessChannelLayout(audio_bus->channels()),
                               sample_rate, 16, audio_bus->frames()));
    last_sample_rate_ = sample_rate;
    last_num_channels_ = audio_bus->channels();
    last_bus_frames_ = audio_bus->frames();
  }

  MediaStreamAudioSource::DeliverDataToTracks(*audio_bus, capture_time);
}

}  // namespace content
