// ==========================================================================
//
// Function Name: csl_audvoc_render_start
//
// Description: Start the data transfer of audio path render
//
// =========================================================================
Result_t csl_audio_render_start ( UInt32 streamID )
{
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	AUDDRV_InOut_Enum_t input_path_to_mixer = AUDDRV_AUDIO_OUTPUT;
	
	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_start:: streamID = %d\n", streamID);

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	
	
	if(OSDAL_DMA_Start_Transfer(audDrv->dmaCH) != OSDAL_ERR_OK)
	{
		Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_start::Error, Start transfer failed.\n");
	}

	if (streamID == CSL_AUDVOC_STREAM_POLYRINGER)
		input_path_to_mixer = AUDDRV_RINGTONE_OUTPUT;
	
	AUDDRV_EnableHWOutput (
			input_path_to_mixer,
			AUDDRV_SPKR_NONE,  //this param bears no meaning in this context.
			FALSE,	//this param bears no meaning in this context.
			AUDIO_SAMPLING_RATE_UNDEFINED,  //this param bears no meaning in this context.
			AUDIO_CHANNEL_STEREO,
			AUDDRV_REASON_DATA_DRIVER
       );

	return RESULT_OK;
}
//===========================================================
//
// Function Name: AUDDRV_VoiceRender_Init
//
//	Description: Shut down voice render driver, free internal variables and task queue.
// 
//================================================================== 
Result_t AUDDRV_VoiceRender_Shutdown( VORENDER_TYPE_t type )
{
	VORENDER_Drv_t	*audDrv = NULL;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	if (audDrv->isRunning == FALSE)
		return RESULT_OK;

	
	// destroy the audio ringbuffer queue
	AUDQUE_Destroy (audDrv->audQueue);


	OSHEAP_Delete(audDrv->ringBuffer); 

	OSTASK_Destroy(audDrv->task);

	OSQUEUE_Destroy(audDrv->msgQueue);

	OSSEMAPHORE_Destroy (audDrv->stopSema);
	OSSEMAPHORE_Destroy (audDrv->addBufSema);
	OSSEMAPHORE_Destroy (audDrv->stopDspAmrWbSema);

	audDrv->isRunning = FALSE;

	Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceRender_Shutdown::Exit.\n");

	return RESULT_OK;
}
// ===================================================================
//
// Function Name: AUDDRV_VoiceCapture_Stop
//
// Description: Stop data transfer of voice capture driver.
//
// ====================================================================
Result_t AUDDRV_VoiceCapture_Stop( 
                      VOCAPTURE_TYPE_t      type,
                      Boolean                 immediately )
{
	VOCAPTURE_Drv_t	*audDrv = NULL;
	VOCAPTURE_MSG_t	msg;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	memset (&msg, 0, sizeof(VOCAPTURE_MSG_t));
	msg.msgID = VOCAPTURE_MSG_STOP;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);

	// make sure the task is stopped.
	OSSEMAPHORE_Obtain (audDrv->stopSema, TICKS_FOREVER);


	Log_DebugPrintf(LOGID_AUDIO, " : AUDDRV_VoiceCapture_Stop::Stop capture. type = 0x%x, audDrv->type = 0x%x\n", type, audDrv->drvType);

	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: csl_audvoc_capture_stop
//
// Description: Stop the data transfer of the audio path capture
//
// =========================================================================
Result_t csl_audio_capture_stop( UInt32 streamID )
{
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	
	Log_DebugPrintf(LOGID_AUDIO, " csl_audvoc_capture_stop:: DMA streamID = %d\n", streamID);

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	

    if(OSDAL_DMA_Stop_Transfer(audDrv->dmaCH) != OSDAL_ERR_OK)
	{
		Log_DebugPrintf(LOGID_AUDIO, "csl_audvoc_capture_stop::Error, Stop transfer failed.\n");
	}
	
	if (streamID == CSL_AUDVOC_STREAM_AUDIO)
	{
		AUDDRV_DisableHWInput ( AUDDRV_AUDIO_INPUT, AUDDRV_REASON_DATA_DRIVER );
	}
	else if (streamID == CSL_AUDVOC_STREAM_BTW)
	{
		AUDDRV_Disable_MixerTap ( AUDDRV_MIXERTap_WB_INPUT, AUDDRV_REASON_DATA_DRIVER );
	}
	
	
	
	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: csl_audio_render_stop
//
// Description: Stop immediately the data transfer of audio path render
//
// =========================================================================
Result_t csl_audio_render_stop ( UInt32 streamID )
{
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	AUDDRV_InOut_Enum_t input_path_to_mixer = AUDDRV_AUDIO_OUTPUT;
	
	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_stop::Stop DMA transfer, streamID = 0x%x.\n", streamID);

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	

	if (streamID == CSL_AUDVOC_STREAM_POLYRINGER)
		input_path_to_mixer = AUDDRV_RINGTONE_OUTPUT;
	
	AUDDRV_DisableHWOutput ( input_path_to_mixer, AUDDRV_REASON_DATA_DRIVER );

    //if(OSDAL_DMA_Stop_Transfer(dmaChAudio) != OSDAL_ERR_OK) // No OSDAL_DMA API for force_shutdown_channel yet, waiting for Drivers team
	if(OSDAL_DMA_Force_Shutdown_Channel((DMA_CHANNEL)dmaChAudio) != OSDAL_ERR_OK)
	{
		Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_stop::Error, Stop transfer failed.\n");
	}
	

	return RESULT_OK;

}
//===========================================================
//
// Function Name: AUDDRV_VoiceRender_Resume
//
//	Description: Stop the data transfer in voice render driver. 
// 
//==================================================================
Result_t AUDDRV_VoiceRender_Stop( 
                      VORENDER_TYPE_t      type,
                      Boolean                 immediately )
{
	VORENDER_Drv_t	*audDrv = NULL;
	VORENDER_MSG_t	msg;

	Log_DebugPrintf(LOGID_AUDIO, " AUDDRV_VoiceRender_Stop::Stop capture. type = 0x%x, immediately = 0x%x\n", type, immediately);

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	memset (&msg, 0, sizeof(VORENDER_MSG_t));

	if (immediately == TRUE)
	{
		msg.msgID = VORENDER_MSG_STOP;
	}
	else
	{
		msg.msgID = VORENDER_MSG_FINISH;
	}

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);

	// make sure the task is stopped.
	if (immediately == TRUE)
	{
		OSSEMAPHORE_Obtain (audDrv->stopSema, TICKS_FOREVER);
	}

	return RESULT_OK;
}
//===========================================================
//
// Function Name: AUDDRV_VoiceRender_Write
//
//	Description: Send audio data to voice render driver. 
// 
//================================================================== 
UInt32 AUDDRV_VoiceRender_Write( 
                    VORENDER_TYPE_t     type,
                    UInt8*                 pBuf,
                    UInt32	               nSize )
{
	VORENDER_Drv_t	*audDrv = NULL;
	VORENDER_MSG_t	msg;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	memset (&msg, 0, sizeof(VORENDER_MSG_t));
	msg.msgID = VORENDER_MSG_ADD_BUFFER;
	msg.parm1 = (UInt32)pBuf;
	msg.parm2 = nSize;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);

	// wait for the data copy finished.
	OSSEMAPHORE_Obtain (audDrv->addBufSema, TICKS_FOREVER);

	Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceRender_Write :: srcBufCopied = 0x%x\n", audDrv->srcBufCopied);

	return audDrv->srcBufCopied;
}
// ===================================================================
//
// Function Name: AUDDRV_VoiceCapture_Init
//
// Description: Initialize voice capture driver internal variables and task queue. 
//
// ====================================================================
Result_t AUDDRV_VoiceCapture_Init( VOCAPTURE_TYPE_t type )
{
	VOCAPTURE_Drv_t	*audDrv = NULL;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	if (audDrv->isRunning)
		return RESULT_OK;

	memset (audDrv, 0, sizeof(VOCAPTURE_Drv_t));

	audDrv->drvType = type;
	audDrv->stopSema = OSSEMAPHORE_Create(0, OSSUSPEND_PRIORITY);
	audDrv->addBufSema = OSSEMAPHORE_Create(0, OSSUSPEND_PRIORITY);

	switch (audDrv->drvType)
	{
		case VOCAPTURE_TYPE_AMRNB:
		case VOCAPTURE_TYPE_PCM:
			audDrv->msgQueue = OSQUEUE_Create( QUEUESIZE_AUDDRV_VPUCAPTURE,
											sizeof(VOCAPTURE_MSG_t), OSSUSPEND_PRIORITY );
			OSQUEUE_ChangeName(audDrv->msgQueue, (const char *) "AUDDRV_VPUCAPTURE_Q" );

			audDrv->task = OSTASK_Create( (TEntry_t) VPUCapture_TaskEntry,
										TASKNAME_AUDDRV_VPUCAPTURE,
										TASKPRI_AUDDRV_VPUCAPTURE,
										STACKSIZE_AUDDRV_VPUCAPTURE
										);
			break;

		case VOCAPTURE_TYPE_AMRWB:
			audDrv->msgQueue = OSQUEUE_Create( QUEUESIZE_AUDDRV_AMRWBCAPTURE,
											sizeof(VOCAPTURE_MSG_t), OSSUSPEND_PRIORITY );
			OSQUEUE_ChangeName(audDrv->msgQueue, (const char *) "AUDDRV_AMRWBCAPTURE_Q" );

			audDrv->task = OSTASK_Create( (TEntry_t) AMRWBCapture_TaskEntry,
										TASKNAME_AUDDRV_AMRWBCAPTURE,
										TASKPRI_AUDDRV_AMRWBCAPTURE,
										STACKSIZE_AUDDRV_AMRWBCAPTURE
										);
			break;

		default:
			Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceCapture_Init:: Doesn't support audio driver type drvType = 0x%x\n", audDrv->drvType);
			return RESULT_ERROR;
//			break;
	}
	
	audDrv->isRunning = TRUE;

	Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceCapture_Init::Exit.\n");

	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: csl_audvoc_render_configure
//
// Description: Configure the audio path render
//
// =========================================================================
Result_t csl_audio_render_configure ( AUDIO_SAMPLING_RATE_t    sampleRate, 
						AUDIO_CHANNEL_NUM_t    numChannels,
						AUDIO_BITS_PER_SAMPLE_t bitsPerSample,
						UInt8 *ringBuffer,
						UInt32 numBlocks,
						UInt32 blockSize,
						CSL_AUDRENDER_CB csl_audio_render_cb,
						UInt32 streamID
						)
{
	OSDAL_DMA_DWIDTH dataWidth = OSDAL_DMA_DATA_SIZE_16BIT; // default is 16
	OSDAL_DMA_CLIENT	dstClient = OSDAL_DMA_CLIENT_AUDIO_OUT_FIFO;
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	OSDAL_DMA_CALLBACK dmaCB = NULL;
	
	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_configure:: streamID = 0x%x, sampleRate =0x%x, numChannels = 0x%x, numbBuffers = 0x%x, blockSize = 0x%x\n", 
					streamID, sampleRate, numChannels, numBlocks, blockSize);
	
	if (numChannels==AUDIO_CHANNEL_STEREO || numChannels==AUDIO_CHANNEL_STEREO_LEFT || numChannels==AUDIO_CHANNEL_STEREO_RIGHT)
	{
		dataWidth = OSDAL_DMA_DATA_SIZE_32BIT;
	}

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	

	audDrv->dmaCB = csl_audio_render_cb;
	if (streamID == CSL_AUDVOC_STREAM_AUDIO)
	{
		dmaCB = (OSDAL_DMA_CALLBACK)AUDIO_DMA_CB;
		//chal_audioaopath_SetSampleRate (NULL, sampleRate );
	}
	else if (streamID == CSL_AUDVOC_STREAM_POLYRINGER)
	{
		dmaCB = (OSDAL_DMA_CALLBACK)PLR_DMA_CB;
		//chal_audiopopath_SetSampleRate (NULL, sampleRate );
		dstClient = OSDAL_DMA_CLIENT_POLYRING_OUT_FIFO;
	}
	
	if ( ConfigDMA (audDrv->dmaCH, ringBuffer, numBlocks, blockSize, dstClient, dataWidth, dmaCB) != RESULT_OK)
	{
		// do clean up
	}

	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: AUDDRV_VoiceRender_GetQueueLoad
//
// Description: Get the size of the data in the driver queue.
//
// =========================================================================
UInt32 AUDDRV_VoiceRender_GetQueueLoad(VORENDER_TYPE_t      type)
{
	VORENDER_Drv_t	*audDrv = NULL;
	UInt32 load;
	
	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	load = AUDQUE_GetLoad(audDrv->audQueue);
	
	Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceRender_GetQueueLoad::type = 0x%x, audDrv->type = 0x%x, load = 0x%x\n", type, audDrv->drvType, load);

	return load;
}
// ===================================================================
//
// Function Name: AUDDRV_VoiceCapture_Pause
//
// Description: Pause data transfer of voice capture driver.
//
// ====================================================================
Result_t AUDDRV_VoiceCapture_Pause ( VOCAPTURE_TYPE_t      type )
{
	VOCAPTURE_Drv_t	*audDrv = NULL;
	VOCAPTURE_MSG_t	msg;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	memset (&msg, 0, sizeof(VOCAPTURE_MSG_t));
	msg.msgID = VOCAPTURE_MSG_PAUSE;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);
	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: PLR_DMA_CB
//
// Description: The callback function when there is DMA request to audio path 
//
// =========================================================================
static void PLR_DMA_CB(OSDAL_DMA_CALLBACK_STATUS status)
{
	CSL_AUDVOC_Drv_t	*audDrv = NULL;

	//Log_DebugPrintf(LOGID_SOC_AUDIO, "PLR_DMA_CB:: DMA callback.\n");

	if (status != OSDAL_ERR_OK)
	{
		Log_DebugPrintf(LOGID_SOC_AUDIO, "PLR_DMA_CB:: Fatal error! DMA transfer failure.\n");
		return;
	}
	
	audDrv = GetDriverByType(CSL_AUDVOC_STREAM_POLYRINGER);
	
	if (audDrv->dmaCB != NULL)
		audDrv->dmaCB(audDrv->streamID);
}
//===========================================================
//
// Function Name: AUDDRV_VoiceRender_Resume
//
//	Description: Resume the data transfer in voice render driver. 
// 
//==================================================================
Result_t AUDDRV_VoiceRender_Resume( VORENDER_TYPE_t      type )
{
	VORENDER_Drv_t	*audDrv = NULL;
	VORENDER_MSG_t	msg;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	memset (&msg, 0, sizeof(VORENDER_MSG_t));
	msg.msgID = VORENDER_MSG_RESUME;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);

	return RESULT_OK;
}
// ==========================================================================
//
// Function Name:  csl_audio_render_deinit
//
// Description: Shutdown the audio path render
//
// =========================================================================
Result_t  csl_audio_render_deinit (UInt32 streamID)
{
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	Log_DebugPrintf(LOGID_SOC_AUDIO, " csl_audvoc_render_deinit::release DMA channel, streamID=%d.\n", streamID);	

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	
	
	// release the DMA channel
	OSDAL_DMA_Release_Channel(audDrv->dmaCH);
	
	memset(audDrv, 0, sizeof(CSL_AUDVOC_Drv_t));
	
	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: csl_audvoc_capture_init
//
// Description: Init audio path capture. 
//
// =========================================================================
UInt32 csl_audio_capture_init( CSL_AUDIO_DEVICE_e source, CSL_AUDIO_DEVICE_e sink )
{
	OSDAL_DMA_CLIENT	srcClient = OSDAL_DMA_CLIENT_AUDIO_IN_FIFO;
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	UInt32 streamID = CSL_AUDVOC_STREAM_NONE;

	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_capture_init:: \n");
	if (source == CSL_AUDVOC_DEV_CAPTURE_BTW)
		srcClient = OSDAL_DMA_CLIENT_AUDIO_WB_MIXERTAP;
		
	// Get DMA channel
    if(OSDAL_DMA_Obtain_Channel(srcClient, OSDAL_DMA_CLIENT_MEMORY, &dmaChAudio) != OSDAL_ERR_OK)
    {
        Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_capture_init:: Error, Obtain channel failed.\n");
		return CSL_AUDVOC_STREAM_NONE;
    }

	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_capture_init:: DMA channel for audio path capture 0x%x\n", dmaChAudio);

	if (source == CSL_AUDVOC_DEV_CAPTURE_AUDIO)
	{
		streamID = CSL_AUDVOC_STREAM_AUDIO;
	}
	else if (source == CSL_AUDVOC_DEV_CAPTURE_BTW)
	{
		streamID = CSL_AUDVOC_STREAM_BTW;
	}
	else
	{
		return streamID;     
	}
	
	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return CSL_AUDVOC_STREAM_NONE;
	
	memset(audDrv, 0, sizeof(CSL_AUDVOC_Drv_t));
	audDrv->streamID = streamID;
	audDrv->source = source;
	audDrv->sink = sink;
	audDrv->dmaCH = dmaChAudio;
	
	return audDrv->streamID;
}
// ==========================================================================
//
// Function Name: csl_audvoc_capture_configure
//
// Description: Configure audio path capture. 
//
// =========================================================================
Result_t csl_audio_capture_configure( AUDIO_SAMPLING_RATE_t    sampleRate, 
						AUDIO_CHANNEL_NUM_t    numChannels,
						AUDIO_BITS_PER_SAMPLE_t bitsPerSample,						
						UInt8 *ringBuffer,
						UInt32 numBlocks,
						UInt32 blockSize,
						CSL_AUDCAPTURE_CB csl_audio_capture_cb,
						UInt32 streamID
						)
{
	OSDAL_DMA_DWIDTH dataWidth = OSDAL_DMA_DATA_SIZE_16BIT; // default is 16
	OSDAL_DMA_CLIENT	srcClient = OSDAL_DMA_CLIENT_AUDIO_IN_FIFO;
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	OSDAL_DMA_CALLBACK dmaCB = NULL;

	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_capture_configure:: DMA streamID = 0x%x, sampleRate =0x%x, numChannels = 0x%x, bits/sample = 0x%x numbBuffers = 0x%x, blockSize = 0x%x\n", 
					streamID, sampleRate, numChannels, bitsPerSample, numBlocks, blockSize);

	if (numChannels == AUDIO_CHANNEL_STEREO)
	{
		dataWidth = OSDAL_DMA_DATA_SIZE_32BIT;
	}

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	

	audDrv->dmaCB = csl_audio_capture_cb;
	if (streamID == CSL_AUDVOC_STREAM_AUDIO)
	{
		dmaCB = (OSDAL_DMA_CALLBACK)AUDIO_DMA_CB;
	}
	else if (streamID == CSL_AUDVOC_STREAM_BTW)
	{
		dmaCB = (OSDAL_DMA_CALLBACK)BTW_DMA_CB;
		srcClient = OSDAL_DMA_CLIENT_AUDIO_WB_MIXERTAP;
	}
	if ( ConfigDMA (audDrv->dmaCH, ringBuffer, numBlocks, blockSize, srcClient, dataWidth, dmaCB) != RESULT_OK)
	{
		// do clean up
	}

	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: AUDDRV_VoiceRender_FlushBuffer
//
// Description: Flush the voice render driver queue.
//
// =========================================================================
Result_t AUDDRV_VoiceRender_FlushBuffer(VORENDER_TYPE_t      type)
{
	VORENDER_Drv_t	*audDrv = NULL;
	VORENDER_MSG_t	msg = {VORENDER_MSG_CONFIG, 0, 0};

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	msg.msgID = VORENDER_MSG_FLUSH_BUFFER;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);

	Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceRender_FlushBuffer \n");

	return RESULT_OK;
}
// ==========================================================================
//
// Function Name: csl_audvoc_render_init
//
// Description: Init the audio path render
//
// =========================================================================
UInt32 csl_audio_render_init (CSL_AUDIO_DEVICE_e source, CSL_AUDIO_DEVICE_e sink)
{
	OSDAL_DMA_CLIENT	dstClient = OSDAL_DMA_CLIENT_AUDIO_OUT_FIFO;
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	UInt32 streamID = CSL_AUDVOC_STREAM_NONE;
	
	if (sink == CSL_AUDVOC_DEV_RENDER_POLYRINGER)
		dstClient = OSDAL_DMA_CLIENT_POLYRING_OUT_FIFO;
	
	// Get DMA channel
    if(OSDAL_DMA_Obtain_Channel(OSDAL_DMA_CLIENT_MEMORY, dstClient, &dmaChAudio) != OSDAL_ERR_OK)
    {
        Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_init:: Error, Obtain channel failed.\n");
		return CSL_AUDVOC_STREAM_NONE;
    }

	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_render_init:: DMA channel for audio path render 0x%x\n", dmaChAudio);

	if (sink == CSL_AUDVOC_DEV_RENDER_AUDIO)
	{
		streamID = CSL_AUDVOC_STREAM_AUDIO;
	}
	else if (sink == CSL_AUDVOC_DEV_RENDER_POLYRINGER)
	{
		streamID = CSL_AUDVOC_STREAM_POLYRINGER;
	}
	else
	{
		return streamID;     
	}
	
	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return CSL_AUDVOC_STREAM_NONE;
	
	memset(audDrv, 0, sizeof(CSL_AUDVOC_Drv_t));
	audDrv->streamID = streamID;
	audDrv->source = source;
	audDrv->sink = sink;
	audDrv->dmaCH = dmaChAudio;
	
	return audDrv->streamID;
}
// ===================================================================
//
// Function Name: AUDDRV_VoiceCapture_SetBufDoneCB
//
// Description: register buffer done callback 
// when driver finishes coping the data from the buffer to driver queue
// driver calls this callback to notify.
//
// ====================================================================
Result_t AUDDRV_VoiceCapture_SetBufDoneCB ( 
                     VOCAPTURE_TYPE_t    type,
                     AUDDRV_VoiceCapture_BufDoneCB_t           bufDone_cb )
{
	VOCAPTURE_Drv_t	*audDrv = NULL;
	VOCAPTURE_MSG_t	msg;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	memset (&msg, 0, sizeof(VOCAPTURE_MSG_t));
	msg.msgID = VOCAPTURE_MSG_REGISTER_BUFDONE_CB;
	msg.parm1 = (UInt32)bufDone_cb;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);

	return RESULT_OK;
}
// =========================================================================
// Function Name: AMRWB_Render_Request
//
//	Description: DSP AMRWB Request new data. The DSP interrupt handler will call it to request
// new data.
//==================================================================================== 
void AMRWB_Render_Request(VPStatQ_t reqMsg)
{
	VORENDER_MSG_t	msg;
	VORENDER_Drv_t	*audDrv = NULL;

	// we may still get dsp int after task is gone, ignore these late fellows
	audDrv = GetDriverByType (VORENDER_TYPE_AMRWB);
	if ((audDrv == NULL) || (audDrv->isRunning == FALSE))
	{
		Log_DebugPrintf(LOGID_AUDIO, "## [AMRWB][%s] entered wrong state ##\n", __FUNCTION__);
		return;
	}
	memset (&msg, 0, sizeof(VORENDER_MSG_t));

	switch (reqMsg.status)
	{
		case VP_STATUS_PRAM_CODEC_DONEPLAY:
			// dsp finishes play, need to stop.
			OSSEMAPHORE_Release (audDrv->stopDspAmrWbSema);
			break;

		case VP_STATUS_PRAM_CODEC_INPUT_EMPTY:
		case VP_STATUS_PRAM_CODEC_INPUT_LOW:
			msg.msgID = VORENDER_MSG_SHM_REQUEST;
			msg.parm1 = reqMsg.arg1; //dsp_read_index
			msg.parm2 = reqMsg.arg2; //dsp_write_index
			OSQUEUE_Post(sAMRWB_Drv.msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);
			break;
#if 0 // not supported by DSP since Athena
		case VP_STATUS_PRAM_CODEC_CANCELPLAY:
			// dsp cancels play, need to stop immediately. 
			// should go through normal process, set done flag, disble vpu stuff ???
			msg.msgID = VORENDER_MSG_STOP;
			OSQUEUE_Post(sAMRWB_Drv.msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);
			break;
#endif			
		default:
			Log_DebugPrintf(LOGID_AUDIO, "## [AMRWB][%s] received unknown msg ##\n", __FUNCTION__);
			break;
	}
}
// ==========================================================================
//
// Function Name: csl_audio_render_get_dma_params
//
// Description: Resume the data transfer of audio path render
//
// =========================================================================
Result_t csl_audio_render_get_dma_params( UInt32 streamID, UInt32* dma_addr, UInt32* xfer_size )
{
    #define CHAN_REG_INCREMENT      0x20

    UInt32 dmaChAudio;
    CSL_AUDVOC_Drv_t	*audDrv = NULL;
    UInt32 dma_base_address = DMAC_BASE_ADDR;
    UInt32 dma_ch0_src_address = dma_base_address + 0x100;
    UInt32 dma_ch0_control_address = dma_base_address + 0x10c;

    audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return CSL_AUDVOC_STREAM_NONE;
    // get the DMA channel id
    dmaChAudio = audDrv->dmaCH;

    *dma_addr  =  *((UInt32*)(dma_ch0_src_address + CHAN_REG_INCREMENT * dmaChAudio));
    *xfer_size =  *((UInt32*)(dma_ch0_control_address + CHAN_REG_INCREMENT * dmaChAudio));

    *xfer_size &= (0x00000fff);
    return RESULT_OK;
}
// ==========================================================================
//
// Function Name: csl_audvoc_capture_start
//
// Description: Start the data transfer of the audio path capture
//
// =========================================================================
Result_t csl_audio_capture_start( UInt32 streamID )
{
	CSL_AUDVOC_Drv_t	*audDrv = NULL;
	Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_capture_start:: DMA streamID = %d\n", streamID);

	audDrv = GetDriverByType (streamID);

	if (audDrv == NULL)
		return RESULT_ERROR;	
	
	if(OSDAL_DMA_Start_Transfer(audDrv->dmaCH) != OSDAL_ERR_OK)
	{
		Log_DebugPrintf(LOGID_SOC_AUDIO, "csl_audvoc_capture_start::Error, Start transfer failed.\n");
	}

	if (streamID == CSL_AUDVOC_STREAM_BTW)
	{
		Log_DebugPrintf(LOGID_AUDIO, "csl_audio_capture_start BT wb tap \n");
	
		AUDDRV_Enable_MixerTap ( AUDDRV_MIXERTap_WB_INPUT, 
			AUDDRV_SPKR_NONE,   ////this param bears no meaning in this context.
			AUDDRV_SPKR_NONE,   ////this param bears no meaning in this context.
			AUDIO_SAMPLING_RATE_UNDEFINED,  //this param bears no meaning in this context
			AUDDRV_REASON_DATA_DRIVER
			);
	}
	else
	{
		AUDDRV_EnableHWInput ( AUDDRV_AUDIO_INPUT, 
			AUDDRV_MIC_NONE,    //this param bears no meaning in this context.
			AUDIO_SAMPLING_RATE_UNDEFINED,  //this param bears no meaning in this context.
			AUDDRV_REASON_DATA_DRIVER
		   );
	}

	return RESULT_OK;
}
// ===================================================================
//
// Function Name: AUDDRV_VoiceCapture_SetConfig
//
// Description: Configuree voice capture dirver, 
// Set parameters before start capture.
//
// ====================================================================
Result_t AUDDRV_VoiceCapture_SetConfig(
                        VOCAPTURE_TYPE_t      type,
						UInt32				speech_mode,
						UInt8				amr_data_rate,
						VOCAPTURE_RECORD_MODE_t record_mode,
                        AUDIO_SAMPLING_RATE_t    sample_rate,
						Boolean				audio_proc_enable,
						Boolean				vp_dtx_enable)
{
	VOCAPTURE_Drv_t	*audDrv = NULL;
	VOCAPTURE_Configure_t	*config;
	VOCAPTURE_MSG_t	msg;
	
	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	config = (VOCAPTURE_Configure_t *)OSHEAP_Alloc(sizeof(VOCAPTURE_Configure_t));

	config->speechMode = speech_mode;
	config->dataRate = amr_data_rate;
	config->recordMode = record_mode;
	config->samplingRate = sample_rate;
	config->procEnable = audio_proc_enable;
	config->dtxEnable = vp_dtx_enable;

	memset (&msg, 0, sizeof(VOCAPTURE_MSG_t));
	msg.msgID = VOCAPTURE_MSG_CONFIG;
	msg.parm1 = (UInt32)config;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);
	

	return RESULT_OK;
}
//*********************************************************************
//
// Function Name: AUDDRV_VoiceRender_SetTransferParameters
//
// Description:Set the driver transfer parameters before configure driver, if needed.
//
//	@param	type						The voice render driver type
//	@param	callbackThreshold(in ms)	Driver will callback when buffer size is lower than the threshold
//	@param	interruptInterval(in ms)	The DSP intterrupt interval
//	@return	Result_t
//	@note   Driver will use default values if this function is not called	
//**************************************************************************
Result_t AUDDRV_VoiceRender_SetTransferParameters(
                        VORENDER_TYPE_t      type,
                        UInt32				callbackThreshold,
                        UInt32				interruptInterval)
{
	VORENDER_Drv_t	*audDrv = NULL;
	VORENDER_MSG_t	msg = {VORENDER_MSG_SET_TRANSFER, 0, 0};
	
	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	Log_DebugPrintf(LOGID_SOC_AUDIO, "AUDDRV_VoiceRender_SetTransferParameters:: type = 0x%x, callbackThreshold = 0x%x, interruptInterval = 0x%x\n", 
								audDrv->drvType, callbackThreshold, interruptInterval);
	
	msg.msgID = VORENDER_MSG_SET_TRANSFER;
	msg.parm1 = (UInt32)callbackThreshold;
	msg.parm2 = (UInt32)interruptInterval;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);
	
	return RESULT_OK;
}
//===========================================================
//
// Function Name: AUDDRV_VoiceRender_SetConfig
//
//	Description: Configure voice render driver, Set parameters before start render.
// 
//================================================================== 
Result_t AUDDRV_VoiceRender_SetConfig(
                        VORENDER_TYPE_t				type,
						VORENDER_PLAYBACK_MODE_t	playbackMode,
						VORENDER_VOICE_MIX_MODE_t   mixMode,
						AUDIO_SAMPLING_RATE_t		samplingRate,
						UInt32						speechMode, // used by AMRNB and AMRWB
						UInt32						dataRateSelection // used by AMRNB and AMRWB     
					)
{
	VORENDER_Drv_t	*audDrv = NULL;
	VORENDER_Configure_t	*config;
	VORENDER_MSG_t	msg;
	
	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	config = (VORENDER_Configure_t *)OSHEAP_Alloc(sizeof(VORENDER_Configure_t));

	config->playbackMode = playbackMode;
	config->mixMode = mixMode;
	config->samplingRate = samplingRate;
	config->speechMode = speechMode;
	config->dataRateSelection = dataRateSelection;
	
	memset (&msg, 0, sizeof(VORENDER_MSG_t));

	msg.msgID = VORENDER_MSG_CONFIG;
	msg.parm1 = (UInt32)config;

	OSQUEUE_Post(audDrv->msgQueue, (QMsg_t*)&msg, TICKS_FOREVER);
	

	return RESULT_OK;
}
//===========================================================
//
// Function Name: AUDDRV_VoiceRender_Init
//
//	Description: Initialize voice render driver, init internal variables and task queue.
// 
//==================================================================
Result_t AUDDRV_VoiceRender_Init( VORENDER_TYPE_t type )
{
	VORENDER_Drv_t	*audDrv = NULL;

	audDrv = GetDriverByType (type);

	if (audDrv == NULL)
		return RESULT_ERROR;

	if (audDrv->isRunning)
		return RESULT_OK;

	memset (audDrv, 0, sizeof(VORENDER_Drv_t));

	audDrv->drvType = type;
	audDrv->stopSema = OSSEMAPHORE_Create(0, OSSUSPEND_PRIORITY);
	audDrv->addBufSema = OSSEMAPHORE_Create(0, OSSUSPEND_PRIORITY);
	audDrv->stopDspAmrWbSema = OSSEMAPHORE_Create(0, OSSUSPEND_PRIORITY);

	switch (audDrv->drvType)
	{
		case VORENDER_TYPE_AMRNB:
		case VORENDER_TYPE_PCM_VPU:
			audDrv->msgQueue = OSQUEUE_Create( QUEUESIZE_AUDDRV_VPURENDER,
											sizeof(VORENDER_MSG_t), OSSUSPEND_PRIORITY );
			OSQUEUE_ChangeName(audDrv->msgQueue, (const char *) "AUDDRV_VPURENDER_Q" );

			audDrv->task = OSTASK_Create( (TEntry_t) VPU_Render_TaskEntry,
										TASKNAME_AUDDRV_VPURENDER,
										TASKPRI_AUDDRV_VPURENDER,
										STACKSIZE_AUDDRV_VPURENDER
										);
			break;

		case VORENDER_TYPE_PCM_ARM2SP:
		case VORENDER_TYPE_PCM_ARM2SP2:	
			audDrv->msgQueue = OSQUEUE_Create( QUEUESIZE_AUDDRV_ARM2SPRENDER,
											sizeof(VORENDER_MSG_t), OSSUSPEND_PRIORITY );
			OSQUEUE_ChangeName(audDrv->msgQueue, (const char *) "AUDDRV_ARM2SPRENDER_Q" );

			audDrv->task = OSTASK_CreateWArg( (TEntryWArg_t) ARM2SP_Render_TaskEntry,
										TASKNAME_AUDDRV_ARM2SPRENDER,
										TASKPRI_AUDDRV_ARM2SPRENDER,
										STACKSIZE_AUDDRV_ARM2SPRENDER,
										(TArgc_t)audDrv,
										(TArgv_t)NULL										
										);
			break;

		case VORENDER_TYPE_AMRWB:
			audDrv->msgQueue = OSQUEUE_Create( QUEUESIZE_AUDDRV_AMRWBRENDER,
											sizeof(VORENDER_MSG_t), OSSUSPEND_PRIORITY );
			OSQUEUE_ChangeName(audDrv->msgQueue, (const char *) "AUDDRV_AMRWBRENDER_Q" );

			audDrv->task = OSTASK_Create( (TEntry_t) AMRWB_Render_TaskEntry,
										TASKNAME_AUDDRV_AMRWBRENDER,
										TASKPRI_AUDDRV_AMRWBRENDER,
										STACKSIZE_AUDDRV_AMRWBRENDER
										);
			break;

		default:
			Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceRender_Init:: Doesn't support audio driver type drvType = 0x%x\n", audDrv->drvType);
			return RESULT_ERROR;
//			break;
	}
	
	audDrv->isRunning = TRUE;

	Log_DebugPrintf(LOGID_AUDIO, "AUDDRV_VoiceRender_Init::Exit.\n");

	return RESULT_OK;
}