// Copyright 2018 Google Inc. 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/media_capture/encoders/flac_audio_encoder.h"

#include <string>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/string_util.h"

namespace {

// See https://tools.ietf.org/html/rfc2586 for MIME type
const char kFlacMimeType[] = "audio/flac";

// This is a guesstimated value. This number should be > 1.
const double kEstimatedFlacCompressionRatio = 1.30;

}  // namespace

namespace cobalt {
namespace media_capture {
namespace encoders {

bool FlacAudioEncoder::IsFlacMIMEType(const base::StringPiece& mime_type) {
  base::StringPiece mime_type_container = mime_type;
  size_t pos = mime_type.find_first_of(';');
  if (pos != base::StringPiece::npos) {
    mime_type_container = base::StringPiece(mime_type.begin(), pos);
  }
  const base::StringPiece flac_mime_type(kFlacMimeType);
  auto match_iterator =
      std::search(mime_type_container.begin(), mime_type_container.end(),
                  flac_mime_type.begin(), flac_mime_type.end(),
                  base::CaseInsensitiveCompareASCII<char>());
  return match_iterator == mime_type_container.begin();
}

FlacAudioEncoder::FlacAudioEncoder() : thread_("flac_encoding_thread") {
  thread_.Start();
}

FlacAudioEncoder::~FlacAudioEncoder() {
  thread_.message_loop_proxy()->PostBlockingTask(
      FROM_HERE,
      base::Bind(&FlacAudioEncoder::DestroyEncoder, base::Unretained(this)));
}

void FlacAudioEncoder::Encode(const ShellAudioBus& audio_bus,
                              base::TimeTicks reference_time) {
  scoped_ptr<ShellAudioBus> audio_bus_copy(
      new ShellAudioBus(audio_bus.channels(), audio_bus.frames(),
                        audio_bus.sample_type(), audio_bus.storage_type()));
  audio_bus_copy->Assign(audio_bus);

  // base::Unretained usage is safe here, since we're posting to a thread that
  // we own.
  thread_.message_loop_proxy()->PostTask(
      FROM_HERE, base::Bind(&FlacAudioEncoder::DoEncode, base::Unretained(this),
                            base::Passed(&audio_bus_copy), reference_time));
}

void FlacAudioEncoder::Finish(base::TimeTicks reference_time) {
  thread_.message_loop_proxy()->PostBlockingTask(
      FROM_HERE, base::Bind(&FlacAudioEncoder::DoFinish, base::Unretained(this),
                            reference_time));
}

std::string FlacAudioEncoder::GetMimeType() const {
  return flac_encoder_->GetMimeType();
}

int64 FlacAudioEncoder::GetEstimatedOutputBitsPerSecond(
    const media_stream::AudioParameters& params) const {
  DCHECK_EQ(params.bits_per_sample(), 16);
  DCHECK_EQ(params.channel_count(), 1);
  return static_cast<int64>(params.GetBitsPerSecond() /
                            kEstimatedFlacCompressionRatio);
}

void FlacAudioEncoder::OnSetFormat(
    const media_stream::AudioParameters& params) {
  // base::Unretained usage is safe here, since we're posting to a thread that
  // we own.
  thread_.message_loop_proxy()->PostTask(
      FROM_HERE, base::Bind(&FlacAudioEncoder::CreateEncoder,
                            base::Unretained(this), params));
}

void FlacAudioEncoder::CreateEncoder(
    const media_stream::AudioParameters& params) {
  flac_encoder_.reset(new speech::AudioEncoderFlac(params.sample_rate()));
}

void FlacAudioEncoder::DestroyEncoder() { flac_encoder_.reset(); }

void FlacAudioEncoder::DoEncode(scoped_ptr<ShellAudioBus> audio_bus,
                                base::TimeTicks reference_time) {
  DCHECK(flac_encoder_);
  flac_encoder_->Encode(audio_bus.get());
  auto data = flac_encoder_->GetAndClearAvailableEncodedData();
  if (data.empty()) {
    return;
  }
  PushDataToAllListeners(reinterpret_cast<uint8*>(&data[0]), data.size(),
                         reference_time);
}

void FlacAudioEncoder::DoFinish(base::TimeTicks reference_time) {
  if (!flac_encoder_) {
    return;
  }
  flac_encoder_->Finish();
  auto data = flac_encoder_->GetAndClearAvailableEncodedData();
  if (data.empty()) {
    PushDataToAllListeners(nullptr, 0, reference_time);
    return;
  }
  PushDataToAllListeners(reinterpret_cast<uint8*>(&data[0]), data.size(),
                         reference_time);
}

}  // namespace encoders
}  // namespace media_capture
}  // namespace cobalt
