// Copyright (C) 2020 The Android Open Source Project
//
// 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 "AudioProxyStreamOut.h"

#include "HidlTypeUtil.h"

#define CHECK_OPT_API(func)                           \
  do {                                                \
    if (!mStream->func) return Result::NOT_SUPPORTED; \
  } while (0)

namespace audio_proxy {
namespace AUDIO_PROXY_CPP_VERSION {
namespace {

template <typename T>
size_t getArraySize(const T* const arr, T terminator) {
  if (!arr) {
    return 0;
  }

  const T* ptr = arr;
  while (*ptr != terminator) {
    ptr++;
  }

  return ptr - arr;
}

template <typename T, typename H>
hidl_vec<H> convertToHidlVec(const T* const arr, T terminator) {
  const size_t size = getArraySize(arr, terminator);
  hidl_vec<H> vec(size);

  for (size_t i = 0; i < size; i++) {
    vec[i] = H(arr[i]);
  }

  return vec;
}

std::vector<audio_proxy_key_val_t> buildKeyValVec(
    const hidl_vec<ParameterValue>& parameters) {
  std::vector<audio_proxy_key_val_t> kvVec(parameters.size() + 1);

  for (size_t i = 0; i < parameters.size(); i++) {
    kvVec[i] = {parameters[i].key.c_str(), parameters[i].value.c_str()};
  }

  // Terminator.
  kvVec.back() = {};
  return kvVec;
}

std::vector<const char*> buildKeyVec(const hidl_vec<hidl_string>& keys) {
  std::vector<const char*> keyVec(keys.size() + 1);
  for (size_t i = 0; i < keys.size(); i++) {
    keyVec[i] = keys[i].c_str();
  }

  // Terminator.
  keyVec.back() = nullptr;
  return keyVec;
}

void onParametersAvailable(void* obj, const audio_proxy_key_val_t* params) {
  std::vector<ParameterValue>* results =
      static_cast<std::vector<ParameterValue>*>(obj);
  while (params->key != nullptr) {
    ParameterValue result;
    result.key = params->key;
    result.value = params->val;
    results->push_back(result);
    params++;
  }
}
}  // namespace

AudioProxyStreamOut::AudioProxyStreamOut(audio_proxy_stream_out_t* stream,
                                         audio_proxy_device_t* device)
    : mStream(stream), mDevice(device) {}

AudioProxyStreamOut::~AudioProxyStreamOut() {
  mDevice->close_output_stream(mDevice, mStream);
}

uint64_t AudioProxyStreamOut::getFrameCount() const {
  return mStream->get_frame_count(mStream);
}

uint32_t AudioProxyStreamOut::getSampleRate() const {
  return mStream->get_sample_rate(mStream);
}

Result AudioProxyStreamOut::setSampleRate(uint32_t rate) {
  CHECK_OPT_API(set_sample_rate);
  return toResult(mStream->set_sample_rate(mStream, rate));
}

hidl_vec<uint32_t> AudioProxyStreamOut::getSupportedSampleRates(
    AudioFormat format) const {
  return convertToHidlVec<uint32_t, uint32_t>(
      mStream->get_supported_sample_rates(
          mStream, static_cast<audio_proxy_format_t>(format)),
      0);
}

size_t AudioProxyStreamOut::getBufferSize() const {
  return mStream->get_buffer_size(mStream);
}

hidl_bitfield<AudioChannelMask> AudioProxyStreamOut::getChannelMask() const {
  return hidl_bitfield<AudioChannelMask>(mStream->get_channel_mask(mStream));
}

Result AudioProxyStreamOut::setChannelMask(
    hidl_bitfield<AudioChannelMask> mask) {
  CHECK_OPT_API(set_channel_mask);
  return toResult(mStream->set_channel_mask(
      mStream, static_cast<audio_proxy_channel_mask_t>(mask)));
}

hidl_vec<hidl_bitfield<AudioChannelMask>>
AudioProxyStreamOut::getSupportedChannelMasks(AudioFormat format) const {
  const audio_proxy_channel_mask_t* channelMasks =
      mStream->get_supported_channel_masks(
          mStream, static_cast<audio_proxy_format_t>(format));

  return convertToHidlVec<audio_proxy_channel_mask_t,
                          hidl_bitfield<AudioChannelMask>>(
      channelMasks, AUDIO_PROXY_CHANNEL_INVALID);
}

AudioFormat AudioProxyStreamOut::getFormat() const {
  return AudioFormat(mStream->get_format(mStream));
}

hidl_vec<AudioFormat> AudioProxyStreamOut::getSupportedFormats() const {
  return convertToHidlVec<audio_proxy_format_t, AudioFormat>(
      mStream->get_supported_formats(mStream), AUDIO_PROXY_FORMAT_INVALID);
}

Result AudioProxyStreamOut::setFormat(AudioFormat format) {
  CHECK_OPT_API(set_format);
  return toResult(
      mStream->set_format(mStream, static_cast<audio_proxy_format_t>(format)));
}

Result AudioProxyStreamOut::standby() {
  return toResult(mStream->standby(mStream));
}

Result AudioProxyStreamOut::setParameters(
    const hidl_vec<ParameterValue>& context,
    const hidl_vec<ParameterValue>& parameters) {
  std::vector<audio_proxy_key_val_t> contextKvVec = buildKeyValVec(context);
  std::vector<audio_proxy_key_val_t> parameterKvVec =
      buildKeyValVec(parameters);
  return toResult(mStream->set_parameters(mStream, contextKvVec.data(),
                                          parameterKvVec.data()));
}

hidl_vec<ParameterValue> AudioProxyStreamOut::getParameters(
    const hidl_vec<ParameterValue>& context,
    const hidl_vec<hidl_string>& keys) const {
  std::vector<audio_proxy_key_val_t> contextKvVec = buildKeyValVec(context);
  std::vector<const char*> keyVec = buildKeyVec(keys);

  std::vector<ParameterValue> results;
  results.reserve(keys.size());

  mStream->get_parameters(mStream, contextKvVec.data(), keyVec.data(),
                          onParametersAvailable, &results);

  return hidl_vec<ParameterValue>(results);
}

ssize_t AudioProxyStreamOut::write(const void* buffer, size_t bytes) {
  return mStream->write(mStream, buffer, bytes);
}

uint32_t AudioProxyStreamOut::getLatency() const {
  return mStream->get_latency(mStream);
}

Result AudioProxyStreamOut::getRenderPosition(uint32_t* dsp_frames) const {
  CHECK_OPT_API(get_render_position);
  return toResult(mStream->get_render_position(mStream, dsp_frames));
}

Result AudioProxyStreamOut::getNextWriteTimestamp(int64_t* timestamp) const {
  CHECK_OPT_API(get_next_write_timestamp);
  return toResult(mStream->get_next_write_timestamp(mStream, timestamp));
}

Result AudioProxyStreamOut::getPresentationPosition(uint64_t* frames,
                                                    TimeSpec* timestamp) const {
  struct timespec ts;
  int ret = mStream->get_presentation_position(mStream, frames, &ts);
  if (ret != 0) {
    return toResult(ret);
  }

  timestamp->tvSec = ts.tv_sec;
  timestamp->tvNSec = ts.tv_nsec;
  return Result::OK;
}

Result AudioProxyStreamOut::pause() {
  return toResult(mStream->pause(mStream));
}

Result AudioProxyStreamOut::resume() {
  return toResult(mStream->resume(mStream));
}

bool AudioProxyStreamOut::supportsDrain() const {
  return mStream->drain != nullptr;
}

Result AudioProxyStreamOut::drain(AudioDrain type) {
  return toResult(
      mStream->drain(mStream, static_cast<audio_proxy_drain_type_t>(type)));
}

Result AudioProxyStreamOut::flush() {
  return toResult(mStream->flush(mStream));
}

Result AudioProxyStreamOut::setVolume(float left, float right) {
  CHECK_OPT_API(set_volume);
  return toResult(mStream->set_volume(mStream, left, right));
}

}  // namespace AUDIO_PROXY_CPP_VERSION
}  // namespace audio_proxy
