// Copyright (c) 2019 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 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 "libcef/browser/audio_capturer.h"
#include "libcef/browser/browser_host_impl.h"

#include "components/mirroring/service/captured_audio_input.h"
#include "content/public/browser/audio_loopback_stream_creator.h"
#include "media/audio/audio_input_device.h"

namespace {

media::ChannelLayout TranslateChannelLayout(
    cef_channel_layout_t channel_layout) {
  // Verify that our enum matches Chromium's values. The enum values match
  // between those enums and existing values don't ever change, so it's enough
  // to check that there are no new ones added.
  static_assert(
      static_cast<int>(CEF_CHANNEL_LAYOUT_MAX) ==
          static_cast<int>(media::CHANNEL_LAYOUT_MAX),
      "cef_channel_layout_t must match the ChannelLayout enum in Chromium");
  return static_cast<media::ChannelLayout>(channel_layout);
}

void StreamCreatorHelper(
    content::WebContents* source_web_contents,
    content::AudioLoopbackStreamCreator* audio_stream_creator,
    mojo::PendingRemote<mirroring::mojom::AudioStreamCreatorClient> client,
    const media::AudioParameters& params,
    uint32_t total_segments) {
  audio_stream_creator->CreateLoopbackStream(
      source_web_contents, params, total_segments,
      base::BindRepeating(
          [](mojo::PendingRemote<mirroring::mojom::AudioStreamCreatorClient>
                 client,
             mojo::PendingRemote<media::mojom::AudioInputStream> stream,
             mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
                 client_receiver,
             media::mojom::ReadOnlyAudioDataPipePtr data_pipe) {
            mojo::Remote<mirroring::mojom::AudioStreamCreatorClient>
                audio_client(std::move(client));
            audio_client->StreamCreated(
                std::move(stream), std::move(client_receiver),
                std::move(data_pipe), false /* initially_muted */);
          },
          base::Passed(&client)));
}

}  // namespace

CefAudioCapturer::CefAudioCapturer(const CefAudioParameters& params,
                                   CefRefPtr<CefBrowserHostImpl> browser,
                                   CefRefPtr<CefAudioHandler> audio_handler)
    : params_(params),
      browser_(browser),
      audio_handler_(audio_handler),
      audio_stream_creator_(content::AudioLoopbackStreamCreator::
                                CreateInProcessAudioLoopbackStreamCreator()) {
  media::AudioParameters audio_params(
      media::AudioParameters::AUDIO_PCM_LINEAR,
      TranslateChannelLayout(params.channel_layout), params.sample_rate,
      params.frames_per_buffer);

  if (!audio_params.IsValid()) {
    LOG(ERROR) << "Invalid audio parameters";
    return;
  }

  DCHECK(browser_);
  DCHECK(audio_handler_);
  DCHECK(browser_->web_contents());

  channels_ = audio_params.channels();
  audio_input_device_ = new media::AudioInputDevice(
      std::make_unique<mirroring::CapturedAudioInput>(base::BindRepeating(
          &StreamCreatorHelper, base::Unretained(browser_->web_contents()),
          base::Unretained(audio_stream_creator_.get()))),
      media::AudioInputDevice::kLoopback);

  audio_input_device_->Initialize(audio_params, this);
  audio_input_device_->Start();
}

CefAudioCapturer::~CefAudioCapturer() {
  StopStream();
}

void CefAudioCapturer::OnCaptureStarted() {
  audio_handler_->OnAudioStreamStarted(browser_, params_, channels_);
  DCHECK(!capturing_);
  capturing_ = true;
}

void CefAudioCapturer::Capture(const media::AudioBus* source,
                               base::TimeTicks audio_capture_time,
                               double /*volume*/,
                               bool /*key_pressed*/) {
  const int channels = source->channels();
  std::array<const float*, media::CHANNELS_MAX> data;
  DCHECK(channels == channels_);
  DCHECK(channels <= static_cast<int>(data.size()));
  for (int c = 0; c < channels; ++c) {
    data[c] = source->channel(c);
  }
  base::TimeDelta pts = audio_capture_time - base::TimeTicks::UnixEpoch();
  audio_handler_->OnAudioStreamPacket(browser_, data.data(), source->frames(),
                                      pts.InMilliseconds());
}

void CefAudioCapturer::OnCaptureError(const std::string& message) {
  audio_handler_->OnAudioStreamError(browser_, message);
  StopStream();
}

void CefAudioCapturer::StopStream() {
  if (audio_input_device_)
    audio_input_device_->Stop();
  if (capturing_)
    audio_handler_->OnAudioStreamStopped(browser_);

  audio_input_device_ = nullptr;
  capturing_ = false;
}