/*
 *  Copyright (c) 2018 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/android/aaudio_player.h"

#include "absl/memory/memory.h"
#include "api/array_view.h"
#include "modules/audio_device/android/audio_manager.h"
#include "modules/audio_device/fine_audio_buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"

namespace webrtc {

enum AudioDeviceMessageType : uint32_t {
  kMessageOutputStreamDisconnected,
};

AAudioPlayer::AAudioPlayer(AudioManager* audio_manager)
    : main_thread_(rtc::Thread::Current()),
      aaudio_(audio_manager, AAUDIO_DIRECTION_OUTPUT, this) {
  RTC_LOG(INFO) << "ctor";
  thread_checker_aaudio_.Detach();
}

AAudioPlayer::~AAudioPlayer() {
  RTC_LOG(INFO) << "dtor";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  Terminate();
  RTC_LOG(INFO) << "#detected underruns: " << underrun_count_;
}

int AAudioPlayer::Init() {
  RTC_LOG(INFO) << "Init";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  if (aaudio_.audio_parameters().channels() == 2) {
    RTC_DLOG(LS_WARNING) << "Stereo mode is enabled";
  }
  return 0;
}

int AAudioPlayer::Terminate() {
  RTC_LOG(INFO) << "Terminate";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  StopPlayout();
  return 0;
}

int AAudioPlayer::InitPlayout() {
  RTC_LOG(INFO) << "InitPlayout";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  RTC_DCHECK(!initialized_);
  RTC_DCHECK(!playing_);
  if (!aaudio_.Init()) {
    return -1;
  }
  initialized_ = true;
  return 0;
}

bool AAudioPlayer::PlayoutIsInitialized() const {
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  return initialized_;
}

int AAudioPlayer::StartPlayout() {
  RTC_LOG(INFO) << "StartPlayout";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  RTC_DCHECK(!playing_);
  if (!initialized_) {
    RTC_DLOG(LS_WARNING)
        << "Playout can not start since InitPlayout must succeed first";
    return 0;
  }
  if (fine_audio_buffer_) {
    fine_audio_buffer_->ResetPlayout();
  }
  if (!aaudio_.Start()) {
    return -1;
  }
  underrun_count_ = aaudio_.xrun_count();
  first_data_callback_ = true;
  playing_ = true;
  return 0;
}

int AAudioPlayer::StopPlayout() {
  RTC_LOG(INFO) << "StopPlayout";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  if (!initialized_ || !playing_) {
    return 0;
  }
  if (!aaudio_.Stop()) {
    RTC_LOG(LS_ERROR) << "StopPlayout failed";
    return -1;
  }
  thread_checker_aaudio_.Detach();
  initialized_ = false;
  playing_ = false;
  return 0;
}

bool AAudioPlayer::Playing() const {
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  return playing_;
}

void AAudioPlayer::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
  RTC_DLOG(INFO) << "AttachAudioBuffer";
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  audio_device_buffer_ = audioBuffer;
  const AudioParameters audio_parameters = aaudio_.audio_parameters();
  audio_device_buffer_->SetPlayoutSampleRate(audio_parameters.sample_rate());
  audio_device_buffer_->SetPlayoutChannels(audio_parameters.channels());
  RTC_CHECK(audio_device_buffer_);
  // Create a modified audio buffer class which allows us to ask for any number
  // of samples (and not only multiple of 10ms) to match the optimal buffer
  // size per callback used by AAudio.
  fine_audio_buffer_ = absl::make_unique<FineAudioBuffer>(audio_device_buffer_);
}

int AAudioPlayer::SpeakerVolumeIsAvailable(bool& available) {
  available = false;
  return 0;
}

void AAudioPlayer::OnErrorCallback(aaudio_result_t error) {
  RTC_LOG(LS_ERROR) << "OnErrorCallback: " << AAudio_convertResultToText(error);
  // TODO(henrika): investigate if we can use a thread checker here. Initial
  // tests shows that this callback can sometimes be called on a unique thread
  // but according to the documentation it should be on the same thread as the
  // data callback.
  // RTC_DCHECK_RUN_ON(&thread_checker_aaudio_);
  if (aaudio_.stream_state() == AAUDIO_STREAM_STATE_DISCONNECTED) {
    // The stream is disconnected and any attempt to use it will return
    // AAUDIO_ERROR_DISCONNECTED.
    RTC_LOG(WARNING) << "Output stream disconnected";
    // AAudio documentation states: "You should not close or reopen the stream
    // from the callback, use another thread instead". A message is therefore
    // sent to the main thread to do the restart operation.
    RTC_DCHECK(main_thread_);
    main_thread_->Post(RTC_FROM_HERE, this, kMessageOutputStreamDisconnected);
  }
}

aaudio_data_callback_result_t AAudioPlayer::OnDataCallback(void* audio_data,
                                                           int32_t num_frames) {
  RTC_DCHECK_RUN_ON(&thread_checker_aaudio_);
  // Log device id in first data callback to ensure that a valid device is
  // utilized.
  if (first_data_callback_) {
    RTC_LOG(INFO) << "--- First output data callback: "
                  << "device id=" << aaudio_.device_id();
    first_data_callback_ = false;
  }

  // Check if the underrun count has increased. If it has, increase the buffer
  // size by adding the size of a burst. It will reduce the risk of underruns
  // at the expense of an increased latency.
  // TODO(henrika): enable possibility to disable and/or tune the algorithm.
  const int32_t underrun_count = aaudio_.xrun_count();
  if (underrun_count > underrun_count_) {
    RTC_LOG(LS_ERROR) << "Underrun detected: " << underrun_count;
    underrun_count_ = underrun_count;
    aaudio_.IncreaseOutputBufferSize();
  }

  // Estimate latency between writing an audio frame to the output stream and
  // the time that same frame is played out on the output audio device.
  latency_millis_ = aaudio_.EstimateLatencyMillis();
  // TODO(henrika): use for development only.
  if (aaudio_.frames_written() % (1000 * aaudio_.frames_per_burst()) == 0) {
    RTC_DLOG(INFO) << "output latency: " << latency_millis_
                   << ", num_frames: " << num_frames;
  }

  // Read audio data from the WebRTC source using the FineAudioBuffer object
  // and write that data into |audio_data| to be played out by AAudio.
  // Prime output with zeros during a short initial phase to avoid distortion.
  // TODO(henrika): do more work to figure out of if the initial forced silence
  // period is really needed.
  if (aaudio_.frames_written() < 50 * aaudio_.frames_per_burst()) {
    const size_t num_bytes =
        sizeof(int16_t) * aaudio_.samples_per_frame() * num_frames;
    memset(audio_data, 0, num_bytes);
  } else {
    fine_audio_buffer_->GetPlayoutData(
        rtc::MakeArrayView(static_cast<int16_t*>(audio_data),
                           aaudio_.samples_per_frame() * num_frames),
        static_cast<int>(latency_millis_ + 0.5));
  }

  // TODO(henrika): possibly add trace here to be included in systrace.
  // See https://developer.android.com/studio/profile/systrace-commandline.html.
  return AAUDIO_CALLBACK_RESULT_CONTINUE;
}

void AAudioPlayer::OnMessage(rtc::Message* msg) {
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  switch (msg->message_id) {
    case kMessageOutputStreamDisconnected:
      HandleStreamDisconnected();
      break;
  }
}

void AAudioPlayer::HandleStreamDisconnected() {
  RTC_DCHECK_RUN_ON(&main_thread_checker_);
  RTC_DLOG(INFO) << "HandleStreamDisconnected";
  if (!initialized_ || !playing_) {
    return;
  }
  // Perform a restart by first closing the disconnected stream and then start
  // a new stream; this time using the new (preferred) audio output device.
  StopPlayout();
  InitPlayout();
  StartPlayout();
}
}  // namespace webrtc
