sdk-hwV1.3/external/eyesee-mpp/middleware/sun8iw21/media/component/AOChannel_Component.c

2096 lines
77 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
/******************************************************************************
Copyright (C), 2001-2016, Allwinner Tech. Co., Ltd.
******************************************************************************
File Name : AOChannel_Component.c
Version : Initial Draft
Author : Allwinner BU3-PD2 Team
Created : 2016/05/12
Last Modified :
Description : mpi functions implement
Function List :
History :
******************************************************************************/
//#define LOG_NDEBUG 0
#define LOG_TAG "AOChannel_Component"
#include <utils/plat_log.h>
#include <errno.h>
#include <sys/prctl.h>
#include <mm_component.h>
#include <tmessage.h>
#include <tsemaphore.h>
#include <cdx_list.h>
#include <SystemBase.h>
#include <media_common_aio.h>
#include <resample.h>
#include <change_speed.h>
#include "AOChannel_Component.h"
#include <ConfigOption.h>
#if (MPPCFG_AGC == OPTION_AGC_ENABLE)
#include <agc_float.h>
#endif
static void *AOChannel_ComponentThread(void *pThreadData);
static ERRORTYPE AOChannel_SendCommand(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_COMMANDTYPE Cmd, PARAM_IN unsigned int nParam1, PARAM_IN void* pCmdData)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S *)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
CompInternalMsgType eCmd;
ERRORTYPE eError = SUCCESS;
message_t msg;
//alogv("AOChannel_SendCommand: %d", Cmd);
if (NULL == pChnData) {
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CONF_CMD_BAIL;
}
if (Cmd == COMP_CommandMarkBuffer) {
if (NULL == pCmdData) {
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CONF_CMD_BAIL;
}
}
if (pChnData->state == COMP_StateInvalid) {
eError = ERR_AO_SYS_NOTREADY;
goto COMP_CONF_CMD_BAIL;
}
switch (Cmd) {
case COMP_CommandStateSet:
eCmd = SetState;
break;
case COMP_CommandFlush:
eCmd = Flush;
break;
case COMP_CommandPortDisable:
eCmd = StopPort;
break;
case COMP_CommandPortEnable:
eCmd = RestartPort;
break;
case COMP_CommandMarkBuffer:
eCmd = MarkBuf;
if (nParam1 > 0) {
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CONF_CMD_BAIL;
}
break;
default:
eCmd = -1;
break;
}
msg.command = eCmd;
msg.para0 = nParam1;
put_message(&pChnData->mCmdQueue, &msg);
COMP_CONF_CMD_BAIL:
return eError;
}
static ERRORTYPE AOChannel_GetState(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT COMP_STATETYPE* pState)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (NULL == pChnData || NULL == pState) {
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CONF_CMD_BAIL;
}
*pState = pChnData->state;
COMP_CONF_CMD_BAIL:
return eError;
}
static ERRORTYPE AOChannel_SetCallbacks(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_CALLBACKTYPE* pCallbacks, PARAM_IN void* pAppData)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (NULL == pChnData || NULL == pCallbacks || NULL == pAppData) {
aloge("pChnData=%p, pCallbacks=%p, pAppData=%p", pChnData, pCallbacks, pAppData);
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CONF_CMD_BAIL;
}
pChnData->pCallbacks = pCallbacks;
pChnData->pAppData = pAppData;
COMP_CONF_CMD_BAIL:
return eError;
}
ERRORTYPE AOSetAVSync(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN char avSyncFlag)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pChnData->av_sync = avSyncFlag;
return eError;
}
ERRORTYPE AOSetTimeActiveRefClock(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_TIME_CONFIG_ACTIVEREFCLOCKTYPE *pRefClock)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
if(pRefClock->eClock == COMP_TIME_RefClockAudio)
{
pChnData->is_ref_clock = TRUE;
}
else
{
aloge("fatal error! check RefClock[0x%x]", pRefClock->eClock);
pChnData->is_ref_clock = FALSE;
}
return eError;
}
ERRORTYPE AONotifyStartToRun(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pChnData->start_to_play = TRUE;
return eError;
}
ERRORTYPE AOSetStreamEof(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN BOOL drainFlag)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
alogd("AO end flag is set! drain pcm flag:%d!", drainFlag);
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
pChnData->mWaitDrainPcmSemFlag = drainFlag;
pChnData->priv_flag |= CDX_comp_PRIV_FLAGS_STREAMEOF;
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
message_t msg;
msg.command = AOChannel_InputPcmAvailable;
put_message(&pChnData->mCmdQueue, &msg);
// if (pChnData->mWaitDrainPcmSemFlag == TRUE)
// {
// cdx_sem_down(&pChnData->mWaitDrainPcmSem);
// }
return eError;
}
ERRORTYPE AOClearStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
pChnData->priv_flag &= ~CDX_comp_PRIV_FLAGS_STREAMEOF;
pChnData->mbEof = FALSE;
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
return eError;
}
static ERRORTYPE AOReleaseFrame_l(
PARAM_IN AO_CHN_DATA_S *pChnData,
PARAM_IN AOCompInputFrame *pInFrame)
{
ERRORTYPE omxRet = SUCCESS;
AOCompInputFrame *pEntry;
BOOL bFindFlag = FALSE;
list_for_each_entry(pEntry, &pChnData->mAudioInputFrameUsedList, mList)
{
if(pEntry == pInFrame)
{
bFindFlag = TRUE;
break;
}
}
if(FALSE == bFindFlag)
{
list_for_each_entry(pEntry, &pChnData->mAudioInputFrameReadyList, mList)
{
if(pEntry == pInFrame)
{
bFindFlag = TRUE;
break;
}
}
}
if(bFindFlag)
{
if (pChnData->mInputPortTunnelFlag[AO_INPORT_SUFFIX_AUDIO])
{
COMP_INTERNAL_TUNNELINFOTYPE *pADecTunnel = &pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_PCM];
COMP_BUFFERHEADERTYPE obh;
obh.nOutputPortIndex = pADecTunnel->nTunnelPortIndex;
obh.nInputPortIndex = pADecTunnel->nPortIndex;
obh.pOutputPortPrivate = (void*)&pEntry->mAFrame;
omxRet = COMP_FillThisBuffer(pADecTunnel->hTunnel, &obh);
if(omxRet != SUCCESS)
{
aloge("fatal error! fill this buffer fail[0x%x], pts=[%lld], nId=[%d], check code!",
omxRet, pInFrame->mAFrame.mTimeStamp, pInFrame->mAFrame.mId);
}
else
{
list_move_tail(&pEntry->mList, &pChnData->mAudioInputFrameIdleList);
}
}
else
{
COMP_BUFFERHEADERTYPE obh;
obh.pOutputPortPrivate = (void*)&pEntry->mAFrame;
//must return pcm to APP!
pChnData->pCallbacks->EmptyBufferDone(pChnData->hSelf, pChnData->pAppData, &obh);
list_move_tail(&pEntry->mList, &pChnData->mAudioInputFrameIdleList);
}
}
else
{
aloge("fatal error! not find pInFrame[%p], pts[%lld], nId[%d] in used and ready list.",
pInFrame, pInFrame->mAFrame.mTimeStamp, pInFrame->mAFrame.mId);
omxRet = ERR_AO_ILLEGAL_PARAM;
}
return SUCCESS;
}
ERRORTYPE AOReleaseFrame(
PARAM_IN AO_CHN_DATA_S *pChnData,
PARAM_IN AOCompInputFrame *pFrame)
{
ERRORTYPE eError;
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
eError = AOReleaseFrame_l(pChnData, pFrame);
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
return eError;
}
static ERRORTYPE AOAddFrame_l(
PARAM_IN AO_CHN_DATA_S *pChnData,
PARAM_IN AUDIO_FRAME_S *pInFrame)
{
AOCompInputFrame *pNode;
if(list_empty(&pChnData->mAudioInputFrameIdleList))
{
alogw("input frame list is empty, increase one");
pNode = (AOCompInputFrame*)malloc(sizeof(AOCompInputFrame));
if(NULL == pNode)
{
aloge("fatal error! malloc fail!");
}
list_add_tail(&pNode->mList, &pChnData->mAudioInputFrameIdleList);
pChnData->mFrameNodeNum++;
}
pNode = list_first_entry(&pChnData->mAudioInputFrameIdleList, AOCompInputFrame, mList);
memcpy(&pNode->mAFrame, pInFrame, sizeof(AUDIO_FRAME_S));
list_move_tail(&pNode->mList, &pChnData->mAudioInputFrameReadyList);
return SUCCESS;
}
ERRORTYPE AOSeek(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pChnData->seek_flag = 1;
AOCompInputFrame *pEntry, *pTmp;
ERRORTYPE omxRet = SUCCESS;
int cnt = 0;
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
list_for_each_entry_safe(pEntry, pTmp, &pChnData->mAudioInputFrameUsedList, mList)
{
AOReleaseFrame_l(pChnData, pEntry);
cnt++;
}
list_for_each_entry_safe(pEntry, pTmp, &pChnData->mAudioInputFrameReadyList, mList)
{
AOReleaseFrame_l(pChnData, pEntry);
cnt++;
}
alogd("AO seek, release [%d]input audio Frame!", cnt);
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
return eError;
}
static ERRORTYPE AOChannel_SetSaveFileInfo(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN AUDIO_SAVE_FILE_INFO_S *pFileInfo)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S *)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
if (COMP_StateIdle != pChnData->state && COMP_StateExecuting != pChnData->state)
{
aloge("call SetSaveFileInfo in wrong state[0x%x]!", pChnData->state);
return ERR_AO_NOT_PERM;
}
int nPathLen = strlen(pFileInfo->mFilePath) + strlen(pFileInfo->mFileName) + 1;
pChnData->mpSaveFileFullPath = (char*)malloc(nPathLen);
if (NULL == pChnData->mpSaveFileFullPath)
{
aloge("malloc %d fail! FilePath:[%s], FileName:[%s]", nPathLen, pFileInfo->mFilePath, pFileInfo->mFileName);
return ERR_AO_NOMEM;
}
memset(pChnData->mpSaveFileFullPath, 0, nPathLen);
strcpy(pChnData->mpSaveFileFullPath, pFileInfo->mFilePath);
strcat(pChnData->mpSaveFileFullPath, pFileInfo->mFileName);
pChnData->mFpSaveFile = fopen(pChnData->mpSaveFileFullPath, "wb+");
if (pChnData->mFpSaveFile)
{
alogd("create file(%s) to save pcm file", pChnData->mpSaveFileFullPath);
pChnData->mSaveFileFlag = TRUE;
pChnData->mSaveFileSize = 0;
}
else
{
aloge("create file(%s) failed!", pChnData->mpSaveFileFullPath);
pChnData->mSaveFileFlag = FALSE;
}
return SUCCESS;
}
static ERRORTYPE AOChannel_QueryFileStatus(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT AUDIO_SAVE_FILE_INFO_S *pFileInfo)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S *)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
if (COMP_StateIdle != pChnData->state && COMP_StateExecuting != pChnData->state)
{
aloge("call SetSaveFileInfo in wrong state[0x%x]!", pChnData->state);
return ERR_AO_NOT_PERM;
}
memset(pFileInfo, 0, sizeof(AUDIO_SAVE_FILE_INFO_S));
if (pChnData->mSaveFileFlag)
{
pFileInfo->bCfg = pChnData->mSaveFileFlag;
pFileInfo->mFileSize = pChnData->mSaveFileSize;
const char *ptr = strrchr(pChnData->mpSaveFileFullPath, '/');
int pathLen = ptr - pChnData->mpSaveFileFullPath;
strncpy(pFileInfo->mFilePath, pChnData->mpSaveFileFullPath, pathLen);
strcpy(pFileInfo->mFileName, ptr);
}
else
{
alogw("AO NOT in save file status!");
}
return SUCCESS;
}
#if (MPPCFG_SOFTDRC == OPTION_SOFTDRC_ENABLE)
static ERRORTYPE AODrcInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
drcLog_prms_t drc_prms;
drc_prms.sampling_rate = pChnData->mDrcCfg.sampling_rate;
drc_prms.attack_time = pChnData->mDrcCfg.attack_time;
drc_prms.release_time = pChnData->mDrcCfg.release_time;
drc_prms.max_gain = pChnData->mDrcCfg.max_gain;
drc_prms.min_gain = pChnData->mDrcCfg.min_gain;
drc_prms.noise_threshold = pChnData->mDrcCfg.noise_threshold;
drc_prms.target_level = pChnData->mDrcCfg.target_level;
pChnData->mDrc = drcLog_create(&drc_prms);
return eError;
}
#endif
#if (MPPCFG_AGC == OPTION_AGC_ENABLE)
static ERRORTYPE AOAgcInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
if ((pChnData->mAgcCfg.fTargetDb < -30 || pChnData->mAgcCfg.fTargetDb > 0)
|| (pChnData->mAgcCfg.fMaxGainDb < 0 || pChnData->mAgcCfg.fMaxGainDb > 30))
{
aloge("fatal error! agc float init param invalid[%f-%f]", pChnData->mAgcCfg.fTargetDb, pChnData->mAgcCfg.fMaxGainDb);
pChnData->mpAgcHandle = NULL;
eError = ERR_AO_ILLEGAL_PARAM;
}
else
{
if(NULL == pChnData->mpAgcHandle)
{
int nSampleRate = map_AUDIO_SAMPLE_RATE_E_to_SampleRate(pChnData->mAioAttr.enSamplerate);
int nChnCnt = pChnData->mAioAttr.mChnCnt;
pChnData->mpAgcHandle = func_agc_init(nSampleRate, nChnCnt, pChnData->mAgcCfg.fTargetDb, pChnData->mAgcCfg.fMaxGainDb);
if (pChnData->mpAgcHandle)
{
alogd("agc float init param:%d-%d-%f-%f", nSampleRate, nChnCnt, pChnData->mAgcCfg.fTargetDb, pChnData->mAgcCfg.fMaxGainDb);
eError = SUCCESS;
}
else
{
eError = ERR_AO_ILLEGAL_PARAM;
aloge("fatal error! agc float init failed");
}
}
else
{
alogw("Be careful! aoChn[%d-%d] agc float lib aready exist!", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
}
}
return eError;
}
static ERRORTYPE AOAgcDestroy(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
if(pChnData->mpAgcHandle)
{
func_agc_exit((agc_handle*)pChnData->mpAgcHandle);
pChnData->mpAgcHandle = NULL;
}
return eError;
}
#endif
static ERRORTYPE AOChannel_SetChnMute(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN BOOL bMute)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
pChnData->mbMute = bMute;
return SUCCESS;
}
static ERRORTYPE AOChannel_GetChnMute(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT BOOL *pbMute)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
*pbMute = pChnData->mbMute;
return SUCCESS;
}
static ERRORTYPE AOChannel_SetVps(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN float fVps)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
if(fVps < 0.5 || fVps > 4)
{
aloge("fatal error! fVps[%f] is wrong!", fVps);
return ERR_AO_ILLEGAL_PARAM;
}
pChnData->mfVps = fVps;
return SUCCESS;
}
static ERRORTYPE AOChannel_GetVps(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT float *pfVps)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
*pfVps = pChnData->mfVps;
return SUCCESS;
}
static ERRORTYPE AOChannel_SetConfig(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_IN void* pComponentConfigStructure)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
switch (nIndex)
{
case COMP_IndexParamPortDefinition:
{
COMP_PARAM_PORTDEFINITIONTYPE *port = (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure;
int i;
for(i = 0; i < AO_CHN_MAX_PORTS; i++) {
if (port->nPortIndex == pChnData->sPortDef[i].nPortIndex) {
memcpy(&pChnData->sPortDef[i], port, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
}
if (i == AO_CHN_MAX_PORTS) {
eError = FAILURE;
}
break;
}
case COMP_IndexParamCompBufferSupplier:
{
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier = (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure;
int i;
for(i=0; i<AO_CHN_MAX_PORTS; i++) {
if(pChnData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) {
memcpy(&pChnData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if(i == AO_CHN_MAX_PORTS) {
eError = FAILURE;
}
break;
}
case COMP_IndexVendorMPPChannelInfo:
{
pChnData->mMppChnInfo = *(MPP_CHN_S*)pComponentConfigStructure;
break;
}
case COMP_IndexVendorAOChnSendFrame:
{
alogd("Not use this any more! non-tunnel send frame api use EmptyThisBuffer().");
break;
}
case COMP_IndexVendorAIOReSmpEnable:
{
pChnData->mbEnableReSmp = TRUE;
break;
}
case COMP_IndexVendorAIOReSmpDisable:
{
pChnData->mbEnableReSmp = FALSE;
break;
}
case COMP_IndexVendorAIOVqeAttr:
{
memcpy(&pChnData->mVqeCfg, (AO_VQE_CONFIG_S*)pComponentConfigStructure, sizeof(AO_VQE_CONFIG_S));
break;
}
case COMP_IndexVendorAIOVqeEnable:
{
pChnData->mUseVqeLib = TRUE;
break;
}
case COMP_IndexVendorAIOVqeDisable:
{
pChnData->mUseVqeLib = FALSE;
break;
}
case COMP_IndexVendorAIODrcEnable:
{
#if (MPPCFG_SOFTDRC == OPTION_SOFTDRC_ENABLE)
pChnData->mUseDrcLib = TRUE;
memcpy(&pChnData->mDrcCfg, (AO_DRC_CONFIG_S*)pComponentConfigStructure, sizeof(AO_DRC_CONFIG_S));
eError = AODrcInit(hComponent);
#endif
break;
}
case COMP_IndexVendorAIOAgcEnable:
{
#if (MPPCFG_AGC == OPTION_AGC_ENABLE)
pthread_mutex_lock(&pChnData->mAgcLock);
if(!pChnData->mUseAgcLib)
{
memcpy(&pChnData->mAgcCfg, (AGC_FLOAT_CONFIG_S*)pComponentConfigStructure, sizeof(AGC_FLOAT_CONFIG_S));
pChnData->mUseAgcLib = TRUE;
}
else
{
alogd("aoChn[%d-%d] agc already enable", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
}
pthread_mutex_unlock(&pChnData->mAgcLock);
#else
aloge("fatal error! agc disable");
eError = ERR_AO_NOT_SUPPORT;
#endif
break;
}
case COMP_IndexVendorAIOAgcDisable:
{
#if (MPPCFG_AGC == OPTION_AGC_ENABLE)
pthread_mutex_lock(&pChnData->mAgcLock);
pChnData->mUseAgcLib = FALSE;
eError = AOAgcDestroy(hComponent);
pthread_mutex_unlock(&pChnData->mAgcLock);
#else
aloge("fatal error! agc disable");
eError = ERR_AO_NOT_SUPPORT;
#endif
break;
}
case COMP_IndexVendorSetAVSync:
{
eError = AOSetAVSync(hComponent, *(char*)pComponentConfigStructure);
break;
}
case COMP_IndexConfigTimeActiveRefClock:
{
eError = AOSetTimeActiveRefClock(hComponent, (COMP_TIME_CONFIG_ACTIVEREFCLOCKTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorNotifyStartToRun:
{
eError = AONotifyStartToRun(hComponent);
break;
}
case COMP_IndexVendorSetStreamEof:
{
eError = AOSetStreamEof(hComponent, *(BOOL *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorClearStreamEof:
{
eError = AOClearStreamEof(hComponent);
break;
}
case COMP_IndexVendorSeekToPosition:
{
eError = AOSeek(hComponent);
break;
}
case COMP_IndexVendorAOSetSaveFileInfo:
{
AUDIO_SAVE_FILE_INFO_S *pSaveFileInfo = (AUDIO_SAVE_FILE_INFO_S*)pComponentConfigStructure;
eError = AOChannel_SetSaveFileInfo(hComponent, pSaveFileInfo);
break;
}
case COMP_IndexVendorAOChnPcmCardType:
{
pChnData->card_id = *(PCM_CARD_TYPE_E*)pComponentConfigStructure;
break;
}
case COMP_IndexVendorAOChnMute:
{
eError = AOChannel_SetChnMute(hComponent, *(BOOL*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAOChnVps:
{
eError = AOChannel_SetVps(hComponent, *(float*)pComponentConfigStructure);
break;
}
default:
eError = FAILURE;
break;
}
return eError;
}
static ERRORTYPE AOChannel_GetConfig(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_INOUT void* pComponentConfigStructure)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
switch (nIndex)
{
case COMP_IndexParamPortDefinition:
{
COMP_PARAM_PORTDEFINITIONTYPE *port = (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure;
int i;
for(i = 0; i < AO_CHN_MAX_PORTS; i++) {
if (port->nPortIndex == pChnData->sPortDef[i].nPortIndex) {
memcpy(port, &pChnData->sPortDef[i], sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
}
if (i == AO_CHN_MAX_PORTS) {
eError = FAILURE;
}
break;
}
case COMP_IndexParamCompBufferSupplier:
{
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier = (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure;
int i;
for(i=0; i<AO_CHN_MAX_PORTS; i++) {
if(pChnData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) {
memcpy(pPortBufSupplier, &pChnData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if(i == AO_CHN_MAX_PORTS) {
eError = FAILURE;
}
break;
}
case COMP_IndexVendorMPPChannelInfo:
{
*(MPP_CHN_S*)pComponentConfigStructure = pChnData->mMppChnInfo;
break;
}
case COMP_IndexVendorAIOVqeAttr:
{
*(AO_VQE_CONFIG_S*)pComponentConfigStructure = pChnData->mVqeCfg;
break;
}
case COMP_IndexVendorAOQueryChnStat:
{
// todo
break;
}
case COMP_IndexVendorAOQueryFileStatus:
{
AUDIO_SAVE_FILE_INFO_S *pSaveFileInfo = (AUDIO_SAVE_FILE_INFO_S*)pComponentConfigStructure;
eError = AOChannel_QueryFileStatus(hComponent, pSaveFileInfo);
break;
}
case COMP_IndexVendorAOChnMute:
{
eError = AOChannel_GetChnMute(hComponent, (BOOL*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAOChnVps:
{
eError = AOChannel_GetVps(hComponent, (float*)pComponentConfigStructure);
break;
}
default:
eError = FAILURE;;
break;
}
return eError;
}
static ERRORTYPE AOChannel_ComponentTunnelRequest(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN unsigned int nPort,
PARAM_IN COMP_HANDLETYPE hTunneledComp,
PARAM_IN unsigned int nTunneledPort,
PARAM_INOUT COMP_TUNNELSETUPTYPE* pTunnelSetup)
{
ERRORTYPE eError = SUCCESS;
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef;
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo;
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier;
int i;
if (pChnData->state == COMP_StateExecuting)
{
alogw("Be careful! tunnel request may be some danger in StateExecuting");
}
else if(pChnData->state != COMP_StateIdle)
{
aloge("fatal error! tunnel request can't be in state[0x%x]", pChnData->state);
eError = ERR_AO_INCORRECT_STATE_OPERATION;
goto COMP_CMD_FAIL;
}
for (i = 0; i < AO_CHN_MAX_PORTS; ++i) {
if (pChnData->sPortDef[i].nPortIndex == nPort) {
pPortDef = &pChnData->sPortDef[i];
break;
}
}
if (i == AO_CHN_MAX_PORTS) {
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
for (i = 0; i < AO_CHN_MAX_PORTS; ++i) {
if (pChnData->sPortTunnelInfo[i].nPortIndex == nPort) {
pPortTunnelInfo = &pChnData->sPortTunnelInfo[i];
break;
}
}
if (i == AO_CHN_MAX_PORTS) {
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
for (i = 0; i < AO_CHN_MAX_PORTS; ++i) {
if (pChnData->sPortBufSupplier[i].nPortIndex == nPort) {
pPortBufSupplier = &pChnData->sPortBufSupplier[i];
break;
}
}
if (i == AO_CHN_MAX_PORTS) {
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
pPortTunnelInfo->nPortIndex = nPort;
pPortTunnelInfo->hTunnel = hTunneledComp;
pPortTunnelInfo->nTunnelPortIndex = nTunneledPort;
pPortTunnelInfo->eTunnelType = (pPortDef->eDomain == COMP_PortDomainOther) ? TUNNEL_TYPE_CLOCK : TUNNEL_TYPE_COMMON;
if(NULL==hTunneledComp && 0==nTunneledPort && NULL==pTunnelSetup) {
alogd("Cancel setup tunnel on port[%d]", nPort);
eError = SUCCESS;
goto COMP_CMD_FAIL;
}
if (pPortTunnelInfo->eTunnelType == TUNNEL_TYPE_CLOCK)
{
CDX_NotifyStartToRunTYPE NotifyStartToRunInfo;
NotifyStartToRunInfo.nPortIndex = pPortTunnelInfo->nTunnelPortIndex;
NotifyStartToRunInfo.mbNotify = TRUE;
COMP_SetConfig(pPortTunnelInfo->hTunnel, COMP_IndexVendorNotifyStartToRunInfo, (void*)&NotifyStartToRunInfo);
}
if(pPortDef->eDir == COMP_DirOutput) {
if (pChnData->mOutputPortTunnelFlag) {
aloge("AO_Comp outport already bind, why bind again?!");
eError = FAILURE;
goto COMP_CMD_FAIL;
}
pTunnelSetup->nTunnelFlags = 0;
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
// ao -> ai
pChnData->mOutputPortTunnelFlag = TRUE;
} else {
if (pChnData->mInputPortTunnelFlag[AO_INPORT_SUFFIX_AUDIO] && pChnData->mInputPortTunnelFlag[AO_INPORT_SUFFIX_CLOCK]) {
aloge("AO_Comp inport already bind, why bind again?!");
eError = FAILURE;
goto COMP_CMD_FAIL;
}
//Check the data compatibility between the ports using one or more GetParameter calls.
//B checks if its input port is compatible with the output port of component A.
COMP_PARAM_PORTDEFINITIONTYPE out_port_def;
out_port_def.nPortIndex = nTunneledPort;
((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamPortDefinition, &out_port_def);
if(out_port_def.eDir != COMP_DirOutput) {
aloge("fatal error! tunnel port index[%d] direction is not output!", nTunneledPort);
eError = ERR_AO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
pPortDef->format = out_port_def.format;
//The component B informs component A about the final result of negotiation.
if(pTunnelSetup->eSupplier != pPortBufSupplier->eBufferSupplier) {
alogw("Low probability! use input portIndex[%d] buffer supplier[%d] as final!", nPort, pPortBufSupplier->eBufferSupplier);
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
}
COMP_PARAM_BUFFERSUPPLIERTYPE oSupplier;
oSupplier.nPortIndex = nTunneledPort;
((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
oSupplier.eBufferSupplier = pTunnelSetup->eSupplier;
((MM_COMPONENTTYPE*)hTunneledComp)->SetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
// adec->ao or ai->ao
if (pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].nPortIndex == nPort)
pChnData->mInputPortTunnelFlag[AO_INPORT_SUFFIX_AUDIO] = TRUE;
else if (pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_CLK].nPortIndex == nPort)
pChnData->mInputPortTunnelFlag[AO_INPORT_SUFFIX_CLOCK] = TRUE;
}
COMP_CMD_FAIL:
return eError;
}
/**
* send frame to ao dev in tunnel/non-tunnel mode.
*
* @return SUCCESS
* @param hComponent AOComp handle.
* @param pBuffer frame buffer info.
*/
static ERRORTYPE AOChannel_EmptyThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
AUDIO_FRAME_S *pInFrame;
pthread_mutex_lock(&pChnData->mStateLock);
if(pChnData->state!=COMP_StateIdle && pChnData->state!=COMP_StateExecuting && pChnData->state!=COMP_StatePause)
{
aloge("Call function in invalid state[0x%x]!", pChnData->state);
pthread_mutex_unlock(&pChnData->mStateLock);
return ERR_AO_SYS_NOTREADY;
}
pInFrame = pBuffer->pOutputPortPrivate;
if (pChnData->mInputPortTunnelFlag[AO_INPORT_SUFFIX_AUDIO])
{
if(pBuffer->nInputPortIndex == pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].nPortIndex)
{
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
AOAddFrame_l(pChnData, pInFrame);
if(pChnData->mWaitInputFrameFlag || pChnData->mbEof)
{
pChnData->mWaitInputFrameFlag = FALSE;
message_t msg;
msg.command = AOChannel_InputPcmAvailable;
put_message(&pChnData->mCmdQueue, &msg);
}
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
}
else
{
aloge("Fatal error! inputPortIndex[%d] match nothing!", pBuffer->nInputPortIndex);
eError = FAILURE;
}
}
else
{
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
AOAddFrame_l(pChnData, pInFrame);
if(pChnData->mWaitInputFrameFlag || pChnData->mbEof)
{
pChnData->mWaitInputFrameFlag = FALSE;
message_t msg;
msg.command = AOChannel_InputPcmAvailable;
put_message(&pChnData->mCmdQueue, &msg);
}
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
}
pthread_mutex_unlock(&pChnData->mStateLock);
return eError;
}
static ERRORTYPE AOGetInputFrames(AO_CHN_DATA_S *pChnData)
{
ERRORTYPE eError;
if(!list_empty(&pChnData->mAudioInputFrameReadyList))
{
list_splice_tail_init(&pChnData->mAudioInputFrameReadyList, &pChnData->mAudioInputFrameUsedList);
eError = SUCCESS;
}
else
{
eError = FAILURE;
}
return eError;
}
static ERRORTYPE AOChannel_FillThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (pBuffer->nOutputPortIndex == pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].nPortIndex) {
#if 0
AUDIO_FRAME_S *frame = pBuffer->pOutputPortPrivate;
AUDIO_FRAME_S *tmp = pChnData->mpPcmMgr->getFreeFrame(pChnData->mpPcmMgr);
if (tmp != NULL) {
*frame = *tmp;
} else {
aloge("getFreeFrame error!");
eError = FAILURE;
}
#endif
} else if (pBuffer->nOutputPortIndex == pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_AI].nPortIndex) {
#if 0
AUDIO_FRAME_S *pFrm = (AUDIO_FRAME_S*)pBuffer->pOutputPortPrivate;
pChnData->mpPcmMgr->releaseFrame(pChnData->mpPcmMgr, pFrm);
if (pChnData->mWaitAllFrameReleaseFlag) {
if (pChnData->mpPcmMgr->usingFrmEmpty(pChnData->mpPcmMgr)) {
cdx_sem_signal(&pChnData->mAllFrameRelSem);
}
}
#endif
} else {
aloge("fatal error! invalid outPortIndex[%d]", pBuffer->nOutputPortIndex);
}
return eError;
}
static ERRORTYPE AOChannel_ComponentDeInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)(((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate);
CompInternalMsgType eCmd = Stop;
message_t msg;
ERRORTYPE eError = SUCCESS;
msg.command = eCmd;
put_message(&pChnData->mCmdQueue, &msg);
alogd("wait AO channel component exit!...");
pthread_join(pChnData->mThreadId, (void*) &eError);
cdx_sem_deinit(&pChnData->mAllFrameRelSem);
cdx_sem_deinit(&pChnData->mWaitDrainPcmSem);
message_destroy(&pChnData->mCmdQueue);
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
if (!list_empty(&pChnData->mAudioInputFrameUsedList))
{
aloge("fatal error! inputUsedFrame must be 0!");
}
if (!list_empty(&pChnData->mAudioInputFrameReadyList))
{
aloge("fatal error! inputReadyFrame must be 0!");
}
if (!list_empty(&pChnData->mAudioInputFrameIdleList))
{
AOCompInputFrame *pEntry, *pTmp;
int cnt = 0;
list_for_each_entry_safe(pEntry, pTmp, &pChnData->mAudioInputFrameIdleList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
cnt++;
}
if (cnt != pChnData->mFrameNodeNum)
{
aloge("fatal error! Why node_cnt[%d] in IdleList not match mFrameNodeNum[%d]?!", cnt, pChnData->mFrameNodeNum);
}
}
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
pthread_mutex_destroy(&pChnData->mStateLock);
pthread_mutex_destroy(&pChnData->mInputFrameListMutex);
pthread_mutex_destroy(&pChnData->mOutputBufMutex);
#ifdef CFG_AUDIO_EFFECT_RESAMPLE
if (pChnData->res != NULL)
{
Destroy_Resampler(pChnData->res);
pChnData->res = NULL;
}
#endif
if(pChnData->mpResampler)
{
speex_resampler_destroy(pChnData->mpResampler);
pChnData->mpResampler = NULL;
}
if(pChnData->mpReSmpOutBuf)
{
free(pChnData->mpReSmpOutBuf);
pChnData->mpReSmpOutBuf = NULL;
}
if (pChnData->mpVpsSampleConverter)
{
sonicDestroyStream(pChnData->mpVpsSampleConverter);
pChnData->mpVpsSampleConverter = NULL;
}
if(pChnData->mpVpsOutBuf)
{
free(pChnData->mpVpsOutBuf);
pChnData->mpVpsOutBuf = NULL;
pChnData->mVpsOutBufSize = 0;
pChnData->mVpsOutValidLen = 0;
}
#if (MPPCFG_SOFTDRC == OPTION_SOFTDRC_ENABLE)
if(pChnData->mUseDrcLib)
drcLog_destroy(pChnData->mDrc);
#endif
#if (MPPCFG_AGC == OPTION_AGC_ENABLE)
AOAgcDestroy(hComponent);
if(pChnData->mpAgcTmpBuff)
{
free(pChnData->mpAgcTmpBuff);
pChnData->mpAgcTmpBuff = NULL;
}
pChnData->mnAgcTmpBuffLen = 0;
#endif
pthread_mutex_destroy(&pChnData->mAgcLock);
if (pChnData->mSaveFileFlag)
{
fclose(pChnData->mFpSaveFile);
free(pChnData->mpSaveFileFullPath);
}
if(pChnData->pMuteBuf)
{
free(pChnData->pMuteBuf);
pChnData->pMuteBuf = NULL;
}
free(pChnData);
alogd("AO component exited!");
return SUCCESS;
}
ERRORTYPE AOChannel_ComponentInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
MM_COMPONENTTYPE *pComp;
AO_CHN_DATA_S *pChnData;
ERRORTYPE eError = SUCCESS;
int err;
pComp = (MM_COMPONENTTYPE*)hComponent;
// Create private data
pChnData = (AO_CHN_DATA_S*)malloc(sizeof(AO_CHN_DATA_S));
if (pChnData == NULL) {
aloge("Alloc AO_CHN_DATA_S error!");
return FAILURE;
}
memset(pChnData, 0x0, sizeof(AO_CHN_DATA_S));
pComp->pComponentPrivate = (void*)pChnData;
pChnData->state = COMP_StateLoaded;
pChnData->hSelf = hComponent;
// Fill in function pointers
pComp->SetCallbacks = AOChannel_SetCallbacks;
pComp->SendCommand = AOChannel_SendCommand;
pComp->GetConfig = AOChannel_GetConfig;
pComp->SetConfig = AOChannel_SetConfig;
pComp->GetState = AOChannel_GetState;
pComp->ComponentTunnelRequest = AOChannel_ComponentTunnelRequest;
pComp->ComponentDeInit = AOChannel_ComponentDeInit;
pComp->EmptyThisBuffer = AOChannel_EmptyThisBuffer;
pComp->FillThisBuffer = AOChannel_FillThisBuffer;
pChnData->sPortParam.nPorts = 0;
pChnData->sPortParam.nStartPortNumber = 0x0;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_CLK].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_CLK].bEnabled = TRUE;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_CLK].eDomain = COMP_PortDomainOther;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_CLK].eDir = COMP_DirInput;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_IN_CLK].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_IN_CLK].eBufferSupplier = COMP_BufferSupplyOutput;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_CLK].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_CLK].eTunnelType = TUNNEL_TYPE_CLOCK;
pChnData->sPortParam.nPorts++;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].bEnabled = TRUE;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].eDomain = COMP_PortDomainAudio;
pChnData->sPortDef[AO_CHN_PORT_INDEX_IN_PCM].eDir = COMP_DirInput;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_IN_PCM].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_IN_PCM].eBufferSupplier = COMP_BufferSupplyOutput;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_PCM].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_PCM].eTunnelType = TUNNEL_TYPE_COMMON;
pChnData->sPortParam.nPorts++;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_PLAY].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_PLAY].bEnabled = TRUE;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_PLAY].eDomain = COMP_PortDomainAudio;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_PLAY].eDir = COMP_DirOutput;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_OUT_PLAY].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_OUT_PLAY].eBufferSupplier = COMP_BufferSupplyOutput;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_OUT_PLAY].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_OUT_PLAY].eTunnelType = TUNNEL_TYPE_COMMON;
pChnData->sPortParam.nPorts++;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_AI].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_AI].bEnabled = TRUE;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_AI].eDomain = COMP_PortDomainAudio;
pChnData->sPortDef[AO_CHN_PORT_INDEX_OUT_AI].eDir = COMP_DirOutput;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_OUT_AI].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortBufSupplier[AO_CHN_PORT_INDEX_OUT_AI].eBufferSupplier = COMP_BufferSupplyOutput;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_OUT_AI].nPortIndex = pChnData->sPortParam.nPorts;
pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_OUT_AI].eTunnelType = TUNNEL_TYPE_COMMON;
pChnData->sPortParam.nPorts++;
// if (audioHw_AO_GetPcmConfig(pChnData->mMppChnInfo.mDevId, &pChnData->mpPcmCfg) != SUCCESS) {
// aloge("audioHw_AO_GetPcmConfig error!");
// eError = FAILURE;
// goto ERR_EXIT0;
// }
// if (audioHw_AO_GetAIOAttr(pChnData->mMppChnInfo.mDevId, &pChnData->mpAioAttr) != SUCCESS) {
// aloge("audioHw_AO_GetAIOAttr error!");
// eError = FAILURE;
// goto ERR_EXIT0;
// }
INIT_LIST_HEAD(&pChnData->mAudioInputFrameIdleList);
INIT_LIST_HEAD(&pChnData->mAudioInputFrameReadyList);
INIT_LIST_HEAD(&pChnData->mAudioInputFrameUsedList);
int i;
for (i = 0; i < AO_CHN_MAX_CACHE_FRAME; i++)
{
AOCompInputFrame *pNode = (AOCompInputFrame*)malloc(sizeof(AOCompInputFrame));
if (NULL == pNode)
{
aloge("fatal error! malloc fail[%s]!", strerror(errno));
break;
}
memset(pNode, 0, sizeof(AOCompInputFrame));
list_add_tail(&pNode->mList, &pChnData->mAudioInputFrameIdleList);
pChnData->mFrameNodeNum++;
}
err = pthread_mutex_init(&pChnData->mInputFrameListMutex, NULL);
if(err != 0)
{
aloge("Fatal error! pthread mutex init fail!");
eError = FAILURE;
goto ERR_EXIT0;
}
err = pthread_mutex_init(&pChnData->mOutputBufMutex, NULL);
if(err != 0)
{
aloge("Fatal error! pthread mutex init fail!");
eError = FAILURE;
goto ERR_EXIT0;
}
err = pthread_mutex_init(&pChnData->mStateLock, NULL);
if(err != 0)
{
aloge("Fatal error! pthread mutex init fail!");
eError = FAILURE;
goto ERR_EXIT0;
}
err = pthread_mutex_init(&pChnData->mAgcLock, NULL);
if(err != 0)
{
aloge("fatal error! pthread mutex init fail!");
eError = FAILURE;
goto ERR_EXIT0;
}
if (message_create(&pChnData->mCmdQueue) < 0){
aloge("message error!");
eError = FAILURE;
goto ERR_EXIT2;
}
err = cdx_sem_init(&pChnData->mAllFrameRelSem, 0);
if (err != 0) {
aloge("cdx_sem_init AllFrameRelSem error!");
goto ERR_EXIT3;
}
err = cdx_sem_init(&pChnData->mWaitDrainPcmSem, 0);
if (err != 0) {
aloge("cdx_sem_init mWaitDrainPcmSem error!");
goto ERR_EXIT4;
}
//pChnData->res = Creat_Resampler();
//if(pChnData->res == NULL)
//{
// aloge("create resample res error!");
// goto ERR_EXIT4;
//}
pChnData->mfVps = 1;
err = pthread_create(&pChnData->mThreadId, NULL, AOChannel_ComponentThread, pChnData);
if (err) {
eError = FAILURE;
goto ERR_EXIT6;
}
alogd("create AOChannel threadId[0x%lx]", pChnData->mThreadId);
return eError;
ERR_EXIT6:
ERR_EXIT5:
//Destroy_Resampler(pChnData->res);
//pChnData->res = NULL;
cdx_sem_deinit(&pChnData->mWaitDrainPcmSem);
ERR_EXIT4:
cdx_sem_deinit(&pChnData->mAllFrameRelSem);
ERR_EXIT3:
message_destroy(&pChnData->mCmdQueue);
ERR_EXIT2:
pthread_mutex_destroy(&pChnData->mStateLock);
//ERR_EXIT1:
// pcmBufMgrDestroy(pChnData->mpPcmMgr);
ERR_EXIT0:
free(pChnData);
return eError;
}
#ifdef CFG_AUDIO_EFFECT_GAIN
static int audioGainHandle(AO_CHN_DATA_S *pChnData, AUDIO_FRAME_S *pInFrm)
{
AudioGain AGX;
memset(&AGX, 0x00, sizeof(AudioGain));
AGX.InputChan = (pInFrm->mSoundmode==AUDIO_SOUND_MODE_MONO)?1:2;
AGX.OutputChan = AGX.InputChan;
AGX.InputLen = pInFrm->mLen;
AGX.OutputPtr = AGX.InputPtr = (short*)pInFrm->mpAddr;
AGX.preamp = pChnData->mVqeCfg.stGainCfg.s8GainValue;
do_AudioGain(&AGX);
return AGX.InputLen;
}
#endif
#ifdef CFG_AUDIO_EFFECT_EQ
static int audioEQHandle(AO_CHN_DATA_S *pChnData, AUDIO_FRAME_S *pInFrm)
{
short *proc_ptr;
int sample_rate = pChnData->mpAioAttr->enSamplerate;
if (AUDIO_BIT_WIDTH_16 != pInFrm->mBitwidth)
{
aloge("audio pcm format error! bitwidth=%d", pInFrm->mBitwidth);
return FAILURE;
}
eq_prms_t prms[4] =
{
{4, 600, 1, BANDPASS_PEAK, sample_rate},
{4, 1000, 1, BANDPASS_PEAK, sample_rate},
{4, 2000, 2, BANDPASS_PEAK, sample_rate},
{4, 4000, 1, BANDPASS_PEAK, sample_rate},
};
if (pChnData->equalizer == NULL)
{
pChnData->equalizer = eq_create(&prms[0], sizeof(prms)/sizeof(prms[0]));
if (pChnData->equalizer == NULL)
{
aloge("eq create fail!");
return FAILURE;
}
}
proc_ptr = (short*)pInFrm->mpAddr;
int left_item_cnt = sizeof(pInFrm->mLen);
while (left_item_cnt>0)
{
int proc_sz = (left_item_cnt>64)? 64:left_item_cnt;
eq_process(pChnData->equalizer, proc_ptr, proc_sz);
proc_ptr += proc_sz;
left_item_cnt -= proc_sz;
}
return pInFrm->mLen;
}
#endif
#ifdef CFG_AUDIO_EFFECT_RESAMPLE
static int audioResampleHandle(AO_CHN_DATA_S *pChnData, PARAM_INOUT AUDIO_FRAME_S *pInFrm)
{
int outsamples, outlen;
ResCfg cfg;
if (pChnData->res == NULL)
{
pChnData->res = Creat_Resampler();
if (pChnData->res == NULL)
{
aloge("create resample res error!");
return 0;
}
}
cfg.inch = pInFrm->mSoundmode + 1;
cfg.insrt = pChnData->mpPcmCfg->sampleRate;
cfg.inbuf = pInFrm->mpAddr;
cfg.samples = 1024;
cfg.outsrt = pChnData->mVqeCfg.s32WorkSampleRate; // dst sample rate
pChnData->res->prepare(pChnData->res, &cfg);
outsamples = pChnData->res->process(pChnData->res);
outlen = outsamples*2*cfg.inch; // 2: format must be S16_LE
pChnData->res->getData(pChnData->res, pChnData->tmpHandleBuf, outlen);
// update pInFrm with resample process result.
pInFrm->mpAddr = pChnData->tmpHandleBuf;
pInFrm->mLen = outlen;
return outlen;
}
#endif
static int audioEffectProc(AO_CHN_DATA_S *pChnData, PARAM_INOUT AUDIO_FRAME_S *pInFrm)
{
int ret = 0;
{
//alogd("inframe_size=%d", inFrame->mLen);
#ifdef CFG_AUDIO_EFFECT_GAIN
if (pChnData->mVqeCfg.bGainOpen)
{
ret = audioGainHandle(pChnData, pInFrm);
}
#endif
#ifdef CFG_AUDIO_EFFECT_EQ
if (pChnData->mVqeCfg.bEqOpen)
{
ret = audioEQHandle(pChnData, pInFrm);
}
#endif
#ifdef CFG_AUDIO_EFFECT_RESAMPLE
if (((pChnData->mVqeCfg.s32WorkSampleRate >= AUDIO_SAMPLE_RATE_8000) \
&& (pChnData->mVqeCfg.s32WorkSampleRate <= AUDIO_SAMPLE_RATE_48000)) \
&& (pChnData->mVqeCfg.s32WorkSampleRate != pChnData->mpPcmCfg->sampleRate))
{
// pInFrm may be updated!
ret = audioResampleHandle(pChnData, pInFrm);
}
#endif
}
return ret;
}
/*
* may use mpReSmpOutBuf to replace pPcmFrame->mpAddr.
* pPcmFrame is temporary variable, so there is no problem to do this.
*/
static void AOResampleProcess(AO_CHN_DATA_S *pChnData, AUDIO_FRAME_S *pPcmFrame)
{
int ret;
if(pPcmFrame->mSamplerate<=0 || pPcmFrame->mSamplerate>=AUDIO_SAMPLE_RATE_BUTT)
{
aloge("fatal error! pcmFrame sampleRate[%d] is wrong, don't resample!", pPcmFrame->mSamplerate);
return;
}
if(pChnData->mAioAttr.mChnCnt != 1)
{
alogd("Sorry. only support one channel temporary.");
return;
}
if(pChnData->mAioAttr.enBitwidth != pPcmFrame->mBitwidth)
{
aloge("fatal error! bitWidth is not same:%d!=%d", pChnData->mAioAttr.enBitwidth, pPcmFrame->mBitwidth);
}
if(pChnData->mAioAttr.enSamplerate == pPcmFrame->mSamplerate)
{
return;
}
int nLen = pPcmFrame->mLen*((pChnData->mAioAttr.enSamplerate+pPcmFrame->mSamplerate-1)/pPcmFrame->mSamplerate);
if(nLen > pChnData->mReSmpOutBufSize)
{
if(pChnData->mpReSmpOutBuf)
{
free(pChnData->mpReSmpOutBuf);
}
pChnData->mpReSmpOutBuf = malloc(nLen);
if(NULL == pChnData->mpReSmpOutBuf)
{
aloge("fatal error! malloc fail");
}
pChnData->mReSmpOutBufSize = nLen;
}
if(pChnData->mReSmpInSampleRate != pPcmFrame->mSamplerate)
{
alogd("srcSampleRate change:%d->%d", pChnData->mReSmpInSampleRate, pPcmFrame->mSamplerate);
if(pChnData->mpResampler)
{
alogd("need destroy Resampler!");
speex_resampler_destroy(pChnData->mpResampler);
pChnData->mpResampler = NULL;
}
pChnData->mReSmpInSampleRate = pPcmFrame->mSamplerate;
}
if(NULL == pChnData->mpResampler)
{
pChnData->mpResampler = speex_resampler_init(pChnData->mAioAttr.mChnCnt, pPcmFrame->mSamplerate, pChnData->mAioAttr.enSamplerate, 1, NULL);
if(NULL == pChnData->mpResampler)
{
aloge("fatal error! create Resampler fail");
goto _err0;
}
ret = speex_resampler_set_rate(pChnData->mpResampler, pPcmFrame->mSamplerate, pChnData->mAioAttr.enSamplerate);
if(ret != 0)
{
aloge("fatal error! resampler set rate fail[%d]", ret);
goto _err1;
}
}
uint32_t nInSampleCount = pPcmFrame->mLen/(pPcmFrame->mBitwidth+1);
uint32_t nInSampleNum = nInSampleCount;
uint32_t nOutSampleCount = pChnData->mReSmpOutBufSize/(pPcmFrame->mBitwidth+1);
uint32_t nOutSampleNum = nOutSampleCount;
ret = speex_resampler_process_int(pChnData->mpResampler, 0, pPcmFrame->mpAddr, &nInSampleNum, (short*)pChnData->mpReSmpOutBuf, &nOutSampleNum);
if(ret != 0)
{
aloge("fatal error! resample process fail:%d", ret);
}
if(nInSampleCount - nInSampleNum != 0)
{
alogw("fatal error! resample samples: [%d-%d-%d-%d]", nInSampleCount, nInSampleNum, nOutSampleCount, nOutSampleNum);
}
pChnData->mReSmpOutValidLen = nOutSampleNum*(pPcmFrame->mBitwidth+1);
pPcmFrame->mSamplerate = pChnData->mAioAttr.enSamplerate;
pPcmFrame->mpAddr = pChnData->mpReSmpOutBuf;
pPcmFrame->mLen = pChnData->mReSmpOutValidLen;
return;
_err1:
speex_resampler_destroy(pChnData->mpResampler);
pChnData->mpResampler = NULL;
_err0:
return;
}
/**
increase or decrease sample number to implement vps.
*/
static ERRORTYPE AOVpsProcess(AO_CHN_DATA_S *pChnData, AUDIO_FRAME_S *pPcmFrame)
{
ERRORTYPE ret = SUCCESS;
int rc;
int nSampleRate = map_AUDIO_SAMPLE_RATE_E_to_SampleRate(pChnData->mAioAttr.enSamplerate);
int nChnCnt = pChnData->mAioAttr.mChnCnt;
int nBitwidth = map_AUDIO_BIT_WIDTH_E_to_BitWidth(pChnData->mAioAttr.enBitwidth);
float fVps = pChnData->mfVps;
//if vps = 1, don't need process when vps lib has no input data.
if(1 == fVps)
{
if(pChnData->mpVpsSampleConverter)
{
int numInputSamples = sonicGetNumInputSamples(pChnData->mpVpsSampleConverter);
if(numInputSamples <= 0)
{
if(numInputSamples < 0)
{
aloge("fatal error! check sonicStreamStruct input samples:[%d]!", numInputSamples);
}
return ret;
}
else
{
alogd("Be careful! catch it! vps change to 1, but vps lib has [%d] input samples to process, so continue!", numInputSamples);
}
}
else
{
return ret;
}
}
if(NULL == pChnData->mpVpsSampleConverter)
{
//alogd("sampleRate:%d, chnCnt:%d, Bitwidth:%d, fVps:%f", nSampleRate, nChnCnt, nBitwidth, fVps);
pChnData->mpVpsSampleConverter = (void*)sonicCreateStream(nSampleRate, nChnCnt);
if(NULL == pChnData->mpVpsSampleConverter)
{
aloge("fatal error! create sonic stream fail");
}
}
sonicSetSpeed(pChnData->mpVpsSampleConverter, fVps);
int nAlsaFrameLen = (nChnCnt*nBitwidth/8);
if(pPcmFrame->mLen%nAlsaFrameLen != 0)
{
aloge("fatal error! check audio frame![%d-%d-%d]", pPcmFrame->mLen, nChnCnt, nBitwidth);
}
int numSamples = pPcmFrame->mLen/nAlsaFrameLen;
//alogd("numSamples:%d, frameLen:%d, alsaFrameLen:%d", numSamples, pPcmFrame->mLen, nAlsaFrameLen);
rc = sonicWriteShortToStream(pChnData->mpVpsSampleConverter, (short *)pPcmFrame->mpAddr, numSamples);
if(1 == rc)
{
int numOutSamples = numSamples / fVps;
int numMaxOutSamples = numOutSamples + 1024; //must consider previous left datas.
int nOutBufSize = numMaxOutSamples*nAlsaFrameLen;
if(pChnData->mVpsOutBufSize < nOutBufSize)
{
if(pChnData->mpVpsOutBuf)
{
free(pChnData->mpVpsOutBuf);
pChnData->mpVpsOutBuf = NULL;
}
pChnData->mVpsOutBufSize = 0;
pChnData->mVpsOutValidLen = 0;
}
if(NULL == pChnData->mpVpsOutBuf)
{
pChnData->mpVpsOutBuf = (char*)malloc(nOutBufSize);
if(pChnData->mpVpsOutBuf)
{
pChnData->mVpsOutBufSize = nOutBufSize;
pChnData->mVpsOutValidLen = 0;
}
else
{
aloge("fatal error! malloc fail.");
}
}
int nOutputSamples = sonicReadShortFromStream(pChnData->mpVpsSampleConverter, (short *)pChnData->mpVpsOutBuf, numMaxOutSamples);
if(nOutputSamples != numOutSamples)
{
//alogd("outputSamples diff:[%d, %d-%d=%d]", numMaxOutSamples, nOutputSamples, numOutSamples, nOutputSamples - numOutSamples);
}
else
{
//alogd("outputSamples diff-none:[%d, %d-%d=%d]", numMaxOutSamples, nOutputSamples, numOutSamples, nOutputSamples - numOutSamples);
}
pChnData->mVpsOutValidLen = nOutputSamples*nAlsaFrameLen;
pPcmFrame->mpAddr = pChnData->mpVpsOutBuf;
pPcmFrame->mLen = pChnData->mVpsOutValidLen;
}
else
{
aloge("fatal error! ret:%d, check code!", rc);
ret = FAILURE;
}
return ret;
}
#define AUDIO_RENDER_FIRST_FRAME_FLAG 1
#define AUDIO_RENDER_INIT_RENDER_FLAG 2
static void *AOChannel_ComponentThread(void *pThreadData)
{
unsigned int cmddata;
CompInternalMsgType cmd;
message_t cmdmsg;
AO_CHN_DATA_S *pChnData = (AO_CHN_DATA_S*)pThreadData;
ERRORTYPE eError;
MM_COMPONENTTYPE *pClkTunnelComp = NULL;
MM_COMPONENTTYPE *pADecTunnelComp = NULL;
COMP_INTERNAL_TUNNELINFOTYPE* pClkTunnel = NULL;
COMP_INTERNAL_TUNNELINFOTYPE* pADecTunnel = NULL;
alogv("AO channel ComponentThread start run...");
sprintf(pChnData->mThreadName, "AOChn[%d-%d]", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
prctl(PR_SET_NAME, (unsigned long)pChnData->mThreadName, 0, 0, 0);
long long RelativeTime = 0;
long long CurrentTime;
pChnData->audio_rend_flag = AUDIO_RENDER_FIRST_FRAME_FLAG | AUDIO_RENDER_INIT_RENDER_FLAG;
while (1) {
PROCESS_MESSAGE:
if (get_message(&pChnData->mCmdQueue, &cmdmsg) == 0) {
cmd = cmdmsg.command;
cmddata = (unsigned int)cmdmsg.para0;
if (cmd == SetState) {
//alogv("cmd=SetState, cmddata=%d", cmddata);
pthread_mutex_lock(&pChnData->mStateLock);
if (pChnData->state == (COMP_STATETYPE) (cmddata)) {
CompSendEvent(pChnData, COMP_EventError, ERR_AO_SAMESTATE, 0);
} else {
switch ((COMP_STATETYPE)cmddata) {
case COMP_StateInvalid:
{
pChnData->state = COMP_StateInvalid;
CompSendEvent(pChnData, COMP_EventError, ERR_AO_INVALIDSTATE, 0);
CompSendEvent(pChnData, COMP_EventCmdComplete, COMP_CommandStateSet, pChnData->state);
break;
}
case COMP_StateLoaded:
{
if (pChnData->state != COMP_StateIdle)
{
aloge("fatal error! AO incorrect state transition [0x%x]->Loaded!", pChnData->state);
CompSendEvent(pChnData, COMP_EventError, ERR_AO_INCORRECT_STATE_TRANSITION, 0);
}
ERRORTYPE omxRet;
//release all frames.
alogd("release all frames to ADec, when state[0x%x]->[0x%x]", pChnData->state, COMP_StateLoaded);
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
if(!list_empty(&pChnData->mAudioInputFrameUsedList))
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pChnData->mAudioInputFrameUsedList)
{
cnt++;
}
alogd("release [%d]used inputFrame!", cnt);
AOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pChnData->mAudioInputFrameUsedList, mList)
{
AOReleaseFrame_l(pChnData, pEntry);
}
}
if(!list_empty(&pChnData->mAudioInputFrameReadyList))
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pChnData->mAudioInputFrameReadyList)
{
cnt++;
}
alogd("release [%d]ready inputFrame!", cnt);
AOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pChnData->mAudioInputFrameReadyList, mList)
{
AOReleaseFrame_l(pChnData, pEntry);
}
}
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
pChnData->state = COMP_StateLoaded;
CompSendEvent(pChnData, COMP_EventCmdComplete, COMP_CommandStateSet, pChnData->state);
break;
}
case COMP_StateIdle:
{
if (pChnData->state == COMP_StateInvalid) {
CompSendEvent(pChnData, COMP_EventError, ERR_AO_INCORRECT_STATE_OPERATION, 0);
} else {
pChnData->state = COMP_StateIdle;
pChnData->mbEof = FALSE;
CompSendEvent(pChnData, COMP_EventCmdComplete, COMP_CommandStateSet, pChnData->state);
}
break;
}
case COMP_StateExecuting:
{
// Transition can only happen from pause or idle state
if (pChnData->state == COMP_StateIdle || pChnData->state == COMP_StatePause)
{
pClkTunnel = &pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_CLK];
pClkTunnelComp = (MM_COMPONENTTYPE*)(pClkTunnel->hTunnel);
//pADecTunnel = &pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_IN_PCM];
//pADecTunnelComp = (MM_COMPONENTTYPE*)(pADecTunnel->hTunnel);
if (pChnData->state == COMP_StateIdle)
{
pChnData->audio_rend_flag |= AUDIO_RENDER_FIRST_FRAME_FLAG;
if (!pChnData->av_sync)
pChnData->start_to_play = TRUE;
else
pChnData->start_to_play = FALSE;
pChnData->wait_time_out = 0;
if (pChnData->seek_flag)
{
alogd("seek in idle state?");
pChnData->seek_flag = 0;
}
}
else if (pChnData->state == COMP_StatePause)
{
//if current Pause is caused by jump, we need set first frame flag. Because we need reset start_time to clock_component.
if(pChnData->seek_flag)
{
pChnData->audio_rend_flag |= AUDIO_RENDER_FIRST_FRAME_FLAG;
if (!pChnData->av_sync)
pChnData->start_to_play = TRUE;
else
pChnData->start_to_play = FALSE;
pChnData->wait_time_out = 0;
pChnData->seek_flag = 0;
}
}
if (pChnData->priv_flag & CDX_comp_PRIV_FLAGS_REINIT)
{
alogd("pChnData->priv_flag = %#x, reinit AudioRender...", pChnData->priv_flag);
pChnData->audio_rend_flag |= AUDIO_RENDER_INIT_RENDER_FLAG;
pChnData->priv_flag &= ~CDX_comp_PRIV_FLAGS_REINIT;
}
if (pChnData->state == COMP_StatePause)
{
//*resume the audio track.
if (!(pChnData->audio_rend_flag & AUDIO_RENDER_INIT_RENDER_FLAG))
{
}
}
pChnData->state = COMP_StateExecuting;
CompSendEvent(pChnData, COMP_EventCmdComplete, COMP_CommandStateSet, pChnData->state);
}
else
{
CompSendEvent(pChnData, COMP_EventError, ERR_AO_INCORRECT_STATE_OPERATION, 0);
}
break;
}
case COMP_StatePause:
{
if (pChnData->state == COMP_StateIdle || pChnData->state == COMP_StateExecuting)
{
pChnData->state = COMP_StatePause;
CompSendEvent(pChnData, COMP_EventCmdComplete, COMP_CommandStateSet, pChnData->state);
}
else
{
CompSendEvent(pChnData, COMP_EventError, ERR_AO_INCORRECT_STATE_OPERATION, 0);
}
break;
}
default:
break;
}
}
pthread_mutex_unlock(&pChnData->mStateLock);
} else if (cmd == AOChannel_InputPcmAvailable) {
//pChnData->mWaitInputFrameFlag = FALSE;
//alogv("AOChannel_InputPcmAvailable");
} else if (cmd == AOChannel_OutBufAvailable) {
alogv("AOChannel_OutBufAvailable. But NOT use!");
} else if (cmd == StopPort) {
} else if (cmd == Stop) {
goto EXIT;
}
goto PROCESS_MESSAGE;
}
if (pChnData->state != COMP_StateExecuting)
{
alogv("AO channel Component state[0x%x] not OMX_StateExecuting", pChnData->state);
TMessage_WaitQueueNotEmpty(&pChnData->mCmdQueue, 0);
goto PROCESS_MESSAGE;
}
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
if (pChnData->mbEof)
{
alogd("AO EOF!");
int cnt = 0;
AOGetInputFrames(pChnData);
if (!list_empty(&pChnData->mAudioInputFrameUsedList))
{
AOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pChnData->mAudioInputFrameUsedList, mList)
{
AOReleaseFrame_l(pChnData, pEntry);
cnt++;
}
}
if(cnt > 0)
{
alogd("release [%d]audio frames when eof!", cnt);
}
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
TMessage_WaitQueueNotEmpty(&pChnData->mCmdQueue, 0);
goto PROCESS_MESSAGE;
}
ERRORTYPE ret;
COMP_TIME_CONFIG_TIMESTAMPTYPE time_stamp;
ret = AOGetInputFrames(pChnData);
if(ret == SUCCESS)
{
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
}
else if (!list_empty(&pChnData->mAudioInputFrameUsedList))
{
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
}
else
{
pChnData->mWaitInputFrameFlag = TRUE;
if (pChnData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
alogd("A. AOChn[%d-%d] notify player eof!", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
if (pChnData->mWaitDrainPcmSemFlag)
{
alogd("AOChn[%d-%d] drain pcm ring buf!", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
int64_t tm1,tm2;
tm1 = CDX_GetSysTimeUsMonotonic();
if(audioHw_AO_IsDevStarted(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId))
{
audioHw_AO_DrainPcmRingBuf(pChnData->mMppChnInfo.mDevId,pChnData->mMppChnInfo.mChnId);
}
else
{
aloge("fatal error! AOChn[%d-%d] is not start, so do not drain!", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
}
tm2 = CDX_GetSysTimeUsMonotonic();
pChnData->mWaitDrainPcmSemFlag = FALSE;
alogd("AOChn[%d-%d] drain pcm ring buf done, cost[%lld]ms!", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId, (tm2-tm1)/1000);
//cdx_sem_up(&pChnData->mWaitDrainPcmSem);
}
//pChnData->state = COMP_StateIdle;
CompSendEvent(pChnData, COMP_EventBufferFlag, COMP_CommandStateSet, 0);
pChnData->mbEof = TRUE;
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
goto PROCESS_MESSAGE;
}
else
{
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
}
TMessage_WaitQueueNotEmpty(&pChnData->mCmdQueue, 0);
goto PROCESS_MESSAGE;
}
if (pChnData->audio_rend_flag & AUDIO_RENDER_FIRST_FRAME_FLAG) {
AOCompInputFrame *pNode = list_first_entry(&pChnData->mAudioInputFrameUsedList, AOCompInputFrame, mList);
AUDIO_FRAME_S *pFirstFrame = &pNode->mAFrame;
alogd("AO get first pcm from ADec, nBufferLen: %d, nTimeStamp:%lldus, param[%d-%d-%d],use it to init AudioRenderHal",
pFirstFrame->mLen, pFirstFrame->mTimeStamp, pFirstFrame->mSamplerate, pFirstFrame->mBitwidth, pFirstFrame->mSoundmode);
if (pChnData->audio_rend_flag & AUDIO_RENDER_INIT_RENDER_FLAG) {
AIO_ATTR_S aio_attr;
memset(&aio_attr, 0, sizeof(aio_attr));
aio_attr.mPcmCardId = pChnData->card_id;
aio_attr.enSamplerate = pFirstFrame->mSamplerate;
aio_attr.enBitwidth = pFirstFrame->mBitwidth;
aio_attr.mChnCnt = pFirstFrame->mSoundmode==AUDIO_SOUND_MODE_MONO ? 1:2;
audioHw_AO_Dev_lock(pChnData->mMppChnInfo.mDevId);
if(!audioHw_AO_IsDevConfigured(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId))
{
alogd("audioDev[%d-%d] is not config, config it now, [%d-%d-%d-%d]", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId,
aio_attr.mPcmCardId, aio_attr.enSamplerate, aio_attr.enBitwidth, aio_attr.mChnCnt);
audioHw_AO_SetChnPubAttr(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId, &aio_attr);
}
audioHw_AO_GetChnPubAttr(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId, &pChnData->mAioAttr);
if(!audioHw_AO_IsDevStarted(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId))
{
alogd("audioDev[%d-%d] is not start, start it now", pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
audioHw_AO_EnableChn(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId);
}
audioHw_AO_Dev_unlock(pChnData->mMppChnInfo.mDevId);
alogd("audio render hal init and run ok:%d!",(pChnData->mMppChnInfo.mChnId));
pChnData->audio_rend_flag &= ~AUDIO_RENDER_INIT_RENDER_FLAG;
}
if (NULL != pClkTunnelComp)
{
time_stamp.nPortIndex = pClkTunnel->nTunnelPortIndex;
time_stamp.nTimestamp = pFirstFrame->mTimeStamp;
//set audio start time.
alogd("AO set config start_time to [%lld]us", time_stamp.nTimestamp);
pClkTunnelComp->SetConfig(pClkTunnelComp, COMP_IndexConfigTimeClientStartTime, &time_stamp);
RelativeTime = pFirstFrame->mTimeStamp;
//wait 1.
while(pChnData->start_to_play != TRUE)
{
alogd("AO wait 50ms for flag change...");
usleep(50*1000);
if (pChnData->wait_time_out > 20)
{
alogw("AO wait too long, force clock component to start.");
pClkTunnelComp->SetConfig(pClkTunnelComp, COMP_IndexVendorConfigTimeClientForceStart, &time_stamp);
pChnData->wait_time_out = 0;
}
pChnData->wait_time_out++;
if (get_message_count(&pChnData->mCmdQueue) > 0)
{
alogd("AO detect message come when start_to_play is not ture!");
goto PROCESS_MESSAGE;
}
}
}
pChnData->audio_rend_flag &= ~AUDIO_RENDER_FIRST_FRAME_FLAG;
}
if (NULL == pChnData->mpCurrentInputFrame)
{
pthread_mutex_lock(&pChnData->mInputFrameListMutex);
if (!list_empty(&pChnData->mAudioInputFrameUsedList))
{
pChnData->mpCurrentInputFrame = list_first_entry(&pChnData->mAudioInputFrameUsedList, AOCompInputFrame, mList);
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
}
else
{
alogw("Why no node in UsedList?! Impossible!!!");
pthread_mutex_unlock(&pChnData->mInputFrameListMutex);
goto PROCESS_MESSAGE;
}
}
AUDIO_FRAME_S *pPcmFrame = &(pChnData->mpCurrentInputFrame->mAFrame);
if (NULL != pClkTunnelComp)
{
pClkTunnelComp->GetConfig(pClkTunnelComp, COMP_IndexConfigTimeCurrentMediaTime, &time_stamp);
CurrentTime = pPcmFrame->mTimeStamp;
if (pChnData->is_ref_clock && CurrentTime - RelativeTime > AVS_ADJUST_PERIOD)
{
//avs_adjust_period is based on media clock time coordinate.
//alogv("AO adjust av clock, AudioPts:Cur[%lld], Relative[%lld]", CurrentTime, RelativeTime);
time_stamp.nTimestamp = pPcmFrame->mTimeStamp;
pClkTunnelComp->SetConfig(pClkTunnelComp, COMP_IndexVendorAdjustClock, &time_stamp);
RelativeTime = CurrentTime;
}
}
AUDIO_FRAME_S tmpPcmFrame = *pPcmFrame;
if(pChnData->mbEnableReSmp)
{
AOResampleProcess(pChnData, &tmpPcmFrame);
}
AOVpsProcess(pChnData, &tmpPcmFrame);
#if (MPPCFG_SOFTDRC == OPTION_SOFTDRC_ENABLE)
if (pChnData->mUseDrcLib)
{
drcLog_process(pChnData->mDrc,tmpPcmFrame.mpAddr,tmpPcmFrame.mLen/2,1);
}
#endif
if (pChnData->mUseVqeLib)
{
ret = audioEffectProc(pChnData, &tmpPcmFrame);
}
#if (MPPCFG_AGC == OPTION_AGC_ENABLE)
pthread_mutex_lock(&pChnData->mAgcLock);
if (pChnData->mUseAgcLib)
{
if(NULL == pChnData->mpAgcHandle)
{
AOAgcInit(pChnData->hSelf);
}
if(pChnData->mpAgcHandle)
{
if(pChnData->mnAgcTmpBuffLen < tmpPcmFrame.mLen)
{
if(pChnData->mpAgcTmpBuff)
{
free(pChnData->mpAgcTmpBuff);
pChnData->mpAgcTmpBuff = NULL;
}
pChnData->mpAgcTmpBuff = (short*)malloc(tmpPcmFrame.mLen);
if(pChnData->mpAgcTmpBuff)
{
pChnData->mnAgcTmpBuffLen = tmpPcmFrame.mLen;
}
else
{
aloge("fatal error! malloc fail!");
pChnData->mnAgcTmpBuffLen = 0;
}
}
int nBitWidth = map_AUDIO_BIT_WIDTH_E_to_BitWidth(pChnData->mAioAttr.enBitwidth);
int nSampleNum = tmpPcmFrame.mLen/(nBitWidth/8); //samples in all channels, not alsa frame.
ret = func_agc_proc((agc_handle*)pChnData->mpAgcHandle, (short*)tmpPcmFrame.mpAddr, pChnData->mpAgcTmpBuff, nSampleNum);
if (0 == ret)
{
memcpy(tmpPcmFrame.mpAddr, (void*)pChnData->mpAgcTmpBuff, tmpPcmFrame.mLen);
}
else
{
aloge("fatal error! func agc_proc failed[%d]", ret);
}
}
else
{
aloge("fatal error! agc float lib not create?");
}
}
pthread_mutex_unlock(&pChnData->mAgcLock);
#endif
{
MM_COMPONENTTYPE *pAiTunnelComp;
COMP_INTERNAL_TUNNELINFOTYPE *pAiTunnel;
COMP_BUFFERHEADERTYPE obh;
pAiTunnel = &pChnData->sPortTunnelInfo[AO_CHN_PORT_INDEX_OUT_AI];
pAiTunnelComp = (MM_COMPONENTTYPE*)(pAiTunnel->hTunnel);
if (pAiTunnelComp != NULL)
{
AUDIO_FRAME_S frame = tmpPcmFrame;
obh.nOutputPortIndex = pAiTunnel->nTunnelPortIndex;
obh.pOutputPortPrivate = &frame;
pAiTunnelComp->EmptyThisBuffer(pAiTunnelComp, &obh);
}
}
if (pChnData->mSaveFileFlag)
{
fwrite(tmpPcmFrame.mpAddr, 1, tmpPcmFrame.mLen, pChnData->mFpSaveFile);
pChnData->mSaveFileSize += tmpPcmFrame.mLen;
}
if(pChnData->mbMute)
{
if((pChnData->pMuteBuf != NULL) && (pChnData->nMuteBufSize < tmpPcmFrame.mLen))
{
free(pChnData->pMuteBuf);
pChnData->pMuteBuf = NULL;
}
if(NULL == pChnData->pMuteBuf)
{
pChnData->pMuteBuf = (char*)malloc(tmpPcmFrame.mLen);
if(NULL == pChnData->pMuteBuf)
{
aloge("fatal error! malloc fail!");
}
pChnData->nMuteBufSize = tmpPcmFrame.mLen;
memset(pChnData->pMuteBuf, 0, pChnData->nMuteBufSize);
}
//change tmpPcmFrame's buf to muteBuf;
tmpPcmFrame.mpAddr = pChnData->pMuteBuf;
}
ret = audioHw_AO_FillPcmRingBuf(pChnData->mMppChnInfo.mDevId, pChnData->mMppChnInfo.mChnId, tmpPcmFrame.mpAddr, tmpPcmFrame.mLen);
if (ret != SUCCESS)
{
aloge("fatal error! send to alsaLib fail[0x%x], but still release frame", ret);
}
AOReleaseFrame(pChnData, pChnData->mpCurrentInputFrame);
pChnData->mpCurrentInputFrame = NULL;
}
EXIT:
alogv("AO channel ComponentThread stop!");
return NULL;
}