9

純粋な Java を使用する VOIP アプリケーションを実装しています。ユーザーがヘッドセットを使用していない場合 (ほとんどの場合、マイクが内蔵されているラップトップ) に発生するエコーの問題があります。

現在起きていること

VOIP アプリケーションの基本は、Java のメディア フレームワークの単なるデータラインです。基本的に、出力用にスピーカーに書き込む前に、オーディオ データに対して何らかのデジタル信号処理を実行したいと考えています。

  public synchronized void addAudioData(byte[] ayAudioData)
  {
    m_oBuffer.enqueue(ayAudioData);
    this.notify();
  }

ご覧のとおり、オーディオ データが到着し、バッファにエンキューされます。これは危険な接続に対応し、さまざまなパケット サイズを許可するためです。また、オーディオ データをスピーカー ラインに再生する前に、高度な DSP 操作に必要なだけのオーディオ データにアクセスできることも意味します。

動作するエコー キャンセラを 1 つ管理しましたが、多くのインタラクティブなユーザー入力が必要なため、自動エコー キャンセラが必要です。

手動エコーキャンセラー

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;
  }

適応フィルター

私は、適応フィルターが進むべき道であることを読みました。具体的には、最小平均二乗フィルターです。しかし、私は立ち往生しています。上記のほとんどのサンプル コードは C および C++ で記述されており、Java にうまく変換されません。

それらを Java で実装する方法についてアドバイスがある人はいますか? 他のアイデアも大歓迎です。前もって感謝します。

4

4 に答える 4

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;
  }
于 2011-04-13T06:12:52.657 に答える
4

Speex AECを使用します。オープン ソースであり、C で記述されており (JNI で使用)、動作します。2 つの異なる VoIP アプリケーションで正常に使用でき、ほとんどのエコーがキャンセルされます。

于 2011-03-09T14:21:26.193 に答える
4

誰かが興味を持っている場合に備えて、正規化された最小平均二乗アルゴリズムといくつかのフィルターを C から Java に使用する、Paul R によって言及されたアコースティック エコー キャンセレーションメソッドを基本的に変換することにより、公正で機能するエコー キャンセラーを構築することができました。JNI ルートはおそらくまだより良い方法ですが、可能であれば純粋な Java に固執するのが好きです。それらのフィルターがどのように機能するかを確認し、 DSP Tutorのフィルターに関する多くの情報を読み取ることで、除去されるノイズの量や高周波を除去する方法などをある程度制御できるようになりました。

いくつかのヒント:

  1. どこから何を削除するかを覚えておいてください。これを数回切り替える必要がありました。
  2. この方法の最も重要な変数は収束率です。これは、上記のリンクのコードで Stepsize と呼ばれる変数です。
  3. 個々のコンポーネントを一度に 1 つずつ取り出し、それらが何をするかを理解し、それらを構築し、個別にテストしました。たとえば、Double Talk Detector をテストして、機能することを確認しました。次に、フィルターを 1 つずつ取り出し、オーディオ ファイルでテストして、それらが機能することを確認しました。次に、正規化された最小平均二乗部分を取り出してテストしてから、すべてをまとめました。

これが他の誰かに役立つことを願っています!

于 2010-09-23T08:48:38.687 に答える
1

これは非常に複雑な領域であり、使用可能な AEC ソリューションを機能させるには、かなりの研究開発を行う必要があります。優れたAEC はすべて独自仕様であり、エコー キャンセレーションには、LMS などの適応フィルターを実装するだけではありません。最初に MATLAB (または Octave) を使用してエコー キャンセレーション アルゴリズムを開発することをお勧めします。「現実世界の」テレコムで適切に機能するように見えるものがある場合は、アルゴリズムを C で実装し、リアルタイムでテスト/評価できます。これが機能したら、JNI を使用して Java から C 実装を呼び出すことができます。

于 2010-08-04T06:45:04.667 に答える