[Feature][Modem]Update MTK MODEM V1.6 baseline version: MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6

MTK modem version: MT2735_IVT_MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6.tar.gz
RF  modem version: NA

Change-Id: I45a4c2752fa9d1a618beacd5d40737fb39ab64fb
diff --git a/mcu/driver/audio/src/v1/ExtBgSnd.c b/mcu/driver/audio/src/v1/ExtBgSnd.c
new file mode 100644
index 0000000..5b1b0fc
--- /dev/null
+++ b/mcu/driver/audio/src/v1/ExtBgSnd.c
@@ -0,0 +1,880 @@
+#include "kal_public_api.h"
+#include "kal_general_types.h"
+#include "sync_data.h"
+
+#include "kal_trace.h"
+#include "l1sp_trc.h"
+
+#include "l1audio.h"
+#include "am.h"
+//#include "speech_def.h"
+//#include "afe_def.h" // for output device setting
+//#include "sp_drv.h"
+
+#include "sal_exp.h"
+#include "bgSnd.h"
+
+//#define DSP_BGS_UP_DOWN_INT_SEPERATE
+
+
+#define BGSND_BUFFER_LEN_NB              (160) //unit is sample (16bit)
+#define BGSND_BUFFER_LEN_WB              (320) //unit is sample (16bit)
+#define BGSND_BUFFER_LEN_SWB             (640) //unit is sample (16bit)
+#define BGSND_BUFFER_LEN_FB              (960) //unit is sample (16bit)
+
+#define BGSND_BUFFER_LEN                 (BGSND_BUFFER_LEN_SWB)
+
+#define MAX_NUM_BGSND_PROCESS (2)
+
+
+//================= DSP BGSND INTERFACE ====================
+
+typedef enum {
+	DSP_BGSND_STATE_IDLE = 0,
+	DSP_BGSND_STATE_RUN, 
+	DSP_BGSND_STATE_STOPPING,
+}DSP_BGSND_STATE_TYPE;
+
+typedef struct{
+	DSP_BGSND_STATE_TYPE   state;
+		                    
+	bool                   fSph[MAX_NUM_BGSND_PROCESS];
+	uint16                 gain[MAX_NUM_BGSND_PROCESS];
+		                    
+   void                   (*Ext_Hisr[MAX_NUM_BGSND_PROCESS])(void);
+}DSP_BKGSND_T; 
+
+DSP_BKGSND_T DSP_BGSnd;
+
+//================= Extended BGSND INTERFACE ====================
+#define MAX_SIZE_EXT_BGSND_SRC (2)     // AP bkgsnd + VoLTE UL bkgsnd
+#define EXT_BGSND_BUF_PTR_DIFF (2)
+#define EXT_BGSND_SRC_BUF_SIZE ((BGSND_BUFFER_LEN) * 2 + EXT_BGSND_BUF_PTR_DIFF) //buffering 2 frames
+
+
+#define MAX_LEVEL_EXT_BGSND_GAIN (7)  
+
+typedef struct{
+   EXT_SRC_STATE_TYPE     state[MAX_NUM_BGSND_PROCESS];
+   void       (*offHdr)();//(int id);                     //TODO Trigger MED to close DSP bgsnd
+   void       (*Hdr[MAX_NUM_BGSND_PROCESS])(void); // under HISR
+   uint16     dspLastSample[MAX_NUM_BGSND_PROCESS];
+   
+   uint32     len_WriteSrcBuffer_this_time;
+   //event handling
+   //void       (*EventHandler)(void); 
+   //void       *event_data;
+   
+   //gain handling  
+	bool       fSph[MAX_NUM_BGSND_PROCESS];  
+	uint16     gain[MAX_NUM_BGSND_PROCESS];  
+   
+   //buffer handling
+   uint32     bufSize[MAX_NUM_BGSND_PROCESS], bufRead[MAX_NUM_BGSND_PROCESS], bufWrite[MAX_NUM_BGSND_PROCESS]; 
+   uint32     bufDataCount[MAX_NUM_BGSND_PROCESS];
+   uint16     buffer[MAX_NUM_BGSND_PROCESS][EXT_BGSND_SRC_BUF_SIZE]; 
+   
+}EXT_BGSND_SRC_T;
+
+typedef struct{   
+   bool                     is_used[MAX_SIZE_EXT_BGSND_SRC];
+   bool                     is_send_event[MAX_SIZE_EXT_BGSND_SRC];
+   EXT_BGSND_SRC_T          src[MAX_SIZE_EXT_BGSND_SRC];
+   uint16                   num_src_used;   
+   	                      
+   uint16                   buffer[MAX_NUM_BGSND_PROCESS][BGSND_BUFFER_LEN];  //accumulate all sources multiplied by gains into this buffer
+                            
+	uint16                   aud_id;
+   bool                   skip_hisr;
+   kal_spinlockid          bgs_spinlockID;
+}EXT_BGSND_T;
+
+static EXT_BGSND_T Ext_BGSnd;
+
+void EXT_BGSND_Hisr(BGSND_PROCESS_TYPE type);
+
+/*
+int has_ul = 0;
+int has_dl = 0;
+int ul_data[320], dl_data[320];*/
+
+
+static void DSP_BGSND_INIT()
+{	
+  MD_TRC_DSP_BGSND_INIT_ENTER();
+	memset(&DSP_BGSnd, 0, sizeof(DSP_BKGSND_T));
+	//has_ul = has_dl = 0;
+	MD_TRC_DSP_BGSND_INIT_LEAVE();
+}
+
+static void DSP_BGSND_ConfigMixer(kal_bool bSPHFlag, kal_int8 SNDGain, BGSND_PROCESS_TYPE type)
+{
+  MD_TRC_DSP_BGSND_CONFIGMIXER_ENTER();	
+  MD_TRC_DSP_BGSND_CONFIGMIXER_BGSND_PROCESS_TYPE(type, bSPHFlag, SNDGain);
+   
+	ASSERT(SNDGain>=0 && SNDGain<=7);
+	if( SNDGain == 0)
+		DSP_BGSnd.gain[type] = 0;
+	else {
+		DSP_BGSnd.gain[type] = (kal_int16)(32767 >> (7 - SNDGain));
+	}
+	DSP_BGSnd.fSph[type] = bSPHFlag;
+	MD_TRC_DSP_BGSND_CONFIGMIXER_LEAVE();
+}
+
+static void DSP_BGSND_UpdateMixer() // private
+{
+  MD_TRC_DSP_BGSND_UPDATEMIXER_ENTER();	   
+   if ( AM_IsSpeechOn() || AM_IsVoIPOn()) {
+   	SAL_Bgsnd_Config(DSP_BGSnd.gain[BGSND_UL_PROCESS], DSP_BGSnd.gain[BGSND_DL_PROCESS], DSP_BGSnd.fSph[BGSND_UL_PROCESS], DSP_BGSnd.fSph[BGSND_DL_PROCESS]);
+   } else {
+      //When enable BT, spe_setSpeechMode() will do Speech Off and Speech On. This function may run between Off and ON, so do not use ASSERT().
+      //ASSERT(false);
+      SAL_Bgsnd_Config(DSP_BGSnd.gain[BGSND_UL_PROCESS], DSP_BGSnd.gain[BGSND_DL_PROCESS], 0, 0);
+   }
+  MD_TRC_DSP_BGSND_UPDATEMIXER_LEAVE();	   
+}
+
+
+void DSP_BGSND_Stop(void)
+{
+  MD_TRC_DSP_BGSND_STOP_ENTER();
+   DSP_BGSnd.state = DSP_BGSND_STATE_STOPPING;
+	{  //turn off DSP BGSND	
+   	uint32 I;
+   	if(SAL_Bgsnd_IsRunning())
+   		SAL_Bgsnd_SetFinal();
+   	for ( I = 0; ; I++ ) {
+   		if ( SAL_Bgsnd_IsIdle())	 /* DSP returns to idle state */
+   			break;
+   		ASSERT_REBOOT( I < 20 );
+   		kal_sleep_task( AUD_1TICK(2) );
+   	}
+   	
+   	AM_SND_PlaybackOff( true );
+   }
+   
+#ifdef DSP_BGS_UP_DOWN_INT_SEPERATE
+	L1Audio_UnhookHisrHandler(D2C_SOUND_EFFECT_INT_ID_DL);  
+	L1Audio_UnhookHisrHandler(D2C_SOUND_EFFECT_INT_ID_UL);  
+#else
+	L1Audio_UnhookHisrHandler(D2C_SOUND_EFFECT_INT_ID_DL);
+#endif 
+   DSP_BGSnd.state = DSP_BGSND_STATE_IDLE;
+  MD_TRC_DSP_BGSND_STOP_LEAVE();   
+}
+
+
+/*
+static kal_uint16 tempMicData[320]
+	// = { 0x4808,0x85, 0x156,0, 0x4,0, 0x146,0x9000, 
+	= { 
+	0xfff4,0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 
+	0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 
+	0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 
+	0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a78, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa576, 0xfff3, 0x5a79, 0x7fff, 0x5a8b, 
+   0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000c, 0xa588, 
+   0x8001, 0xa576, 0xfff4, 0x5a79, 0x7fff, 0x5a8b, 0x000d, 0xa587, 0x8001, 0xa575, 	
+
+	0xfff4,0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 
+	0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 
+	0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 
+	0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a78, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa576, 0xfff3, 0x5a79, 0x7fff, 0x5a8b, 
+   0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000c, 0xa588, 
+   0x8001, 0xa576, 0xfff4, 0x5a79, 0x7fff, 0x5a8b, 0x000d, 0xa587, 0x8001, 0xa575, 
+
+	0xfff4,0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 
+	0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 
+	0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 
+	0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a78, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa576, 0xfff3, 0x5a79, 0x7fff, 0x5a8b, 
+   0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000c, 0xa588, 
+   0x8001, 0xa576, 0xfff4, 0x5a79, 0x7fff, 0x5a8b, 0x000d, 0xa587, 0x8001, 0xa575, 
+   
+	0xfff4,0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 
+	0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 
+	0x8001, 0xa575, 0xfff4, 0x5a7a, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 
+	0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a78, 
+	0x7fff, 0x5a8a, 0x000d, 0xa587, 0x8001, 0xa576, 0xfff3, 0x5a79, 0x7fff, 0x5a8b, 
+   0x000d, 0xa587, 0x8001, 0xa575, 0xfff4, 0x5a79, 0x7fff, 0x5a8a, 0x000c, 0xa588, 
+   0x8001, 0xa576, 0xfff4, 0x5a79, 0x7fff, 0x5a8b, 0x000d, 0xa587, 0x8001, 0xa575 	
+
+};*/
+
+
+void DSP_BGSND_Hisr(void * param)
+{
+   int i;
+   uint16 *src_buf;
+   volatile uint16 *dst_buf;
+
+   BGSND_PROCESS_TYPE type = (BGSND_PROCESS_TYPE) param; 
+   
+   MD_TRC_DSP_BGSND_HISR_ENTER();   
+   
+   MD_TRC_DSP_BGSND_HISR_BGSND_PROCESS_TYPE(type, DSP_BGSnd.state);
+   
+   ASSERT( type == BGSND_DL_PROCESS || type == BGSND_UL_PROCESS );
+	
+   if ((DSP_BGSND_STATE_RUN != DSP_BGSnd.state)){
+      return;
+   }
+
+   if(!SAL_Bgsnd_IsRunning())
+      return;      		   
+
+   DSP_BGSnd.Ext_Hisr[type]();
+   src_buf = Ext_BGSnd.buffer[type];
+
+   dst_buf = src_buf;
+   //set up the DSP address and pointers
+   switch(type){
+      case BGSND_DL_PROCESS:
+         //dst_buf_len = SAL_Bgsnd_GetDataLen_DL();
+         dst_buf     = SAL_Bgsnd_GetBuf_DL();
+         break;
+      case BGSND_UL_PROCESS:
+         //dst_buf_len = SAL_Bgsnd_GetDataLen_UL();
+         dst_buf     = SAL_Bgsnd_GetBuf_UL();
+         break;
+   }         	      
+
+   for(i=0; i<BGSND_BUFFER_LEN_SWB; i++){
+      //*dst_buf++ = *src_buf++;
+      dst_buf[i] = src_buf[i];
+   }
+   Data_Sync_Barrier();
+
+   MD_TRC_DSP_BGSND_HISR_LEAVE(); 
+}
+#if !defined(DSP_BGS_UP_DOWN_INT_SEPERATE)
+void DSP_BGSND_Shared_Hisr_DL_UL(void * param)
+{
+  MD_TRC_DSP_BGSND_SHARED_HISR_DL_UL_ENTER();   
+   DSP_BGSND_Hisr((void * )BGSND_UL_PROCESS);
+   DSP_BGSND_Hisr((void * )BGSND_DL_PROCESS);
+  MD_TRC_DSP_BGSND_SHARED_HISR_DL_UL_LEAVE();  
+}
+#endif
+
+static void DSP_BGSND_Start(void (*Ext_DLHisr)(void), 
+                            void (*Ext_ULHisr)(void))
+{
+   MD_TRC_DSP_BGSND_START_ENTER();
+   ASSERT(AM_IsSpeechOn() || AM_IsVoIPOn());	
+	
+   DSP_BGSnd.Ext_Hisr[BGSND_DL_PROCESS]      = Ext_DLHisr;
+   DSP_BGSnd.Ext_Hisr[BGSND_UL_PROCESS]      = Ext_ULHisr; 
+	
+#ifdef DSP_BGS_UP_DOWN_INT_SEPERATE
+	L1Audio_HookHisrHandler(D2C_SOUND_EFFECT_INT_ID_DL, DSP_BGSND_Hisr, (void *)BGSND_DL_PROCESS);  
+	L1Audio_HookHisrHandler(D2C_SOUND_EFFECT_INT_ID_UL, DSP_BGSND_Hisr, (void *)BGSND_UL_PROCESS);  
+#else
+	L1Audio_HookHisrHandler(D2C_SOUND_EFFECT_INT_ID_DL, DSP_BGSND_Shared_Hisr_DL_UL, 0);  	
+#endif
+
+	// gain setting and update 
+	// Although these settings are allowed to modify during run time,
+	// extended bgsnd should be fixed because the changes of volume from 
+	// each sources are calculated in MCU side.
+   DSP_BGSND_ConfigMixer(KAL_TRUE, 7, BGSND_UL_PROCESS);
+	DSP_BGSND_ConfigMixer(KAL_TRUE, 7, BGSND_DL_PROCESS);
+
+	DSP_BGSND_UpdateMixer();
+	{  //turn on DSP BGSND
+		uint32 I;
+   	AM_SND_PlaybackOn();
+   	SAL_Bgsnd_SetInit();		
+		for( I = 0; ; I++ ) {
+			if(SAL_Bgsnd_IsRunning())
+				break;
+			ASSERT_REBOOT( I < 20 );
+			kal_sleep_task( AUD_1TICK(2) );
+		}
+	}	
+	
+	DSP_BGSnd.state = DSP_BGSND_STATE_RUN;
+	MD_TRC_DSP_BGSND_START_LEAVE();
+}
+/*===============  Ext BGSND interface ========= */
+
+uint32 EXT_BGSND_init()
+{
+   MD_TRC_EXT_BGSND_INIT_ENTER();
+   DSP_BGSND_INIT();
+   memset((void *)&Ext_BGSnd, 0, sizeof(EXT_BGSND_T));      
+   // get audio ID
+	Ext_BGSnd.aud_id = L1Audio_GetAudioID(); 
+	Ext_BGSnd.skip_hisr = 0;
+	Ext_BGSnd.bgs_spinlockID = kal_create_spinlock("bgs_spinlock");
+	MD_TRC_EXT_BGSND_INIT_LEAVE();
+// L1Audio_SetEventHandler( Ext_BGSnd.aud_id, (L1Audio_EventHandler) EXT_BGSND_EventHandler );
+  return 0;
+}
+
+void EXT_BGSND_DLHisr(void);
+void EXT_BGSND_ULHisr(void);
+
+
+uint32 EXT_BGSND_Start(void (*offHdr)(void),
+                       void (*DLHisr)(void),       //move data from src -> ext
+                       void (*ULHisr)(void),       //move data from src -> ext 
+                       kal_int8 DLSNDGain,
+                       kal_int8 ULSNDGain /*,                           
+                       void (*EventHandler)(void)*/)
+{
+   int i, j;
+
+   Ext_BGSnd.skip_hisr = 0;
+  MD_TRC_EXT_BGSND_START_ENTER();
+   
+   ASSERT(!(NULL==DLHisr && NULL==ULHisr));
+   ASSERT(NULL!=offHdr); //without this, we cannot stop DSP BGSND
+     
+   for(i=0; i<MAX_SIZE_EXT_BGSND_SRC; i++){
+     MD_TRC_EXT_BGSND_START_DEBUG1(i);
+      if(!Ext_BGSnd.is_used[i]){
+        MD_TRC_EXT_BGSND_START_DEBUG2(i);
+         EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[i];
+		 memset(pSrc, 0, sizeof(EXT_BGSND_SRC_T)); 
+
+         pSrc->Hdr[BGSND_DL_PROCESS]   = DLHisr;
+         pSrc->Hdr[BGSND_UL_PROCESS]   = ULHisr;        
+         pSrc->offHdr = offHdr;
+         for(j=0; j<MAX_NUM_BGSND_PROCESS; j++){//TODO temp solution
+            
+            pSrc->state[j]  = EXT_SRC_STATE_RUN;      
+            //pSrc->fSph[j]   = true; //TODO
+            //pSrc->gain[j]   = 7;    //TODO     
+            
+         	// buffer reset
+         	memset(pSrc->buffer[j], 0, sizeof(kal_uint16)*EXT_BGSND_SRC_BUF_SIZE);
+         	pSrc->bufSize[j]  = EXT_BGSND_SRC_BUF_SIZE;
+         	pSrc->bufRead[j]  = 0;
+         	pSrc->bufWrite[j] = EXT_BGSND_BUF_PTR_DIFF;
+            pSrc->bufDataCount[j] = 0;
+         }   
+         if(AM_IsSpeechOn() || AM_IsVoIPOn()){
+            EXT_BGSND_ConfigMixer(i, true, DLSNDGain, BGSND_DL_PROCESS); 
+            EXT_BGSND_ConfigMixer(i, true, ULSNDGain, BGSND_UL_PROCESS);
+         }else{
+            EXT_BGSND_ConfigMixer(i, false, DLSNDGain, BGSND_DL_PROCESS); 
+            EXT_BGSND_ConfigMixer(i, false, ULSNDGain, BGSND_UL_PROCESS);            
+         }         	
+      	Ext_BGSnd.is_used[i] = true;     
+         if( 0 == Ext_BGSnd.num_src_used++){
+           MD_TRC_EXT_BGSND_START_SELECTED_SRC(i,  Ext_BGSnd.num_src_used);
+      	   // lock DSP for sherif writing.	
+      	   L1Audio_SetFlag( Ext_BGSnd.aud_id ); // REIMIND: Before Locking SleepMode, to access DSP sherrif tasks much time. So access DSP must be after SetFlag1       
+            DSP_BGSND_Start(EXT_BGSND_DLHisr, EXT_BGSND_ULHisr);
+         }      	 	
+        MD_TRC_EXT_BGSND_START_DEBUG3(i);
+      	break;
+      }
+     MD_TRC_EXT_BGSND_START_DEBUG4(i);
+   }   
+  MD_TRC_EXT_BGSND_START_DEBUG5(i);
+   ASSERT(i < MAX_SIZE_EXT_BGSND_SRC);  
+  		
+  MD_TRC_EXT_BGSND_START_LEAVE();         
+   return i;
+}
+
+void EXT_BGSND_Flush(uint32 id) //under MED Task, triggered by the AP message, BGSND_OFF
+{                               //flush buffer first, and then close it ; HISR will consume the buffer until it is empty. 
+   int j;
+  MD_TRC_EXT_BGSND_FLUSH_ENTER();   
+   ASSERT(Ext_BGSnd.is_used[id]);
+   
+   EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id];
+  MD_TRC_EXT_BGSND_FLUSH_ID(id);
+   
+   for(j=0; j<MAX_NUM_BGSND_PROCESS; j++){  
+      if(EXT_SRC_STATE_RUN == pSrc->state[j]){    
+         pSrc->state[j] = EXT_SRC_STATE_FLUSHING;
+      }else{//prevent double entry to the procedure of flushing
+        MD_TRC_EXT_BGSND_FLUSH_STATE(pSrc->state[j]);         
+      }
+   }
+  MD_TRC_EXT_BGSND_FLUSH_LEAVE();   
+}
+
+// under MED Task, triggered by the EXT_HISR when UL/DL buffer flushes completely.
+// Even if many src would like to close DSP BGSND, we don't think about the race condition since the request of closing is processed by MED's queue.
+// Due to it may force close. so status check nees to remove. 
+void EXT_BGSND_Close(uint32 id) 
+{
+  MD_TRC_EXT_BGSND_CLOSE_ENTER();     
+   ASSERT(Ext_BGSnd.is_used[id]);
+   EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id]; 
+      
+   // ASSERT(EXT_SRC_STATE_FLUSHING_OVER==pSrc->state[BGSND_DL_PROCESS]);
+   // ASSERT(EXT_SRC_STATE_FLUSHING_OVER==pSrc->state[BGSND_UL_PROCESS]);
+  MD_TRC_EXT_BGSND_CLOSE_SELECTED_SRC(id,  Ext_BGSnd.num_src_used);
+    
+   {  //flush buffer first, and then close it   // buffer reset
+   	Ext_BGSnd.is_used[id] = false;  // [IMPORTANT] HISR using the information to check BGS is under use or not. so put the line before clean all information.     		
+   	Ext_BGSnd.num_src_used--;  
+   }
+	
+   pSrc->state[BGSND_DL_PROCESS] = pSrc->state[BGSND_UL_PROCESS] = EXT_SRC_STATE_STOPPING;    
+	
+   if( 0 == Ext_BGSnd.num_src_used){ 
+      DSP_BGSND_Stop();      
+      L1Audio_ClearFlag( Ext_BGSnd.aud_id );
+
+   }  
+   pSrc->state[BGSND_DL_PROCESS] = pSrc->state[BGSND_UL_PROCESS] = EXT_SRC_STATE_IDLE;    
+  MD_TRC_EXT_BGSND_CLOSE_LEAVE();     
+}
+
+void EXT_BGSND_DLHisr(void)
+{
+  MD_TRC_EXT_BGSND_DLHISR_ENTER();
+   EXT_BGSND_Hisr(BGSND_DL_PROCESS);
+  MD_TRC_EXT_BGSND_DLHISR_LEAVE();
+}
+
+void EXT_BGSND_ULHisr(void)
+{
+  MD_TRC_EXT_BGSND_ULHISR_ENTER();
+   EXT_BGSND_Hisr(BGSND_UL_PROCESS);
+  MD_TRC_EXT_BGSND_ULHISR_LEAVE();
+}
+
+/*static*/ int32 EXT_BGSND_GetDataCount(uint32 id, BGSND_PROCESS_TYPE type)
+{
+	int32 count = 0; 
+	MD_TRC_EXT_BGSND_GETDATACOUNT_ENTER();
+	
+	ASSERT( type == BGSND_DL_PROCESS || type == BGSND_UL_PROCESS );
+	EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id];
+            
+   count = pSrc->bufDataCount[type];
+/*   for(j=0; j<MAX_BGSND_BUFFER_PROCESS_BIT; j++){
+      if(type & (1<<j)){         
+         type = 1<<j;
+      	if(pSrc->bufWrite[type]<pSrc->bufRead[type]){
+      		count = (pSrc->bufSize[type] - EXT_BGSND_BUF_PTR_DIFF)+pSrc->bufWrite[type] - pSrc->bufRead[type];
+      	} else {
+      		count = pSrc->bufWrite[type] - pSrc->bufRead[type];
+      	}	               
+      }
+   }	
+
+	if( count > EXT_BGSND_BUF_PTR_DIFF) {
+		count -= EXT_BGSND_BUF_PTR_DIFF;
+	} else {
+		count = 0;
+	}
+
+	if(count&1){
+		count = count -1;
+	}*/
+	MD_TRC_EXT_BGSND_GETDATACOUNT_COUNT(count);
+	MD_TRC_EXT_BGSND_GETDATACOUNT_LEAVE();
+	return count;
+}
+
+void EXT_BGSND_Hisr(BGSND_PROCESS_TYPE type)
+{
+   int i;
+   if(Ext_BGSnd.skip_hisr){
+   		return;
+   }
+   
+  MD_TRC_EXT_BGSND_HISR_ENTER();
+  MD_TRC_EXT_BGSND_HISR_BGSND_PROCESS_TYPE(type);
+      
+   //reset buffer data
+   if( BGSND_DL_PROCESS == type){// align DL timing
+      for(i=0; i<BGSND_BUFFER_LEN; i++){ // To do , reduce computation
+         Ext_BGSnd.buffer[BGSND_DL_PROCESS][i] = 0;    
+      }    
+      for(i=0; i<BGSND_BUFFER_LEN; i++){ 
+         Ext_BGSnd.buffer[BGSND_UL_PROCESS][i] = 0;    
+      }         
+   }
+   DSP_BGSND_UpdateMixer();      
+   for(i=0; i<MAX_SIZE_EXT_BGSND_SRC; i++){         
+      EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[i];   
+      if(Ext_BGSnd.is_used[i]){
+        MD_TRC_EXT_BGSND_HISR_SELECTED_SRC(i, pSrc->state[type]);
+
+         //point 1
+         if(pSrc->Hdr[type]){  // Point1 must be before point2 since it is expected that in pSrc->Hdr[type](),  len_WriteSrcBuffer_this_time will be updated by EXT_BGSND_WriteSrcBuffer
+            pSrc->Hdr[type](); // Each Hdr should update buffer[BGSND_ L_PROCESS] by EXT_BGSND_Buf_Add
+         }
+              
+         //point 2
+         if(EXT_SRC_STATE_FLUSHING == pSrc->state[type]){ // FLUSHING --> FLUSHING_OVER            
+            //if(EXT_BGSND_GetDataCount(i, type) <= EXT_BGSND_BUF_PTR_DIFF){
+            if( (0 == pSrc->len_WriteSrcBuffer_this_time) && (EXT_BGSND_GetDataCount(i, type) < BGSND_BUFFER_LEN) ){
+              MD_TRC_EXT_BGSND_HISR_EXT_SRC_STATE_FLUSHING_OVER(i, type); 
+               pSrc->state[type] = EXT_SRC_STATE_FLUSHING_OVER;
+               if(EXT_SRC_STATE_FLUSHING_OVER == pSrc->state[1-type]){ // 1-type is just for the opposite.  DL <-> UL
+                 MD_TRC_EXT_BGSND_HISR_ENTER_SRC_OFFHDR(i); 
+                  Ext_BGSnd.skip_hisr = 1;
+                  pSrc->offHdr();   //FLUSHING_OVER --> STOPPING
+                 MD_TRC_EXT_BGSND_HISR_LEAVE_SRC_OFFHDR(i); 
+                 MD_TRC_EXT_BGSND_HISR_FLUSH_SRC_OFFHDR_COMPLETELY(i);            
+               }else{//wait DL's flushing
+                 MD_TRC_EXT_BGSND_HISR_WAIT_SRC_HDR_TO_FLUSH_COMPLETELY(i);
+               }
+            }else{
+              MD_TRC_EXT_BGSND_HISR_FLUSHING(i, type, EXT_BGSND_GetDataCount(i, type));  
+            }
+         }else{
+           MD_TRC_EXT_BGSND_HISR_NOT_FLUSHING(i, type, pSrc->state[type]);  
+         }
+         
+
+                   
+      }else{
+        MD_TRC_EXT_BGSND_HISR_HDR_IS_NOT_USED(i);    
+      }
+      pSrc->len_WriteSrcBuffer_this_time = 0;
+   }  
+  MD_TRC_EXT_BGSND_HISR_LEAVE();
+}
+
+/*
+void EXT_BGSND_Buf_Add(uint32 id, uint16* src_buf, int src_len, BGSND_PROCESS_TYPE type) // write into ext buffer
+{
+   int i;
+   uint16 *dst_buf; 
+   EXT_BGSND_SRC_T *pSrc;
+   
+  MD_TRC_BGSND_DSP_BGSND_BUF_ADD(id, src_len, type);
+   
+   ASSERT(Ext_BGSnd.is_used[id]);
+   pSrc = &Ext_BGSnd.src[id]; 
+   
+   ASSERT( BGSND_BUFFER_LEN == src_len);//must be wb
+   ASSERT( type == BGSND_DL_PROCESS || type == BGSND_UL_PROCESS );   
+
+   { // DL    
+      dst_buf = Ext_BGSnd.buffer[type];
+        
+      for(i=0; i<src_len; i++){//accumulate DSP_DLBuffer
+         if( src_buf[i] < (0x1111111111111111 - dst_buf[i])){ //limiter
+            dst_buf[i] += src_buf[i];
+         }else{
+           MD_TRC_BKGSND_DSP_BUF_ADD_BUF(i, src_buf[i], i, dst_buf[i]);  
+         }
+      }      
+   }
+}*/
+
+/*
+uint32 EXT_BGSND_SetEvent(uint32 id, void *data )
+{
+   ASSERT(Ext_BGSnd.is_used[id] && Ext_BGSnd.src[id].EventHandler);
+   is_send_event[id] = true;
+   Ext_BGSnd.src[i].event_data = data;
+   L1Audio_SetEvent(Ext_BGSnd.src.aud_id, NULL);
+}
+
+void EXT_BGSND_EventHandler(void)
+{
+   for(i=0; i<MAX_SIZE_EXT_BGSND_SRC; i++){//dispatch the event
+      if(Ext_BGSnd.is_send_event[i] && Ext_BGSnd.src[i].EventHandler){  
+         Ext_BGSnd.src[i].EventHandler(Ext_BGSnd.src[i].event_data);
+         Ext_BGSnd.is_send_event[i] = false;
+      }
+   }   
+}
+*/
+
+void EXT_BGSND_WriteSrcBuffer(uint32 id, kal_uint8 *srcBuf, kal_int32 bufLen, BGSND_PROCESS_TYPE type)
+{
+   int32 freeLen; 
+   int32 srcBufLen = bufLen >> 1; // unit: 8bits -> 16bits
+   int32 currentRead; 
+   EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id];
+   
+   MD_TRC_EXT_BGSND_WRITESRCBUFFER_ENTER();
+   kal_take_spinlock(Ext_BGSnd.bgs_spinlockID, KAL_INFINITE_WAIT); 	
+   currentRead = pSrc->bufRead[type];          
+   
+   pSrc->len_WriteSrcBuffer_this_time = bufLen;
+   
+	if(currentRead > pSrc->bufWrite[type]) {	// one segment
+		
+		freeLen = pSrc->bufSize[type] - pSrc->bufDataCount[type] - EXT_BGSND_BUF_PTR_DIFF;
+
+		MD_TRC_L1SND_WRITE_DATA(1, id, type,  srcBufLen, freeLen, pSrc->bufRead[type], pSrc->bufWrite[type]+srcBufLen); /* using write information which is after memory copy*/
+		
+		ASSERT(srcBufLen <= freeLen); // unit is 2 byte
+		memcpy(pSrc->buffer[type]+pSrc->bufWrite[type], srcBuf, srcBufLen*sizeof(uint16));		
+	
+		pSrc->bufWrite[type] += srcBufLen;
+        pSrc->bufDataCount[type] += srcBufLen;
+	}else { // two segment		
+		int32 segment; 
+		kal_uint8 *p2SrcBuf;
+
+		freeLen = pSrc->bufSize[type] - pSrc->bufDataCount[type] - EXT_BGSND_BUF_PTR_DIFF;
+
+		MD_TRC_L1SND_WRITE_DATA(2, id, type,  srcBufLen, freeLen, 0, 0); 
+		ASSERT(srcBufLen <= freeLen);
+
+		p2SrcBuf = srcBuf;
+		segment = pSrc->bufSize[type] - pSrc->bufWrite[type]; // bug
+		if(segment > srcBufLen){
+			segment = srcBufLen;
+		}
+
+		if(segment>0) { //first segment		
+			memcpy(pSrc->buffer[type]+pSrc->bufWrite[type], p2SrcBuf, segment*sizeof(kal_uint16));					
+			//update pointer
+			p2SrcBuf = srcBuf + segment*sizeof(kal_uint16); 
+			pSrc->bufWrite[type] += segment;
+            pSrc->bufDataCount[type] += segment;
+			if(pSrc->bufWrite[type]>=pSrc->bufSize[type]){				
+				pSrc->bufWrite[type] = 0; 
+			}
+			MD_TRC_L1SND_WRITE_DATA(3, id, type, 0, 0, pSrc->bufRead[type], pSrc->bufWrite[type]);
+	
+			segment = srcBufLen - segment; 
+		}
+
+		if(segment>0) { //second segement
+			memcpy(pSrc->buffer[type], p2SrcBuf, segment*sizeof(kal_uint16));	
+			pSrc->bufWrite[type] = segment;
+            pSrc->bufDataCount[type] += segment;
+
+			MD_TRC_L1SND_WRITE_DATA(4, id, type, 0, 0, pSrc->bufRead[type], pSrc->bufWrite[type]);	
+		}
+	}         
+	kal_give_spinlock(Ext_BGSnd.bgs_spinlockID); 
+	MD_TRC_EXT_BGSND_WRITESRCBUFFER_LEAVE();
+}
+
+//from DL Src buffer -> DL ext buffer, multiplied by gain
+//from UL Src buffer -> UL ext buffer
+void EXT_BGSND_WriteExtBuffer(uint32 id, int gain, BGSND_PROCESS_TYPE type) // ToDo
+{
+	volatile uint16 *toPtr;
+   int32 count, segment, i;
+   uint16 *dataPtr;
+   uint16 gainFactor;
+  MD_TRC_EXT_BGSND_WRITEEXTBUFFER_ENTER();   
+  MD_TRC_EXT_BGSND_WRITEEXTBUFFER_SELECTED_SRC(id, type);   
+	ASSERT( type == BGSND_DL_PROCESS || type == BGSND_UL_PROCESS );
+  kal_take_spinlock(Ext_BGSnd.bgs_spinlockID, KAL_INFINITE_WAIT); 	
+   EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id];
+  MD_TRC_EXT_BGSND_WRITEEXTBUFFER_FSPH(pSrc->fSph[type], pSrc->gain[type]);      
+
+   gainFactor = pSrc->gain[type];
+   
+   count = EXT_BGSND_GetDataCount(id, type);   
+   toPtr = Ext_BGSnd.buffer[type];   
+   
+  MD_TRC_EXT_BGSND_WRITEEXTBUFFER_COUNT(count);  
+   
+   if (count > BGSND_BUFFER_LEN)
+      count = BGSND_BUFFER_LEN;         
+   
+   
+   if(count > 0) {
+	   /* First Segemnt */
+		if(pSrc->bufWrite[type] < pSrc->bufRead[type]) {
+		   segment = (pSrc->bufSize[type] - pSrc->bufRead[type]);
+		} else {
+			segment = (pSrc->bufWrite[type] - pSrc->bufRead[type]);
+		}
+
+		if(segment&1){ // keep two sample alight
+			segment =segment - 1;
+		}      
+
+		if (segment > count)
+			segment = count;
+			   
+	   if (segment > 0) {
+	      dataPtr = &(pSrc->buffer[type][pSrc->bufRead[type]]);
+	      
+	      if(pSrc->fSph[type] && MAX_LEVEL_EXT_BGSND_GAIN!=gainFactor){
+   	      for (i=0; i<segment; i++) {			
+               
+            kal_int16 x = (*dataPtr>>gainFactor);
+            kal_int16 y = (kal_int16)(*toPtr);
+            kal_int16 result = x + y;
+            
+            if (((x ^ y) >= 0) && (x ^ result) < 0) {
+                if (x < 0)
+                    result = 0x8000;
+                else
+                    result = 0x7FFF;
+                kal_prompt_trace(MOD_L1SP, "[EXT_BGSND_WriteExtBuffer] Saturation1 %d %d", x, y);
+
+            }
+               *toPtr = result;
+               toPtr++;
+               dataPtr++;     				
+   	      }
+   	      pSrc->dspLastSample[type] = *(toPtr-1);
+   	   }else{
+	         toPtr   += segment;
+	         dataPtr += segment;
+	         
+	         pSrc->dspLastSample[type] = 0;
+	      }   
+
+	      pSrc->bufRead[type] += segment;
+	      pSrc->bufDataCount[type] -= segment;
+	      if (pSrc->bufRead[type] >= pSrc->bufSize[type])
+	         pSrc->bufRead[type] = (pSrc->bufRead[type]-pSrc->bufSize[type]);
+
+			MD_TRC_EXT_BGSND_WRITEEXTBUFFER_FILLED_TO_DSP(1, segment, pSrc->bufRead[type], pSrc->bufWrite[type]);
+	   }
+
+		segment = count - segment;
+
+	   if (segment > 0) {
+	      dataPtr = &(pSrc->buffer[type][pSrc->bufRead[type]]);
+	      if(pSrc->fSph[type] && MAX_LEVEL_EXT_BGSND_GAIN!=gainFactor){
+   	      for (i=0; i<segment; i++) {  				
+
+            kal_int16 x = (*dataPtr>>gainFactor);
+            kal_int16 y = (kal_int16)(*toPtr);
+            kal_int16 result = x + y;
+            
+            if (((x ^ y) >= 0) && ((x ^ result) < 0)) {
+                if (x < 0)
+                    result = 0x8000;
+                else
+                    result = 0x7FFF;
+                 kal_prompt_trace(MOD_L1SP, "[EXT_BGSND_WriteExtBuffer] Saturation2 %d, %d",x ,y);
+
+            }
+               *toPtr = result;
+               toPtr++;
+               dataPtr++;     				
+   	      }  
+   	      pSrc->dspLastSample[type] = *(dataPtr-1);  	      
+	      }else{
+	         toPtr   += segment;
+	         dataPtr += segment;
+	         
+	         pSrc->dspLastSample[type] = 0;
+	      }
+	      
+	      pSrc->bufRead[type] += segment;
+          pSrc->bufDataCount[type] -= segment;
+	      if (pSrc->bufRead[type] >= pSrc->bufSize[type])
+	         pSrc->bufRead[type] = (pSrc->bufRead[type]-pSrc->bufSize[type]);
+
+			MD_TRC_EXT_BGSND_WRITEEXTBUFFER_FILLED_TO_DSP(2, segment, pSrc->bufRead[type], pSrc->bufWrite[type]);	
+	   }		
+	}  
+	
+   /* Put silence (last sample) if MCU buffer is empty */
+   if (count > 0 && count < BGSND_BUFFER_LEN && EXT_SRC_STATE_RUN == pSrc->state[type]) {      		
+      kal_uint16 last_sample = pSrc->dspLastSample[type];      
+      // segment = dsp_buf_len - count;
+      segment = BGSND_BUFFER_LEN - count;
+      //for (i=0; i<segment; i++)) {
+      //   *toPtr++ = last_sample;     				
+      //}	
+     MD_TRC_EXT_BGSND_WRITEEXTBUFFER_FILLED_TO_DSP_WITH_LAST_SAMPLE(segment, last_sample);
+      if(pSrc->fSph[type] && MAX_LEVEL_EXT_BGSND_GAIN!=gainFactor){
+         for (i=0; i<segment; i++) {
+            //*toPtr++ = *dataPtr++;     				
+            kal_int16 x = (last_sample>>gainFactor);
+            kal_int16 y = (kal_int16)(*toPtr);
+            kal_int16 result = x + y;
+            
+            if (((x ^ y) >= 0) && ((x ^ result) < 0)) {
+                if (x < 0)
+                    result = 0x8000;
+                else
+                    result = 0x7FFF;
+                 kal_prompt_trace(MOD_L1SP, "[EXT_BGSND_WriteExtBuffer] Saturation3 %d %d",x,y);
+  
+            }
+
+            *toPtr = result;	               
+            toPtr++;			
+         }   
+      }else{
+         toPtr += segment;
+      } 	
+   }//else{ //it means no data should be played, so we don't append to the size of a frame any more
+   //  kal_trace( TRACE_FUNC, EXT_BGSND_WRITEEXTBUFFER_SKIP_TO_DSP, count, pSrc->state[type]);      
+   //}        	 
+   
+/*   {
+      //just for debugging
+      int i;
+      for(i=0; i<10; i++){
+        MD_TRC_EXT_BGSND_WRITEEXTBUFFER(
+                                     Ext_BGSnd.buffer[type][0],Ext_BGSnd.buffer[type][1],
+                                     Ext_BGSnd.buffer[type][2],Ext_BGSnd.buffer[type][3],
+                                     Ext_BGSnd.buffer[type][4],Ext_BGSnd.buffer[type][5],
+                                     Ext_BGSnd.buffer[type][6],Ext_BGSnd.buffer[type][7],
+                                     Ext_BGSnd.buffer[type][8],Ext_BGSnd.buffer[type][9]
+);
+      
+      }        
+   }*/
+  kal_give_spinlock(Ext_BGSnd.bgs_spinlockID);    
+  MD_TRC_EXT_BGSND_WRITEEXTBUFFER_LEAVE();    
+}
+
+int32 EXT_BGSND_GetFreeSpace(uint32 id, BGSND_PROCESS_TYPE type)
+{
+
+	ASSERT( type == BGSND_DL_PROCESS || type == BGSND_UL_PROCESS );
+	EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id];	
+	
+  MD_TRC_EXT_BGSND_GETFREESPACE_ENTER(); 
+  MD_TRC_EXT_BGSND_GETFREESPACE_INFO(pSrc->bufSize[type], pSrc->bufRead[type], pSrc->bufWrite[type]); 
+   
+
+   
+  MD_TRC_EXT_BGSND_GETFREESPACE_LEAVE();    
+	return  (pSrc->bufSize[type] - EXT_BGSND_BUF_PTR_DIFF - pSrc->bufDataCount[type]);	
+}
+
+
+void EXT_BGSND_ConfigMixer(int id, kal_bool bSPHFlag, kal_int8 SNDGain, BGSND_PROCESS_TYPE type)
+{
+   EXT_BGSND_SRC_T *pSrc = &Ext_BGSnd.src[id];   
+  MD_TRC_EXT_BGSND_CONFIGMIXER_ENTER(); 
+   ASSERT(SNDGain>=0 && SNDGain<=MAX_LEVEL_EXT_BGSND_GAIN);
+  MD_TRC_EXT_BGSND_CONFIGMIXER_BSPHFLAG(bSPHFlag, SNDGain); 
+   pSrc->fSph[type] = bSPHFlag;
+   pSrc->gain[type] = MAX_LEVEL_EXT_BGSND_GAIN-SNDGain;
+  MD_TRC_EXT_BGSND_CONFIGMIXER_LEAVE();  
+   /*
+   SNDGain = 7 --> Volume >> 0
+   SNDGain = 6 --> Volume >> 1
+   SNDGain = 5 --> Volume >> 2
+   
+   SNDGain = 0 --> Volume * 0 = 0
+   */   
+}
+
+
+EXT_SRC_STATE_TYPE EXT_BGSND_GetStatus(int id,  BGSND_PROCESS_TYPE enULDL)
+{
+   ASSERT( id < MAX_SIZE_EXT_BGSND_SRC );
+   ASSERT( enULDL < MAX_NUM_BGSND_PROCESS );
+   return(Ext_BGSnd.src[id].state[enULDL]);
+}
+
+
+//================= Extended SPC BGSND INTERFACE ====================
+
+
+
+
+