sdk-hwV1.3/external/eyesee-mpp/middleware/sun8iw21/media/audio/aec/WebRtcAec.c

344 lines
11 KiB
C

#define LOG_NDEBUG 0
#define LOG_TAG "WebRtcAec"
#include <utils/plat_log.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <media_common_aio.h>
#include <aec_lib.h>
#include "WebRtcAec.h"
WebRtcAecContext* ConstructWebRtcAecContext()
{
WebRtcAecContext *pCtx = (WebRtcAecContext*)malloc(sizeof(WebRtcAecContext));
if(NULL == pCtx)
{
aloge("fatal error! malloc fail");
}
memset(pCtx, 0, sizeof(*pCtx));
#ifdef AI_HW_AEC_DEBUG_EN
pCtx->tmp_pcm_fp_in = fopen("/mnt/extsd/tmp_in_ai_pcm", "wb");
pCtx->tmp_pcm_fp_ref = fopen("/mnt/extsd/tmp_ref_ai_pcm", "wb");
pCtx->tmp_pcm_fp_out = fopen("/mnt/extsd/tmp_out_ai_pcm", "wb");
if(NULL==pCtx->tmp_pcm_fp_in || NULL==pCtx->tmp_pcm_fp_ref || NULL==pCtx->tmp_pcm_fp_out)
{
aloge("fatal error! aec_debug_file_create_failed");
}
#endif
return pCtx;
}
void DestructWebRtcAecContext(WebRtcAecContext *pCtx)
{
int ret;
if(NULL != pCtx->aecmInst)
{
ret = WebRtcAec_Free(pCtx->aecmInst);
if(0 == ret)
{
//aloge("aec_released");
pCtx->aecmInst = NULL;
}
else
{
aloge("fatal error! aec_free_failed");
}
}
if(NULL != pCtx->tmpBuf)
{
free(pCtx->tmpBuf);
pCtx->tmpBuf = NULL;
}
if(NULL != pCtx->out_buff)
{
free(pCtx->out_buff);
pCtx->out_buff = NULL;
}
if(NULL != pCtx->ref_buff)
{
free(pCtx->ref_buff);
pCtx->ref_buff = NULL;
}
if(NULL != pCtx->near_buff)
{
free(pCtx->near_buff);
pCtx->near_buff = NULL;
}
#ifdef AI_HW_AEC_DEBUG_EN
if(NULL != pCtx->tmp_pcm_fp_in)
{
fclose(pCtx->tmp_pcm_fp_in);
pCtx->tmp_pcm_fp_in = NULL;
}
if(NULL != pCtx->tmp_pcm_fp_ref)
{
fclose(pCtx->tmp_pcm_fp_ref);
pCtx->tmp_pcm_fp_ref = NULL;
}
if(NULL != pCtx->tmp_pcm_fp_out)
{
fclose(pCtx->tmp_pcm_fp_out);
pCtx->tmp_pcm_fp_out = NULL;
}
#endif
free(pCtx);
}
/**
implement of AecProcessFuncType.
*/
int WebRtcAecProcess(void *cookie, AUDIO_FRAME_S *pFrm, BOOL bSuspendAec)
{
int rc;
int ret;
int aec_delay_ms = 0;
//webrtc only supports 1chn1ref.
if(pFrm->mSoundmode != AUDIO_SOUND_MODE_AW_1Chn1Ref)
{
aloge("fatal error! WebRtcAec invalid sound mode:%d", pFrm->mSoundmode);
return -1;
}
int nSampleRate = (int)map_AUDIO_SAMPLE_RATE_E_to_SampleRate(pFrm->mSamplerate);
int nBitWidth = (int)map_AUDIO_BIT_WIDTH_E_to_BitWidth(pFrm->mBitwidth);
if(nBitWidth != 16)
{
aloge("fatal error! bitWidth[%d] must be 16!", nBitWidth);
}
int nChnNum = 2;
int nChnLen = pFrm->mLen/nChnNum; //unit: bytes
WebRtcAecContext *pCtx = (WebRtcAecContext*)cookie;
if(NULL == pCtx->aecmInst)
{
alogv("aec_to_init:%d", nSampleRate);
ret = WebRtcAec_Create(&pCtx->aecmInst);
if(NULL == pCtx->aecmInst || 0 != ret)
{
aloge("fatal error! aec_instance_create_fail:%d", ret);
return -1;
}
ret = WebRtcAec_Init(pCtx->aecmInst, nSampleRate, nSampleRate);
if(0 != ret)
{
aloge("fatal error! aec_init_failed:%d", ret);
}
AecConfig config;
memset(&config,0,sizeof(AecConfig));
config.nlpMode = kAecNlpConservative;
ret = WebRtcAec_set_config(pCtx->aecmInst, config);
if(0 != ret)
{
aloge("fatal error! aec_cfg_failed:%d", ret);
}
}
if(NULL == pCtx->near_buff)
{
pCtx->near_buff = (short *)malloc(nChnLen*2);
if(NULL == pCtx->near_buff)
{
aloge("fatal error! malloc fail:%d", nChnLen*2);
}
pCtx->near_buff_len = nChnLen*2;
pCtx->near_buff_data_remain_len = 0;
}
else
{
if(pCtx->near_buff_len != nChnLen*2)
{
aloge("fatal error! why aec near buf len wrong?[%d != %d*2]", pCtx->near_buff_len, nChnLen);
}
}
if(NULL == pCtx->ref_buff)
{
pCtx->ref_buff = (short *)malloc(nChnLen*2);
if(NULL == pCtx->ref_buff)
{
aloge("fatal error! malloc fail:%d", nChnLen*2);
}
pCtx->ref_buff_len = nChnLen*2;
pCtx->ref_buff_data_remain_len = 0;
}
else
{
if(pCtx->ref_buff_len != nChnLen*2)
{
aloge("fatal error! why aec ref buf len wrong?[%d != %d*2]", pCtx->ref_buff_len, nChnLen);
}
}
if(NULL == pCtx->out_buff)
{
pCtx->out_buff = (short *)malloc(nChnLen*2);
if(NULL == pCtx->out_buff)
{
aloge("fatal error! malloc fail:%d", nChnLen*2);
}
pCtx->out_buff_len = nChnLen*2;
pCtx->out_buff_data_remain_len = 0;
}
else
{
if(pCtx->out_buff_len != nChnLen*2)
{
aloge("fatal error! why aec out buf len wrong?[%d != %d*2]", pCtx->out_buff_len, nChnLen);
}
}
if(NULL == pCtx->tmpBuf)
{
pCtx->tmpBuf = (short *)malloc(nChnLen*2);
if(NULL == pCtx->tmpBuf)
{
aloge("fatal error! malloc fail:%d", nChnLen*2);
}
pCtx->tmpBufLen = nChnLen*2;
}
else
{
if(pCtx->tmpBufLen != nChnLen*2)
{
aloge("fatal error! why aec out tmp buf len wrong?[%d != %d*2]", pCtx->tmpBufLen, nChnLen);
}
}
// move data in near buffer and reference buffer to internal buffer for conjunction with remaining data for last process.
if(pCtx->near_buff_data_remain_len != pCtx->ref_buff_data_remain_len)
{
aloge("fatal error! capture and ref remain data: %d!=%d bytes", pCtx->near_buff_data_remain_len, pCtx->ref_buff_data_remain_len);
}
if(pCtx->near_buff_data_remain_len + nChnLen <= pCtx->near_buff_len)
{
short *pNearStart = (short*)((char*)pCtx->near_buff + pCtx->near_buff_data_remain_len);
short *pRefStart = (short*)((char*)pCtx->ref_buff + pCtx->ref_buff_data_remain_len);
short *pAudFrameStart = (short*)pFrm->mpAddr;
int nFrameSize = nChnLen/(nBitWidth/8); //one frame contain the number of alsaFrames.
for(int i = 0; i < nFrameSize; i++)
{
//assume sample length is 16bit.
pNearStart[i] = pAudFrameStart[2*i];
pRefStart[i] = pAudFrameStart[2*i + 1];
}
pCtx->near_buff_data_remain_len += nFrameSize*(nBitWidth/8);
pCtx->ref_buff_data_remain_len += nFrameSize*(nBitWidth/8);
}
else
{
aloge("fatal error! _near_buff_over_flow:%d-%d-%d-%d", pCtx->near_buff_data_remain_len, pCtx->near_buff_len, nChnLen, pFrm->mLen);
}
int frm_size = 160; // 160 samples as one unit processed by aec library
short tmp_near_buffer[160]; //captureMic data
short tmp_far_buffer[160]; //ref data(i.d. daudio0 data)
short *near_frm_ptr = (short *)pCtx->near_buff;
short *ref_frm_ptr = (short *)pCtx->ref_buff;
short *processed_frm_ptr = (short *)pCtx->tmpBuf;
int size = pCtx->near_buff_data_remain_len; //bytes
int left = size / sizeof(short); //sample number.
// start to process
while(left >= frm_size)
{
memcpy((char *)tmp_near_buffer, (char *)near_frm_ptr, frm_size*sizeof(short));
memcpy((char*)tmp_far_buffer, (char*)ref_frm_ptr, frm_size*sizeof(short));
if (FALSE == bSuspendAec)
{
ret = WebRtcAec_BufferFarend(pCtx->aecmInst, tmp_far_buffer, frm_size);
if(0 != ret)
{
aloge("fatal error! aec_insert_far_data_failed:%d-%d", ret, ((aecpc_t*)pCtx->aecmInst)->lastError);
}
ret = WebRtcAec_Process(pCtx->aecmInst, tmp_near_buffer, NULL, processed_frm_ptr, NULL, frm_size, aec_delay_ms, 0);
if(0 != ret)
{
aloge("aec_process_failed:%d-%d", ret, ((aecpc_t*)pCtx->aecmInst)->lastError);
}
}
else
{
memcpy(processed_frm_ptr, near_frm_ptr, frm_size*sizeof(short));
}
#ifdef AI_HW_AEC_DEBUG_EN
if(NULL != pCtx->tmp_pcm_fp_in)
{
fwrite(tmp_near_buffer, 1, frm_size*sizeof(short), pCtx->tmp_pcm_fp_in);
pCtx->tmp_pcm_in_size += frm_size*sizeof(short);
}
if(NULL != pCtx->tmp_pcm_fp_ref)
{
fwrite(tmp_far_buffer, 1, frm_size*sizeof(short), pCtx->tmp_pcm_fp_ref);
pCtx->tmp_pcm_ref_size += frm_size*sizeof(short);
}
// aloge("zjx_tbin:%d-%d",pCap->tmp_pcm_in_size,pCap->tmp_pcm_ref_size);
#endif
near_frm_ptr += frm_size;
ref_frm_ptr += frm_size;
processed_frm_ptr += frm_size;
left -= frm_size;
pCtx->near_buff_data_remain_len -= frm_size*sizeof(short);
pCtx->ref_buff_data_remain_len -= frm_size*sizeof(short);
}
// move remaining data in internal buffer to the beginning of the buffer
if(left > 0)
{
memmove((char*)pCtx->near_buff, (char*)near_frm_ptr, pCtx->near_buff_data_remain_len);
memmove((char*)pCtx->ref_buff, (char*)ref_frm_ptr, pCtx->ref_buff_data_remain_len);
}
unsigned int out_offset = (unsigned int)processed_frm_ptr - (unsigned int)pCtx->tmpBuf;
// move the out data produced by aec library to the internal buffer for conjunction with remaining data left for last process
if(out_offset + pCtx->out_buff_data_remain_len > pCtx->out_buff_len)
{
aloge("fatal error! aec_out_buff_over_flow:%d-%d-%d", out_offset, pCtx->out_buff_data_remain_len, pCtx->out_buff_len);
}
else
{
memcpy((char *)pCtx->out_buff + pCtx->out_buff_data_remain_len, (char *)pCtx->tmpBuf, out_offset);
pCtx->out_buff_data_remain_len += out_offset;
}
// fetch one valid output frame from output internal buffer, the length of valid frame must equal to chunsize.
if(pCtx->out_buff_data_remain_len >= nChnLen)
{
memcpy((char *)pFrm->mpAddr, (char *)pCtx->out_buff, nChnLen);
pFrm->mLen = nChnLen;
pCtx->out_buff_data_remain_len -= nChnLen;
pFrm->mSoundmode = AUDIO_SOUND_MODE_MONO;
#ifdef AI_HW_AEC_DEBUG_EN
if(NULL != pCtx->tmp_pcm_fp_out)
{
fwrite(pFrm->mpAddr, 1, pFrm->mLen, pCtx->tmp_pcm_fp_out);
pCtx->tmp_pcm_out_size += pFrm->mLen;
}
// aloge("zjx_tbo:%d-%d-%d",pCap->tmp_pcm_out_size,pFrm->mLen,pCap->mCfg.chunkSize*sizeof(short));
#endif
if(pCtx->out_buff_data_remain_len > nChnLen)
{
aloge("fatal error! aec_out_buff_data too long:%d-%d", nChnLen, pCtx->out_buff_data_remain_len);
}
memmove((char *)pCtx->out_buff, ((char *)pCtx->out_buff+nChnLen), pCtx->out_buff_data_remain_len);
rc = 0;
}
else
{
rc = 1;
}
return rc;
}