Воспроизведение звука, поступающего с микрофона в режиме реального времени
Я пытаюсь заставить приложение записывать звук, поступающий с микрофона, и воспроизводить его обратно (примерно) в режиме реального времени, однако без успеха.
Я использую классы AudioRecord и AudioTrack для записи и воспроизведения, соответственно. Я пробовал разные подходы, я пытался записать входящий звук и записать его в файл, и он работал нормально. Я также пытался воспроизвести звук из этого файла ПОСЛЕ с помощью AudioTrack, и он тоже работал отлично. Проблема в том, что я пытаюсь воспроизвести звук в режиме реального времени, вместо того, чтобы читать файл после его написания.
Вот код:
//variables
private int audioSource = MediaRecorder.AudioSource.MIC;
private int samplingRate = 44100; /* in Hz*/
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private int bufferSize = AudioRecord.getMinBufferSize(samplingRate, channelConfig, audioFormat);
private int sampleNumBits = 16;
private int numChannels = 1;
// …
AudioRecord recorder = new AudioRecord(audioSource, samplingRate, channelConfig, audioFormat, bufferSize);
recorder.startRecording();
isRecording = true;
AudioTrack audioPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
if(audioPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING)
audioPlayer.play();
//capture data and record to file
int readBytes=0, writtenBytes=0;
do{
readBytes = recorder.read(data, 0, bufferSize);
if(AudioRecord.ERROR_INVALID_OPERATION != readBytes){
writtenBytes += audioPlayer.write(data, 0, readBytes);
}
}
while(isRecording);
Вызывается исключение java.lang.IllegalStateException, вызванное тем, что "play() вызван неинициализированным AudioTrack".
Однако, если я изменяю инициализацию AudioTrack, например, чтобы использовать частоту дискретизации 8000 Гц и формат выборки 8 бит (вместо 16), он больше не генерирует исключение, и приложение работает, хотя оно вызывает ужасные шумы.
Когда я проигрываю AudioTrack из файла, нет никаких проблем с инициализацией AudioTrack, я пробовал 44100 и 16 бит, и он работал правильно, создавая правильный звук.
Любая помощь?
Ответы
Ответ 1
Все родные Android-аудио закодированы. Вы можете воспроизводить только форматы PCM в режиме реального времени или использовать специальный streaming кодек, который я не считаю тривиальным для Android.
Дело в том, что если вы хотите одновременно записывать/воспроизводить аудио, вам нужно будет создать свой собственный звуковой буфер и хранить в нем необработанные аудиофайлы, закодированные в PCM (я не уверен, что вы думаете о духе! или все это на вас, голова, поэтому я постараюсь быть ясной, но не пережевывать вашу резину).
PCM - это цифровое представление аналогового сигнала, в котором ваши аудио образцы представляют собой набор "моментальных снимков" исходной акустической волны. Поскольку все виды умных математиков и инженеров видели потенциал в попытке уменьшить количество бит, с которыми вы представляете эти данные, они придумали всевозможные кодеры. Кодированный (сжатый) сигнал представляется очень по-разному от необработанного сигнала ИКМ и должен быть декодирован (en-cod-er + dec-oder = codec). Если вы не используете специальные алгоритмы и медиатекстовые кодеки, невозможно воспроизвести закодированный сигнал, как вы пытаетесь, потому что он не кодирует образец по образцу, а скорее кадр за кадром, где вам нужен весь кадр образцов, если не полный сигнал, чтобы декодировать этот кадр.
Способ сделать это - это вручную хранить образцы звука, поступающие из буфера микрофона, и вручную подавать их в выходной буфер. Вам нужно будет сделать некоторую кодировку для этого, но я считаю, что есть некоторые приложения с открытым исходным кодом, на которые вы можете посмотреть и взять пик в своем источнике (если вы не захотите продать свое приложение позже, конечно, но это целое другое обсуждение).
Если вы разрабатываете Android 2.3 или новее и не слишком боитесь программирования в родном коде, вы можете попробовать использовать OpelSL ES. Android-особенности OpenSL ES перечислены здесь. Эта платформа позволяет вам несколько более гибко манипулировать аудио, и вы можете найти именно то, что вам нужно, если ваше приложение будет сильно полагаться на обработку звука.
Надеюсь, что это поможет. Ура! =)
Ответ 2
Вызывается исключение java.lang.IllegalStateException с тем, что вызванный "play(), вызванный неинициализированным AudioTrack".
Это потому, что размер буфера слишком мал. Я попробовал "bufferSize + = 2048;", тогда это нормально.
Ответ 3
У меня была аналогичная проблема, и я решил ее, добавив это разрешение в файл манифеста:
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>