Эхоподавление WebRTC на Android. Слишком маленький буфер
У меня возникла проблема при попытке сделать эхоподавление на Android с помощью WebRTC. Я в основном слежу за проектом, размещенным здесь, но я пытаюсь осуществлять прямую трансляцию с удаленного устройства.
/* Prepare AEC */
MobileAEC aecm = new MobileAEC(null);
aecm.setAecmMode(MobileAEC.AggressiveMode.MILD)
.prepare();
/*Get Minimum Buffer Size */
int minBufSize = AudioRecord.getMinBufferSize(HBConstants.SAMPLE_RATE,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT) ;
int audioLength=minBufSize/2;
byte[] buf = new byte[minBufSize];
short[] audioBuffer = new short[audioLength];
short[] aecOut = new short[audioLength];
/*Prepare Audio Track */
AudioTrack speaker = new AudioTrack(AudioManager.STREAM_MUSIC,
HBConstants.SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, audioLength,
AudioTrack.MODE_STREAM);
speaker.play();
isRunning = true;
/*Loop around and read incoming network buffer. PlayerQueue is a read LinkedBlockingQueue set elsewhere containing incoming network data */
while (isRunning) {
try {
buf = playerQueue.take();
/* Convert to short buffer and send to aecm*/
ByteBuffer.wrap(buf).order(ByteOrder.nativeOrder())
.asShortBuffer().get(audioBuffer);
aecm.farendBuffer(audioBuffer, audioLength);
aecm.echoCancellation(audioBuffer, null, aecOut,
(short) (audioLength), (short) 10);
/*Send output to speeker */
speaker.write(aecOut, 0, audioLength);
} catch (Exception ie) {
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
}
Когда я делаю это, я получаю это исключение:
12-23 17:31:11.290: W/System.err(8717): java.lang.Exception: setFarendBuffer() failed due to invalid arguments.
12-23 17:31:11.290: W/System.err(8717): at com.android.webrtc.audio.MobileAEC.farendBuffer(MobileAEC.java:204)
12-23 17:31:11.290: W/System.err(8717): at com.example.twodottwo.PlayerThread.run(PlayerThread.java:62)
12-23 17:31:11.290: W/System.err(8717): at java.lang.Thread.run(Thread.java:841)
Теперь я немного покопался в коде и обнаружил, что сэмплер будет принимать только 80 или 160 сэмплов за раз. Чтобы компенсировать это, я пытался получить только 160 выборок за раз, но это меньше минимального размера буфера в объекте AudioRecord и выдает ошибку.
Таким образом, чтобы обойти это, я также попробовал этот код и установил очередь, чтобы доставлять только максимум 320 байтов за раз (так как мы используем 2 байта для краткости):
ShortBuffer sb = ShortBuffer.allocate(audioLength);
int samples = audioLength / 160;
while(i < samples) {
buf = playerQueue.take();
ByteBuffer.wrap(buf).order(ByteOrder.nativeOrder()).asShortBuffer().get(audioBuffer);
aecm.farendBuffer(audioBuffer, 160);
aecm.echoCancellation(audioBuffer, null, aecOut, (short) (160), (short) 10);
sb.put(aecOut);
i ++;
}
speaker.write(sb.array(), 0, audioLength);
Теперь это должно буферизовать каждый массив из 160 элементов и передать его в библиотеку WebRtc, чтобы выполнить эхо-команду. Кажется, он просто производит случайный шум. Я попытался также изменить порядок результирующего массива, но все равно производит случайный шум.
Есть ли способ разделить образец звука и заставить его звучать как оригинал так, как нравится WebRTC? или есть способ заставить WebRtc принимать больше образцов одновременно? Я думаю, что либо было бы хорошо, но на данный момент я немного застрял.