/*
 *  Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "modules/audio_device/test_audio_device_impl.h"

#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <span>
#include <utility>

#include "api/environment/environment.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/units/time_delta.h"
#include "modules/audio_device/audio_device_buffer.h"
#include "modules/audio_device/audio_device_generic.h"
#include "modules/audio_device/include/test_audio_device.h"
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/task_utils/repeating_task.h"

namespace webrtc {
namespace {

constexpr int kFrameLengthUs = 10000;

}  // namespace

TestAudioDevice::TestAudioDevice(
    const Environment& env,
    std::unique_ptr<TestAudioDeviceModule::Capturer> capturer,
    std::unique_ptr<TestAudioDeviceModule::Renderer> renderer,
    float speed)
    : env_(env),
      capturer_(std::move(capturer)),
      renderer_(std::move(renderer)),
      process_interval_us_(kFrameLengthUs / speed),
      audio_buffer_(nullptr),
      rendering_(false),
      capturing_(false) {
  auto good_sample_rate = [](int sr) {
    return sr == 8000 || sr == 16000 || sr == 24000 || sr == 32000 ||
           sr == 44100 || sr == 48000;
  };

  if (renderer_) {
    const int sample_rate = renderer_->SamplingFrequency();
    playout_buffer_.resize(TestAudioDeviceModule::SamplesPerFrame(sample_rate) *
                               renderer_->NumChannels(),
                           0);
    RTC_CHECK(good_sample_rate(sample_rate));
  }
  if (capturer_) {
    RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency()));
  }
}

AudioDeviceGeneric::InitStatus TestAudioDevice::Init() {
  task_queue_ = env_.task_queue_factory().CreateTaskQueue(
      "TestAudioDeviceModuleImpl", TaskQueueFactory::Priority::kNormal);

  RepeatingTaskHandle::Start(task_queue_.get(), [this]() {
    ProcessAudio();
    return TimeDelta::Micros(process_interval_us_);
  });
  return InitStatus::OK;
}

int32_t TestAudioDevice::PlayoutIsAvailable(bool& available) {
  MutexLock lock(&lock_);
  available = renderer_ != nullptr;
  return 0;
}

int32_t TestAudioDevice::InitPlayout() {
  MutexLock lock(&lock_);

  if (rendering_) {
    return -1;
  }

  if (audio_buffer_ != nullptr && renderer_ != nullptr) {
    // Update webrtc audio buffer with the selected parameters
    audio_buffer_->SetPlayoutSampleRate(renderer_->SamplingFrequency());
    audio_buffer_->SetPlayoutChannels(renderer_->NumChannels());
  }
  rendering_initialized_ = true;
  return 0;
}

bool TestAudioDevice::PlayoutIsInitialized() const {
  MutexLock lock(&lock_);
  return rendering_initialized_;
}

int32_t TestAudioDevice::StartPlayout() {
  MutexLock lock(&lock_);
  RTC_CHECK(renderer_);
  rendering_ = true;
  return 0;
}

int32_t TestAudioDevice::StopPlayout() {
  MutexLock lock(&lock_);
  rendering_ = false;
  return 0;
}

int32_t TestAudioDevice::RecordingIsAvailable(bool& available) {
  MutexLock lock(&lock_);
  available = capturer_ != nullptr;
  return 0;
}

int32_t TestAudioDevice::InitRecording() {
  MutexLock lock(&lock_);

  if (capturing_) {
    return -1;
  }

  if (audio_buffer_ != nullptr && capturer_ != nullptr) {
    // Update webrtc audio buffer with the selected parameters
    audio_buffer_->SetRecordingSampleRate(capturer_->SamplingFrequency());
    audio_buffer_->SetRecordingChannels(capturer_->NumChannels());
  }
  capturing_initialized_ = true;
  return 0;
}

bool TestAudioDevice::RecordingIsInitialized() const {
  MutexLock lock(&lock_);
  return capturing_initialized_;
}

int32_t TestAudioDevice::StartRecording() {
  MutexLock lock(&lock_);
  capturing_ = true;
  return 0;
}

int32_t TestAudioDevice::StopRecording() {
  MutexLock lock(&lock_);
  capturing_ = false;
  return 0;
}

bool TestAudioDevice::Playing() const {
  MutexLock lock(&lock_);
  return rendering_;
}

bool TestAudioDevice::Recording() const {
  MutexLock lock(&lock_);
  return capturing_;
}

void TestAudioDevice::ProcessAudio() {
  MutexLock lock(&lock_);
  if (audio_buffer_ == nullptr) {
    return;
  }
  if (capturing_ && capturer_ != nullptr) {
    // Capture 10ms of audio. 2 bytes per sample.
    const bool keep_capturing = capturer_->Capture(&recording_buffer_);
    if (!recording_buffer_.empty()) {
      audio_buffer_->SetRecordedBuffer(
          recording_buffer_.data(),
          recording_buffer_.size() / capturer_->NumChannels(),
          std::make_optional(env_.clock().CurrentTime().ns()));
      audio_buffer_->DeliverRecordedData();
    }
    if (!keep_capturing) {
      capturing_ = false;
    }
  }
  if (rendering_) {
    const int sampling_frequency = renderer_->SamplingFrequency();
    int32_t samples_per_channel = audio_buffer_->RequestPlayoutData(
        TestAudioDeviceModule::SamplesPerFrame(sampling_frequency));
    audio_buffer_->GetPlayoutData(playout_buffer_.data());
    size_t samples_out = samples_per_channel * renderer_->NumChannels();
    RTC_CHECK_LE(samples_out, playout_buffer_.size());
    const bool keep_rendering = renderer_->Render(
        std::span<const int16_t>(playout_buffer_.data(), samples_out));
    if (!keep_rendering) {
      rendering_ = false;
    }
  }
}

void TestAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audio_buffer) {
  MutexLock lock(&lock_);
  RTC_DCHECK(audio_buffer || audio_buffer_);
  audio_buffer_ = audio_buffer;

  if (renderer_ != nullptr) {
    audio_buffer_->SetPlayoutSampleRate(renderer_->SamplingFrequency());
    audio_buffer_->SetPlayoutChannels(renderer_->NumChannels());
  }
  if (capturer_ != nullptr) {
    audio_buffer_->SetRecordingSampleRate(capturer_->SamplingFrequency());
    audio_buffer_->SetRecordingChannels(capturer_->NumChannels());
  }
}

}  // namespace webrtc
