2011-07-18 12 views
1

私は2つのデバイス間でマイクオーディオをストリーミングしていますが、すべて動作していますが、エコーが悪いです。AudioRecordとAudioTrack echo

は、ここで私は

int sampleRate = 22050; 
    int channelMode = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 
    int buffersize = 2*AudioTrack.getMinBufferSize(sampleRate, channelMode, audioFormat); 

    AudioRecord arec = new AudioRecord(MediaRecorder.AudioSource.MIC, 
      sampleRate, channelMode, 
      AudioFormat.ENCODING_PCM_16BIT, buffersize); 

    buffer = new byte[buffersize]; 
    arec.startRecording(); 

    while (true) { 
     arec.read(buffer, 0, buffersize); 
     new Thread(new Runnable(){ 
      @Override 
      public void run() { 
       try {    
        mOutputStream.write(buffer); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       }     
      }    
     }).start(); 
    } 

記録スレッド

読むスレッドここ

int sampleFreq = 22050; 
     int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
     int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 
     int minBuffer = 2*AudioTrack.getMinBufferSize(sampleFreq, channelConfig, audioFormat); 

     AudioTrack atrack = new AudioTrack(AudioManager.STREAM_MUSIC, 
         sampleFreq, 
         channelConfig, 
         audioFormat, 
         minBuffer, 
         AudioTrack.MODE_STREAM); 
     atrack.play(); 

     byte[] buffer = new byte[minBuffer]; 
     while (true) { 
      try {     
       // Read from the InputStream     
       bytes = mmInStream.read(buffer);      
       atrack.write(buffer, 0, buffer.length); 
       atrack.flush();       
      } catch (IOException e) { 
       Log.e(TAG, "disconnected", e); 
       break; 
      } 
     } 

をやっている私が何か間違ったことをやっていますか?

答えて

3

エコーキャンセルロジックが必要です。ここでは、Arm5(WM8650)プロセッサ(Android 2.2)でエコーを削除する方法を示します。

  1. PCMフレームをエンコーダに送る前に、SpeexをJNIでラップし、エコー処理ルーチンを呼び出しました。私が試したSpeexの設定に関係なく、エコーはキャンセルされませんでした。

  2. Speexは再生とエコーフレームの遅延に非常に敏感なので、キューを実装し、AudioTrackに送信されたすべてのパケットをキューに入れました。キューのサイズは、内部AudioTrackバッファのサイズとほぼ同じでなければなりません。 AudioTrackがその内部バッファからサウンドカードにパケットを送るときに、この方法でパケットはおおよそecho_playbackに送られました。このアプローチでは遅延は取り除かれましたが、エコーはまだキャンセルされませんでした。

  3. WebRtcエコーキャンセル部分をJNIでラップし、エンコーダにパケットを送信する前にそのメソッドを呼び出しました。エコーはまだ残っていましたが、ライブラリは明らかにそれをキャンセルしようとしていました。

  4. 私はP2に記載されているバッファー技術を適用し、最終的に動作するようになりました。しかし、各デバイスの遅延を調整する必要があります。また、WebRtcにはエコーキャンセレーションのモバイル版とフルバージョンがあります。フルバージョンはプロセッサを大幅に遅くし、おそらくARM7のみで実行する必要があります。モバイル版は動作しますが品質は低いです

私はこれが誰かを助けることを望みます。バッファは前の呼び出しからの完全なままで、新しいものがいっぱいでない場合は、トラックの一部(そうbytes < buffer.length)あなたは再プレイホールド

bytes = mmInStream.read(buffer);      
atrack.write(buffer, 0, buffer.length); 

+0

2番目の点について詳細を教えてください.... – aProgrammer

2

はこのことでした。

0

これは私もお互いに接続された二つのAndroidデバイスと同じ問題を抱えています私のコード

public class AudioCall { 

private static final String LOG_TAG = "AudioCall"; 
private static final int SAMPLE_RATE = 8000; // Hertz 
private static final int SAMPLE_INTERVAL = 20; // Milliseconds 
private static final int SAMPLE_SIZE = 2; // Bytes 
private static final int BUF_SIZE = SAMPLE_INTERVAL * SAMPLE_INTERVAL * SAMPLE_SIZE * 2; //Bytes 
private InetAddress address; // Address to call 
private int port = 50000; // Port the packets are addressed to 
private boolean mic = false; // Enable mic? 
private boolean speakers = false; // Enable speakers? 

public AudioCall(InetAddress address) { 

    this.address = address; 
} 

public void startCall() { 

    startMic(); 
    startSpeakers(); 
} 

public void endCall() { 

    Log.i(LOG_TAG, "Ending call!"); 
    muteMic(); 
    muteSpeakers(); 
} 

public void muteMic() { 

    mic = false; 
} 

public void muteSpeakers() { 

    speakers = false; 
} 

public void startMic() { 
    // Creates the thread for capturing and transmitting audio 
    mic = true; 
    Thread thread = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      // Create an instance of the AudioRecord class 
      AudioRecord audioRecorder = new AudioRecord (MediaRecorder.AudioSource.MIC, SAMPLE_RATE, 
        AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 
        AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)*10); 
      int bytes_read = 0; 
      int bytes_sent = 0; 
      byte[] buf = new byte[BUF_SIZE]; 
      try { 
       // Create a socket and start recording 
       Log.i(LOG_TAG, "Packet destination: " + address.toString()); 
       DatagramSocket socket = new DatagramSocket(); 
       audioRecorder.startRecording(); 
       while(mic) { 
        // Capture audio from the mic and transmit it 
        bytes_read = audioRecorder.read(buf, 0, BUF_SIZE); 
        DatagramPacket packet = new DatagramPacket(buf, bytes_read, address, port); 
        socket.send(packet); 
        bytes_sent += bytes_read; 
        Log.i(LOG_TAG, "Total bytes sent: " + bytes_sent); 
        Thread.sleep(SAMPLE_INTERVAL, 0); 
       } 
       // Stop recording and release resources 
       audioRecorder.stop(); 
       audioRecorder.release(); 
       socket.disconnect(); 
       socket.close(); 
       mic = false; 
       return; 
      } 
      catch(InterruptedException e) { 

       Log.e(LOG_TAG, "InterruptedException: " + e.toString()); 
       mic = false; 
      } 
      catch(SocketException e) { 

       Log.e(LOG_TAG, "SocketException: " + e.toString()); 
       mic = false; 
      } 
      catch(UnknownHostException e) { 

       Log.e(LOG_TAG, "UnknownHostException: " + e.toString()); 
       mic = false; 
      } 
      catch(IOException e) { 

       Log.e(LOG_TAG, "IOException: " + e.toString()); 
       mic = false; 
      } 
     } 
    }); 
    thread.start(); 
} 

public void startSpeakers() { 
    // Creates the thread for receiving and playing back audio 
    if(!speakers) { 

     speakers = true; 
     Thread receiveThread = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       // Create an instance of AudioTrack, used for playing back audio 
       Log.i(LOG_TAG, "Receive thread started. Thread id: " + Thread.currentThread().getId()); 
       AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, 
         AudioFormat.ENCODING_PCM_16BIT, BUF_SIZE, AudioTrack.MODE_STREAM); 
       track.play(); 
       try { 
        // Define a socket to receive the audio 
        DatagramSocket socket = new DatagramSocket(port); 
        byte[] buf = new byte[BUF_SIZE]; 
        while(speakers) { 
         // Play back the audio received from packets 
         DatagramPacket packet = new DatagramPacket(buf, BUF_SIZE); 
         socket.receive(packet); 
         Log.i(LOG_TAG, "Packet received: " + packet.getLength()); 
         track.write(packet.getData(), 0, BUF_SIZE); 
        } 
        // Stop playing back and release resources 
        socket.disconnect(); 
        socket.close(); 
        track.stop(); 
        track.flush(); 
        track.release(); 
        speakers = false; 
        return; 
       } 
       catch(SocketException e) { 

        Log.e(LOG_TAG, "SocketException: " + e.toString()); 
        speakers = false; 
       } 
       catch(IOException e) { 

        Log.e(LOG_TAG, "IOException: " + e.toString()); 
        speakers = false; 
       } 
      } 
     }); 
     receiveThread.start(); 
    } 
    } 
} 

です。 デバイスがエコーを作成し始めると、いくつかのリンクを共有して問題を解決すると非常に役に立ちます。

+0

これは質問に対する回答ではありません。 [類似の質問を検索する](https://stackoverflow.com/search)、またはページの右側にある関連するリンクされた質問を参照して回答を見つけることができます。関連しているが異なる質問がある場合は、[新しい質問をする](https://stackoverflow.com/questions/ask)を開き、コンテキストを提供するためのリンクを追加してください。参照:[質問する、回答を得る、気を散らす](https://stackoverflow.com/tour)。 – Dwhitz