//===========================================================================================
// Function Name: CopyBufferToQueue
//
//	Description: Copy the passed in buffer to the voice render driver queue. 
// Return the size of bytes has been copied.
//====================================================================================
static UInt32	CopyBufferToQueue (VORENDER_Drv_t *audDrv, UInt8 *buf, UInt32 size)
{
	UInt32 copied = 0;
	AUDQUE_Queue_t	*aq = audDrv->audQueue;
	
	// write to queue
	copied = AUDQUE_Write (aq, buf, size);
	
	if (copied == size)
	{
		// only callback if all data is copied
		audDrv->bufDoneCb (buf, size, audDrv->drvType);
	}
	
	
	// if we haven't copied all data, and will copy the left when 
	// we get the next callback. Save the break point.
	audDrv->srcBuf = buf;
	audDrv->srcBufSize = size;
	audDrv->srcBufCopied = copied;

	Log_DebugPrintf(LOGID_AUDIO, "CopyBufferToQueue :: srcBufCopied = 0x%x, readPtr = 0x%x, writePtr = 0x%x\n", audDrv->srcBufCopied, aq->readPtr, aq->writePtr);

	// deliver the data to dsp when data is available.
	if (audDrv->drvType == VORENDER_TYPE_AMRWB)
	{
		Log_DebugPrintf(LOGID_AUDIO, "CopyBufferToQueue :: qload=0x%x,writeIndex=0x%x,readIndex=0x%x\n",AUDQUE_GetLoad(aq),arm_writeIndex, dsp_readIndex);
		ProcessSharedMemRequest (audDrv, arm_writeIndex, dsp_readIndex);
	}

	return copied;
}
//==============================================================================================
// Function Name: AMRWB_Render_TaskEntry
//
//	Description: The main task entry of voice render when using DSP AMRWB decoder
//==============================================================
static void AMRWB_Render_TaskEntry ()
{
	VORENDER_MSG_t	msg;

	OSStatus_t		status;

	VORENDER_Drv_t	*audDrv = &sAMRWB_Drv;
	

	Log_DebugPrintf(LOGID_AUDIO, "AMRWBRender_TaskEntry: AMRWBRender_TaskEntry is running \r\n");

	while(TRUE)
	{
		status = OSQUEUE_Pend( audDrv->msgQueue, (QMsg_t *)&msg, TICKS_FOREVER );
		if (status == OSSTATUS_SUCCESS)
		{
			Log_DebugPrintf(LOGID_AUDIO, " AMRWBRender_TaskEntry::msgID = 0x%x.\n", msg.msgID);

			switch (msg.msgID)
			{
				case VORENDER_MSG_SET_TRANSFER:
					 audDrv->callbackThreshold = (UInt32)msg.parm1;
					 audDrv->interruptInterval = (UInt32)msg.parm2;
					 break;
				
				case VORENDER_MSG_CONFIG:
					ConfigAudDrv (audDrv, (VORENDER_Configure_t *)msg.parm1);
					break;

				case VORENDER_MSG_REGISTER_BUFDONE_CB:
					audDrv->bufDoneCb = (AUDDRV_VoiceRender_BufDoneCB_t)msg.parm1;
					break;

				case VORENDER_MSG_START:
					Log_DebugPrintf(LOGID_AUDIO, " AMRWBRender_TaskEntry::Start render\n");
					// Need to reset them, otherwise will use the values from the last play.
					arm_writeIndex = 0;
					dsp_readIndex = 0;
					dspif_AMRWB_play_start ( audDrv->config.playbackMode,
												audDrv->config.mixMode,
												audDrv->config.samplingRate,
												audDrv->config.speechMode, // used by AMRNB and AMRWB
												audDrv->config.dataRateSelection, // used by AMRNB and AMRWB
												audDrv->numFramesPerInterrupt);
					// need to reset sema after start dsp. dsp can send duplicate msgs to us.
					OSSEMAPHORE_ResetCnt(audDrv->stopDspAmrWbSema);
					break;

				case VORENDER_MSG_FINISH:
					audDrv->isFinishing = TRUE;
					break;

				case VORENDER_MSG_STOP:
					Log_DebugPrintf(LOGID_AUDIO, " AMRWBRender_TaskEntry::Stop render.\n");
					dspif_AMRWB_play_init_stop();
					//make sure dsp is stopped
					OSSEMAPHORE_Obtain (audDrv->stopDspAmrWbSema, TICKS_FOREVER);
					dspif_AMRWB_play_stop();
					CheckBufDoneUponStop(audDrv);
					Log_DebugPrintf(LOGID_AUDIO, " AMRWBRender_TaskEntry::Stop render - done.\n");
					OSSEMAPHORE_Release (audDrv->stopSema);
					break;

				case VORENDER_MSG_PAUSE:
					break;

				case VORENDER_MSG_RESUME:
					break;

				case VORENDER_MSG_ADD_BUFFER:
					CopyBufferToQueue (audDrv, (UInt8 *)msg.parm1, msg.parm2);
					OSSEMAPHORE_Release (audDrv->addBufSema);
					break;

				case VORENDER_MSG_FLUSH_BUFFER:
					Log_DebugPrintf(LOGID_AUDIO, "AMRWBRender_TaskEntry:: Flushed queue.\n");
					// flush the data in the Q
					AUDQUE_Flush(audDrv->audQueue);
					// Need to reset them, otherwise will use the values from the last play.
					arm_writeIndex = 0;
					dsp_readIndex = 0;
					// this will make dsp to flush data inside dsp
					dspif_AMRWB_play_start ( audDrv->config.playbackMode,
												audDrv->config.mixMode,
												audDrv->config.samplingRate,
												audDrv->config.speechMode, // used by AMRNB and AMRWB
												audDrv->config.dataRateSelection, // used by AMRNB and AMRWB
												audDrv->numFramesPerInterrupt);
					// need to reset sema after start dsp. dsp can send duplicate msgs to us.
					OSSEMAPHORE_ResetCnt(audDrv->stopDspAmrWbSema);
					break;

				case VORENDER_MSG_SHM_REQUEST:
					ProcessSharedMemRequest (audDrv, (UInt16)msg.parm1, (UInt16)msg.parm2);
					break;

				default:
					Log_DebugPrintf(LOGID_AUDIO, "AMRWBRender_TaskEntry: Unsupported msg, msgID = 0x%x \r\n", msg.msgID);
					break;
			}
		}
	}
}
//==============================================================================================
// Function Name: ARM2SP_Render_TaskEntry
//
//	Description: The main task entry of voice render when using DSP ARM2SP
//==============================================================
static void ARM2SP_Render_TaskEntry (void* arg)
{
	VORENDER_MSG_t	msg;

	OSStatus_t		status;

	VORENDER_Drv_t	*audDrv = (VORENDER_Drv_t*)arg;
	
	/* ARM2SP commands
	Start:    cmd(arg0, arg1=0)
	Pause:    cmd(arg0=0, arg1=1)    //ptr not reset
	Resume w/o fast forward:    cmd(arg0, arg1=1)    //prt continue
	Resumd w/ fast forward:    cmd(arg0, arg1=0) + arm flush left-over data    //same as new play
	*/


	Log_DebugPrintf(LOGID_AUDIO, "ARM2SP_Render_TaskEntry: ARM2SP_Render_TaskEntry is running \r\n");

	while(TRUE)
	{
		status = OSQUEUE_Pend( audDrv->msgQueue, (QMsg_t *)&msg, TICKS_FOREVER );
		if (status == OSSTATUS_SUCCESS)
		{
			Log_DebugPrintf(LOGID_AUDIO, " ARM2SP_Render_TaskEntry::msgID = 0x%x. parm1 = 0x%x, parm2 = 0x%x\n", 
											msg.msgID, msg.parm1, msg.parm2);
			switch (msg.msgID)
			{
				case VORENDER_MSG_SET_TRANSFER:
					 audDrv->callbackThreshold = (UInt32)msg.parm1;
					 audDrv->interruptInterval = (UInt32)msg.parm2;
					 break;

				case VORENDER_MSG_CONFIG:
					ConfigAudDrv (audDrv, (VORENDER_Configure_t *)msg.parm1);
					break;

				case VORENDER_MSG_REGISTER_BUFDONE_CB:
					audDrv->bufDoneCb = (AUDDRV_VoiceRender_BufDoneCB_t)msg.parm1;
					break;

				case VORENDER_MSG_START:
					dspif_ARM2SP_play_start ( AUDDRV_ARM2SP_GetInstanceID(audDrv->drvType),
												audDrv->config.playbackMode,
												audDrv->config.mixMode,
												audDrv->config.samplingRate,
												audDrv->numFramesPerInterrupt);
					break;

				case VORENDER_MSG_FINISH:
					audDrv->isFinishing = TRUE;
					break;

				case VORENDER_MSG_STOP:
					Log_DebugPrintf(LOGID_AUDIO, " ARM2SP_Render_TaskEntry::Stop render.\n");
					dspif_ARM2SP_play_stop(AUDDRV_ARM2SP_GetInstanceID(audDrv->drvType));
					CheckBufDoneUponStop(audDrv);
					OSSEMAPHORE_Release (audDrv->stopSema);
					break;

				case VORENDER_MSG_PAUSE:
					Log_DebugPrintf(LOGID_AUDIO, " ARM2SP_Render_TaskEntry::Pause render.\n");
					dspif_ARM2SP_play_pause(AUDDRV_ARM2SP_GetInstanceID(audDrv->drvType));
					break;

				case VORENDER_MSG_RESUME:
					dspif_ARM2SP_play_resume( AUDDRV_ARM2SP_GetInstanceID(audDrv->drvType),
												audDrv->config.playbackMode,
												audDrv->config.mixMode,
												audDrv->config.samplingRate,
												audDrv->numFramesPerInterrupt);
					break;

				case VORENDER_MSG_ADD_BUFFER:
					CopyBufferToQueue (audDrv, (UInt8 *)msg.parm1, msg.parm2);
					OSSEMAPHORE_Release (audDrv->addBufSema);
					break;

				case VORENDER_MSG_FLUSH_BUFFER:
					AUDQUE_Flush(audDrv->audQueue);
					dspif_ARM2SP_play_flush(AUDDRV_ARM2SP_GetInstanceID(audDrv->drvType));
					Log_DebugPrintf(LOGID_AUDIO, "ARM2SP_Render_TaskEntry:: Flushed queue.\n");
					break;
				
				case VORENDER_MSG_SHM_REQUEST:
					Log_DebugPrintf(LOGID_AUDIO, "AUDDRV ARM2SP VORENDER_MSG_SHM_REQUEST\n");
					
					ProcessSharedMemRequest (audDrv, (UInt16)msg.parm1, (UInt16)msg.parm2);
					break;

				default:
					Log_DebugPrintf(LOGID_AUDIO, "ARM2SP_Render_TaskEntry: Unsupported msg, msgID = 0x%x \r\n", msg.msgID);
					break;
			}
		}
	}
}
//==============================================================================================
// Function Name: VPU_Render_TaskEntry
//
//	Description: The main task entry of voice render when using DSP VPU
//==============================================================
static void VPU_Render_TaskEntry (void)
{
	VORENDER_MSG_t	msg;

	OSStatus_t		status;

	VORENDER_Drv_t	*audDrv = &sVPU_Drv;
	

	Log_DebugPrintf(LOGID_AUDIO, "VPU_Render_TaskEntry: VPU_Render_TaskEntry is running \r\n");

	while(TRUE)
	{
		status = OSQUEUE_Pend( audDrv->msgQueue, (QMsg_t *)&msg, TICKS_FOREVER );
		if (status == OSSTATUS_SUCCESS)
		{
			Log_DebugPrintf(LOGID_AUDIO, " VPU_Render_TaskEntry::msgID = 0x%x. parm1 = 0x%x, parm2 = 0x%x\n", 
											msg.msgID, msg.parm1, msg.parm2);

			switch (msg.msgID)
			{
				case VORENDER_MSG_SET_TRANSFER:
					 audDrv->callbackThreshold = (UInt32)msg.parm1;
					 audDrv->interruptInterval = (UInt32)msg.parm2;
					 break;
					 
				case VORENDER_MSG_CONFIG:
					ConfigAudDrv (audDrv, (VORENDER_Configure_t *)msg.parm1);
					break;

				case VORENDER_MSG_REGISTER_BUFDONE_CB:
					audDrv->bufDoneCb = (AUDDRV_VoiceRender_BufDoneCB_t)msg.parm1;
					break;

				case VORENDER_MSG_START:
					{
						dspif_VPU_play_start ( audDrv->config.playbackMode,
												audDrv->config.mixMode,
												audDrv->config.samplingRate,
												audDrv->config.speechMode, // used by AMRNB and AMRWB
												audDrv->config.dataRateSelection, // used by AMRNB and AMRWB
												audDrv->numFramesPerInterrupt);

						Log_DebugPrintf(LOGID_AUDIO, " VPU_Render_TaskEntry::Start render, playbackMode = 0x%x,  speechMode = 0x%x, dataRate = 0x%x, mixMode = 0x%x\n", 
							audDrv->config.playbackMode, audDrv->config.speechMode, audDrv->config.dataRateSelection, audDrv->config.mixMode);
					}
				
					break;

				case VORENDER_MSG_FINISH:
					audDrv->isFinishing = TRUE;
					break;

				case VORENDER_MSG_STOP:
					// stop or cancel, to be consisdered.
					dspif_VPU_play_stop();
					CheckBufDoneUponStop(audDrv);
					Log_DebugPrintf(LOGID_AUDIO, " VPU_Render_TaskEntry::Stop render.\n");
					OSSEMAPHORE_Release (audDrv->stopSema);
					break;

				case VORENDER_MSG_PAUSE:
					break;

				case VORENDER_MSG_RESUME:
					break;

				case VORENDER_MSG_ADD_BUFFER:
					CopyBufferToQueue (audDrv, (UInt8 *)msg.parm1, msg.parm2);
					OSSEMAPHORE_Release (audDrv->addBufSema);
					break;

				case VORENDER_MSG_FLUSH_BUFFER:
					AUDQUE_Flush(audDrv->audQueue);
					Log_DebugPrintf(LOGID_AUDIO, "VPU_Render_TaskEntry:: Flushed queue.\n");
					break;

				case VORENDER_MSG_SHM_REQUEST:
					ProcessSharedMemRequest (audDrv, (UInt16)msg.parm1, (UInt16)msg.parm2);
					break;

				default:
					Log_DebugPrintf(LOGID_AUDIO, "VPU_Render_TaskEntry: Unsupported msg, msgID = 0x%x \r\n", msg.msgID);
					break;
			}
		}
	}
}
// ===================================================================
//
// Function Name: AMRWBCapture_TaskEntry
//
// Description: The main task entry of the voice capture driver when using DSP ARMWB.
//
// ====================================================================
static void AMRWBCapture_TaskEntry (void)
{
	VOCAPTURE_MSG_t	msg;

	OSStatus_t		status;

	VOCAPTURE_Drv_t	*audDrv = &sAMRWB_Drv;
	

	Log_DebugPrintf(LOGID_AUDIO, "AMRWBCapture_TaskEntry: AMRWBCapture_TaskEntry is running \r\n");

	while(TRUE)
	{
		status = OSQUEUE_Pend( audDrv->msgQueue, (QMsg_t *)&msg, TICKS_FOREVER );
		if (status == OSSTATUS_SUCCESS)
		{
			Log_DebugPrintf(LOGID_AUDIO, " : AMRWBCapture_TaskEntry::msgID = 0x%x.\n", msg.msgID);

			switch (msg.msgID)
			{
				case VOCAPTURE_MSG_SET_TRANSFER:
					 audDrv->callbackThreshold = (UInt32)msg.parm1;
					 audDrv->interruptInterval = (UInt32)msg.parm2;
					 break;

				case VOCAPTURE_MSG_CONFIG:
					ConfigAudDrv (audDrv, (VOCAPTURE_Configure_t *)msg.parm1);
					break;

				case VOCAPTURE_MSG_REGISTER_BUFDONE_CB:
					audDrv->bufDoneCb = (AUDDRV_VoiceCapture_BufDoneCB_t)msg.parm1;
					break;

				case VOCAPTURE_MSG_START:	
					Log_DebugPrintf(LOGID_AUDIO, " : AMRWBCapture_TaskEntry::Start capture.\n");
					dspif_AMRWB_record_start ( audDrv->config.recordMode,
								audDrv->config.samplingRate,
								audDrv->config.speechMode, // used by AMRNB and AMRWB
								audDrv->config.dataRate, // used by AMRNB and AMRWB
								audDrv->config.procEnable,
								audDrv->config.dtxEnable,
								audDrv->numFramesPerInterrupt);
					break;

				case VOCAPTURE_MSG_STOP:
					//which cmd to stop the recording, besides the disable audio cmd (done when disable path)?
					Log_DebugPrintf(LOGID_AUDIO, " : AMRWBCapture_TaskEntry::Stop capture.\n");
					dspif_AMRWB_record_stop();
					CheckBufDoneUponStop(audDrv);
					OSSEMAPHORE_Release (audDrv->stopSema);
					break;

				case VOCAPTURE_MSG_PAUSE:
					break;

				case VOCAPTURE_MSG_RESUME:
					break;

				case VOCAPTURE_MSG_ADD_BUFFER:
					CopyBufferFromQueue (audDrv, (UInt8 *)msg.parm1, msg.parm2);
					OSSEMAPHORE_Release (audDrv->addBufSema);
					break;

				case VOCAPTURE_MSG_SHM_REQUEST:
					ProcessSharedMemRequest (audDrv, (UInt16)msg.parm1, (msg.parm2)<<1);
					break;

				default:
					Log_DebugPrintf(LOGID_AUDIO, "AMRWBCapture_TaskEntry: Unsupported msg, msgID = 0x%x \r\n", msg.msgID);
					break;
			}
		}
	}
}