如何避免使用AudioRecord进行自动增益控制?

时间:2013-01-17 10:54:33

标签: android api audio-recording

如何使用android.media.AudioRecord进行录音,而无需任何依赖智能手机制造商的花式信号处理,如自动增益控制(AGC)和/或均衡,噪音抑制,回声消除,......只需纯麦克风信号φ

背景

MediaRecorder.AudioSource提供了九个常量,

  • DEFAULTMIC最初在那里,
  • API级别4中添加了
  • VOICE_UPLINKVOICE_DOWNLINKVOICE_CALL
  • 在API 7中添加了
  • CAMCORDERVOICE_RECOGNITION
  • 在API 11中添加了
  • VOICE_COMMUNICATION
  • REMOTE_SUBMIX在API 19中添加,但第三方应用程序无法使用。

但他们都没有在所有智能手机上做得干净。相反,我必须自己发现,哪个设备使用哪个MediaRecorder.AudioSource恒定的信号处理块组合。

在API级别20中添加第10个常量(例如PURE_MIC会很高兴。

但只要没有,我该怎么做呢?

4 个答案:

答案 0 :(得分:6)

简短回答是“没什么”。

AudioSources对应于各种逻辑音频输入设备,具体取决于您连接到手机的附件和当前用例,而当前用例又对应于物理设备(主要内置麦克风,辅助麦克风,有线耳机麦克风)等等。用不同的调音。

OEM对每个这样的物理设备和调整组合进行调整,以满足外部要求(例如CTS,操作员要求等)和OEM本身设置的内部声学要求。此过程可能会导致各种滤波器(如AGC,噪声抑制,均衡等)进入硬件编解码器或多媒体DSP级别的音频输入路径。

虽然PURE_MIC来源可能对某些应用程序有用,但它不是今天可用的。 在许多设备上,您可以使用amixer写入硬件编解码器的ALSA控件来控制麦克风增益,甚至可能是过滤器链。但是,这显然是一种非常特定于平台的方法,我也怀疑你必须以root用户或音频用户身份运行才能执行此操作。

答案 1 :(得分:2)

默认情况下,某些设备会将AGC效果添加到声音输入区域。因此,您需要获取对相应AudioEffect对象的引用并强制它禁用。

首先,获取链接到AudioRecord音频会话的AutomaticGainControl对象,然后将其设置为禁用:

if (AutomaticGainControl.isAvailable()) {
    AutomaticGainControl agc = AutomaticGainControl.create(
            myAudioRecord.getAudioSessionId()
        );
    agc.setEnabled(false);
}

答案 2 :(得分:1)

注意:大多数音频源(包括DEFAULT)都会对音频信号进行处理。要录制原始音频,请选择UNPROCESSED。某些设备不支持未处理的输入。首先调用AudioManager.getProperty(“PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED”)以验证它是否可用。如果不是,请尝试使用VOICE_RECOGNITION,而不使用AGC或噪声抑制。即使不支持该属性,也可以将UNPROCESSED用作音频源,但在这种情况下无法保证信号是否未被处理。

Android文档链接https://developer.android.com/guide/topics/media/mediarecorder.html#example

    AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
    if(audioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED) !=null)
        mRecorder.setAudioSource(MediaRecorder.AudioSource.UNPROCESSED);
    else
        mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION);

答案 3 :(得分:0)

MIC应该很好,其余的则需要知道它们是否受支持。

我为此做了一堂课

enum class AudioSource(val audioSourceValue: Int, val minApi: Int) {
    VOICE_CALL(MediaRecorder.AudioSource.VOICE_CALL, 4), DEFAULT(MediaRecorder.AudioSource.DEFAULT, 1), MIC(MediaRecorder.AudioSource.MIC, 1),
    VOICE_COMMUNICATION(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 11), CAMCORDER(MediaRecorder.AudioSource.CAMCORDER, 7),
    VOICE_RECOGNITION(MediaRecorder.AudioSource.VOICE_RECOGNITION, 7),
    VOICE_UPLINK(MediaRecorder.AudioSource.VOICE_UPLINK, 4), VOICE_DOWNLINK(MediaRecorder.AudioSource.VOICE_DOWNLINK, 4),
    @TargetApi(Build.VERSION_CODES.KITKAT)
    REMOTE_SUBMIX(MediaRecorder.AudioSource.REMOTE_SUBMIX, 19),
    @TargetApi(Build.VERSION_CODES.N)
    UNPROCESSED(MediaRecorder.AudioSource.UNPROCESSED, 24);

    fun isSupported(context: Context): Boolean =
            when {
                Build.VERSION.SDK_INT < minApi -> false
                this != UNPROCESSED -> true
                else -> {
                    val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
                    Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && "true" == audioManager.getProperty(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED)
                }
            }

    companion object {
        fun getAllSupportedValues(context: Context): ArrayList<AudioSource> {
            val values = AudioSource.values()
            val result = ArrayList<AudioSource>(values.size)
            for (value in values)
                if (value.isSupported(context))
                    result.add(value)
            return result
        }
    }

}