344 lines
11 KiB
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;
|
|
}
|
|
|