Tôi đang tạo ứng dụng VoIP (loa) Android-to-Android bằng cách sử dụng lớp AudioRecord và AudioTrack, cùng với Speex qua NDK để hủy bỏ tiếng vang. Tôi đã có thể chuyển thành công và lấy dữ liệu từ hàm speex_echo_cancellation() của Speex, nhưng tiếng vang vẫn còn.Cấu hình hủy bỏ tiếng vọng Speex
Đây là liên quan android đang thread đang ghi âm/gửi và nhận/chơi âm thanh:
//constructor
public MyThread(DatagramSocket socket, int frameSize, int filterLength){
this.socket = socket;
nativeMethod_initEchoState(frameSize, filterLength);
}
public void run(){
short[] audioShorts, recvShorts, recordedShorts, filteredShorts;
byte[] audioBytes, recvBytes;
int shortsRead;
DatagramPacket packet;
//initialize recorder and player
int samplingRate = 8000;
int managerBufferSize = 2000;
AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC, samplingRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, managerBufferSize, AudioTrack.MODE_STREAM);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, samplingRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, managerBufferSize);
recorder.startRecording();
player.play();
//record first packet
audioShorts = new short[1000];
shortsRead = recorder.read(audioShorts, 0, audioShorts.length);
//convert shorts to bytes to send
audioBytes = new byte[shortsRead*2];
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioShorts);
//send bytes
packet = new DatagramPacket(audioBytes, audioBytes.length);
socket.send(packet);
while (!this.isInterrupted()){
//recieve packet/bytes (received audio data should have echo cancelled already)
recvBytes = new byte[2000];
packet = new DatagramPacket(recvBytes, recvBytes.length);
socket.receive(packet);
//convert bytes to shorts
recvShorts = new short[packet.getLength()/2];
ByteBuffer.wrap(packet.getData(), 0, packet.getLength()).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(recvShorts);
//play shorts
player.write(recvShorts, 0, recvShorts.length);
//record shorts
recordedShorts = new short[1000];
shortsRead = recorder.read(recordedShorts, 0, recordedShorts.length);
//send played and recorded shorts into speex,
//returning audio data with the echo removed
filteredShorts = nativeMethod_speexEchoCancel(recordedShorts, recvShorts);
//convert filtered shorts to bytes
audioBytes = new byte[shortsRead*2];
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(filteredShorts);
//send off bytes
packet = new DatagramPacket(audioBytes, audioBytes.length);
socket.send(packet);
}//end of while loop
}
Đây là có liên quan đang NDK/JNI:
void nativeMethod_initEchoState(JNIEnv *env, jobject jobj, jint frameSize, jint filterLength){
echo_state = speex_echo_state_init(frameSize, filterLength);
}
jshortArray nativeMethod_speexEchoCancel(JNIEnv *env, jobject jObj, jshortArray input_frame, jshortArray echo_frame){
//create native shorts from java shorts
jshort *native_input_frame = (*env)->GetShortArrayElements(env, input_frame, NULL);
jshort *native_echo_frame = (*env)->GetShortArrayElements(env, echo_frame, NULL);
//allocate memory for output data
jint length = (*env)->GetArrayLength(env, input_frame);
jshortArray temp = (*env)->NewShortArray(env, length);
jshort *native_output_frame = (*env)->GetShortArrayElements(env, temp, 0);
//call echo cancellation
speex_echo_cancellation(echo_state, native_input_frame, native_echo_frame, native_output_frame);
//convert native output to java layer output
jshortArray output_shorts = (*env)->NewShortArray(env, length);
(*env)->SetShortArrayRegion(env, output_shorts, 0, length, native_output_frame);
//cleanup and return
(*env)->ReleaseShortArrayElements(env, input_frame, native_input_frame, 0);
(*env)->ReleaseShortArrayElements(env, echo_frame, native_echo_frame, 0);
(*env)->ReleaseShortArrayElements(env, temp, native_output_frame, 0);
return output_shorts;
}
Những mã chạy tốt và dữ liệu âm thanh chắc chắn được gửi/nhận/xử lý/phát từ android-to-android. Với tốc độ mẫu âm thanh 8000 Hz và kích thước gói 2000bytes/1000shorts, tôi đã nhận thấy rằng một frameSize 1000 là cần thiết để âm thanh phát được mượt mà. Hầu hết giá trị của filterLength (còn gọi là chiều dài đuôi theo Speex doc) sẽ chạy, nhưng dường như không có tác dụng gì đối với việc loại bỏ echo.
Có ai hiểu đủ AEC để cung cấp cho tôi một số gợi ý về việc triển khai hoặc định cấu hình Speex không? Cảm ơn vì đã đọc.
Tôi cũng có vấn đề tương tự. Bạn có giải pháp nào cho vấn đề của mình không? – aProgrammer
Hi u tìm thấy một giải pháp cho vấn đề? Cảm ơn lỗi – SoH