// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/speech/audio_encoder_flac.h"

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_number_conversions.h"

namespace cobalt {
namespace speech {

namespace {
const char kContentTypeFLAC[] = "audio/x-flac; rate=";
const int kFLACCompressionLevel = 0;  // 0 for speed
const int kBitsPerSample = 16;
const float kMaxInt16AsFloat32 = 32767.0f;
}  // namespace

AudioEncoderFlac::AudioEncoderFlac(int sample_rate)
    : encoder_(FLAC__stream_encoder_new()) {
  DCHECK(encoder_);

  // Set the number of channels to be encoded.
  FLAC__stream_encoder_set_channels(encoder_, 1);
  // Set the sample resolution of the input to be encoded.
  FLAC__stream_encoder_set_bits_per_sample(encoder_, kBitsPerSample);
  // Set the sample rate (in Hz) of the input to be encoded.
  FLAC__stream_encoder_set_sample_rate(encoder_,
                                       static_cast<uint32>(sample_rate));
  // Set the compression level. A higher level usually means more computation
  // but higher compression.
  FLAC__stream_encoder_set_compression_level(encoder_, kFLACCompressionLevel);

  // Initialize the encoder instance to encode native FLAC stream.
  FLAC__StreamEncoderInitStatus encoder_status =
      FLAC__stream_encoder_init_stream(encoder_, WriteCallback, NULL, NULL,
                                       NULL, this);
  DCHECK_EQ(encoder_status, FLAC__STREAM_ENCODER_INIT_STATUS_OK);
}

AudioEncoderFlac::~AudioEncoderFlac() {
  DCHECK(thread_checker_.CalledOnValidThread());
  FLAC__stream_encoder_delete(encoder_);
}

void AudioEncoderFlac::Encode(const ShellAudioBus* audio_bus) {
  DCHECK(thread_checker_.CalledOnValidThread());

  DCHECK_EQ(audio_bus->channels(), 1);
  uint32 frames = static_cast<uint32>(audio_bus->frames());
  scoped_array<FLAC__int32> flac_samples(new FLAC__int32[frames]);
  for (uint32 i = 0; i < frames; ++i) {
    if (audio_bus->sample_type() == ShellAudioBus::kFloat32) {
      flac_samples[i] = static_cast<FLAC__int32>(
          audio_bus->GetFloat32Sample(0, i) * kMaxInt16AsFloat32);
    } else {
      DCHECK_EQ(audio_bus->sample_type(), ShellAudioBus::kInt16);
      flac_samples[i] =
          static_cast<FLAC__int32>(audio_bus->GetInt16Sample(0, i));
    }
  }

  FLAC__int32* flac_samples_ptr = flac_samples.get();
  // Submit data for encoding.
  FLAC__bool success =
      FLAC__stream_encoder_process(encoder_, &flac_samples_ptr, frames);
  DCHECK(success);
}

void AudioEncoderFlac::Finish() {
  DCHECK(thread_checker_.CalledOnValidThread());

  // Finish the encoding. It causes the encoder to encode any data still in
  // its input pipe, and finally reset the encoder to the unintialized state.
  FLAC__stream_encoder_finish(encoder_);
}

std::string AudioEncoderFlac::GetMimeType() const {
  DCHECK(thread_checker_.CalledOnValidThread());

  return std::string(kContentTypeFLAC) +
         base::UintToString(FLAC__stream_encoder_get_sample_rate(encoder_));
}

std::string AudioEncoderFlac::GetAndClearAvailableEncodedData() {
  DCHECK(thread_checker_.CalledOnValidThread());

  std::string result = encoded_data_;
  encoded_data_.clear();
  return result;
}

// A write callback which will be called anytime there is a raw encoded data to
// write. The call to FLAC__stream_encoder_init_stream() currently will also
// immediately call the write callback several times, once with the FLAC
// signature, and once for each encoded metadata block.
FLAC__StreamEncoderWriteStatus AudioEncoderFlac::WriteCallback(
    const FLAC__StreamEncoder* encoder, const FLAC__byte buffer[], size_t bytes,
    unsigned int samples, unsigned int current_frame, void* client_data) {
  UNREFERENCED_PARAMETER(encoder);
  UNREFERENCED_PARAMETER(samples);
  UNREFERENCED_PARAMETER(current_frame);

  AudioEncoderFlac* audio_encoder =
      reinterpret_cast<AudioEncoderFlac*>(client_data);
  DCHECK(audio_encoder);
  DCHECK(audio_encoder->thread_checker_.CalledOnValidThread());

  audio_encoder->encoded_data_.append(reinterpret_cast<const char*>(buffer),
                                      bytes);

  return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}

}  // namespace speech
}  // namespace cobalt
