/*****************************************************************************
 * Copyright (c) 2018, Broadcom Inc.                                         *
 *                                                                           *
 * All Rights Reserved.                                                      *
 *                                                                           *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Inc.;             *
 * the contents of this file may not be disclosed to third parties, copied   *
 * or duplicated in any form, in whole or in part, without the prior         *
 * written permission of Broadcom Inc.                                       *
 *****************************************************************************/
/**
 * @file vend_entry_sp.c
 * @brief entry function for speech overlay
 */

#include "dsp_sdk_types.h"
#include "overlay.h"
#include "vend_sp.h"
#include "dsp_sdk_trace.h"

#ifdef ENABLE_SS_SPEECH
#include "speech_api.h"
#endif

#ifdef ENABLE_INEAR_ALGO
#include "SamsungSolomonVoiceW.h"
#endif

/* Inear test mode: Turn on TEST_INEAR_BYPASS and choose a input signal to output */
#define DEBUG_CALC_MCPS

#ifdef DEBUG_CALC_MCPS	//hoon_test to measure complexity
#include <xtensa/xtruntime.h>
#endif

//#define TEST_INEAR_BYPASS

#ifdef TEST_INEAR_BYPASS
#define TEST_INEAR_MAIN_IN
//#define TEST_INEAR_SUB_IN
//#define TEST_INEAR_THIRD_IN
//#define TEST_INEAR_RX_IN
//#define TEST_INEAR_FOURTH_IN
#endif

#ifdef TEST_INEAR_MAIN_IN
INT32 g_inear_test = 0;
#endif
#ifdef TEST_INEAR_SUB_IN
INT32 g_inear_test = 1;
#endif
#ifdef TEST_INEAR_RX_IN
INT32 g_inear_test = 2;
#endif
#ifdef TEST_INEAR_THIRD_IN
INT32 g_inear_test = 3;
#endif
#ifdef TEST_INEAR_FOURTH_IN
INT32 g_inear_test = 4;
#endif

#define TEST_DYVE_BYPASS

#ifdef TEST_DYVE_BYPASS
#define TEST_DYVE_SPEECH_IN
//#define TEST_DYVE_NOISE_IN
#endif

#ifdef TEST_DYVE_SPEECH_IN
INT32 g_dyve_test = 0;
#endif
#ifdef TEST_DYVE_NOISE_IN
INT32 g_dyve_test = 1;
#endif

/**
 * Declaration of overlay info and entry function. Do not change it.
 */
INT32 vend_entry_sp(OVERLAY_ST_t *p_overlay_parameter) __attribute__((section(".iram0_overlay_entry.text")));

OVERLAY_INFO_t ovl_sp_info __attribute__((section(".dram0_overlay_info.data"))) =
{
    MAGIC_PATTERN_SP,
    (void *)vend_entry_sp
};



/**
 * function prototypes
 */
INT32 vend_ss_speech_enc_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_ss_speech_enc_exec(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_ss_speech_dec_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_ss_speech_dec_exec(OVERLAY_ST_t *p_overlay_parameter);
#ifdef ENABLE_DYVE_ALGO_AND_BUFF
INT32 vend_dyve_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_dyve_exec(OVERLAY_ST_t *p_overlay_parameter);
#endif
INT32 vend_inear_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_inear_exec(OVERLAY_ST_t *p_overlay_parameter);



/**
 * Variable declarations.
 * Note: Total scratch memory size can't exceed 128KB
 */
UINT32 g_ss_speech_enc_scratch[SS_SPEECH_ENC_SCRATCH_MEM_SIZE_INT32];     /* Scratch memory for enc */
UINT32 g_ss_speech_dec_scratch[SS_SPEECH_DEC_SCRATCH_MEM_SIZE_INT32];     /* Scratch memory for dec */
INT16 Speech_buf_RX_Outer[320];
INT16 AMS_State;

/**
 * Entry function of speech overlay
 */
INT32 vend_entry_sp(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

    switch(p_overlay_parameter->algo_idx)
    {
        case ALGO_IDX_SS_SPEECH_ENC_INIT:
            ret = vend_ss_speech_enc_init(p_overlay_parameter);
            break;
        case ALGO_IDX_SS_SPEECH_ENC_EXEC:
            ret = vend_ss_speech_enc_exec(p_overlay_parameter);
            break;
        case ALGO_IDX_SS_SPEECH_DEC_INIT:
            ret = vend_ss_speech_dec_init(p_overlay_parameter);
            break;
        case ALGO_IDX_SS_SPEECH_DEC_EXEC:
            ret = vend_ss_speech_dec_exec(p_overlay_parameter);
            break;
#ifdef ENABLE_DYVE_ALGO_AND_BUFF
        case ALGO_IDX_DYVE_INIT:
            ret = vend_dyve_init(p_overlay_parameter);
            break;
        case ALGO_IDX_DYVE_EXEC:
            ret = vend_dyve_exec(p_overlay_parameter);
            break;
#endif
        case ALGO_IDX_INEAR_INIT:
            ret = vend_inear_init(p_overlay_parameter);
            break;
        case ALGO_IDX_INEAR_EXEC:
            ret = vend_inear_exec(p_overlay_parameter);
            break;
        default:
            ret = MIN_INT32;
            break;
    }
    return ret;
}




/**
 * ss_speech encoder init process.
 */
INT32 vend_ss_speech_enc_init(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;


#ifdef HACK_VEND_SP_TOBE_MSBC

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL ENC_INIT] Hack SS speech encoder as mSBC encoder");

//    msbc_enc_Init(gp_sp_enc_inst);
    (*g_hack_ptrs[1])(gp_sp_enc_inst);

    return ret;
#endif


#ifdef ENABLE_SS_SPEECH

    SS_SPEECH_ENC_EXT_ST_t *p_ss_speech_enc_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.ss_speech_enc_external_parameter;
    UINT32  dram_base_addr = (UINT32)g_ss_speech_enc_scratch;
    void *enc;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init SS speech encoder start");

    p_ss_speech_enc_external_param->frame_cnt = 0;
    p_ss_speech_enc_external_param->frame_size = SS_SPEECH_FRAME_SIZE;
    p_ss_speech_enc_external_param->mem_offset = 0;
    p_ss_speech_enc_external_param->dram_enc_size = sizeof(g_ss_speech_enc_scratch);


    //allocate memory
    MALLOC_BYTE(p_ss_speech_enc_external_param->enc_inst, speech_encoder_get_size(), dram_base_addr, p_ss_speech_enc_external_param->mem_offset);
    MALLOC_BYTE(p_ss_speech_enc_external_param->in_buf, SS_SPEECH_FRAME_SIZE*2, dram_base_addr, p_ss_speech_enc_external_param->mem_offset);
    MALLOC_BYTE(p_ss_speech_enc_external_param->out_buf, SS_SPEECH_MAX_PACKET *2, dram_base_addr, p_ss_speech_enc_external_param->mem_offset); //30 bytes * 2 frame in one packet

    enc = p_ss_speech_enc_external_param->enc_inst;

    if(p_ss_speech_enc_external_param->mem_offset > p_ss_speech_enc_external_param->dram_enc_size)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SS_speech_enc dRAM buffer is not enough 0x%x 0x%x",p_ss_speech_enc_external_param->mem_offset, p_ss_speech_enc_external_param->dram_enc_size);
        ret = -1;
        return ret;
    }
    else
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SS_speech_enc dRAM buffer allocation done, size =0x%x",p_ss_speech_enc_external_param->mem_offset);
    }

    speech_encoder_init(enc, SS_SPEECH_FS);


    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init SS speech encoder end");

#endif

    return ret;
}


#ifdef DEBUG_CALC_MCPS	//hoon_test
UINT32 time_start;
UINT32 time_end;
UINT32 time_diff;

UINT32 time_peak_ssc_enc = 0;
UINT32 time_peak_ssc_dec = 0;
UINT32 time_peak_inear = 0;

UINT32 fram_cnt_enc=0;
UINT32 fram_cnt_dec=0;
UINT32 fram_cnt_inear=0;
#endif
/**
 * ss_speech encoder execute process.
 */
INT32 vend_ss_speech_enc_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

#ifdef HACK_VEND_SP_TOBE_MSBC

    //ret = msbc_enc_Encode(gp_sp_enc_inst);
    ret = (*g_hack_ptrs[3])(gp_sp_enc_inst);
    g_vend_sp_enc_cnt++;

    if((g_vend_sp_enc_cnt & 0xFF) == 0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP OVL] SS speech encode frame cnt0x%x (HFP)", g_vend_sp_enc_cnt);
    }

    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL ENC_EXEC] Hack mSBC encoder encode fail");
    }
    return ret;
#endif



#ifdef ENABLE_SS_SPEECH

    SS_SPEECH_ENC_EXT_ST_t *p_ss_speech_enc_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.ss_speech_enc_external_parameter;

    /* out_buf conatains (frame_0 + frame_1 + padding_2byte). Before sending to OTA, H2 header will be added in au_task_SendSpeechEncVendOutputFrame() */

    /* Handle re-sending frame */
    memcpy(p_ss_speech_enc_external_param->out_buf, (p_ss_speech_enc_external_param->out_buf + SS_SPEECH_DATA_LEN), SS_SPEECH_DATA_LEN);

	//TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] speech_encode() start!");	
	
#ifdef DEBUG_CALC_MCPS
	time_start = xthal_get_ccount();
#endif	
    ret = speech_encode(p_ss_speech_enc_external_param->enc_inst, (INT16 *)p_ss_speech_enc_external_param->in_buf, SS_SPEECH_FRAME_SIZE, (p_ss_speech_enc_external_param->out_buf + SS_SPEECH_DATA_LEN), SS_SPEECH_DATA_LEN);

    /* Add padding 2 bytes */
    {
        UINT8 *pu8_dest_buf = p_ss_speech_enc_external_param->out_buf;
        pu8_dest_buf += (SS_SPEECH_DATA_LEN * 2);
        *pu8_dest_buf = 0;
        pu8_dest_buf++;
        *pu8_dest_buf = 0;
    }
	
#ifdef DEBUG_CALC_MCPS
	time_end = xthal_get_ccount();
	time_diff = time_end - time_start;
	if(time_diff > time_peak_ssc_enc)
		time_peak_ssc_enc = time_diff;

	fram_cnt_enc++;
	if(fram_cnt_enc % 133 ==0)
	{
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] ssc speech encoder excution cycle(Peak) : %d", time_peak_ssc_enc); 
		fram_cnt_enc = 0;
	}
#endif
	//TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] speech_encode() End!");	


    if(ret != SS_SPEECH_DATA_LEN)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL ENC_EXE] SS speech encoder fail ret=%d", ret);
    }
    else
    {
        ret = VEND_SUCCESS;
    }

    p_ss_speech_enc_external_param->frame_cnt++;

#endif
    return ret;
}


/**
 * ss_speech decoder init process.
 */
INT32 FrameCnt;
INT32 PLC_Frame;
INT32 CRC_Frame;
INT32 vend_ss_speech_dec_init(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

#ifdef HACK_VEND_SP_TOBE_MSBC
    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL DEC_INIT] Hack SS speech decoder as mSBC decoder");

//    msbc_dec_Init(gp_sp_dec_inst);
    (*g_hack_ptrs[0])(gp_sp_dec_inst);
    return ret;
#endif


#ifdef ENABLE_SS_SPEECH
    SS_SPEECH_DEC_EXT_ST_t *p_ss_speech_dec_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.ss_speech_dec_external_parameter;
    UINT32  dram_base_addr = (UINT32)g_ss_speech_dec_scratch;
    void *dec;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init SS speech decoder start");

    p_ss_speech_dec_external_param->frame_cnt = 0;
    p_ss_speech_dec_external_param->dram_dec_size = sizeof(g_ss_speech_dec_scratch);
    p_ss_speech_dec_external_param->mem_offset = 0;


    //allocate memory
    MALLOC_BYTE(p_ss_speech_dec_external_param->dec_inst, speech_decoder_get_size(), dram_base_addr, p_ss_speech_dec_external_param->mem_offset);
    MALLOC_BYTE(p_ss_speech_dec_external_param->in_buf, SS_SPEECH_MAX_PACKET*2, dram_base_addr, p_ss_speech_dec_external_param->mem_offset);
    MALLOC_BYTE(p_ss_speech_dec_external_param->out_buf, SS_SPEECH_FRAME_SIZE*2, dram_base_addr, p_ss_speech_dec_external_param->mem_offset);


    dec = p_ss_speech_dec_external_param->dec_inst;

    if(p_ss_speech_dec_external_param->mem_offset > p_ss_speech_dec_external_param->dram_dec_size)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SS_speech_dec dRAM buffer is not enough 0x%x 0x%x",p_ss_speech_dec_external_param->mem_offset,p_ss_speech_dec_external_param->dram_dec_size);
        ret = -1;
        return ret;
    }
    else
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SS_speech_dec dRAM buffer allocation done size=0x%x",p_ss_speech_dec_external_param->mem_offset);
    }

    speech_decoder_init(dec, SS_SPEECH_FS);
	FrameCnt = 0;
	PLC_Frame = 0;
	CRC_Frame = 0;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init SS speech decoder end");

#endif

    return ret;
}



/**
 * ss_speech decoder execute process.
 */
UINT8  dec_rcv_buf[28];
INT32  dec_rcv_buf_flag=0;
INT32 vend_ss_speech_dec_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

#if 1   //hoon_test
    INT32 i;
#endif
#ifdef HACK_VEND_SP_TOBE_MSBC

    //ret = msbc_dec_Decode(gp_sp_dec_inst);
    ret = (*g_hack_ptrs[2])(gp_sp_dec_inst);
    g_vend_sp_dec_cnt++;

    if((g_vend_sp_dec_cnt & 0xFF) == 0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP OVL] SS speech decode frame cnt0x%x (HFP)", g_vend_sp_dec_cnt);
    }

    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL DEC_EXEC] Hack mSBC decoder decode fail");
    }

    return ret;
#endif



#ifdef ENABLE_SS_SPEECH
    SS_SPEECH_DEC_EXT_ST_t *p_ss_speech_dec_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.ss_speech_dec_external_parameter;

#ifdef DEBUG_CALC_MCPS	
	time_start = xthal_get_ccount();
#endif

    if(p_ss_speech_dec_external_param->plc_frame == 0)
    {
        ret = speech_decode(p_ss_speech_dec_external_param->dec_inst, ((p_ss_speech_dec_external_param->in_buf)+2), SS_SPEECH_DATA_LEN, (INT16 *)p_ss_speech_dec_external_param->out_buf, SS_SPEECH_FRAME_SIZE,0);
		FrameCnt++;
#if 1   //hoon_test
        if(ret != SS_SPEECH_FRAME_SIZE)
        {
            if(dec_rcv_buf_flag == 1)
            {
                ret = speech_decode(p_ss_speech_dec_external_param->dec_inst, dec_rcv_buf, SS_SPEECH_DATA_LEN, (INT16 *)p_ss_speech_dec_external_param->out_buf, SS_SPEECH_FRAME_SIZE,0);
                dec_rcv_buf_flag = 0; //buffer data is used
            }
            else
            {
				//Run plc algorithm
                ret = speech_decode(p_ss_speech_dec_external_param->dec_inst, NULL, SS_SPEECH_DATA_LEN, (INT16 *)p_ss_speech_dec_external_param->out_buf, SS_SPEECH_FRAME_SIZE,1);
				CRC_Frame++;
            }
        }

        // update recover buffer
        for(i=0;i<SS_SPEECH_DATA_LEN;i++)
        {
            dec_rcv_buf[i] = p_ss_speech_dec_external_param->in_buf[/*SS_SPEECH_DATA_LEN+2*/30+i];
        }
        dec_rcv_buf_flag = 1;
#endif
    }
    else
    {
		FrameCnt++;
        if(dec_rcv_buf_flag == 1)
        {
            ret = speech_decode(p_ss_speech_dec_external_param->dec_inst, dec_rcv_buf, SS_SPEECH_DATA_LEN, (INT16 *)p_ss_speech_dec_external_param->out_buf, SS_SPEECH_FRAME_SIZE,0);
            dec_rcv_buf_flag = 0; //buffer data is used
        }
        else
        {
			//Run plc algorithm
            ret = speech_decode(p_ss_speech_dec_external_param->dec_inst, NULL, SS_SPEECH_DATA_LEN, (INT16 *)p_ss_speech_dec_external_param->out_buf, SS_SPEECH_FRAME_SIZE,1);
			PLC_Frame++;
        }
    }
#ifdef DEBUG_CALC_MCPS
	time_end = xthal_get_ccount();
	time_diff = time_end - time_start;
	if(time_diff > time_peak_ssc_dec)
		time_peak_ssc_dec = time_diff;

	fram_cnt_dec++;
	if(fram_cnt_dec % 133 ==0)
	{
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] ssc speech decoder excution cycle(Peak) : %d", time_peak_ssc_dec); 
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] ssc speech DBG_MSG Total Frame : %d, PLC Frame : %d, CRC Frame : %d", FrameCnt, PLC_Frame, CRC_Frame);
		fram_cnt_dec = 0;
	}
#endif		

    if(ret != SS_SPEECH_FRAME_SIZE)
    {
        TRACE(TRACE_DEBUG, MODULE_ID_DSP, "[DSP VEND][SS SPEECH DEC] decode fail ret=%d", ret);
    }
    else
    {
        p_ss_speech_dec_external_param->frame_cnt++;
        ret = VEND_SUCCESS;
    }

#endif

    return ret;
}


/**
 * DyVE init process.
 */
INT32 vend_dyve_init(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init DyVE start");

#ifdef ENABLE_DYVE_ALGO_AND_BUFF
#if 0//def ENABLE_DYVE_ALGO
    DYVE_EXT_ST_t *p_dyve_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.dyve_external_parameter;
    VEND_BUF_t *p_long_buf_dyve_in_speech = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_DYVE_IN_SPEECH];
    VEND_BUF_t *p_long_buf_dyve_in_noise = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_DYVE_IN_NOISE];
    VEND_BUF_t *p_long_buf_dyve_out = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_DYVE_OUT];

    SamsungDiamondVoiceParam *DiamondVoice_DVConfig;
    SamsungDiamondVoiceEngine_Handle_t *SamsungDiamondVoiceEngine_var;

    p_dyve_external_param->mem_offset = 0;

    p_dyve_external_param->short_input_frame_cnt = 0;
    p_dyve_external_param->long_input_frame_cnt = 0;
    p_dyve_external_param->short_output_frame_cnt = 0;
    p_dyve_external_param->long_output_frame_cnt = 0;

    //memory allocation
    //MALLOC_BYTE(p_dyve_external_param->dyve_vars, sizeof(SamsungDiamondVoiceEngine_Handle_t), g_dyve_scratch, p_dyve_external_param->mem_offset);
    //MALLOC_BYTE(p_dyve_external_param->dyve_param, sizeof(SamsungDiamondVoiceParam), g_dyve_scratch, p_dyve_external_param->mem_offset);

    if(p_dyve_external_param->mem_offset > sizeof(g_dyve_scratch))
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] DyVE dRAM buffer not enough");
        ret = -1;
        return ret;
    }

    p_dyve_external_param->in_long_buf = p_long_buf_dyve_in_speech->buf;
    p_dyve_external_param->in_long_buf_tx = p_long_buf_dyve_in_noise->buf;
    p_dyve_external_param->out_long_buf = p_long_buf_dyve_in_noise->buf;

    DiamondVoice_DVConfig = (SamsungDiamondVoiceParam *) p_dyve_external_param->dyve_param;
    SamsungDiamondVoiceEngine_var = (SamsungDiamondVoiceEngine_Handle_t *) p_dyve_external_param->dyve_vars;

    // Initialization
    ret = SamsungDiamondVoiceEngineInit(SamsungDiamondVoiceEngine_var, DYVE_DIAMONDVOICE_FRAME_WB);
    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP VEND][DyVE] SamsungDiamondVoiceEngineInit fail");
        return ret;
    }

    // DyVE Mode
    DiamondVoice_DVConfig.dvMode = (SAMSUNGDYVERCV_ON);
    ret = SamsungDiamondVoiceEngineModeConfig(SamsungDiamondVoiceEngine_var, DiamondVoice_DVConfig);
    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP VEND][DyVE] SamsungDiamondVoiceEngineModeConfig fail");
        return ret;
    }

    // DyVE Function Parameter
    DiamondVoice_DVConfig.dyveStepMaxGain = step_maxgain;
    DiamondVoice_DVConfig.dyveMicSensitivity = 6;
    DiamondVoice_DVConfig.dyvePreemphasis = 0;
    DiamondVoice_DVConfig.dyveMicGain = -25;
    DiamondVoice_DVConfig.dyveRMSLimiter = 0;
    DiamondVoice_DVConfig.dyveRxVADThd = 0;
    DiamondVoice_DVConfig.dyveRxFilter = (short *)DyVERXFIRCoef;
    ret = SamsungDiamondVoiceEngineDyVEConfig(SamsungDiamondVoiceEngine_var, DiamondVoice_DVConfig);

    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP VEND][DyVE] SamsungDiamondVoiceEngineDyVEConfig fail");
        //return ret;
    }
#endif
#endif
    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init DyVE end");

    return ret;
}


#ifdef ENABLE_DYVE_ALGO_AND_BUFF
/**
 * DyVE execute process.
 */
INT32 vend_dyve_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

    DYVE_EXT_ST_t *p_dyve_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.dyve_external_parameter;
    VEND_BUF_t *p_long_buf_dyve_out = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_DYVE_OUT];

#ifdef ENABLE_DYVE_ALGO
    VEND_BUF_t *p_long_buf_dyve_in_speech = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_DYVE_IN_SPEECH];
    VEND_BUF_t *p_long_buf_dyve_in_noise = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_DYVE_IN_NOISE];

    if (g_dyve_test == 0)
    {
        ret = au_task_vend_PassBuf(p_long_buf_dyve_out, p_long_buf_dyve_in_speech, p_dyve_external_param->frame_size);
        ret = au_task_vend_FlushBuf(p_long_buf_dyve_in_noise, p_dyve_external_param->frame_size);
    }
    else if (g_dyve_test == 1)
    {
        ret = au_task_vend_PassBuf(p_long_buf_dyve_out, p_long_buf_dyve_in_noise, p_dyve_external_param->frame_size);
        ret = au_task_vend_FlushBuf(p_long_buf_dyve_in_speech, p_dyve_external_param->frame_size);
    }

#else
    INT16 *Output_buf = ((INT16 *)p_dyve_external_param->out_long_buf) + p_long_buf_dyve_out->offset;
    INT16 *Speech_buf = (INT16 *)p_dyve_external_param->in_long_buf;
    INT16 *Noise_buf  = (INT16 *)p_dyve_external_param->in_long_buf_tx;

    SamsungDiamondVoiceParam *DiamondVoice_DVConfig = (SamsungDiamondVoiceParam *) p_dyve_external_param->dyve_param;
    SamsungDiamondVoiceEngine_Handle_t *SamsungDiamondVoiceEngine_var = (SamsungDiamondVoiceEngine_Handle_t *) p_dyve_external_param->dyve_vars;

    ret = SamsungDiamondVoiceEngineExe(SamsungDiamondVoiceEngine_var,DiamondVoice_DVConfig, Output_buf, Speech_buf, Noise_buf);

    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] DyVE exec fail");
        //return ret;
    }

#endif

    return ret;
}
#endif

SamsungSolomonVoiceParam DiamondVoice_DV_TX_Config = { 0, };
SamsungSolomonVoiceEngine_Handle_t SamsungDiamondVoiceEngine_vars_Tx = { 0, };
/**
 * inear init process.
 */
INT32 vend_inear_init(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;
    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init inear start");

    INEAR_EXT_ST_t *p_inear_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.inear_external_parameter;
    VEND_BUF_t *p_long_buf_inear_in_main_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_MAIN_MIC];				//DMAIN
    VEND_BUF_t *p_long_buf_inear_in_sub_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_SUB_MIC];					//DSUB 
    VEND_BUF_t *p_long_buf_inear_in_3rd_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_THIRD_MIC];				//AMIC - in_ear
    VEND_BUF_t *p_long_buf_inear_in_4th_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_FOURTH_MIC];				//ACC
    VEND_BUF_t *p_long_buf_inear_in_farend = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_FAREND];					//RX
    VEND_BUF_t *p_long_buf_inear_out = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_OUT];

    p_inear_external_param->mem_offset = 0;
    p_inear_external_param->short_in_main_frame_cnt = 0;
    p_inear_external_param->long_in_main_frame_cnt = 0;
    p_inear_external_param->short_output_frame_cnt = 0;
    p_inear_external_param->long_output_frame_cnt = 0;

    p_inear_external_param->in_main_long_buf = p_long_buf_inear_in_main_mic->buf;
    p_inear_external_param->in_sub_long_buf = p_long_buf_inear_in_sub_mic->buf;
    p_inear_external_param->in_third_long_buf = p_long_buf_inear_in_3rd_mic->buf;
    p_inear_external_param->in_fourth_long_buf = p_long_buf_inear_in_4th_mic->buf;
    p_inear_external_param->in_long_buf_rx = p_long_buf_inear_in_farend->buf;
    p_inear_external_param->out_long_buf = p_long_buf_inear_out->buf;

#ifdef ENABLE_INEAR_ALGO
	SamsungSolomonVoiceWEngineInit(&SamsungDiamondVoiceEngine_vars_Tx);
	TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SamsungSolomonVoiceWEngineInit is finished");

	SamsungSolomonVoiceWParamSetting(&DiamondVoice_DV_TX_Config, p_inear_external_param->frame_size);
	TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SamsungSolomonVoiceWParamSetting is finished");

	SamsungSolomonVoiceWEngineConfig(&SamsungDiamondVoiceEngine_vars_Tx, &DiamondVoice_DV_TX_Config);
	TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] SamsungSolomonVoiceWEngineConfig is finished");
#endif
	AMS_State = 0;
    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Init inear end");
    return ret;
}


/**
 * inear execute process.
 */
INT32 vend_inear_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;
#ifndef TEST_INEAR_BYPASS
	int i;
#endif

#ifdef ENABLE_INEAR_ALGO
    INEAR_EXT_ST_t *p_inear_external_param = &p_overlay_parameter->ovl_paramter.ovl_sp.inear_external_parameter;
	// channel Routing
    VEND_BUF_t *p_long_buf_inear_in_main_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_MAIN_MIC];
    VEND_BUF_t *p_long_buf_inear_in_sub_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_SUB_MIC];
    VEND_BUF_t *p_long_buf_inear_in_3rd_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_THIRD_MIC];
    VEND_BUF_t *p_long_buf_inear_in_4th_mic = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_FOURTH_MIC];
    VEND_BUF_t *p_long_buf_inear_in_farend = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_IN_FAREND];
    VEND_BUF_t *p_long_buf_inear_out = &p_overlay_parameter->ovl_paramter.ovl_sp.long_buf[IDX_INEAR_OUT];
    INT32 target_offset = p_long_buf_inear_out->offset + p_inear_external_param->frame_size;

	//NREC_onoff hoon_test
#ifndef TEST_INEAR_BYPASS
	INT32 NREC_enable = g_vend_private_param[0];
#endif
	
    if(target_offset > p_long_buf_inear_out->len)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][Inear] SamsungExe output frame full");
        ret = VEND_FAIL;
        return ret;
    }

#ifdef TEST_INEAR_BYPASS
    /* Simulate INEAR process time */
    au_task_TimerDelay(VEND_INEAR_PROCESS_TIME);

	TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL] Test Inear Bypass!!");

    switch(g_inear_test)
    {
        /* main mic to inear out */
        case 0:
            au_task_vend_PassBuf(p_long_buf_inear_out, p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_farend, p_inear_external_param->frame_size);
            if(g_overlay_parameter.vend_the3rdmic_enable)
            {
                au_task_vend_FlushBuf(p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
                au_task_vend_FlushBuf(p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
            }
        break;

        case 1:
            au_task_vend_PassBuf(p_long_buf_inear_out, p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_farend, p_inear_external_param->frame_size);
            if(g_overlay_parameter.vend_the3rdmic_enable)
            {
                au_task_vend_FlushBuf(p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
                au_task_vend_FlushBuf(p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
            }
        break;

        case 2:
            au_task_vend_PassBuf(p_long_buf_inear_out, p_long_buf_inear_in_farend, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
            if(g_overlay_parameter.vend_the3rdmic_enable)
            {
                au_task_vend_FlushBuf(p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
                au_task_vend_FlushBuf(p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
            }
        break;

        case 3:
            if(g_overlay_parameter.vend_the3rdmic_enable)
            {
                au_task_vend_PassBuf(p_long_buf_inear_out, p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
                au_task_vend_FlushBuf(p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
            }
            au_task_vend_FlushBuf(p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_farend, p_inear_external_param->frame_size);
        break;

        case 4:
            if(g_overlay_parameter.vend_the3rdmic_enable)
            {
                au_task_vend_FlushBuf(p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
                au_task_vend_PassBuf(p_long_buf_inear_out, p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
            }
            au_task_vend_FlushBuf(p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
            au_task_vend_FlushBuf(p_long_buf_inear_in_farend, p_inear_external_param->frame_size);
        break;
    }
    return ret;

#else

#ifdef DEBUG_CALC_MCPS
	time_start = xthal_get_ccount();
#endif
	//NREC_onoff hoon_test
	if(NREC_enable == 1)
	{
	    //input size(WB : 320, NB : 160)
		for (i = 0; i < p_inear_external_param->frame_size; i++)
	    {
			Speech_buf_RX_Outer[i] = p_long_buf_inear_in_farend->buf[i];
	    }

		SamsungSolomonVoiceWEngineExe(&SamsungDiamondVoiceEngine_vars_Tx, &DiamondVoice_DV_TX_Config, p_long_buf_inear_in_3rd_mic->buf,
									  p_long_buf_inear_in_main_mic->buf, p_long_buf_inear_in_sub_mic->buf, p_long_buf_inear_in_farend->buf, Speech_buf_RX_Outer, p_long_buf_inear_in_4th_mic->buf, p_long_buf_inear_out->buf + p_long_buf_inear_out->offset); //20180703 kyuhan 2mic in-ear-solution

		if(AMS_State == 0 && SamsungSolomonVoiceWGetAMSStatus(&SamsungDiamondVoiceEngine_vars_Tx) == 1)
		{
			AMS_State = 1;
			TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][Inear]  AMS : %d", AMS_State);
			au_task_SendVendorData(AMS_State);
		}
	}
	else
	{
		//TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][Inear] run bypass(bixby)");
		au_task_vend_PassBuf(p_long_buf_inear_out, p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
		au_task_vend_FlushBuf(p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
		au_task_vend_FlushBuf(p_long_buf_inear_in_farend, p_inear_external_param->frame_size);
		if(g_overlay_parameter.vend_the3rdmic_enable)
		{
			au_task_vend_FlushBuf(p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
			au_task_vend_FlushBuf(p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
		}

#ifdef DEBUG_CALC_MCPS
		fram_cnt_inear++;
		if(fram_cnt_inear % 133 ==0)
		{
			TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][Inear] run bypass(bixby)");
			fram_cnt_inear = 0;
		}
#endif	  

		return ret;
	}

#ifdef DEBUG_CALC_MCPS
	time_end = xthal_get_ccount();
	time_diff = time_end - time_start;
	if(time_diff > time_peak_inear)
		time_peak_inear = time_diff;

	fram_cnt_inear++;
	if(fram_cnt_inear % 133 ==0)
	{
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][Inear]  3-mic inear excution cycle(Peak) : %d", time_peak_inear);
		fram_cnt_inear = 0;
	}
#endif
#endif
    p_long_buf_inear_out->offset += p_inear_external_param->frame_size;

    au_task_vend_FlushBuf(p_long_buf_inear_in_main_mic, p_inear_external_param->frame_size);
    au_task_vend_FlushBuf(p_long_buf_inear_in_sub_mic, p_inear_external_param->frame_size);
    if(g_overlay_parameter.vend_the3rdmic_enable)
    {
        au_task_vend_FlushBuf(p_long_buf_inear_in_3rd_mic, p_inear_external_param->frame_size);
        au_task_vend_FlushBuf(p_long_buf_inear_in_4th_mic, p_inear_external_param->frame_size);
    }
    au_task_vend_FlushBuf(p_long_buf_inear_in_farend, p_inear_external_param->frame_size);

#endif

	return ret;
}



