/*
 *  Copyright (c) 2014 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.
 */

#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_

#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_minmax.h"

namespace webrtc {

template <typename T>
bool AudioEncoderIsacT<T>::Config::IsOk() const {
  if (max_bit_rate < 32000 && max_bit_rate != -1)
    return false;
  if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1)
    return false;

  switch (sample_rate_hz) {
    case 16000:
      if (max_bit_rate > 53400)
        return false;
      if (max_payload_size_bytes > 400)
        return false;
      return (frame_size_ms == 30 || frame_size_ms == 60) &&
             (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 32000));
    case 32000:
      if (max_bit_rate > 160000)
        return false;
      if (max_payload_size_bytes > 600)
        return false;
      return T::has_swb &&
             (frame_size_ms == 30 &&
              (bit_rate == 0 || (bit_rate >= 10000 && bit_rate <= 56000)));
    default:
      return false;
  }
}

template <typename T>
AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config) {
  RecreateEncoderInstance(config);
}

template <typename T>
AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
  RTC_CHECK_EQ(0, T::Free(isac_state_));
}

template <typename T>
int AudioEncoderIsacT<T>::SampleRateHz() const {
  return T::EncSampRate(isac_state_);
}

template <typename T>
size_t AudioEncoderIsacT<T>::NumChannels() const {
  return 1;
}

template <typename T>
size_t AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
  const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
  return static_cast<size_t>(rtc::CheckedDivExact(
      samples_in_next_packet, rtc::CheckedDivExact(SampleRateHz(), 100)));
}

template <typename T>
size_t AudioEncoderIsacT<T>::Max10MsFramesInAPacket() const {
  return 6;  // iSAC puts at most 60 ms in a packet.
}

template <typename T>
int AudioEncoderIsacT<T>::GetTargetBitrate() const {
  return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate;
}

template <typename T>
void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps) {
  // Set target bitrate directly without subtracting per-packet overhead,
  // because that's what AudioEncoderOpus does.
  SetTargetBitrate(target_bps,
                   /*subtract_per_packet_overhead=*/false);
}

template <typename T>
void AudioEncoderIsacT<T>::OnReceivedTargetAudioBitrate(int target_bps) {
  // Set target bitrate directly without subtracting per-packet overhead,
  // because that's what AudioEncoderOpus does.
  SetTargetBitrate(target_bps,
                   /*subtract_per_packet_overhead=*/false);
}

template <typename T>
void AudioEncoderIsacT<T>::OnReceivedUplinkBandwidth(
    int target_audio_bitrate_bps,
    absl::optional<int64_t> /*bwe_period_ms*/) {
  // Set target bitrate, subtracting the per-packet overhead if
  // WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
  // AudioEncoderOpus does.
  SetTargetBitrate(
      target_audio_bitrate_bps,
      /*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
}

template <typename T>
void AudioEncoderIsacT<T>::OnReceivedUplinkAllocation(
    BitrateAllocationUpdate update) {
  // Set target bitrate, subtracting the per-packet overhead if
  // WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
  // AudioEncoderOpus does.
  SetTargetBitrate(
      update.target_bitrate.bps<int>(),
      /*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
}

template <typename T>
void AudioEncoderIsacT<T>::OnReceivedOverhead(
    size_t overhead_bytes_per_packet) {
  overhead_per_packet_ = DataSize::Bytes(overhead_bytes_per_packet);
}

template <typename T>
AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeImpl(
    uint32_t rtp_timestamp,
    rtc::ArrayView<const int16_t> audio,
    rtc::Buffer* encoded) {
  if (!packet_in_progress_) {
    // Starting a new packet; remember the timestamp for later.
    packet_in_progress_ = true;
    packet_timestamp_ = rtp_timestamp;
  }
  size_t encoded_bytes = encoded->AppendData(
      kSufficientEncodeBufferSizeBytes, [&](rtc::ArrayView<uint8_t> encoded) {
        int r = T::Encode(isac_state_, audio.data(), encoded.data());

        if (T::GetErrorCode(isac_state_) == 6450) {
          // Isac is not able to effectively compress all types of signals. This
          // is a limitation of the codec that cannot be easily fixed.
          r = 0;
        }
        RTC_CHECK_GE(r, 0) << "Encode failed (error code "
                           << T::GetErrorCode(isac_state_) << ")";

        return static_cast<size_t>(r);
      });

  if (encoded_bytes == 0)
    return EncodedInfo();

  // Got enough input to produce a packet. Return the saved timestamp from
  // the first chunk of input that went into the packet.
  packet_in_progress_ = false;
  EncodedInfo info;
  info.encoded_bytes = encoded_bytes;
  info.encoded_timestamp = packet_timestamp_;
  info.payload_type = config_.payload_type;
  info.encoder_type = CodecType::kIsac;
  return info;
}

template <typename T>
void AudioEncoderIsacT<T>::Reset() {
  RecreateEncoderInstance(config_);
}

template <typename T>
absl::optional<std::pair<TimeDelta, TimeDelta>>
AudioEncoderIsacT<T>::GetFrameLengthRange() const {
  return {{TimeDelta::Millis(config_.frame_size_ms),
           TimeDelta::Millis(config_.frame_size_ms)}};
}

template <typename T>
void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps,
                                            bool subtract_per_packet_overhead) {
  if (subtract_per_packet_overhead) {
    const DataRate overhead_rate =
        overhead_per_packet_ / TimeDelta::Millis(config_.frame_size_ms);
    target_bps -= overhead_rate.bps();
  }
  target_bps = rtc::SafeClamp(target_bps, kMinBitrateBps,
                              MaxBitrateBps(config_.sample_rate_hz));
  int result = T::Control(isac_state_, target_bps, config_.frame_size_ms);
  RTC_DCHECK_EQ(result, 0);
  config_.bit_rate = target_bps;
}

template <typename T>
void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
  RTC_CHECK(config.IsOk());
  packet_in_progress_ = false;
  if (isac_state_)
    RTC_CHECK_EQ(0, T::Free(isac_state_));
  RTC_CHECK_EQ(0, T::Create(&isac_state_));
  RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, /*coding_mode=*/1));
  RTC_CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz));
  const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate;
  RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));

  if (config.max_payload_size_bytes != -1)
    RTC_CHECK_EQ(
        0, T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes));
  if (config.max_bit_rate != -1)
    RTC_CHECK_EQ(0, T::SetMaxRate(isac_state_, config.max_bit_rate));

  // Set the decoder sample rate even though we just use the encoder. This
  // doesn't appear to be necessary to produce a valid encoding, but without it
  // we get an encoding that isn't bit-for-bit identical with what a combined
  // encoder+decoder object produces.
  RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, config.sample_rate_hz));

  config_ = config;
}

}  // namespace webrtc

#endif  // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
