Как избежать автоматической регулировки усиления с помощью 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
}
}
}