48 kHz のサンプリング レートで動作する VoIP アプリケーションを開発しています。内部で 48 kHz を使用する Opus をコーデックとして使用し、現在のほとんどの Android ハードウェアは 48 kHz でネイティブに動作するため、AEC は私が今欠けているパズルの唯一のピースです。私はすでに WebRTC の実装を見つけましたが、それを機能させる方法がわかりません。メモリがランダムに破損し、遅かれ早かれ全体がクラッシュするようです。クラッシュしていないときは、フレームの半分ほど静かであるかのように、音はやや分厚いです。20 ミリ秒のフレームを処理するコードは次のとおりです。
webrtc::SplittingFilter* splittingFilter;
webrtc::IFChannelBuffer* bufferIn;
webrtc::IFChannelBuffer* bufferOut;
webrtc::IFChannelBuffer* bufferOut2;
// ...
splittingFilter=new webrtc::SplittingFilter(1, 3, 960);
bufferIn=new webrtc::IFChannelBuffer(960, 1, 1);
bufferOut=new webrtc::IFChannelBuffer(960, 1, 3);
bufferOut2=new webrtc::IFChannelBuffer(960, 1, 3);
// ...
int16_t* samples=(int16_t*)data;
float* fsamples[3];
float* foutput[3];
int i;
float* fbuf=bufferIn->fbuf()->bands(0)[0];
// convert the data from 16-bit PCM into float
for(i=0;i<960;i++){
fbuf[i]=samples[i]/(float)32767;
}
// split it into three "bands" that the AEC needs and for some reason can't do itself
splittingFilter->Analysis(bufferIn, bufferOut);
// split the frame into 6 consecutive 160-sample blocks and perform AEC on them
for(i=0;i<6;i++){
fsamples[0]=&bufferOut->fbuf()->bands(0)[0][160*i];
fsamples[1]=&bufferOut->fbuf()->bands(0)[1][160*i];
fsamples[2]=&bufferOut->fbuf()->bands(0)[2][160*i];
foutput[0]=&bufferOut2->fbuf()->bands(0)[0][160*i];
foutput[1]=&bufferOut2->fbuf()->bands(0)[1][160*i];
foutput[2]=&bufferOut2->fbuf()->bands(0)[2][160*i];
int32_t res=WebRtcAec_Process(aecState, (const float* const*) fsamples, 3, foutput, 160, 20, 0);
}
// put the "bands" back together
splittingFilter->Synthesis(bufferOut2, bufferIn);
// convert the processed data back into 16-bit PCM
for(i=0;i<960;i++){
samples[i]=(int16_t) (CLAMP(fbuf[i], -1, 1)*32767);
}
実際のエコー キャンセレーションをコメント アウトし、float 変換と帯域分割を行ったり来たりすると、メモリが破損せず、変な音にならず、無期限に実行されます。(ファーエンド/スピーカー信号をAECに渡します。質問に含めることでコードを混乱させたくありませんでした)
また、Android の組み込み AEC も試しました。機能している間は、キャプチャした信号を 16 kHz からアップサンプリングします。