#include <stdio.h>
#include <string.h>
#include "MWAudioEncode.h"

FAACEncoder::FAACEncoder() :_faac(NULL), _faacCfg(NULL), _channels(0), _callback(NULL),
	_inputSamples(0), _maxOutputBytes(0), _encIn(NULL), _encInOffset(0), _encInSize(0), _encOut(NULL) {
}

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

int FAACEncoder::setCallback(AUDIO_ENCODE_CALLBACK cb, void *param) {
    _callback = cb;
    _param = param;
    
    return 0;
}

int FAACEncoder::open(uint32_t sampleRate, uint16_t channels, uint32_t bitrate) {
    _faac = faacEncOpen(sampleRate, channels, &_inputSamples, &_maxOutputBytes);
    if (NULL == _faac) {
        printf("faacEncOpen failed\n");
        return -1;
    }
    _encInOffset = 0;
    
    _channels = channels;
    
    _faacCfg = faacEncGetCurrentConfiguration(_faac);
    
    _faacCfg->aacObjectType = LOW;
    _faacCfg->mpegVersion = MPEG4;
    if (bitrate > 0) {
        _faacCfg->bitRate = bitrate * 1000 / _channels;
    }
    _faacCfg->outputFormat = 1;
    _faacCfg->inputFormat = FAAC_INPUT_16BIT;
    
    _frameCount = 0;
    
    if (!faacEncSetConfiguration(_faac, _faacCfg)) {
        printf("faacEncSetConfiguration failed\n");
    }
    
    if (_encIn == NULL) {
        _encInSize = (uint32_t)(_inputSamples * sizeof(int16_t));
        _encIn = new uint8_t[_encInSize];
    }
    
    if (_encOut == NULL) {
        _encOut = new uint8_t[_maxOutputBytes];
    }
    
    return 0;
}

int FAACEncoder::close() {
    if (_faac) {
        faacEncClose(_faac);
        _faac = NULL;
    }
    
    if (_encIn) {
        delete [] _encIn;
        _encIn = NULL;
    }
    
    if (_encOut) {
        delete [] _encOut;
        _encOut = NULL;
    }
    
    return 0;
}

void FAACEncoder::encode(uint8_t *data, uint32_t length, uint64_t timestamp) {
    int32_t left = length;
    int32_t offset = 0;

	while (left > 0) {
        uint32_t fillSize = _encInSize - _encInOffset;
        if (left < fillSize) {
            fillSize = left;
        }

        memcpy(_encIn + _encInOffset, data + offset, fillSize);
        offset += fillSize;
        _encInOffset += fillSize;
        left -= fillSize;

        if (_encInOffset < _encInSize) {
            break;
        }
        
		int outSize = faacEncEncode(_faac, (int32_t*)_encIn, (unsigned int)_inputSamples, _encOut, (unsigned int)_maxOutputBytes);
        if (outSize > 0 && _callback) {
            _callback(_encOut, outSize, timestamp, _frameCount, _param);
            _frameCount++;


#if 0
            static FILE *dumpFp = fopen("capture.aac", "wb");
            if (dumpFp) {
                fwrite(_encOut, 1, outSize,dumpFp);
            }
#endif
        }

        _encInOffset = 0;
	}    
}
