【问题标题】:How avoid automatic gain control with AudioRecord?如何避免使用 AudioRecord 进行自动增益控制?
【发布时间】:2012-12-31 21:32:41
【问题描述】:

如何使用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 中添加第十个常量,例如 PURE_MIC,那就太好了。

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

【问题讨论】:

    标签: android api audio-recording


    【解决方案1】:

    简短的回答是“无”。

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

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

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

    【讨论】:

    • 我同意 DEFAULT、MIC、VOICE_*,但我知道 VOICE_RECOGNITION 是专门为避免额外的信号处理而引入的(一些 OEM 显然忽略了)。有没有其他方法,例如audioManager.setParameters 调用的“神奇”组合?
    • 我在音频的 SW 方面工作,所以我不参与调音过程。但我希望在 VOICE_RECOGNITION 情况下需要一个干净的语音信号(没有背景噪声、削波等),以便它可用于语音到文本的处理。因此,我猜至少会使用一个噪声抑制器和一个 AGC / 多频段压缩器。
    • ASR 通常会受益于纯音频,因为它在特征向量提取中执行自己的准 AGC,并且通常使用噪声进行训练。文档“Android 4.1 兼容性定义”(2012 年 9 月 7 日)第 5.3 节明确指出:“必须禁用 VOICE_RECOGNITION、降噪处理和自动增益控制”。制造商希望将其更改为 Android >=4.1,则不需要 PURE_MIC。但我有我的怀疑。所以,还是我的问题:还有其他方法吗?
    • 你找到从MIC获取纯音频的方法了吗?
    • 在我提出问题和更多 API 级别之后的 2 年多之后,我仍然没有看到除了 try&error 之外的任何其他方法。但是,如果有人可以添加具有不同内容的第二个答案,我仍然会很高兴。
    【解决方案2】:

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

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

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

    【讨论】:

    • 谢谢。我对大量设备进行了尝试,但没有成功。您能否说出其中一些设备以及此方法适用的 Android 版本?
    【解决方案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);
    

    【讨论】:

      【解决方案4】:

      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
              }
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-07
        • 2014-04-01
        • 2021-10-27
        • 2016-09-16
        • 1970-01-01
        • 1970-01-01
        • 2013-07-01
        • 1970-01-01
        相关资源
        最近更新 更多