// Copyright 2013 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 "media/audio/alsa/alsa_input.h"

#include <stddef.h>

#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "media/audio/alsa/alsa_output.h"
#include "media/audio/alsa/alsa_util.h"
#include "media/audio/alsa/alsa_wrapper.h"
#include "media/audio/alsa/audio_manager_alsa.h"
#include "media/audio/audio_manager.h"

namespace media {

static const SampleFormat kSampleFormat = kSampleFormatS16;
static const snd_pcm_format_t kAlsaSampleFormat = SND_PCM_FORMAT_S16;

static const int kNumPacketsInRingBuffer = 3;

static const char kDefaultDevice1[] = "default";
static const char kDefaultDevice2[] = "plug:default";

const char AlsaPcmInputStream::kAutoSelectDevice[] = "";

AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerBase* audio_manager,
                                       const std::string& device_name,
                                       const AudioParameters& params,
                                       AlsaWrapper* wrapper)
    : audio_manager_(audio_manager),
      device_name_(device_name),
      params_(params),
      bytes_per_buffer_(params.GetBytesPerBuffer(kSampleFormat)),
      wrapper_(wrapper),
      buffer_duration_(base::TimeDelta::FromMicroseconds(
          params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
          static_cast<float>(params.sample_rate()))),
      callback_(NULL),
      device_handle_(NULL),
      mixer_handle_(NULL),
      mixer_element_handle_(NULL),
      read_callback_behind_schedule_(false),
      audio_bus_(AudioBus::Create(params)),
      capture_thread_("AlsaInput"),
      running_(false) {}

AlsaPcmInputStream::~AlsaPcmInputStream() = default;

bool AlsaPcmInputStream::Open() {
  if (device_handle_)
    return false;  // Already open.

  uint32_t packet_us = buffer_duration_.InMicroseconds();
  uint32_t buffer_us = packet_us * kNumPacketsInRingBuffer;

  // Use the same minimum required latency as output.
  buffer_us = std::max(buffer_us, AlsaPcmOutputStream::kMinLatencyMicros);

  if (device_name_ == kAutoSelectDevice) {
    const char* device_names[] = { kDefaultDevice1, kDefaultDevice2 };
    for (size_t i = 0; i < base::size(device_names); ++i) {
      device_handle_ = alsa_util::OpenCaptureDevice(
          wrapper_, device_names[i], params_.channels(), params_.sample_rate(),
          kAlsaSampleFormat, buffer_us, packet_us);

      if (device_handle_) {
        device_name_ = device_names[i];
        break;
      }
    }
  } else {
    device_handle_ = alsa_util::OpenCaptureDevice(
        wrapper_, device_name_.c_str(), params_.channels(),
        params_.sample_rate(), kAlsaSampleFormat, buffer_us, packet_us);
  }

  if (device_handle_) {
    audio_buffer_.reset(new uint8_t[bytes_per_buffer_]);

    // Open the microphone mixer.
    mixer_handle_ = alsa_util::OpenMixer(wrapper_, device_name_);
    if (mixer_handle_) {
      mixer_element_handle_ = alsa_util::LoadCaptureMixerElement(
          wrapper_, mixer_handle_);
    }
  }

  return device_handle_ != NULL;
}

void AlsaPcmInputStream::Start(AudioInputCallback* callback) {
  DCHECK(!callback_ && callback);
  callback_ = callback;
  StartAgc();
  int error = wrapper_->PcmPrepare(device_handle_);
  if (error < 0) {
    HandleError("PcmPrepare", error);
  } else {
    error = wrapper_->PcmStart(device_handle_);
    if (error < 0)
      HandleError("PcmStart", error);
  }

  if (error < 0) {
    callback_ = NULL;
  } else {
    base::Thread::Options options;
    options.priority = base::ThreadPriority::REALTIME_AUDIO;
    CHECK(capture_thread_.StartWithOptions(options));

    // We start reading data half |buffer_duration_| later than when the
    // buffer might have got filled, to accommodate some delays in the audio
    // driver. This could also give us a smooth read sequence going forward.
    base::TimeDelta delay = buffer_duration_ + buffer_duration_ / 2;
    next_read_time_ = base::TimeTicks::Now() + delay;
    running_ = true;
    capture_thread_.task_runner()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&AlsaPcmInputStream::ReadAudio, base::Unretained(this)),
        delay);
  }
}

bool AlsaPcmInputStream::Recover(int original_error) {
  DCHECK(capture_thread_.task_runner()->BelongsToCurrentThread());
  int error = wrapper_->PcmRecover(device_handle_, original_error, 1);
  if (error < 0) {
    // Docs say snd_pcm_recover returns the original error if it is not one
    // of the recoverable ones, so this log message will probably contain the
    // same error twice.
    LOG(WARNING) << "Unable to recover from \""
                 << wrapper_->StrError(original_error) << "\": "
                 << wrapper_->StrError(error);
    return false;
  }

  if (original_error == -EPIPE) {  // Buffer underrun/overrun.
    // For capture streams we have to repeat the explicit start() to get
    // data flowing again.
    error = wrapper_->PcmStart(device_handle_);
    if (error < 0) {
      HandleError("PcmStart", error);
      return false;
    }
  }

  return true;
}

void AlsaPcmInputStream::StopRunningOnCaptureThread() {
  DCHECK(capture_thread_.IsRunning());
  if (!capture_thread_.task_runner()->BelongsToCurrentThread()) {
    capture_thread_.task_runner()->PostTask(
        FROM_HERE,
        base::BindOnce(&AlsaPcmInputStream::StopRunningOnCaptureThread,
                       base::Unretained(this)));
    return;
  }
  running_ = false;
}

void AlsaPcmInputStream::ReadAudio() {
  DCHECK(capture_thread_.task_runner()->BelongsToCurrentThread());
  DCHECK(callback_);
  if (!running_)
    return;

  snd_pcm_sframes_t frames = wrapper_->PcmAvailUpdate(device_handle_);
  if (frames < 0) {  // Potentially recoverable error?
    LOG(WARNING) << "PcmAvailUpdate(): " << wrapper_->StrError(frames);
    Recover(frames);
  }

  if (frames < params_.frames_per_buffer()) {
    // Not enough data yet or error happened. In both cases wait for a very
    // small duration before checking again.
    // Even Though read callback was behind schedule, there is no data, so
    // reset the next_read_time_.
    if (read_callback_behind_schedule_) {
      next_read_time_ = base::TimeTicks::Now();
      read_callback_behind_schedule_ = false;
    }

    base::TimeDelta next_check_time = buffer_duration_ / 2;
    capture_thread_.task_runner()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&AlsaPcmInputStream::ReadAudio, base::Unretained(this)),
        next_check_time);
    return;
  }

  // Update the AGC volume level once every second. Note that, |volume| is
  // also updated each time SetVolume() is called through IPC by the
  // render-side AGC.
  double normalized_volume = 0.0;
  GetAgcVolume(&normalized_volume);

  int num_buffers = frames / params_.frames_per_buffer();
  while (num_buffers--) {
    int frames_read = wrapper_->PcmReadi(device_handle_, audio_buffer_.get(),
                                         params_.frames_per_buffer());
    if (frames_read == params_.frames_per_buffer()) {
      audio_bus_->FromInterleaved<SignedInt16SampleTypeTraits>(
          reinterpret_cast<int16_t*>(audio_buffer_.get()),
          audio_bus_->frames());

      // TODO(dalecurtis): This should probably use snd_pcm_htimestamp() so that
      // we can have |capture_time| directly instead of computing it as
      // Now() - available frames.
      snd_pcm_sframes_t avail_frames = wrapper_->PcmAvailUpdate(device_handle_);
      if (avail_frames < 0) {
        LOG(WARNING) << "PcmAvailUpdate(): "
                     << wrapper_->StrError(avail_frames);
        avail_frames = 0;  // Error getting number of avail frames, set it to 0
      }
      base::TimeDelta hardware_delay = base::TimeDelta::FromSecondsD(
          avail_frames / static_cast<double>(params_.sample_rate()));

      callback_->OnData(audio_bus_.get(),
                        base::TimeTicks::Now() - hardware_delay,
                        normalized_volume);
    } else if (frames_read < 0) {
      bool success = Recover(frames_read);
      LOG(WARNING) << "PcmReadi failed with error "
                   << wrapper_->StrError(frames_read) << ". "
                   << (success ? "Successfully" : "Unsuccessfully")
                   << " recovered.";
    } else {
      LOG(WARNING) << "PcmReadi returning less than expected frames: "
                   << frames_read << " vs. " << params_.frames_per_buffer()
                   << ". Dropping this buffer.";
    }
  }

  next_read_time_ += buffer_duration_;
  base::TimeDelta delay = next_read_time_ - base::TimeTicks::Now();
  if (delay < base::TimeDelta()) {
    DVLOG(1) << "Audio read callback behind schedule by "
             << (buffer_duration_ - delay).InMicroseconds()
             << " (us).";
    // Read callback is behind schedule. Assuming there is data pending in
    // the soundcard, invoke the read callback immediate in order to catch up.
    read_callback_behind_schedule_ = true;
    delay = base::TimeDelta();
  }

  capture_thread_.task_runner()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&AlsaPcmInputStream::ReadAudio, base::Unretained(this)),
      delay);
}

void AlsaPcmInputStream::Stop() {
  if (!device_handle_ || !callback_)
    return;

  StopAgc();

  StopRunningOnCaptureThread();
  capture_thread_.Stop();
  int error = wrapper_->PcmDrop(device_handle_);
  if (error < 0)
    HandleError("PcmDrop", error);

  callback_ = NULL;
}

void AlsaPcmInputStream::Close() {
  if (device_handle_) {
    Stop();
    int error = alsa_util::CloseDevice(wrapper_, device_handle_);
    if (error < 0)
      HandleError("PcmClose", error);

    if (mixer_handle_)
      alsa_util::CloseMixer(wrapper_, mixer_handle_, device_name_);

    audio_buffer_.reset();
    device_handle_ = NULL;
    mixer_handle_ = NULL;
    mixer_element_handle_ = NULL;
  }

  audio_manager_->ReleaseInputStream(this);
}

double AlsaPcmInputStream::GetMaxVolume() {
  if (!mixer_handle_ || !mixer_element_handle_) {
    DLOG(WARNING) << "GetMaxVolume is not supported for " << device_name_;
    return 0.0;
  }

  if (!wrapper_->MixerSelemHasCaptureVolume(mixer_element_handle_)) {
    DLOG(WARNING) << "Unsupported microphone volume for " << device_name_;
    return 0.0;
  }

  long min = 0;
  long max = 0;
  if (wrapper_->MixerSelemGetCaptureVolumeRange(mixer_element_handle_,
                                                &min,
                                                &max)) {
    DLOG(WARNING) << "Unsupported max microphone volume for " << device_name_;
    return 0.0;
  }
  DCHECK(min == 0);
  DCHECK(max > 0);

  return static_cast<double>(max);
}

void AlsaPcmInputStream::SetVolume(double volume) {
  if (!mixer_handle_ || !mixer_element_handle_) {
    DLOG(WARNING) << "SetVolume is not supported for " << device_name_;
    return;
  }

  int error = wrapper_->MixerSelemSetCaptureVolumeAll(
      mixer_element_handle_, static_cast<long>(volume));
  if (error < 0) {
    DLOG(WARNING) << "Unable to set volume for " << device_name_;
  }

  // Update the AGC volume level based on the last setting above. Note that,
  // the volume-level resolution is not infinite and it is therefore not
  // possible to assume that the volume provided as input parameter can be
  // used directly. Instead, a new query to the audio hardware is required.
  // This method does nothing if AGC is disabled.
  UpdateAgcVolume();
}

double AlsaPcmInputStream::GetVolume() {
  if (!mixer_handle_ || !mixer_element_handle_) {
    DLOG(WARNING) << "GetVolume is not supported for " << device_name_;
    return 0.0;
  }

  long current_volume = 0;
  int error = wrapper_->MixerSelemGetCaptureVolume(
      mixer_element_handle_, static_cast<snd_mixer_selem_channel_id_t>(0),
      &current_volume);
  if (error < 0) {
    DLOG(WARNING) << "Unable to get volume for " << device_name_;
    return 0.0;
  }

  return static_cast<double>(current_volume);
}

bool AlsaPcmInputStream::IsMuted() {
  return false;
}

void AlsaPcmInputStream::SetOutputDeviceForAec(
    const std::string& output_device_id) {
  // Not supported. Do nothing.
}

void AlsaPcmInputStream::HandleError(const char* method, int error) {
  LOG(WARNING) << method << ": " << wrapper_->StrError(error);
  if (callback_)
    callback_->OnError();
}

}  // namespace media
