16

如何在android.media.AudioRecord没有任何依赖智能手机制造商的花哨信号处理(如自动增益控制 (AGC) 和/或均衡、噪声抑制、回声消除等)的情况下进行音频录制……仅使用纯麦克风信号?

背景

MediaRecorder.AudioSource提供九个常数,

  • DEFAULTMIC最初在那里,
  • VOICE_UPLINK, VOICE_DOWNLINK, 并VOICE_CALL在 API 级别 4 中添加,
  • CAMCORDERVOICE_RECOGNITION在 API 7 中添加,
  • VOICE_COMMUNICATION在 API 11 中添加,
  • REMOTE_SUBMIX在 API 19 中添加,但不适用于第三方应用程序。

但是它们中没有一个在所有智能手机上都做得很干净。相反,我必须自己找出似乎,哪个设备使用哪个信号处理块的组合用于哪个MediaRecorder.AudioSource常数。

PURE_MIC如果在 API 级别 20 中添加第十个常量,那就太好了。

但只要这不可用,我能做什么呢?

4

4 回答 4

8

简短的回答是“无”。

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

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

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

于 2013-01-17T14:11:50.783 回答
3

某些设备默认为声音输入通道添加 AGC 效果。因此,您需要获取对相应 AudioEffect 对象的引用并强制将其禁用。

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

if (AutomaticGainControl.isAvailable()) {
    AutomaticGainControl agc = AutomaticGainControl.create(
            myAudioRecord.getAudioSessionId()
        );
    agc.setEnabled(false);
}
于 2016-04-18T12:55:49.377 回答
3

注意:大多数音频源(包括 DEFAULT)都对音频信号进行处理。要录制原始音频,请选择未处理。某些设备不支持未处理的输入。首先调用 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);
于 2017-02-15T01:47:16.077 回答
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
        }
    }

}
于 2019-02-28T14:10:41.363 回答