Java中的回声消除
我正在实现一个使用纯Java的VOIP应用程序。当用户不使用耳机(主要是内置麦克风的笔记本电脑)时,会出现回声问题 当前发生的情况 VOIP应用程序的基本要素只是Java媒体框架的简单数据线。基本上,我希望在将音频数据写入扬声器输出之前,对其执行一些数字信号处理Java中的回声消除,java,echo,signal-processing,javasound,cancellation,Java,Echo,Signal Processing,Javasound,Cancellation,我正在实现一个使用纯Java的VOIP应用程序。当用户不使用耳机(主要是内置麦克风的笔记本电脑)时,会出现回声问题 当前发生的情况 VOIP应用程序的基本要素只是Java媒体框架的简单数据线。基本上,我希望在将音频数据写入扬声器输出之前,对其执行一些数字信号处理 public synchronized void addAudioData(byte[] ayAudioData) { m_oBuffer.enqueue(ayAudioData); this.notify();
public synchronized void addAudioData(byte[] ayAudioData)
{
m_oBuffer.enqueue(ayAudioData);
this.notify();
}
正如您所看到的,音频数据到达并在缓冲区中排队。这是为了满足不可靠的连接,并允许不同的数据包大小。这也意味着,在我将音频数据播放到扬声器线路之前,我可以访问任何高级DSP操作所需的音频数据
我已经管理了一个回声消除器,它确实可以工作,但是它需要大量的交互式用户输入,我希望有一个自动回声消除器
手动回声消除器
public static byte[] removeEcho(int iDelaySamples, float fDecay, byte[] aySamples)
{
m_awDelayBuffer = new short[iDelaySamples];
m_aySamples = new byte[aySamples.length];
m_fDecay = (float) fDecay;
System.out.println("Removing echo");
m_iDelayIndex = 0;
System.out.println("Sample length:\t" + aySamples.length);
for (int i = 0; i < aySamples.length; i += 2)
{
// update the sample
short wOldSample = getSample(aySamples, i);
// remove the echo
short wNewSample = (short) (wOldSample - fDecay * m_awDelayBuffer[m_iDelayIndex]);
setSample(m_aySamples, i, wNewSample);
// update the delay buffer
m_awDelayBuffer[m_iDelayIndex] = wNewSample;
m_iDelayIndex++;
if (m_iDelayIndex == m_awDelayBuffer.length)
{
m_iDelayIndex = 0;
}
}
return m_aySamples;
}
public static byte[]removeEcho(int-iDelaySamples,float-fDecay,byte[]aySamples)
{
m_awDelayBuffer=新短[iDelaySamples];
m_aySamples=新字节[aySamples.length];
m_fDecay=(浮动)fDecay;
System.out.println(“删除回音”);
m_iDelayIndex=0;
System.out.println(“样本长度:\t”+aySamples.length);
对于(int i=0;i
自适应滤波器
我已经读过了,这是一条路要走。具体来说,是一个最小均方滤波器。然而,我被卡住了。上面的大多数代码都是C和C++,它们不能很好的翻译成java。
有人对如何在Java中实现它们有什么建议吗?任何其他想法也将不胜感激。提前谢谢 这是一个非常复杂的领域,要使可用的AEC解决方案发挥作用,您需要做大量的研发工作。所有好的AEC都是专有的,回声消除远不止实现LMS之类的自适应滤波器。我建议您首先使用MATLAB(或Octave)开发回声消除算法-当您有一些似乎与“现实世界”电信公司合作得相当好的东西时,您可以用C语言实现该算法并实时测试/评估它。一旦这项工作开始,您就可以使用JNI从Java调用C实现。如果有人感兴趣,我通过将使用标准化最小均方算法和一些过滤器的方法从C转换为Java,构建了一个公平、有效的回声消除器。JNI路线可能仍然是一条更好的道路,但如果可能的话,我喜欢坚持使用纯Java。通过观察他们的滤波器是如何工作的,并阅读大量关于滤波器的内容,我设法控制了去除多少噪声以及如何去除高频等 一些提示:
我已经在两个不同的VoIP应用程序中成功地使用了它,它取消了大部分回音。已经很久了!希望这门课是对的,但你会发现:
/**
* This filter performs a pre-whitening Normalised Least Means Square on an
* array of bytes. This does the actual echo cancelling.
*
* Echo cancellation occurs with the following formula:
*
* e = d - X' * W
*
* e represents the echo-free signal. d represents the actual microphone signal
* with the echo. X' is the transpose of the loudspeaker signal. W is an array
* of adaptive weights.
*
*/
public class cNormalisedLeastMeansSquareFilter
implements IFilter
{
private byte[] m_ayEchoFreeSignal;// e
private byte[] m_ayEchoSignal;// d
private byte[] m_ayTransposeOfSpeakerSignal;// X'
private double[] m_adWeights;// W
/**
* The transpose and the weights need to be updated before applying the filter
* to an echo signal again.
*
* @param ayEchoSignal
* @param ayTransposeOfSpeakerSignal
* @param adWeights
*/
public cNormalisedLeastMeansSquareFilter(byte[] ayEchoSignal, byte[] ayTransposeOfSpeakerSignal, double[] adWeights)
{
m_ayEchoSignal = ayEchoSignal;
m_ayTransposeOfSpeakerSignal = ayTransposeOfSpeakerSignal;
m_adWeights = adWeights;
}
@Override
public byte[] applyFilter(byte[] ayAudioBytes)
{
// e = d - X' * W
m_ayEchoFreeSignal = new byte[ayAudioBytes.length];
for (int i = 0; i < m_ayEchoFreeSignal.length; ++i)
{
m_ayEchoFreeSignal[i] = (byte) (m_ayEchoSignal[i] - m_ayTransposeOfSpeakerSignal[i] * m_adWeights[i]);
}
return m_ayEchoFreeSignal;
}
/**
*此过滤器在图像上执行预白化归一化最小均方
*字节数组。这将进行实际的回声消除。
*
*回声消除使用以下公式进行:
*
*e=d-X'*W
*
*e表示无回声信号。d表示实际的麦克风信号
*随着回声。X'是扬声器信号的转置。W是一个数组
*自适应权重的设计。
*
*/
公共类cNormalisedLeastMeansSquareFilter
执行IFilter
{
私有字节[]m_ayEchoFreeSignal;//e
专用字节[]m_ayEchoSignal;//d
专用字节[]m_ayTransposeOfSpeakerSignal;//X'
私有双[]m_adWeights;//W
/**
*在应用过滤器之前,需要更新转置和权重
*再次发出回声信号。
*
*@param-ayecho信号
*@param ayTransposeOfSpeakerSignal
*@param adWeights
*/
public cNormalisedLeastMeansSquareFilter(字节[]ayEchoSignal,字节[]AYTransposeOfSpeakersSignal,双[]adWeights)
{
m_ayEchoSignal=ayEchoSignal;
m_ayTransposeOfSpeakerSignal=ayTransposeOfSpeakerSignal;
m_adWeights=adWeights;
}
@凌驾
公共字节[]applyFilter(字节[]ayAudioBytes)
{
//e=d-X'*W
m_ayEchoFreeSignal=新字节[ayAudioBytes.length];
对于(int i=0;i
谢谢你的回复。我一直在努力避免使用JNI,但却迫不及待地想尝试任何东西。你可能会发现你需要在AEC中做平台特定的事情,例如低级操作系统/音频API调用,所以最好是C+JNI。我发现