2016-02-11 41 views
4

我正在構建一個應用程序,要求麥克風取消來自揚聲器的任何聲音。看起來,這個問題幾乎是一個在線陰謀,因爲其他人完全相同的問題從來沒有回覆過長時間。安卓AcousticEchoCanceler似乎不適用於大多數設備

Android的本機硬件加速AcousticEchoCanceler似乎不適用於大多數設備。測試在許多設備和似乎工作的包括Nexus 5和Moto X,而幾乎所有三星設備測試無法刪除背景聲音。注:所有手機測試返回true爲AcousticEchoCanceler.isAvailable()

但是,必須有這是一種解決方案,因爲諸如Skype或WhatsApp這樣的應用程序似乎取消了其應用程序環境之外的聲音,即呼叫在揚聲器上,麥克風會取消收到的任何反饋。

這個簡化的錄製應用程序將聲音記錄到文件中,並在稍後單擊播放時播放它。

MainActivity.java

public class MainActivity extends Activity { 

Button startRec, stopRec, playBack; 
int minBufferSizeIn; 
AudioRecord audioRecord; 
short[] audioData; 
Boolean recording; 
int sampleRateInHz = 48000; 
private String TAG = "TAG"; 

/** 
* Called when the activity is first created. 
*/ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    startRec = (Button) findViewById(R.id.startrec); 
    stopRec = (Button) findViewById(R.id.stoprec); 
    playBack = (Button) findViewById(R.id.playback); 

    startRec.setOnClickListener(startRecOnClickListener); 
    stopRec.setOnClickListener(stopRecOnClickListener); 
    playBack.setOnClickListener(playBackOnClickListener); 
    playBack.setEnabled(false); 
    startRec.setEnabled(true); 
    stopRec.setEnabled(false); 

    minBufferSizeIn = AudioRecord.getMinBufferSize(sampleRateInHz, 
      AudioFormat.CHANNEL_IN_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 

    audioData = new short[minBufferSizeIn]; 

    audioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 
      sampleRateInHz, 
      AudioFormat.CHANNEL_IN_MONO, 
      AudioFormat.ENCODING_PCM_16BIT, 
      minBufferSizeIn); 

} 

OnClickListener startRecOnClickListener 
     = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
     playBack.setEnabled(false); 
     startRec.setEnabled(false); 
     stopRec.setEnabled(true); 
     Thread recordThread = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       recording = true; 
       startRecord(); 
      } 

     }); 

     recordThread.start(); 

    } 
}; 


OnClickListener stopRecOnClickListener 
     = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
     playBack.setEnabled(true); 
     startRec.setEnabled(false); 
     stopRec.setEnabled(false); 
     recording = false; 
    } 
}; 



OnClickListener playBackOnClickListener 
     = new OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     playBack.setEnabled(false); 
     startRec.setEnabled(true); 
     stopRec.setEnabled(false); 
     playRecord(); 
    } 

}; 


@TargetApi(Build.VERSION_CODES.JELLY_BEAN) 
private void startRecord() { 
    File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); 

    try { 
     FileOutputStream outputStream = new FileOutputStream(file); 
     BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); 
     DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream); 

     NoiseSuppressor ns; 
     AcousticEchoCanceler aec; 

     if (NoiseSuppressor.isAvailable()) { 
      ns = NoiseSuppressor.create(audioRecord.getAudioSessionId()); 
      if (ns != null) { 
       ns.setEnabled(true); 
      } else { 
       Log.e(TAG, "AudioInput: NoiseSuppressor is null and not enabled"); 
      } 
     } 

     if (AcousticEchoCanceler.isAvailable()) { 
      aec = AcousticEchoCanceler.create(audioRecord.getAudioSessionId()); 
      if (aec != null) { 
       aec.setEnabled(true); 
      } else { 
       Log.e(TAG, "AudioInput: AcousticEchoCanceler is null and not enabled"); 
      } 
     } 
     audioRecord.startRecording(); 

     while (recording) { 
      int numberOfShort = audioRecord.read(audioData, 0, minBufferSizeIn); 
      for (int i = 0; i < numberOfShort; i++) { 
       dataOutputStream.writeShort(audioData[i]); 
      } 
     } 

     audioRecord.stop(); 
     dataOutputStream.close(); 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

void playRecord() { 
    File file = new File(Environment.getExternalStorageDirectory(), "test.pcm"); 

    int shortSizeInBytes = Short.SIZE/Byte.SIZE; 

    int bufferSizeInBytes = (int) (file.length()/shortSizeInBytes); 
    short[] audioData = new short[bufferSizeInBytes]; 

    try { 
     FileInputStream inputStream = new FileInputStream(file); 
     BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 
     DataInputStream dataInputStream = new DataInputStream(bufferedInputStream); 

     int i = 0; 
     while (dataInputStream.available() > 0) { 
      audioData[i] = dataInputStream.readShort(); 
      i++; 
     } 

     dataInputStream.close(); 

     AudioTrack audioTrack = new AudioTrack(
       AudioManager.STREAM_MUSIC, sampleRateInHz, 
       AudioFormat.CHANNEL_OUT_MONO, 
       AudioFormat.ENCODING_PCM_16BIT, 
       bufferSizeInBytes, 
       AudioTrack.MODE_STREAM); 
     while(audioTrack.getState() != AudioTrack.STATE_INITIALIZED){ 

     } 
     audioTrack.play(); 
     audioTrack.write(audioData, 0, bufferSizeInBytes); 


    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 

} 

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent" 
      android:orientation="vertical" > 

<TextView 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello_world" /> 
<Button 
    android:id="@+id/startrec" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Start Recording Test" /> 
<Button 
    android:id="@+id/stoprec" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Stop Recording" /> 
<Button 
    android:id="@+id/playback" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Play Back" /> 

</LinearLayout> 

AndroidManfist.xml權限

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> 
    <uses-permission android:name="android.permission.RECORD_AUDIO"/> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

要確認設備是否工作只是在後臺播放的東西,然後點擊Start Recording記錄一個小部門,然後點擊Stop Recording此時點擊Play Back並檢查是否聽到背景聲音。如果你能聽到背景聲音,那麼AEC不起作用。 但爲什麼這種不一致發生,或者我如何實現回聲消除(我已經在我的應用程序中使用WebRTC來消除我的應用程序中的噪音)

任何幫助將不勝感激!

回答

2

我在S6設備上遇到同樣的問題。我玩過各種設置,並找到了一套似乎可以啓用AEC的設置。我和您的設置之間的差異似乎是:

  • 16K採樣率
  • audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);

對於其他人,我不確定需要什麼設置才能讓AEC工作。我知道,我與

  • 相同的應用程序48K的採樣率
  • NO audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
  • NO android.permission.MODIFY_AUDIO_SETTINGS

沒有成功AEC。

0

問題:

AudioTrack audioTrack = new AudioTrack(
    AudioManager.STREAM_MUSIC, sampleRateInHz, 
    AudioFormat.CHANNEL_OUT_MONO, 
    AudioFormat.ENCODING_PCM_16BIT, 
    bufferSizeInBytes, 
    AudioTrack.MODE_STREAM); 

應該是:

AudioTrack audioTrack = new AudioTrack(
    AudioManager.STREAM_MUSIC, sampleRateInHz, 
    AudioFormat.CHANNEL_OUT_MONO, 
    AudioFormat.ENCODING_PCM_16BIT, 
    bufferSizeInBytes, 
    AudioTrack.MODE_STREAM 
    sessionId); // this param is important, which is audioRecord. getAudioSessionId() 
相關問題