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

369 lines
12 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
#define LOG_NDEBUG 0
#define LOG_TAG "WebRtcAec"
#include <utils/plat_log.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <SystemBase.h>
#include <mm_comm_aio.h>
#include <media_common_aio.h>
#include <uvoice_ecnr_api.h>
#include <uvoice_license.h>
#include "UvoiceAec.h"
//#define AI_HW_AEC_DEBUG_EN
static UvEcnr_InputMode judgeUvEcnr_InputMode(AUDIO_SOUND_MODE_E eSoundmode)
{
UvEcnr_InputMode eUvMode;
if(AUDIO_SOUND_MODE_AW_1Chn1Ref == eSoundmode)
{
eUvMode = uvoice_ecnr_mode_1mic1ref;
}
else if(AUDIO_SOUND_MODE_AW_2Chn1Ref == eSoundmode)
{
eUvMode = uvoice_ecnr_mode_2mic1ref;
}
else
{
aloge("fatal error! not support sound mode:%d", eSoundmode);
eUvMode = uvoice_ecnr_mode_1mic1ref;
}
return eUvMode;
}
static AUDIO_DEV sgUvAudioDevId;
static AudioDevCallbackFuncType sgUvAudioDevCallback;
static void *sgUvAudioDevCookie;
/**
get server return string to take it to generate license file.
shell command is:
curl -k -s --data-binary $body https://srv01.51asr.com:8007/asrsn_active2
*/
static const char* uvoice_auth_cb(const char* body)
{
//alogd("Body is:%s", body);
UvoiceServerHandshake stHandshake;
memset(&stHandshake, 0, sizeof(stHandshake));
stHandshake.pPostBody = body;
ERRORTYPE ret = sgUvAudioDevCallback(sgUvAudioDevCookie, sgUvAudioDevId, AudioDevEvent_GetUvoiceServerResponse, 0, (void*)&stHandshake);
if(SUCCESS == ret)
{
return strdup(stHandshake.response);
}
else
{
aloge("fatal error! get uvoice server response fail[0x%x]", ret);
return "";
}
}
UvoiceAecContext* ConstructUvoiceAecContext(AIO_ATTR_S *pAttr, PCM_CONFIG_S *pCfg, AudioDevCallbackFuncType pAudioDevCallback,
void *pAudioDevCookie, AUDIO_DEV AudioDevId)
{
sgUvAudioDevId = AudioDevId;
sgUvAudioDevCallback = pAudioDevCallback;
sgUvAudioDevCookie = pAudioDevCookie;
UvoiceLicenseParam stUvLicenseParam;
memset(&stUvLicenseParam, 0, sizeof(stUvLicenseParam));
if(pAudioDevCallback)
{
pAudioDevCallback(pAudioDevCookie, AudioDevId, AudioDevEvent_GetUvoiceLicenseParam, 0, (void*)&stUvLicenseParam);
}
else
{
aloge("fatal error! audioDev[%d] is not set callback!", AudioDevId);
}
int nChnNum = 0;
int nMicChnNum = 0;
int nRefChnNum = 0;
AUDIO_SOUND_MODE_E eInitialSoundMode = judgeInitialSoundModeOfAudioInput(pAttr);
nChnNum = judgeAudioChnNumBySoundMode(eInitialSoundMode, &nMicChnNum, &nRefChnNum);
if(nChnNum > MAX_MICIN_NUM || nMicChnNum > MAX_MICIN_NUM || nRefChnNum > MAX_REFIN_NUM)
{
aloge("fatal error! audio channel number overflow, check code! [%d-%d-%d]", nChnNum, nMicChnNum, nRefChnNum);
return NULL;
}
int nSampleRate = (int)map_AUDIO_SAMPLE_RATE_E_to_SampleRate(pAttr->enSamplerate);
int nChnLen = pCfg->chunkBytes/nChnNum;
int i;
uvoice_ecnr_status st;
UvoiceAecContext *pCtx = (UvoiceAecContext*)malloc(sizeof(UvoiceAecContext));
if(NULL == pCtx)
{
aloge("fatal error! malloc fail");
}
memset(pCtx, 0, sizeof(*pCtx));
UvEcnr_InputMode eInputMode = judgeUvEcnr_InputMode(eInitialSoundMode);
UvEcnr_OutputMode eOutputMode = uvoice_ecnr_mode_phone;
pCtx->mMicChnNum = nMicChnNum;
pCtx->mRefChnNum = nRefChnNum;
pCtx->mChnLen = nChnLen;
uv_activate_param stParam;
memset(&stParam, 0, sizeof(stParam));
stParam.license = stUvLicenseParam.license; //UvoiceLicenseCode;
stParam.license_path = stUvLicenseParam.license_path; //UvoiceLicenseFilePath;
stParam.uuid = stUvLicenseParam.uuid; //UvoiceUUID;
stParam.activate_type = 0;
stParam.auth_cb = uvoice_auth_cb;
int64_t tm0 = CDX_GetSysTimeUsMonotonic()/1000;
pCtx->handle_ecnr = UvEcnr_Create(eInputMode, eOutputMode, nSampleRate, &stParam);
const char* version = UvEcnr_GetVersion();
alogd("[UVOICE] ecnr version: %s, license: %s-%s-%s, param:%d-%d-%d", version, stUvLicenseParam.license,
stUvLicenseParam.license_path, stUvLicenseParam.uuid, eInputMode, eOutputMode, nSampleRate);
// 不适用云端授权调用APIprocess在半小时后将返回错误信息处理输出为全0
//handle_ecnr = UvEcnr_Create((UvEcnr_InputMode)in_mode,(UvEcnr_OutputMode)out_mode,sample_rate, NULL);
// 授权失败时也会返回空句柄注意看LOG
if (NULL == pCtx->handle_ecnr)
{
aloge("fatal error! UvEcnr create fail!");
free(pCtx);
return NULL;
}
int64_t tm1 = CDX_GetSysTimeUsMonotonic()/1000;
st = UvEcnr_Init(pCtx->handle_ecnr);
if(st != UV_ECNR_OK)
{
aloge("fatal error! [UVOICE] ECNR init error:%d!", st);
UvEcnr_Destroy(pCtx->handle_ecnr);
pCtx->handle_ecnr = NULL;
free(pCtx);
return NULL;
}
int64_t tm2 = CDX_GetSysTimeUsMonotonic()/1000;
alogd("UvEncr init cost:[%lld-%lld]ms", tm1-tm0, tm2-tm1);
//malloc memory to buffer.
for(i=0; i<nChnNum; i++)
{
pCtx->in_buff[i] = (short *)malloc(nChnLen*2);
if(NULL == pCtx->in_buff[i])
{
aloge("fatal error! malloc fail:%d", nChnLen*2);
}
}
pCtx->in_buff_len = nChnLen*2;
pCtx->in_buff_data_remain_len = 0;
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;
#ifdef AI_HW_AEC_DEBUG_EN
pCtx->tmp_pcm_fp_in = fopen("/mnt/extsd/tmp_in_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_out)
{
aloge("fatal error! aec_debug_file_create_failed");
}
#endif
return pCtx;
}
void DestructUvoiceAecContext(UvoiceAecContext *pCtx)
{
int ret;
if(pCtx->audio_duration > 0)
{
alogd("total RTF: %.4f (%.2f / %.2f)", pCtx->process_duration/pCtx->audio_duration, pCtx->process_duration, pCtx->audio_duration);
}
if(NULL != pCtx->handle_ecnr)
{
UvEcnr_Destroy(pCtx->handle_ecnr);
pCtx->handle_ecnr = NULL;
}
for(int i=0; i<MAX_MIXEDIN_NUM; i++)
{
if(pCtx->in_buff[i])
{
free(pCtx->in_buff[i]);
pCtx->in_buff[i] = NULL;
}
}
if(NULL != pCtx->out_buff)
{
free(pCtx->out_buff);
pCtx->out_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_out)
{
fclose(pCtx->tmp_pcm_fp_out);
pCtx->tmp_pcm_fp_out = NULL;
}
#endif
free(pCtx);
}
/**
implement of AecProcessFuncType.
*/
int UvoiceAecProcess(void *cookie, AUDIO_FRAME_S *pFrm, BOOL bSuspendAec)
{
int rc;
int ret;
uvoice_ecnr_status st;
int i;
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 nMicChnNum = 0;
int nRefChnNum = 0;
int nChnNum = judgeAudioChnNumBySoundMode(pFrm->mSoundmode, &nMicChnNum, &nRefChnNum);
int nChnLen = pFrm->mLen/nChnNum; //unit: bytes
UvoiceAecContext *pCtx = (UvoiceAecContext*)cookie;
if(NULL == pCtx->handle_ecnr)
{
aloge("fatal error! UvEcnr create fail!");
return -1;
}
if(nMicChnNum != pCtx->mMicChnNum || nRefChnNum != pCtx->mRefChnNum || nChnLen != pCtx->mChnLen)
{
aloge("fatal error! audio channel param change:[%d-%d-%d] != [%d-%d-%d]", nMicChnNum, nRefChnNum, nChnLen,
pCtx->mMicChnNum, pCtx->mRefChnNum, pCtx->mChnLen);
}
if(pCtx->in_buff_len != nChnLen*2)
{
aloge("fatal error! why aec in buf len wrong?[%d != %d*2]", pCtx->in_buff_len, nChnLen);
}
if(pCtx->out_buff_len != nChnLen*2)
{
aloge("fatal error! why aec out buf len wrong?[%d != %d*2]", pCtx->out_buff_len, nChnLen);
}
// move data in near buffer and reference buffer to internal buffer for conjunction with remaining data for last process.
if(pCtx->in_buff_data_remain_len + nChnLen <= pCtx->in_buff_len)
{
int nFrameSize = nChnLen/(nBitWidth/8); //one frame contain the number of alsaFrames.
for(i = 0; i < nFrameSize; i++)
{
//assume sample length is 16bit.
for(int nChnIdx = 0; nChnIdx < nChnNum; nChnIdx++)
{
*(short*)((char*)pCtx->in_buff[nChnIdx]+pCtx->in_buff_data_remain_len) = ((short*)pFrm->mpAddr)[nChnNum*i+nChnIdx];
}
pCtx->in_buff_data_remain_len+=(nBitWidth/8);
}
#ifdef AI_HW_AEC_DEBUG_EN
if(NULL != pCtx->tmp_pcm_fp_in)
{
fwrite(pFrm->mpAddr, 1, pFrm->mLen, pCtx->tmp_pcm_fp_in);
pCtx->tmp_pcm_in_size += pFrm->mLen;
}
#endif
}
else
{
aloge("fatal error! in_buff_over_flow:%d-%d-%d-%d", pCtx->in_buff_data_remain_len, pCtx->in_buff_len, nChnLen, pFrm->mLen);
}
int frm_size = 160; // 160 samples as one unit processed by aec library
int left = pCtx->in_buff_data_remain_len / (nBitWidth/8); //sample number.
int nProcessedSampleNum = 0;
while(left >= frm_size)
{
if (FALSE == bSuspendAec)
{
uv_ecnr_audio_buf audioBuf;
for(i = 0; i < nMicChnNum; i++)
{
audioBuf.audioin[i] = pCtx->in_buff[i] + nProcessedSampleNum;
}
for(i = 0; i < nRefChnNum; i++)
{
audioBuf.audioref[i] = pCtx->in_buff[i+nMicChnNum] + nProcessedSampleNum;
}
short *pOutAudio = NULL;
int64_t tm0 = CDX_GetSysTimeUsMonotonic();
pCtx->audio_duration += (float)frm_size/nSampleRate;
st = UvEcnr_Process(pCtx->handle_ecnr, &audioBuf, &pOutAudio);
int64_t tm1 = CDX_GetSysTimeUsMonotonic();
pCtx->process_duration += (float)(tm1 - tm0) / 1000000.0f;
if(UV_ECNR_OK == st)
{
memcpy((void*)((char*)pCtx->out_buff + pCtx->out_buff_data_remain_len), (void*)pOutAudio, frm_size*(nBitWidth/8));
}
else
{
if(UV_ECNR_VERIFY_ERROR == st)
{
aloge("fatal error! ecnr license time passed.");
}
aloge("fatal error! process wav failed.");
}
// if(((int)pCtx->audio_duration)%10 == 0)
// {
// alogd("RTF: %.4f (%.2f / %.2f)", pCtx->process_duration/pCtx->audio_duration, pCtx->process_duration, pCtx->audio_duration);
// }
}
else
{
memcpy((void*)((char*)pCtx->out_buff + pCtx->out_buff_data_remain_len), (void*)(pCtx->in_buff[0] + nProcessedSampleNum), frm_size*(nBitWidth/8));
}
nProcessedSampleNum += frm_size;
left -= frm_size;
pCtx->in_buff_data_remain_len -= frm_size*(nBitWidth/8);
pCtx->out_buff_data_remain_len += frm_size*(nBitWidth/8);
}
// move remaining data in internal buffer to the beginning of the buffer
if(left > 0)
{
for(i = 0; i < nChnNum; i++)
{
memmove((void*)pCtx->in_buff[i], (void*)(pCtx->in_buff[i] + nProcessedSampleNum), pCtx->in_buff_data_remain_len);
}
}
// 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;
}
#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;
}