2096 lines
77 KiB
C
2096 lines
77 KiB
C
|
/******************************************************************************
|
||
|
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;
|
||
|
}
|