// Copyright 2016 The Fuchsia 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 "src/media/audio/audio_core/audio_input.h"

#include "src/media/audio/audio_core/audio_device_manager.h"

namespace media::audio {

constexpr zx_duration_t kMinFenceDistance = ZX_MSEC(200);
constexpr zx_duration_t kMaxFenceDistance = kMinFenceDistance + ZX_MSEC(20);

// static
fbl::RefPtr<AudioInput> AudioInput::Create(zx::channel channel,
                                           AudioDeviceManager* manager) {
  return fbl::AdoptRef(new AudioInput(std::move(channel), manager));
}

AudioInput::AudioInput(zx::channel channel, AudioDeviceManager* manager)
    : AudioDevice(Type::Input, manager),
      initial_stream_channel_(std::move(channel)) {}

zx_status_t AudioInput::Init() {
  zx_status_t res = AudioDevice::Init();
  if (res != ZX_OK) {
    return res;
  }

  res = driver_->Init(std::move(initial_stream_channel_));
  if (res == ZX_OK) {
    state_ = State::Initialized;
  }

  return res;
}

void AudioInput::OnWakeup() {
  // We were poked.  Are we just starting up?
  if (state_ == State::Initialized) {
    if (driver_->GetDriverInfo() != ZX_OK) {
      ShutdownSelf();
    } else {
      state_ = State::FetchingFormats;
    }
    return;
  }

  UpdateDriverGainState();
}

void AudioInput::OnDriverInfoFetched() {
  state_ = State::Idle;

  uint32_t pref_fps = 48000;
  uint32_t pref_chan = 1;
  fuchsia::media::AudioSampleFormat pref_fmt =
      fuchsia::media::AudioSampleFormat::SIGNED_16;

  zx_status_t res = SelectBestFormat(driver_->format_ranges(), &pref_fps,
                                     &pref_chan, &pref_fmt);
  if (res != ZX_OK) {
    FXL_LOG(ERROR)
        << "Audio input failed to find any compatible driver formats.  Req was "
        << pref_fps << " Hz " << pref_chan << " channel(s) sample format(0x"
        << std::hex << static_cast<uint32_t>(pref_fmt) << ")";
    ShutdownSelf();
    return;
  }

  const auto& hw_gain = driver()->hw_gain_state();
  if (hw_gain.min_gain > hw_gain.max_gain) {
    FXL_LOG(ERROR) << "Audio input has invalid gain limits ["
                   << hw_gain.min_gain << ", " << hw_gain.max_gain << "].";
    ShutdownSelf();
    return;
  }

  // TODO(mpuryear): Save to the hub the configured format for this input.

  // Send config request; recompute distance between start|end sampling fences.
  driver_->Configure(pref_fps, pref_chan, pref_fmt, kMaxFenceDistance);

  int64_t dist = TimelineRate(pref_fps, ZX_SEC(1)).Scale(kMinFenceDistance);
  FXL_DCHECK(dist < std::numeric_limits<uint32_t>::max());
  driver_->SetEndFenceToStartFenceFrames(static_cast<uint32_t>(dist));

  // Tell AudioDeviceManager it can add us to the set of active audio devices.
  ActivateSelf();
}

void AudioInput::OnDriverConfigComplete() {
  driver_->SetPlugDetectEnabled(true);
}

void AudioInput::OnDriverStartComplete() {
  // If we were unplugged while starting, stop now.
  if (!driver_->plugged()) {
    driver_->Stop();
  }
}

void AudioInput::OnDriverStopComplete() {
  // If we were plugged while stopping, start now.
  if (driver_->plugged()) {
    driver_->Start();
  }
}

void AudioInput::OnDriverPlugStateChange(bool plugged, zx_time_t plug_time) {
  if (plugged && (driver_->state() == AudioDriver::State::Configured)) {
    driver_->Start();
  } else if (!plugged && (driver_->state() == AudioDriver::State::Started)) {
    driver_->Stop();
  }

  // Reflect this message to the AudioDeviceManager so it can deal with the
  // routing consequences of the plug state change.
  manager_->ScheduleMainThreadTask([manager = manager_,
                                    output = fbl::WrapRefPtr(this), plugged,
                                    plug_time]() {
    manager->HandlePlugStateChange(std::move(output), plugged, plug_time);
  });
}

void AudioInput::ApplyGainLimits(::fuchsia::media::AudioGainInfo* in_out_info,
                                 uint32_t set_flags) {
  // By the time anyone is calling "ApplyGainLimits", we need to have our basic
  // audio gain control capabilities established.
  ZX_DEBUG_ASSERT(driver()->state() != AudioDriver::State::Uninitialized);
  ZX_DEBUG_ASSERT(driver()->state() != AudioDriver::State::MissingDriverInfo);

  const auto& caps = driver()->hw_gain_state();

  // If someone is trying to enable mute, but our hardware does not support
  // enabling mute, clear the flag.
  //
  // TODO(johngro): It should always be possible to mute.  We should maintain a
  // SW flag for implementing mute in case the hardware cannot.
  if (!caps.can_mute) {
    in_out_info->flags &= ~(::fuchsia::media::AudioGainInfoFlag_Mute);
  }

  // Don't allow AGC unless HW supports it.
  if (!caps.can_agc) {
    in_out_info->flags &= ~(::fuchsia::media::AudioGainInfoFlag_AgcEnabled);
  }

  // If the user is attempting to set gain, enforce the gain limits.
  if (set_flags & fuchsia::media::SetAudioGainFlag_GainValid) {
    // This should have been enforced in OnDriverInfoFetched.
    FXL_DCHECK(caps.min_gain <= caps.max_gain);

    // If the hardware has not supplied a valid gain step size, or an
    // ridiculously small step size, just apply a clamp based on min/max.
    constexpr float kStepSizeLimit = 1e-6;
    if (caps.gain_step <= kStepSizeLimit) {
      in_out_info->gain_db =
          fbl::clamp(in_out_info->gain_db, caps.min_gain, caps.max_gain);
    } else {
      auto min_steps = static_cast<int32_t>(caps.min_gain / caps.gain_step);
      auto max_steps = static_cast<int32_t>(caps.max_gain / caps.gain_step);
      int32_t steps = fbl::clamp(
          static_cast<int32_t>(in_out_info->gain_db / caps.gain_step),
          min_steps, max_steps);
      in_out_info->gain_db = static_cast<float>(steps) * caps.gain_step;
    }
  }
}

void AudioInput::UpdateDriverGainState() {
  if ((state_ != State::Idle) || (device_settings_ == nullptr)) {
    return;
  }

  AudioDeviceSettings::GainState state;
  audio_set_gain_flags_t dirty_flags =
      device_settings_->SnapshotGainState(&state);
  if (!dirty_flags) {
    return;
  }

  driver()->SendSetGain(state, dirty_flags);
}

}  // namespace media::audio
