#include "OpusCodec.h"
#include "BoostLog.h"

namespace Opus {

bool Encoder::open(int32_t samplerate, int32_t channels, uint32_t sampleSize) {
    int error = 0;

    uint32_t maxFrameSize = samplerate / 1000 * 60 * sampleSize * channels; // opus最大60ms一帧编码
    m_buffer.resize(maxFrameSize);

    m_encoder = opus_encoder_create(samplerate, channels, OPUS_APPLICATION_AUDIO, &error);
    if (error != OPUS_OK || m_encoder == nullptr) {
        LOG(error) << "opus_encoder_create() failed, status: " << error;
        return false;
    }

    opus_encoder_ctl(m_encoder, OPUS_SET_VBR(0)); // 0:CBR, 1:VBR
    opus_encoder_ctl(m_encoder, OPUS_SET_VBR_CONSTRAINT(true));
    opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(96000));
    opus_encoder_ctl(m_encoder, OPUS_SET_COMPLEXITY(8)); // 8    0~10
    opus_encoder_ctl(m_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
    opus_encoder_ctl(m_encoder, OPUS_SET_LSB_DEPTH(16)); // 每个采样16个bit，2个byte
    opus_encoder_ctl(m_encoder, OPUS_SET_DTX(0));
    opus_encoder_ctl(m_encoder, OPUS_SET_INBAND_FEC(0));

    return true;
}

void Encoder::close() {
    if (m_encoder != nullptr) {
        opus_encoder_destroy(m_encoder);
        m_encoder = nullptr;
    }
}

Encoder::~Encoder() {
    close();
}

const Opus::Packet Encoder::encode(const int16_t *pcm, int32_t framesize) {
    Packet ret;
    if (m_encoder == nullptr) return ret;
    ret.byteSize = opus_encode(m_encoder, pcm, framesize, m_buffer.data(), m_buffer.size());
    ret.data = m_buffer.data();
    LOG(info) << "framesize: " << framesize << ", record size: " << ret.byteSize;
    return ret;
}

bool Decoder::open(int32_t samplerate, int32_t channels) {

    int error = 0;
    m_decoder = opus_decoder_create(samplerate, channels, &error);
    if (error != OPUS_OK || m_decoder == NULL) {
        LOG(error) << "opus_decoder_create() failed, status: " << error;
        return false;
    }
    opus_decoder_ctl(m_decoder, OPUS_SET_LSB_DEPTH(16));
    return true;
}

int32_t Decoder::decode(const uint8_t *data, int32_t dataSize, int16_t *pcm, int32_t pcmBuffer) {
    int32_t decodedSize = opus_decode(m_decoder, data, dataSize, pcm, pcmBuffer, 0);
    LOG(info) << "dataSize: " << dataSize << ", decodes frame size: " << decodedSize;
    return decodedSize;
}

} // namespace Opus