// ****************** Copyright (c) 2013 by Gigaset Communications GmbH ******
// Filename : tdav_codec_fsl_amr_encwrapper.c
// Owner    : Souparna Lodh [STC]
//-------------------------------------------------------------------------
// Defintion : FSL AMR-NB and AMR-WB codecs.
// Freescale Enhanced Software AMR codec wrapper for encoding
//-------------------------------------------------------------------------
// 30-07-2013, Gigaset Communications GmbH
// Added FSL AMR-NB and AMR-WB codec plugin to Doubango Framework
//*************************************************************************

/*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*	
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*	
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/

#include "tdav_codec_fsl_amr_wrapper.h"

int32_t nbAMREncInstanceInit(AMREncWrapper_t *pEncWrapper)
{
    //__android_log_print("Teleca", "FSL AMR", "nbAMREncInstanceInit in\n");
    int32_t ret = 0;
	int32_t i;
    TSK_DEBUG_INFO("%s++\n", __FUNCTION__);
 
    pEncWrapper->pNbAmrEncConfig = (sAMREEncoderConfigType *)tsk_calloc(sizeof(sAMREEncoderConfigType), sizeof(int8_t));
	if (pEncWrapper->pNbAmrEncConfig == NULL) {
		TSK_DEBUG_ERROR("Can't get memory for AMR Encoder config struct.\n");
		return -1;
	}
    
	/* allocate memory for encoder to use */
	pEncWrapper->pNbAmrEncConfig->pvAMREEncodeInfoPtr         = NULL;

	/* Not used */
	pEncWrapper->pNbAmrEncConfig->pu8APPEInitializedDataStart = NULL;

	/* Set DTX flag */
	pEncWrapper->pNbAmrEncConfig->s16APPEDtxFlag              = NBAMR_NONDTX;

	pEncWrapper->pNbAmrEncConfig->u8NumFrameToEncode          = ENCORD_FRAME;    /* number of frame to be encoded */

	/* encoded data size */
	pEncWrapper->pNbAmrEncConfig->pu32AMREPackedSize          = (NBAMR_U32 *)tsk_malloc(ENCORD_FRAME*sizeof(NBAMR_U32));

	/* user requested mode */
	pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr             = (NBAMR_S8**)tsk_malloc(ENCORD_FRAME * sizeof(NBAMR_S8 *));

	/* used mode by encoder */
	pEncWrapper->pNbAmrEncConfig->pps8AMREUsedModeStr         = (NBAMR_S8**)tsk_malloc(ENCORD_FRAME * sizeof(NBAMR_S8*));

	/* initialize packed data variable for all the frames */
	for (i=0; i<ENCORD_FRAME; i++) {
		*(pEncWrapper->pNbAmrEncConfig->pu32AMREPackedSize+i) = 0;
	}

	eAMREReturnType AmrRet;
	AmrRet = eAMREQueryMem(pEncWrapper->pNbAmrEncConfig);
	if (AmrRet != E_NBAMRE_OK) {
	    TSK_DEBUG_ERROR("Amr encoder query memory fail.\n");
		return -1;
	}

	int32_t MemoryCnt = pEncWrapper->pNbAmrEncConfig->sAMREMemInfo.s32AMRENumMemReqs;
	for (i = 0; i < MemoryCnt; i ++) {
		uint32_t BufferSize;
		uint8_t *pBuffer;

		BufferSize = pEncWrapper->pNbAmrEncConfig->sAMREMemInfo.asMemInfoSub[i].s32AMRESize;
		pBuffer = (uint8_t *)tsk_calloc(BufferSize, sizeof(uint8_t));
		if (pBuffer == NULL) {
			TSK_DEBUG_ERROR("Can't get memory for encoder instance.\n");
			return -1;
		}

		pEncWrapper->pNbAmrEncConfig->sAMREMemInfo.asMemInfoSub[i].pvAPPEBasePtr = pBuffer;
	}
    
    pEncWrapper->amrFrameFormatType = E_AMRFF_MMS;

    TSK_DEBUG_INFO("%s--\n", __FUNCTION__);
    //__android_log_print("Teleca", "FSL AMR", "nbAMREncInstanceInit out\n");
	return ret;

}

int32_t nbAMREncoderInit(AMREncWrapper_t *pEncWrapper)
{
    __android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit in\n");
    int32_t ret = 0,i;
    eAMRDReturnType AmrRet;
    
    TSK_DEBUG_INFO("%s++\n", __FUNCTION__);
    
    switch(pEncWrapper->amrFrameFormatType) {
        case E_AMRFF_Conformance:
            //__android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit Setting Conformance\n");
			pEncWrapper->pNbAmrEncConfig->u8BitStreamFormat = NBAMR_ETSI;
            break;
        case E_AMRFF_MMS:
            //__android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit Setting MMS\n");
			pEncWrapper->pNbAmrEncConfig->u8BitStreamFormat = NBAMR_MMSIO;
            break;
        case E_AMRFF_IF1:
            //__android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit Setting IF1\n");
			pEncWrapper->pNbAmrEncConfig->u8BitStreamFormat = NBAMR_IF1IO;
            break;
        case E_AMRFF_IF2:
            //__android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit Setting IF2\n");
			pEncWrapper->pNbAmrEncConfig->u8BitStreamFormat = NBAMR_IF2IO;
            break;
        default:
            //__android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit out - no BRSTTEAMFormat set\n");
            return -1;
    }

    //Default encoder mode, could be changed using CMR
    for (i = 0; i < ENCORD_FRAME; i++) {
	    /* set default encoding mode */
	    pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR122");
    }

    AmrRet = eAMREEncodeInit(pEncWrapper->pNbAmrEncConfig);
    if (AmrRet != E_NBAMRE_OK) {
	    TSK_DEBUG_ERROR("Amr encoder initialize fail. return: %d\n", AmrRet);
	    return -1;
    }
    TSK_DEBUG_INFO("%s--\n", __FUNCTION__);
    __android_log_print("Teleca", "FSL AMR", "nbAMREncoderInit out\n");
    return ret;
}

int32_t nbAMREncInstanceDeInit(AMREncWrapper_t *pEncWrapper)
{
    int32_t ret = 0, i;
	uint32_t mem_count = pEncWrapper->pNbAmrEncConfig->sAMREMemInfo.s32AMRENumMemReqs;
    TSK_DEBUG_INFO("%s++\n", __FUNCTION__);
	for (i = 0; i < mem_count; i ++) {
		TSK_FREE(pEncWrapper->pNbAmrEncConfig->sAMREMemInfo.asMemInfoSub[i].pvAPPEBasePtr);
	}

    TSK_FREE(pEncWrapper->pNbAmrEncConfig->pps8AMREUsedModeStr);

	TSK_FREE(pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr);

	TSK_FREE(pEncWrapper->pNbAmrEncConfig->pu32AMREPackedSize);

	TSK_FREE(pEncWrapper->pNbAmrEncConfig);

    TSK_DEBUG_INFO("%s--\n", __FUNCTION__);
    return ret;
}

int32_t  nbAMREncodeFrame(AMREncWrapper_t *pEncWrapper,
                          uint8_t *pInputBuffer,
                          enum Mode pEncodngMode,
                          uint8_t *pOutBuffer,
                          uint32_t *pInputDataSize,
                          uint32_t *pOutputDataSize)
{
    //__android_log_print("Teleca", "FSL AMR", "nbAMREncodeFrame in\n");
    int32_t ret = 0,i,j;
    uint8_t *pSrc = pOutBuffer;
    uint8_t *pDst = pOutBuffer;
    uint8_t Header;
    uint8_t u8Mode;

    eAMRDReturnType AmrRet;

    //Set User Requested Encoding modes requested dynamically
    switch(pEncodngMode) {
		case MR122:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR122");
			}
            break;
		case MR475:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR475");
			}
            break;
		case MR515:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR515");
			}
            break;
		case MR59:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR59");
			}
            break;
		case MR67:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR67");
			}
            break;
		case MR74:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR74");
			}
            break;
		case MR795:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR795");
			}
            break;
		case MR102:
			for (i = 0; i < ENCORD_FRAME; i++) {
				/* set user requested encoding mode */
				pEncWrapper->pNbAmrEncConfig->pps8APPEModeStr[i] = (NBAMR_S8*)("MR102");
			}
            break;
		default:
            //will go for default mode - MR122
            break;
    }

	AmrRet = eAMREEncodeFrame(pEncWrapper->pNbAmrEncConfig, (NBAMR_S16*)pInputBuffer, (NBAMR_S16*)pOutBuffer);

    *pOutputDataSize = 0;
	for ( i = 0; i < pEncWrapper->pNbAmrEncConfig->u8NumFrameToEncode; i ++) {
		pSrc = pOutBuffer + i*((NBAMR_MAX_PACKED_SIZE/2)+(NBAMR_MAX_PACKED_SIZE%2))*2;

		Header = pSrc[0];
		u8Mode = (NBAMR_U8) (0x0F & (Header >> 3));
		TSK_DEBUG_INFO("u8Mode: %d\n", u8Mode);

		for ( j = 0; j < pEncWrapper->pNbAmrEncConfig->pu32AMREPackedSize[i]; j ++) {
			*pDst++ = *pSrc++;
		}
		TSK_DEBUG_INFO("Stream frame len: %d\n", pEncWrapper->pNbAmrEncConfig->pu32AMREPackedSize[i]);
		*pOutputDataSize += pEncWrapper->pNbAmrEncConfig->pu32AMREPackedSize[i];
	}
    *pInputDataSize = (ENCORD_FRAME * L_FRAME) * sizeof (NBAMR_S16);

    ret = (AmrRet == E_NBAMRD_OK)? 0 : -1;

    //__android_log_print("Teleca", "FSL AMR", "nbAMREncodeFrame out\n");

    return ret;
}

AMREncWrapper_t *CreateAMREncWrapper(tsk_bool_t nbAMR)
{
	AMREncWrapper_t *pAMREncWrapper;
    TSK_DEBUG_INFO("%s++\n", __FUNCTION__);

	pAMREncWrapper = (AMREncWrapper_t *)tsk_malloc(sizeof(AMREncWrapper_t));
	if(pAMREncWrapper == NULL) {
		TSK_DEBUG_ERROR("Failed to allocate memory for AMR Encoder Wrapper\n");
		return NULL;
	}

	if(nbAMR == tsk_true) {
		//initialize nb AMR decoder wrapper
        pAMREncWrapper->InstanceInit               = nbAMREncInstanceInit;
        pAMREncWrapper->CodecInit                  = nbAMREncoderInit;
        pAMREncWrapper->InstanceDeInit             = nbAMREncInstanceDeInit;
        pAMREncWrapper->encodeFrame                = nbAMREncodeFrame;
        pAMREncWrapper->getFrameOutputSize         = NULL;
        pAMREncWrapper->getBitRate                 = NULL;
    } else {
		//initialize wb AMR decoder wrapper
        pAMREncWrapper->InstanceInit               = NULL;//wbAMREncInstanceInit;
        pAMREncWrapper->CodecInit                  = NULL;//wbAMREncoderInit;
        pAMREncWrapper->InstanceDeInit             = NULL;//wbAMREncInstanceDeInit;
        pAMREncWrapper->encodeFrame                = NULL;//wbAMREncodeFrame;
        pAMREncWrapper->getFrameOutputSize         = NULL;
        pAMREncWrapper->getBitRate                 = NULL;
    }
    TSK_DEBUG_INFO("%s--\n", __FUNCTION__);
    return pAMREncWrapper;
}

void DeleteAMREncWrapper(AMREncWrapper_t *pEncWrapper)
{
    TSK_DEBUG_INFO("%s++\n", __FUNCTION__);
	if(pEncWrapper != NULL) {
		TSK_FREE(pEncWrapper);
	}
    TSK_DEBUG_INFO("%s--\n", __FUNCTION__);
	return;
}

