gpt4 book ai didi

Android AcousticEchoCanceler 不会取消回声

转载 作者:太空狗 更新时间:2023-10-29 14:14:16 25 4
gpt4 key购买 nike

我正在开发的视频聊天应用程序遇到了一个相当烦人的问题,那就是音频回声问题。我在这方面充其量只是个业余爱好者,但我正在从事的项目至少需要功能齐全的音频通信。结果证明视频比我原先预期的要容易得多。预期的结构最终是一个线程在同一部手机上接收输入和另一个播放输出,为了开发这个,我制作了两个小应用程序,在一部手机上接收麦克风输入,并通过数据报套接字将其发送到另一部手机。有问题的手机是运行 Android 4.1.2 的 LG Optimus L7-2 和运行 Android 4.2.2 的 Alcatel Idol Mini(我认为它也被宣传为 Onetouch 或类似的东西。)。传输音频的代码工作完美,背景噪音极小(我猜这要归功于我选择的输入以及后期处理),但是,只要两部手机足够近,我就会得到相当惊人的回声,如果我敢尝试同时在同一个应用程序中输入/输出,情况只会变得更糟。

在我最初尝试以某种方式过滤它失败后(AcousticEchoCanceler 的帮助似乎不如 NoiseSupressor,而 AutomaticGainControl 似乎弊大于利),我读了一些书,但没有发现任何有用的东西。在这一点上,我很困惑,因为我似乎无法摆脱这样一种感觉,即我遗漏了一些明显的东西,而且设置起来不应该那么复杂。

此外,我还提供了用于录音/播放音频的基本代码。

记录器段

package com.example.audiotest;

import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.media.audiofx.AcousticEchoCanceler;
import android.media.audiofx.AutomaticGainControl;
import android.media.audiofx.NoiseSuppressor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
private Button startButton,stopButton;
public byte[] buffer;
public static DatagramSocket socket;
private int port=50005;
AudioRecord recorder;
private int sampleRate = 22050;
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
private boolean status = true;




@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

startButton = (Button) findViewById (R.id.start_button);
stopButton = (Button) findViewById (R.id.stop_button);

startButton.setOnClickListener (startListener);
stopButton.setOnClickListener (stopListener);
Log.v("AudioPlayerApp","minBufSize: " + minBufSize);
//minBufSize += 2048;
minBufSize = 4096;
System.out.println("minBufSize: " + minBufSize);
}

private final OnClickListener stopListener = new OnClickListener() {

@Override
public void onClick(View arg0) {
status = false;
recorder.release();
Log.d("VS","Recorder released");
}

};

private final OnClickListener startListener = new OnClickListener() {

@Override
public void onClick(View arg0) {
status = true;
startStreaming();
}

};

public void startStreaming() {


Thread streamThread = new Thread(new Runnable() {

@Override
public void run() {
try {

DatagramSocket socket = new DatagramSocket();
Log.d("AudioPlayerApp"", "Socket Created");
minBufSize = 4096;
byte[] buffer = new byte[minBufSize];

Log.d("AudioPlayerApp","Buffer created of size " + minBufSize);
DatagramPacket packet;

final InetAddress destination = InetAddress.getByName("192.168.0.13");



recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION,sampleRate,channelConfig,audioFormat,minBufSize);
AcousticEchoCanceler canceler = AcousticEchoCanceler.create(recorder.getAudioSessionId());
NoiseSuppressor ns = NoiseSuppressor.create(recorder.getAudioSessionId());
AutomaticGainControl agc = AutomaticGainControl.create(recorder.getAudioSessionId());
canceler.setEnabled(true);
ns.setEnabled(true);
//agc.setEnabled(true);
recorder.startRecording();

while(status == true) {

//reading data from MIC into buffer
minBufSize = recorder.read(buffer, 0, buffer.length);

//putting buffer in the packet
packet = new DatagramPacket (buffer,buffer.length,destination,port);

socket.send(packet);
}



} catch(UnknownHostException e) {
Log.e("AudioPlayerApp", "UnknownHostException");
} catch (IOException e) {
e.printStackTrace();
Log.e("AudioPlayerApp", "IOException");
}
}

});
streamThread.start();
}
}

还有玩家部分。

package com.test.playsound;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

static int port = 50005;
static String address = "";
static int sampleRate = 22050;
private boolean running = true;
private AudioTrack audioTrack;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("Player", "Init complete");
openPlaySocket();
}

private void openPlaySocket() {
// TODO Auto-generated method stub
Thread t = new Thread(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub
try {

Log.v("AudioPlayerApp", "Opening socket");
DatagramSocket sSock = new DatagramSocket(port);
byte[] output = new byte[4096];
Log.v("AudioPlayerApp", "Generating AudioTrack");

int minBufferSize = AudioTrack.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);

audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
AudioTrack.MODE_STREAM);
DatagramPacket receivePacket = new DatagramPacket(output,
output.length);
//Log.v("AudioPlayerApp", "Playing AudioTrack");
audioTrack.play();
while (running) {
//Log.v("AudioPlayerApp", "Waiting Packet");
sSock.receive(receivePacket);
Log.v("AudioPlayerApp","REcieved packet");
//Log.v("AudioPlayerApp", "Packet recieved");
try {
//Log.v("AudioPlayerApp", "writing data to audioTrack");
audioTrack.write(receivePacket.getData(), 0,
receivePacket.getData().length);
} catch (Exception e) {
Log.v("AudioPlayerApp",
"Failed to write audio: " + e.getMessage());

}
}
/*Log.v("AudioPlayerApp","Opening socket");
ServerSocket sSock = new ServerSocket(port);
Socket sock = sSock.accept();
Log.v("AudioPlayerApp","Socket opened "+port);
*/
} catch (Exception e) {
// TODO: handle exception
Log.v("AudioPlayerApp", "Error: " + e.getMessage());
}
}
});
Log.v("Player", "Starting thread");
t.start();

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);

return true;
}

}

我知道它包含不良做法(例如不检查有问题的设备是否支持某些东西,或释放资源等)但是,这是为了尽快开始测试和修复回声尽可能。我已经确认这两款手机都可以访问 AcousticEchoCanceller、NoiseSupression、录音权限、互联网权限,除了 AudioFormat.VOICECOMMUNICATION 导致我的 AudioRecord 崩溃之外,我没有遇到其他问题。

我正在寻找关于这个主题的任何想法或建议,坦率地说,我很困惑。如何解决录制和播放语音时有回声的问题?

最佳答案

AcousticEchoCanceler 类用于取消或删除扬声器播放的音频和同一设备的麦克风捕获的音频,播放和捕获之间有很小的延迟。

AcousticEchoCanceler 类无法消除由于回声路径的回声延迟长且可变的特性而将两个手机彼此靠近而引起的回声。

关于Android AcousticEchoCanceler 不会取消回声,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24171184/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com