Android的AEC和​​Noise Suppressor在某些设备上不工作

问题描述:

在使用VoIP功能的Android Unity应用程序中,我们发现在某些设备(特别是Galaxy S6)上,麦克风会拾取由扬声器,导致了很多静态,失真和回声。正因为如此,我已经开始致力于本地解决方案,以利用Android的一些AEC和NS功能。Android的AEC和​​Noise Suppressor在某些设备上不工作

我已经写了下面的测试床,它可以在Note 4等一些设备上完美地工作。当Galaxy S6上运行相同的应用程序时,就好像ARC和NS没有被很好地应用或者完全没有应用。

public class MainActivity extends Activity 
{ 
    private AudioRecord mAudioRecorder = null; 
    private AudioTrack mStreamingPlayer = null; 

    private Thread playbackThread = null; 

    private boolean useVoip = true; 

    int bufferSize; 
    int chunkSize; 

    private AutomaticGainControl agc; 
    private NoiseSuppressor suppressor; 
    private AcousticEchoCanceler aec; 

    private boolean manuallyAttachEffects = false; 

    private void StartRecordingAudio() 
    { 
     int sampleRate = 44100; 
     int channelConfig = AudioFormat.CHANNEL_IN_MONO; 
     int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 

     chunkSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 
     bufferSize = chunkSize * 10; 

     int audioSource = MediaRecorder.AudioSource.MIC; 

     if (useVoip && !manuallyAttachEffects) 
     { 
      audioSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION; 
     } 

     mAudioRecorder = new AudioRecord(audioSource, 
             sampleRate, 
             channelConfig, 
             audioFormat, 
             bufferSize); 

     if (useVoip && manuallyAttachEffects) 
     { 
      SetupVoipEffects(mAudioRecorder.getAudioSessionId()); 
     } 

     mAudioRecorder.startRecording(); 

     mStreamingPlayer = new AudioTrack( AudioManager.STREAM_MUSIC, 
              sampleRate, 
              AudioFormat.CHANNEL_OUT_MONO, 
              audioFormat, 
              bufferSize, 
              AudioTrack.MODE_STREAM); 

     mStreamingPlayer.play(); 

     playbackThread = new Thread(new Runnable() 
     { 
      @Override 
      public void run() { 
       readAudioData(); 
      } 

     }); 

     playbackThread.start(); 
    } 

    private void readAudioData() 
    { 
     Thread thisThread = Thread.currentThread(); 

     byte[] buffer = new byte[chunkSize]; 

     while (!thisThread.isInterrupted()) 
     { 
      if (mAudioRecorder == null) 
       break; 

      int bytesRead = mAudioRecorder.read(buffer, 0, chunkSize); 
      if (bytesRead > 0) 
      { 
       if (mStreamingPlayer == null) 
        break; 

       mStreamingPlayer.write(buffer, 0, chunkSize); 
      } 
     } 
    } 

    private void SetupVoipEffects(int sessionId) 
    { 
     if(AutomaticGainControl.isAvailable()) 
     { 
      agc = AutomaticGainControl.create(sessionId); 
      Log.d(LOG_TAG, "AGC is " + (agc.getEnabled()?"enabled":"disabled")); 

      if (!agc.getEnabled()) 
      { 
       agc.setEnabled(true); 
       Log.d(LOG_TAG, "AGC is " + (agc.getEnabled()?"enabled":"disabled" +" after trying to enable")); 
      } 
     } 

     if(NoiseSuppressor.isAvailable()) 
     { 
      suppressor = NoiseSuppressor.create(sessionId); 
      Log.d(LOG_TAG, "NS is " + (suppressor.getEnabled()?"enabled":"disabled")); 

      if (!suppressor.getEnabled()) 
      { 
       suppressor.setEnabled(true); 
       Log.d(LOG_TAG, "NS is " + (suppressor.getEnabled()?"enabled":"disabled" +" after trying to disable")); 
      } 

     } 
     if(AcousticEchoCanceler.isAvailable()) 
     { 
      aec = AcousticEchoCanceler.create(sessionId); 
      Log.d(LOG_TAG, "AEC is " + (aec.getEnabled()?"enabled":"disabled")); 

      if (!aec.getEnabled()) 
      { 
       aec.setEnabled(true); 
       Log.d(LOG_TAG, "AEC is " + (aec.getEnabled()?"enabled":"disabled" +" after trying to disable")); 
      } 
     } 
    } 
} 

我已经尝试了很多东西,如使用VOICE_COMMUNICATION为AudioRecord,使用MIC和手动创建NoiseSuppressor和AcousticEchoCanceller,禁用/启用NuPlayer/AwesomePlayer,等等。这些设备显示AEC被支持和启用,但它似乎并没有发生。使用耳机或使用手机代替扬声器电话时问题完全消失(因此麦克风无法拾取扬声器声音)。我在这里忽略了一些巨大的东西,还是有可能会报告一个错误?

如果AEC和NS在其他设备上无法正常工作,我不会怀疑。

这是Android中的一个已知问题。硬件AEC是不可靠的,即使他们报告了硬件AEC也不会被大量硬件实现/支持。 我会建议部署一个软件AEC以及硬件AEC,以使您的软件更稳定。唯一的问题是软件AEC不太容易正确完成,所以要做好大量的测试准备。