/*****************************************************************************
 * 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_au.c
 * @brief entry function for audio overlay
 */

#include "dsp_sdk_types.h"
#include "overlay.h"
#include "vend_au.h"
#include "dsp_sdk_trace.h"

#define SBM_DSP_DEBUG_CODE_INCLUDE

#define DEBUG_CALC_MCPS

#ifdef DEBUG_CALC_MCPS	//hoon_test to measure complexity
#include <xtensa/xtruntime.h>
#endif

#ifdef DEBUG_CALC_MCPS	//hoon_test
UINT32 time_start;
UINT32 time_end;
UINT32 time_diff;

UINT32 time_peak_audio = 0;

UINT32 fram_cnt_audio=0;
#endif

#define SBM_NUM_NORMAL 100    /* about 1.96sec */

/******************  fast 5.54%, slow 2.76%  *******************/
#define SBM_FAST_SPEED 67380    // 840       2.76%
#define SBM_SLOW_SPEED 63730   // 888        2.76%

//////////////////////////////////////////////////////////////////////
#define SBM_NORMAL_OUTPUT_NUM 864
#define SBM_FAST_OUTPUT_NUM 840
#define SBM_SLOW_OUTPUT_NUM 888
//////////////////////////////////////////////////////////////////////
//#define SS_AUDIO_TEST_MODE
#define SS_AMB_TEST_MODE

#define SSC_SUPPORT_SBM
#define SSC_SUPPORT_PLC


extern INT32 au_task_GetAuBufLevel(UINT8 *buff_depth, UINT32 *que_count);

/* Head tracking test mode: Turn on TEST_HT_BYPASS and choose a input signal to output */
#define TEST_HT_BYPASS

#ifdef TEST_HT_BYPASS
#define TEST_HT_INPUT_1
//#define TEST_HT_INPUT_2
#endif

#ifdef ENABLE_SS_AUDIO
//  #ifndef SS_AUDIO_TEST_MODE
  #include "ssc.h"
//  #endif
#endif

#ifdef SS_AUDIO_TEST_MODE
#define TEST_TONE_SIZE 32
const INT16 g_testTone1dot5K48K16bit[TEST_TONE_SIZE] =
{
    0,      6393,   12540,  18205,  23170,  27246,  30274,  32138,
    32767,  32138,  30274,  27246,  23170,  18205,  12540,  6393,
    0,      -6393,  -12540, -18205, -23170, -27246, -30274, -32138,
    -32768, -32138, -30274, -27246, -23170, -18205, -12540, -6393
};
#endif

#ifdef SSC_SUPPORT_SBM
enum
{
    SBM_STATE_IDLE = 0,
    SBM_STATE_TRIGGERED,
    SBM_STATE_OUTPUT_SAMPLE_CHANGED
};

UINT8 g_SBM_State = SBM_STATE_IDLE;
#endif

/**
 * Declaration of overlay info and entry function. Do not change it.
 */
INT32 vend_entry_au(OVERLAY_ST_t *p_overlay_parameter) __attribute__((section(".iram0_overlay_entry.text")));

OVERLAY_INFO_t ovl_au_info __attribute__((section(".dram0_overlay_info.data"))) =
{
    MAGIC_PATTERN_AU,
    (void *)vend_entry_au
};

//////////////////////////////////////////Dolby
#ifdef ENABLE_SS_AUDIO
  #include "tduht.h"
  #include "iht.h"

#define INPUT_CHANNELS                (2u)
#define BLOCK_NUM                     (1u)
#define TDUHT_MAX_NUM_OUTPUT_CHANNELS (2u)
#define SAMPLE_RATE                   (48000ul)
#define MAX_EXAMPLE_IO_CHANNELS       (TDUHT_MAX_NUM_OUTPUT_CHANNELS)

#define OUTPUT_MODE                   (TDUHT_OUTPUT_FORMAT_BINAURAL)
#define OUTPUT_CHANNELS               (2u)
#define AZIMUTH_DEGREE                (0)

tduht_state *p_ustate;
iht_state *p_istate;
iht_log_info log_info_iht;
tduht_log_info log_info_uht;
#endif

/**
 * function prototypes
 */
INT32 vend_ss_audio_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_ss_audio_exec(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_ambient_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_ambient_exec(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_head_tracking_init(OVERLAY_ST_t *p_overlay_parameter);
INT32 vend_head_tracking_exec(OVERLAY_ST_t *p_overlay_parameter);



/**
 * Variable declarations.
 * Note: Total scratch memory size can't exceed 128KB
 */
//UINT32 g_ss_audio_scratch[SS_AUDIO_SCRATCH_MEM_SIZE_INT32];  /* Scratch memory for ss_audio */
UINT32 g_ambient_scratch[AMBIENT_SCRATCH_MEM_SIZE_INT32];    /* Scratch memory for ambient */


/**
 * Entry function of audio overlay
 */
INT32 vend_entry_au(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

    switch(p_overlay_parameter->algo_idx)
    {
        case ALGO_IDX_SS_AUDIO_INIT:
            ret = vend_ss_audio_init(p_overlay_parameter);
            break;
        case ALGO_IDX_SS_AUDIO_EXEC:
            ret = vend_ss_audio_exec(p_overlay_parameter);
            break;
        case ALGO_IDX_AMBIENT_INIT:
            ret = vend_ambient_init(p_overlay_parameter);
            break;
        case ALGO_IDX_AMBIENT_EXEC:
            ret = vend_ambient_exec(p_overlay_parameter);
            break;
        case ALGO_IDX_HT_INIT:
            ret = vend_head_tracking_init(p_overlay_parameter);
            break;
        case ALGO_IDX_HT_EXEC:
            ret = vend_head_tracking_exec(p_overlay_parameter);
            break;
        default:
            ret = MIN_INT32;
            break;
    }
    return ret;
}

#ifdef SSC_SUPPORT_SBM
#define NUM_MIN_NORMALSPEED 30
INT16 num_min_normalspeed;    // After transition (slow or fast play), Normal play need to be played at least NUM_MIN_NORMALSPEED
#endif

/**
 * Head tracking init process.
 */
INT32 vend_head_tracking_init(OVERLAY_ST_t *p_overlay_parameter)
{
    HT_EXT_ST_t *p_ht_external_param = &p_overlay_parameter->ovl_paramter.ovl_au.ht_external_parameter;
    INT32 ret = VEND_SUCCESS;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] Init head tracking start");
    //size_t tduht_persistent_size;
    void *tduht_persistent_memory;
    //size_t iht_persistent_size;
    void *iht_persistent_memory;
    iht_init_info iht_init_info;
    tduht_init_info tduht_init_info;

    /* The sample rate is fixed at initialisation time. If you want to change
    * sample rate, you will need to instantiate a new library. */
    tduht_init_info.sample_rate = SAMPLE_RATE;
    tduht_init_info.dvlim_process_disable = 0;
    iht_init_info.sample_rate = IHT_SENSOR_DATA_SAMPLERATE_DEFAULT;

    /* Set logging call back function info */
    //log_info_iht.fn_log = (iht_log_fn)printf;
    log_info_iht.level = IHT_LOG_LEVEL_FULL;
    //log_info_uht.fn_log = (tduht_log_fn)printf;
    log_info_uht.level = TDUHT_LOG_LEVEL_FULL;

    //tduht_persistent_size = tduht_query_memory(&tduht_init_info);
    //tduht_persistent_memory = malloc(tduht_persistent_size);
    //iht_persistent_size = iht_query_memory(&iht_init_info);
    //iht_persistent_memory = malloc(iht_persistent_size);

    /* The tduht_init_info struct passed here must be the same as the one
    * passed to tduht_query_memory(). */
    p_ustate = tduht_init(&tduht_init_info, tduht_persistent_memory);

    /* The iht_init_info struct passed here must be the same as the one
    * passed to iht_query_memory(). */
    p_istate = iht_init(&iht_init_info, iht_persistent_memory);

    //brcm init
    p_ht_external_param->process_len = HT_PROCESS_LEN;
    p_ht_external_param->ht_cnt = 0;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] Init head tracking end");

    return ret;
}

/**
 * Head tracking execute process.
 */
INT32 vend_head_tracking_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    HT_EXT_ST_t *p_ht_external_param = &p_overlay_parameter->ovl_paramter.ovl_au.ht_external_parameter;
    INT32 ret = VEND_SUCCESS;
    //dolby
    INT32 i;

    //size_t scratch_size = tduht_query_scratch(); /* IHT needs no scratch memory */
    void *scratch_memory;// = malloc(scratch_size);
    dlb_buffer input;
    dlb_buffer output;
    void *channel_pointers[MAX_EXAMPLE_IO_CHANNELS];
    short audio[MAX_EXAMPLE_IO_CHANNELS * TDUHT_BLOCK_SIZE];

    short iht_in_ypr[IHT_SENSOR_YPR_DEGREE_DATA_SIZE];
    short iht_out_rmatrix[IHT_HEAD_ROTATION_MATRIX_DATA_SIZE];
    short iht_out_azimuth_elevation[IHT_HEAD_ROTATION_AZIMUTH_ELEVATION_DATA_SIZE];

    float d_ypr[IHT_SENSOR_YPR_DEGREE_DATA_SIZE];
    int   d_ypr_scale = 1L << IHT_SENSOR_YPR_DEGREE_FRAC_BITS;

    /* IHT update sample number is calculated with (content sample rate) / (sensor sample rate).
    If they're changed, this caclualation should be changed accordingly. */
    static const unsigned iht_update_sample = SAMPLE_RATE / IHT_SENSOR_DATA_SAMPLERATE_DEFAULT;
    unsigned long blk = 0;

    //(void)p_tduht_info;
    //(void)p_iht_info;

    /* Audio input and output is done using dlb_buffer structures. These have
    * an array of channel pointers, and a stride. We create two dlb_buffer
    * structures which are completely identical except for perhaps the channel
    * counts and strides. This means that processing will be done inplace.
    * We also set up our processing to be done on interleaved data, this is
    * mainly to simplify our IO code. Non-interleaved processing is possible
    * by changing the channel pointers and stride. */
    input.ppdata = channel_pointers;
    input.nchannel = INPUT_CHANNELS;
    input.data_type = DLB_BUFFER_SHORT_16;
    input.nstride = INPUT_CHANNELS;

    /* We don't know the output channel count here yet, but we can set up
    * our channel pointers to handle the worst case now. */
    output.ppdata = channel_pointers;
    output.data_type = DLB_BUFFER_SHORT_16;
    output.nchannel = INPUT_CHANNELS;
    output.nstride = INPUT_CHANNELS;
    for (i = 0; i < MAX_EXAMPLE_IO_CHANNELS; i++)
    {
        channel_pointers[i] = &(audio[i]);
    }

    /* Always enable head tracking in example code*/
    tduht_enable_set(p_ustate, 1);
    tduht_azimuth_set(p_ustate, AZIMUTH_DEGREE);

    /* Set time constan value for automatic re-centering */
    iht_time_constant_param_set(p_istate, IHT_TIME_CONSTANT_IN_SEC_DEFAULT);

    /* IHT will update angles in the block meet following condition. */
    if ((blk * TDUHT_BLOCK_SIZE) % iht_update_sample < TDUHT_BLOCK_SIZE)
    {
        /**
        * tansfrom format for iht_processing
        **/
        for (i = 0; i < IHT_SENSOR_YPR_DEGREE_DATA_SIZE; i++)
        {
            iht_in_ypr[i] = (short)(d_ypr[i] * d_ypr_scale);
        }

        /**
        * iht_process, sensor data in, rotaion info out,
        * and other axis relevant operation inside
        **/
        iht_process(p_istate, iht_in_ypr, iht_out_rmatrix, iht_out_azimuth_elevation, &log_info_iht);

        /* Set azimuth degree */
        tduht_azimuth_set(p_ustate, (const int)iht_out_azimuth_elevation[0]);
    }

    tduht_process(p_ustate, BLOCK_NUM, &input, &output, OUTPUT_MODE, scratch_memory, &log_info_uht);

    /* This function gives a few examples of setting parameters. */
    static unsigned long block = 0;
    const unsigned long second = SAMPLE_RATE / TDUHT_BLOCK_SIZE;

    block++;
    if (block == 1 * second)
    {
        iht_time_constant_smoothing_enable_set(p_istate, 0);
    }
    else if (block == 2 * second)
    {
        iht_time_constant_smoothing_enable_set(p_istate, 1);
    }
    
    blk++;

#if defined (TEST_HT_INPUT_1)
    memcpy(p_ht_external_param->out_buf, p_ht_external_param->in_buf[0], (p_ht_external_param->process_len<<1));
#elif defined (TEST_HT_INPUT_2)
    memcpy(p_ht_external_param->out_buf, p_ht_external_param->in_buf[1], (p_ht_external_param->process_len<<1));
#endif

    return ret;
}

/**
 * ss_audio init process.
 */
INT32 FrameCnt;
INT32 PLC_Frame;
INT32 vend_ss_audio_init(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] Init SS audio start");

#ifdef ENABLE_SS_AUDIO
    SS_AUDIO_EXT_ST_t *p_ss_audio_external_param = &p_overlay_parameter->ovl_paramter.ovl_au.ss_audio_external_parameter;
    void *dec;
    UINT32  dram_base_addr = (UINT32)p_ss_audio_external_param->dram_dec_base_addr;
    //TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] vend_ss_audio_init start. sf=%d", p_ss_audio_external_param->sampling_rate);

    p_ss_audio_external_param->mem_offset = 0;
    p_ss_audio_external_param->frame_size = SS_AUDIO_FRAME_SIZE<<2;
    p_ss_audio_external_param->frame_cnt = 0;


    //allocate memory
    MALLOC_BYTE(p_ss_audio_external_param->dec_inst, ssc_decoder_get_size(SS_AUDIO_CHANNELS), dram_base_addr, p_ss_audio_external_param->mem_offset);
    MALLOC_BYTE(p_ss_audio_external_param->in_buf, SS_AUDIO_MAX_BITSTREAM_SIZE, dram_base_addr, p_ss_audio_external_param->mem_offset);


#ifndef SSC_SUPPORT_SBM
    MALLOC_BYTE(p_ss_audio_external_param->out_buf, SS_AUDIO_FRAME_SIZE*4, dram_base_addr, p_ss_audio_external_param->mem_offset);
#else
    MALLOC_BYTE(p_ss_audio_external_param->out_buf, 1200*4, dram_base_addr, p_ss_audio_external_param->mem_offset);
    p_ss_audio_external_param->trigger_SBM = 0;
    p_ss_audio_external_param->target_buffer_depth = 0;
	num_min_normalspeed = NUM_MIN_NORMALSPEED;
#endif

    dec = p_ss_audio_external_param->dec_inst;

    if(p_ss_audio_external_param->mem_offset > p_ss_audio_external_param->dram_dec_size)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] SS_audio dRAM buffer is not enough!");
        ret = -1;
        return ret;
    }

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] sampling rate is %d", p_ss_audio_external_param->sampling_rate);
    ret = ssc_decoder_init(dec, SS_AUDIO_CHANNELS, p_ss_audio_external_param->sampling_rate);
	FrameCnt = 0;
	PLC_Frame = 0;

#ifdef SSC_SUPPORT_SBM
    g_SBM_State = SBM_STATE_IDLE;
    ssc_set_SBMspeed_test(SBM_SLOW_SPEED,SBM_FAST_SPEED,SBM_NUM_NORMAL);
#endif

    if(ret<0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] ssc_decoder_init error!");
    }
    else
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] ssc_decoder_init success!");
    }
#endif

    TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL] Init SS audio end");

    return ret;
}

/**
 * ss_audio execute process.
 */
INT32 vend_ss_audio_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;
#ifdef ENABLE_SS_AUDIO  //hoon_test
#ifndef SS_AUDIO_TEST_MODE
    void *dec;
    UINT8 syncword[4];
    INT32 n;
#endif
#endif

#ifdef SSC_SUPPORT_SBM
    INT16 sbm_direction = 0;       /* 0: no buf level change, 1: start transition to decrease buf level, -1: start transition to increase buf level */
    INT16 buf_level_offset = 0;    /* the amount of buf level change, formula : ABS(current buf detpth - target buf depth) * 1frame  */
	UINT8 buff_depth = 0;
	UINT32 que_count = 0;
#endif

#ifdef SBM_DSP_DEBUG_CODE_INCLUDE
    INT32 sbm_get_state;
#endif

#ifdef HACK_VEND_AU_TOBE_SBC
    //au_task_1stCodecDecode();
    (*g_hack_ptrs_au)();
    g_vend_au_cnt++;

    if((g_vend_au_cnt & 0xFF) == 0)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU OVL] SS audio exec cnt0x%x (A2DP)", g_vend_au_cnt);
    }

    return ret;
#endif

#ifdef ENABLE_SS_AUDIO

    SS_AUDIO_EXT_ST_t *p_ss_audio_external_param = &p_overlay_parameter->ovl_paramter.ovl_au.ss_audio_external_parameter;

#ifdef SS_AUDIO_TEST_MODE
    INT32 i;
    INT32 j=0;
    INT16 *out = (INT16 *) p_ss_audio_external_param->out_buf;   //size = 864(sample)* 2(channel) * 2(byte/sample)

    for(i=0 ; i<(SS_AUDIO_FRAME_SIZE*2); i+=2)
    {
        out[i] = g_testTone1dot5K48K16bit[j]>>2;
        out[i+1] = g_testTone1dot5K48K16bit[j]>>2;

        j++;
        if(j == 32)
        {
            j=0;
        }
    }

    p_ss_audio_external_param->output_samples = SS_AUDIO_FRAME_SIZE;
    p_ss_audio_external_param->frame_cnt++;
#else
    dec = p_ss_audio_external_param->dec_inst;
    for(n=0; n<4;n++)
        syncword[n] = p_ss_audio_external_param->in_buf[n];

#ifdef SSC_SUPPORT_SBM
    if(p_ss_audio_external_param->trigger_SBM)
    {
        if(p_ss_audio_external_param->current_buffer_depth > p_ss_audio_external_param->target_buffer_depth)
        {
            TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SBM] Trigger Game mode!!");
            buf_level_offset = p_ss_audio_external_param->current_buffer_depth - p_ss_audio_external_param->target_buffer_depth;
            sbm_direction = 1;
            g_SBM_State = SBM_STATE_TRIGGERED;
            TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SBM] Trigger SBM %d -> %d",
                                              p_ss_audio_external_param->current_buffer_depth,
                                              p_ss_audio_external_param->target_buffer_depth);
   //         au_task_NotifyJitterBufLevelChange(EVENTTYPE_JITTER_BUFFER_LEVEL_CHANGE_STARTED, 0);
        }
        else if(p_ss_audio_external_param->current_buffer_depth < p_ss_audio_external_param->target_buffer_depth)
        {
            TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SBM] Trigger Normal mode!!");
            buf_level_offset = p_ss_audio_external_param->target_buffer_depth - p_ss_audio_external_param->current_buffer_depth;
            sbm_direction = -1;
            g_SBM_State = SBM_STATE_TRIGGERED;
            TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SBM] Trigger SBM %d -> %d",
                                              p_ss_audio_external_param->current_buffer_depth,
                                              p_ss_audio_external_param->target_buffer_depth);
 //           au_task_NotifyJitterBufLevelChange(EVENTTYPE_JITTER_BUFFER_LEVEL_CHANGE_STARTED, 0);
        }
        else
        {
            TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SBM] invalid target_buffer_depth %d, current depth %d",
                                              p_ss_audio_external_param->target_buffer_depth,
                                              p_ss_audio_external_param->current_buffer_depth);
        }

        /* Reset variables for the next trigger */
        p_ss_audio_external_param->trigger_SBM = 0;
        p_ss_audio_external_param->target_buffer_depth = 0;
        p_ss_audio_external_param->current_buffer_depth = 0;
    }

    ssc_sbm_interface(sbm_direction, buf_level_offset);
#endif

    if(p_ss_audio_external_param->plc_frame == 0) /* recieved good packet */
    {
		if(syncword[0]==0xFF && syncword[1]==0xEE)
		{
#ifdef DEBUG_CALC_MCPS
			time_start = xthal_get_ccount();
#endif	
			p_ss_audio_external_param->output_samples = ssc_decode(dec, p_ss_audio_external_param->in_buf, (INT16 *)p_ss_audio_external_param->out_buf, SS_AUDIO_FRAME_SIZE, p_ss_audio_external_param->plc_frame, p_ss_audio_external_param->channel); // out will have pcm audio data
			FrameCnt++;
#ifdef DEBUG_CALC_MCPS
			time_end = xthal_get_ccount();
			time_diff = time_end - time_start;
			if(time_diff > time_peak_audio)
				time_peak_audio = time_diff;

			fram_cnt_audio++;
			if(fram_cnt_audio % 133 ==0)
			{
				TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] ssc audio excution cycle(Peak) : %d", time_peak_audio);
				fram_cnt_audio = 0;
			}
#endif
		}
		else
		{
			p_ss_audio_external_param->output_samples = -1;
		}
	}
	else
	{
#ifdef SSC_SUPPORT_PLC    //   p_ss_audio_external_param->plc_frame ==  1 case.

#ifdef DEBUG_CALC_MCPS
	time_start = xthal_get_ccount();
#endif	
		p_ss_audio_external_param->output_samples = ssc_decode(dec, p_ss_audio_external_param->in_buf, (INT16 *)p_ss_audio_external_param->out_buf, SS_AUDIO_FRAME_SIZE, p_ss_audio_external_param->plc_frame, p_ss_audio_external_param->channel);
		FrameCnt++;
		PLC_Frame++;
#ifdef DEBUG_CALC_MCPS
	time_end = xthal_get_ccount();
	time_diff = time_end - time_start;
	if(time_diff > time_peak_audio)
		time_peak_audio = time_diff;

	fram_cnt_audio++;
	if(fram_cnt_audio % 133 ==0)
	{
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] ssc audio PLC excution cycle(Peak) : %d", time_peak_audio);
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP SP_OVL][ssc] ssc audio DBG_MSG Total Frame : %d, PLC Frame : %d", FrameCnt, PLC_Frame);
		fram_cnt_audio = 0;
	}
#endif

#else
		INT16 *dec_out = (INT16 *)p_ss_audio_external_param->out_buf;
		INT16 num_output;
		INT16 state_info = ssc_SBM_getstatus();
		
		if(state_info == 0)
		{
			num_output = SBM_NORMAL_OUTPUT_NUM;
		}
		else if(state_info == 1)
		{
			num_output = SBM_SLOW_OUTPUT_NUM;
		}
		else if(state_info == 2)
		{
			num_output = SBM_FAST_OUTPUT_NUM;
		}
		else
		{
			num_output = 864;
		}

		if(p_ss_audio_external_param->channel != SS_JOINT_CHANNEL)
		{
			for(n=0; n<num_output; n++)
			{
				dec_out[n] = 0;
			}
		}
		else
		{
			for(n=0; n<(num_output*2); n++)
			{
				dec_out[n] = 0;
			}
		}

		p_ss_audio_external_param->output_samples = num_output;
#endif
    }

#ifndef SSC_SUPPORT_SBM
    if(p_ss_audio_external_param->output_samples != SS_AUDIO_FRAME_SIZE)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] decode fail");
        ret = VEND_FAIL;
    }
    else
    {
        p_ss_audio_external_param->frame_cnt++;
    }
#else
	au_task_GetAuBufLevel(&buff_depth, &que_count);
    if (g_SBM_State == SBM_STATE_TRIGGERED && p_ss_audio_external_param->output_samples != SS_AUDIO_FRAME_SIZE)
    {
        g_SBM_State = SBM_STATE_OUTPUT_SAMPLE_CHANGED;
    }
    else if (g_SBM_State == SBM_STATE_OUTPUT_SAMPLE_CHANGED && p_ss_audio_external_param->output_samples == SS_AUDIO_FRAME_SIZE)
    {
		if(num_min_normalspeed == 0)
		{
			g_SBM_State = SBM_STATE_IDLE;
			TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SBM] Send : EVENTTYPE_JITTER_BUFFER_LEVEL_CHANGE_COMPLETED, buff_depth : %d", buff_depth);
			au_task_NotifyJitterBufLevelChange(EVENTTYPE_JITTER_BUFFER_LEVEL_CHANGE_COMPLETED, buff_depth);

			num_min_normalspeed = NUM_MIN_NORMALSPEED;
		}
		else
		{
			num_min_normalspeed--;
		}
    }

    if(p_ss_audio_external_param->output_samples<500 ||  p_ss_audio_external_param->output_samples>1200)
    {
        TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] decode fail");
        ret = VEND_FAIL;
    }
    else
    {
        /* check if number of output sample is multiple of 8*/
        if (p_ss_audio_external_param->output_samples % 8)
        {
            TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] output samples is not multiple of 8 : %d", p_ss_audio_external_param->output_samples);
            p_ss_audio_external_param->output_samples = 0;
            ret = VEND_FAIL;
        }

        p_ss_audio_external_param->frame_cnt++;
    }
#endif

#ifdef SBM_DSP_DEBUG_CODE_INCLUDE
	sbm_get_state = ssc_SBM_getstatus();
	if(sbm_get_state == 0)
	{
		if(p_ss_audio_external_param->output_samples != SBM_NORMAL_OUTPUT_NUM)
		{
				TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] sbm state is not match with num of output samples(Normal)");
		}
	}
	else if(sbm_get_state == 1)
	{
		if(p_ss_audio_external_param->output_samples != SBM_SLOW_OUTPUT_NUM)    // 888 is for the "#define SBM_SLOW_SPEED 63730    /* 888    63700 ~ 63750   2.76% */"
		{
			TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] sbm state is not match with num of output samples(Slow)");
		}
	}
	else if(sbm_get_state == 2)  
	{
		if(p_ss_audio_external_param->output_samples != SBM_FAST_OUTPUT_NUM)  // 
		{
			TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] sbm state is not match with num of output samples(Fast)");
		}
	}
	else if(sbm_get_state == 3 || sbm_get_state == 4)
	{
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] On the SBM transition, new transition is started");
	}
	else
	{
		TRACE(TRACE_INFO, MODULE_ID_DSP, "[DSP AU_OVL][SS AUDIO DEC] Unknown SBM state info");
	}
#endif

#endif
#endif
    return ret;
}

/**
 * ambient init process.
 */
INT32 vend_ambient_init(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;
#ifdef ENABLE_AMBIENT_ALGO
    AMBIENT_EXT_ST_t *p_ambient_external_param = &p_overlay_parameter->ovl_paramter.ovl_au.ambient_external_parameter;
    p_ambient_external_param->mem_offset = 0;
    //allocate memory
    MALLOC_BYTE(p_ambient_external_param->in_buf, (AMBIENT_PCM_N<<2), g_ambient_scratch, p_ambient_external_param->mem_offset);
    MALLOC_BYTE(p_ambient_external_param->out_buf, (AMBIENT_PCM_N<<2), g_ambient_scratch, p_ambient_external_param->mem_offset);

#ifndef SS_AMB_TEST_MODE
    Samsung_Ambient_Init(p_ambient_external_param->sampling_rate, p_ambient_external_param->ambient_mode, AMBIENT_BITWIDTH);
#endif

#endif
    return ret;
}

/**
 * ambient execute process.
 */
INT32 vend_ambient_exec(OVERLAY_ST_t *p_overlay_parameter)
{
    INT32 ret = VEND_SUCCESS;
#ifdef ENABLE_AMBIENT_ALGO
    AMBIENT_EXT_ST_t *p_ambient_external_param = &p_overlay_parameter->ovl_paramter.ovl_au.ambient_external_parameter;
    p_ambient_external_param->ambient_volume = 7;

#ifdef SS_AMB_TEST_MODE
    memcpy(g_overlay_parameter.ovl_paramter.ovl_au.ambient_external_parameter.out_buf,
           g_overlay_parameter.ovl_paramter.ovl_au.ambient_external_parameter.in_buf,
           (AMBIENT_PCM_N<<2));

    /* Simulate AMB process time */
    au_task_TimerDelay(VEND_AMB_PROCESS_TIME);
#else
    Samsung_Ambient_Exe(p_ambient_external_param->in_buf, p_ambient_external_param->out_buf, AMBIENT_PCM_N, p_ambient_external_param->ambient_mode, AMBIENT_WARN_DETECT, p_ambient_external_param->ambient_volume);
#endif

#endif
    return ret;
}
