Java中的声学回声消除

Gar*_*ola 8 java signal-processing javasound echo cancellation

我正在实现一个使用纯Java的VOIP应用程序.当用户不使用耳机时(主要是带有内置麦克风的笔记本电脑),会出现回声问题.

目前发生了什么

VOIP应用程序的细节只是Java媒体框架的简单数据.基本上,我想在将音频数据写入扬声器输出之前对音频数据执行一些数字信号处理.

  public synchronized void addAudioData(byte[] ayAudioData)
  {
    m_oBuffer.enqueue(ayAudioData);
    this.notify();
  }
Run Code Online (Sandbox Code Playgroud)

如您所见,音频数据到达并在缓冲区中排队.这是为了迎合狡猾的连接并允许不同的数据包大小.这也意味着在我将音频数据播放到扬声器线路之前,我可以访问任何花哨的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;
  }
Run Code Online (Sandbox Code Playgroud)

自适应滤波器

我已经读过自适应滤波器了.具体来说,是一个最小均方滤波器.但是,我被卡住了.上面的大多数示例代码都是用C和C++编写的,它们不能很好地转换为Java.

有没有人有关于如何在Java中实现它们的建议?任何其他想法也将不胜感激.提前致谢.

Gar*_*ola 5

好多年了!希望这甚至是正确的课程,但你去了:

/**
 * 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;
  }
Run Code Online (Sandbox Code Playgroud)

  • 您最好将此代码添加到原始答案中,而不是发布新答案。 (4认同)

Pau*_*l R 1

这是一个非常复杂的领域,要获得可用的 AEC 解决方案,您需要进行大量的研发工作。所有好的 AEC 都是专有的,回声消除不仅仅是实现 LMS 等自适应滤波器。我建议您首先使用 MATLAB(或 Octave)开发您的回声消除算法 - 当您有一些看起来与“现实世界”电信工作得相当好的东西时,您可以用 C 实现该算法并实时测试/评估它。一旦工作正常,您就可以使用 JNI 从 Java 调用 C 实现。

  • 您可能会发现您需要在 AEC 中执行特定于平台的操作,例如低级操作系统/音频 API 调用,因此它也可能是 C + JNI。 (2认同)