Как избежать автоматической регулировки усиления с помощью AudioRecord?

Как я могу делать аудиозаписи, используя android.media.AudioRecord без какой-либо обработки необычного сигнала, зависящего от производителя смартфона, такого как автоматическая регулировка усиления (AGC) и / или эквалайзер, подавление шума, эхоподавление, ... только чистый микрофонный сигнал?

Фон

MediaRecorder.AudioSource обеспечивает девять констант,

  • DEFAULT а также MIC изначально быть там,
  • VOICE_UPLINK, VOICE_DOWNLINK, а также VOICE_CALL добавлено на уровне API 4,
  • CAMCORDER а также VOICE_RECOGNITION добавлено в API 7,
  • VOICE_COMMUNICATION добавлен в API 11,
  • REMOTE_SUBMIX добавлен в API 19, но недоступен сторонним приложениям.

Но ни один из них не делает чистую работу на всех смартфонах. Скорее, я должен выяснить сам, кажется, какое устройство использует какие комбинации блоков обработки сигналов для каких MediaRecorder.AudioSource постоянная.

Было бы неплохо иметь десятую константу как PURE_MIC добавлен в API уровень 20.

Но пока это не доступно, что я могу сделать вместо этого?

3 ответа

Решение

Краткий ответ: "Ничего".

Аудиоисточники соответствуют различным логическим устройствам аудиовхода в зависимости от аксессуаров, которые вы подключили к телефону, и текущего варианта использования, который, в свою очередь, соответствует физическим устройствам (основной встроенный микрофон, дополнительный микрофон, микрофон с проводной гарнитурой и т. Д.) с разными настройками.

Каждая такая комбинация физического устройства и настройки подбирается OEM-производителем для соответствия как внешним требованиям (например, CTS, требованиям оператора и т. Д.), Так и внутренним акустическим требованиям, установленным самим OEM-производителем. Этот процесс может привести к введению различных фильтров - таких как AGC, подавление шума, выравнивание и т. Д. - в тракт ввода звука на уровне аппаратного кодека или мультимедийного DSP.

В то время как PURE_MIC Источник может быть полезен для некоторых приложений, это не то, что доступно сегодня.
На многих устройствах вы можете контролировать такие вещи, как усиление микрофона и, возможно, даже цепочку фильтров, используя amixer записать в ALSA элементы управления аппаратного кодека. Однако, очевидно, что это был бы очень специфичный для платформы подход, и я также подозреваю, что вы должны работать от имени пользователя root или аудио, чтобы иметь возможность делать это.

Некоторые устройства по умолчанию добавляют эффект AGC в тракт ввода звука. Следовательно, вам нужно получить ссылку на соответствующий объект AudioEffect и принудительно отключить его.

Сначала получите объект AutomaticGainControl, связанный с аудио-сеансом AudioRecord, а затем просто отключите его:

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

Примечание. Большинство аудиоисточников (включая DEFAULT) применяют обработку к аудиосигналу. Для записи необработанного аудио выберите UNPROCESSED. Некоторые устройства не поддерживают необработанный ввод. Сначала вызовите AudioManager.getProperty("PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED"), чтобы убедиться, что он доступен. Если это не так, попробуйте использовать вместо этого VOICE_RECOGNITION, который не использует AGC или подавление шума. Вы можете использовать UNPROCESSED в качестве источника звука, даже если свойство не поддерживается, но нет никакой гарантии, будет ли сигнал необработанным или нет в этом случае.

Ссылка на документацию по Android https://developer.android.com/guide/topics/media/mediarecorder.html

    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);

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

}
Другие вопросы по тегам