/*
 * Copyright (C) 2008 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 <math.h>

//#define LOG_NDEBUG 0
#define LOG_TAG "A2dpAudioInterface"
#include <utils/Log.h>
#include <utils/String8.h>

#include "A2dpAudioInterface.h"
#include "audio/liba2dp.h"


namespace android {

// ----------------------------------------------------------------------------

//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
//{
//    AudioHardwareInterface* hw = 0;
//
//    hw = AudioHardwareInterface::create();
//    LOGD("new A2dpAudioInterface(hw: %p)", hw);
//    hw = new A2dpAudioInterface(hw);
//    return hw;
//}

A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
    mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
{
}

A2dpAudioInterface::~A2dpAudioInterface()
{
    closeOutputStream((AudioStreamOut *)mOutput);
    delete mHardwareInterface;
}

status_t A2dpAudioInterface::initCheck()
{
    if (mHardwareInterface == 0) return NO_INIT;
    return mHardwareInterface->initCheck();
}

AudioStreamOut* A2dpAudioInterface::openOutputStream(
        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
    if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
        LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
        return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
    }

    status_t err = 0;

    // only one output stream allowed
    if (mOutput) {
        if (status)
            *status = -1;
        return NULL;
    }

    // create new output stream
    A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
    if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
        mOutput = out;
        mOutput->setBluetoothEnabled(mBluetoothEnabled);
        mOutput->setSuspended(mSuspended);
    } else {
        delete out;
    }

    if (status)
        *status = err;
    return mOutput;
}

void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
    if (mOutput == 0 || mOutput != out) {
        mHardwareInterface->closeOutputStream(out);
    }
    else {
        delete mOutput;
        mOutput = 0;
    }
}


AudioStreamIn* A2dpAudioInterface::openInputStream(
        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
        AudioSystem::audio_in_acoustics acoustics)
{
    return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
}

void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
{
    return mHardwareInterface->closeInputStream(in);
}

status_t A2dpAudioInterface::setMode(int mode)
{
    return mHardwareInterface->setMode(mode);
}

status_t A2dpAudioInterface::setMicMute(bool state)
{
    return mHardwareInterface->setMicMute(state);
}

status_t A2dpAudioInterface::getMicMute(bool* state)
{
    return mHardwareInterface->getMicMute(state);
}

status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
{
    AudioParameter param = AudioParameter(keyValuePairs);
    String8 value;
    String8 key;
    status_t status = NO_ERROR;

    LOGV("setParameters() %s", keyValuePairs.string());

    key = "bluetooth_enabled";
    if (param.get(key, value) == NO_ERROR) {
        mBluetoothEnabled = (value == "true");
        if (mOutput) {
            mOutput->setBluetoothEnabled(mBluetoothEnabled);
        }
        param.remove(key);
    }
    key = String8("A2dpSuspended");
    if (param.get(key, value) == NO_ERROR) {
        mSuspended = (value == "true");
        if (mOutput) {
            mOutput->setSuspended(mSuspended);
        }
        param.remove(key);
    }

    if (param.size()) {
        status_t hwStatus = mHardwareInterface->setParameters(param.toString());
        if (status == NO_ERROR) {
            status = hwStatus;
        }
    }

    return status;
}

String8 A2dpAudioInterface::getParameters(const String8& keys)
{
    AudioParameter param = AudioParameter(keys);
    AudioParameter a2dpParam = AudioParameter();
    String8 value;
    String8 key;

    key = "bluetooth_enabled";
    if (param.get(key, value) == NO_ERROR) {
        value = mBluetoothEnabled ? "true" : "false";
        a2dpParam.add(key, value);
        param.remove(key);
    }
    key = "A2dpSuspended";
    if (param.get(key, value) == NO_ERROR) {
        value = mSuspended ? "true" : "false";
        a2dpParam.add(key, value);
        param.remove(key);
    }

    String8 keyValuePairs  = a2dpParam.toString();

    if (param.size()) {
        if (keyValuePairs != "") {
            keyValuePairs += ";";
        }
        keyValuePairs += mHardwareInterface->getParameters(param.toString());
    }

    LOGV("getParameters() %s", keyValuePairs.string());
    return keyValuePairs;
}

size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
    return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
}

status_t A2dpAudioInterface::setVoiceVolume(float v)
{
    return mHardwareInterface->setVoiceVolume(v);
}

status_t A2dpAudioInterface::setMasterVolume(float v)
{
    return mHardwareInterface->setMasterVolume(v);
}

status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
{
    return mHardwareInterface->dumpState(fd, args);
}

// ----------------------------------------------------------------------------

A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
    mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
    // assume BT enabled to start, this is safe because its only the
    // enabled->disabled transition we are worried about
    mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false)
{
    // use any address by default
    strcpy(mA2dpAddress, "00:00:00:00:00:00");
    init();
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
        uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
    int lFormat = pFormat ? *pFormat : 0;
    uint32_t lChannels = pChannels ? *pChannels : 0;
    uint32_t lRate = pRate ? *pRate : 0;

    LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);

    // fix up defaults
    if (lFormat == 0) lFormat = format();
    if (lChannels == 0) lChannels = channels();
    if (lRate == 0) lRate = sampleRate();

    // check values
    if ((lFormat != format()) ||
            (lChannels != channels()) ||
            (lRate != sampleRate())){
        if (pFormat) *pFormat = format();
        if (pChannels) *pChannels = channels();
        if (pRate) *pRate = sampleRate();
        return BAD_VALUE;
    }

    if (pFormat) *pFormat = lFormat;
    if (pChannels) *pChannels = lChannels;
    if (pRate) *pRate = lRate;

    mDevice = device;
    return NO_ERROR;
}

A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
    LOGV("A2dpAudioStreamOut destructor");
    standby();
    close();
    LOGV("A2dpAudioStreamOut destructor returning from close()");
}

ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
{
    Mutex::Autolock lock(mLock);

    size_t remaining = bytes;
    status_t status = -1;

    if (!mBluetoothEnabled || mClosing || mSuspended) {
        LOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
               mBluetoothEnabled %d, mClosing %d, mSuspended %d",
                mBluetoothEnabled, mClosing, mSuspended);
        goto Error;
    }

    status = init();
    if (status < 0)
        goto Error;

    while (remaining > 0) {
        status = a2dp_write(mData, buffer, remaining);
        if (status <= 0) {
            LOGE("a2dp_write failed err: %d\n", status);
            goto Error;
        }
        remaining -= status;
        buffer = ((char *)buffer) + status;
    }

    mStandby = false;

    return bytes;

Error:
    // Simulate audio output timing in case of error
    usleep(((bytes * 1000 )/ frameSize() / sampleRate()) * 1000);

    return status;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
{
    if (!mData) {
        status_t status = a2dp_init(44100, 2, &mData);
        if (status < 0) {
            LOGE("a2dp_init failed err: %d\n", status);
            mData = NULL;
            return status;
        }
        a2dp_set_sink(mData, mA2dpAddress);
    }

    return 0;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
{
    int result = 0;

    if (mClosing) {
        LOGV("Ignore standby, closing");
        return result;
    }

    Mutex::Autolock lock(mLock);

    if (!mStandby) {
        result = a2dp_stop(mData);
        if (result == 0)
            mStandby = true;
    }

    return result;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
{
    AudioParameter param = AudioParameter(keyValuePairs);
    String8 value;
    String8 key = String8("a2dp_sink_address");
    status_t status = NO_ERROR;
    int device;
    LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());

    if (param.get(key, value) == NO_ERROR) {
        if (value.length() != strlen("00:00:00:00:00:00")) {
            status = BAD_VALUE;
        } else {
            setAddress(value.string());
        }
        param.remove(key);
    }
    key = String8("closing");
    if (param.get(key, value) == NO_ERROR) {
        mClosing = (value == "true");
        param.remove(key);
    }
    key = AudioParameter::keyRouting;
    if (param.getInt(key, device) == NO_ERROR) {
        if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
            mDevice = device;
            status = NO_ERROR;
        } else {
            status = BAD_VALUE;
        }
        param.remove(key);
    }

    if (param.size()) {
        status = BAD_VALUE;
    }
    return status;
}

String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
{
    AudioParameter param = AudioParameter(keys);
    String8 value;
    String8 key = String8("a2dp_sink_address");

    if (param.get(key, value) == NO_ERROR) {
        value = mA2dpAddress;
        param.add(key, value);
    }
    key = AudioParameter::keyRouting;
    if (param.get(key, value) == NO_ERROR) {
        param.addInt(key, (int)mDevice);
    }

    LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
    return param.toString();
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
    Mutex::Autolock lock(mLock);

    if (strlen(address) != strlen("00:00:00:00:00:00"))
        return -EINVAL;

    strcpy(mA2dpAddress, address);
    if (mData)
        a2dp_set_sink(mData, mA2dpAddress);

    return NO_ERROR;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled)
{
    LOGD("setBluetoothEnabled %d", enabled);

    Mutex::Autolock lock(mLock);

    mBluetoothEnabled = enabled;
    if (!enabled) {
        return close_l();
    }
    return NO_ERROR;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
{
    LOGV("setSuspended %d", onOff);
    mSuspended = onOff;
    standby();
    return NO_ERROR;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
{
    Mutex::Autolock lock(mLock);
    LOGV("A2dpAudioStreamOut::close() calling close_l()");
    return close_l();
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
{
    if (mData) {
        LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
        a2dp_cleanup(mData);
        mData = NULL;
    }
    return NO_ERROR;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
{
    return NO_ERROR;
}

status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames)
{
    //TODO: enable when supported by driver
    return INVALID_OPERATION;
}

}; // namespace android
