Immediate Audio Input & Output Android
В моем приложении для Android я хотел бы взять немного звука с микрофона смартфона и сразу же воспроизвести его, жить, как микрофон, без запаздывания. В настоящее время я думаю об использовании классов AudioRecord
и AudioTrack
(из того, что я прочитал), но я не совсем уверен, как действовать дальше.
Я проверил некоторые другие вопросы о переполнении стека, но они точно не отвечают на то, что я хотел бы сделать. И большинство из них - с 2012 года.
Итак, как я могу использовать эти классы для одновременного ввода и вывода звука?
ТАКЖЕ: Я посмотрел на MediaRecorder API
, но из того, что я читал, требуется, чтобы вы сохранили звук в файле, который я не хочу делать. Может ли он быть tweeked для удовлетворения моих требований? Или мне лучше использовать AudioRecord
?
Спасибо
EDIT:
Вот мой обновленный код ниже, как @Pradip Pramanick предложил:
final Thread record = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.interrupted()) {
MediaRecorder microphone = new MediaRecorder();
microphone.setAudioSource(MediaRecorder.AudioSource.MIC);
microphone.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
microphone.setOutputFile(filename);
microphone.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
microphone.prepare();
} catch (IOException e) {
e.printStackTrace();
}
microphone.start();
}
}
});
final Thread play = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.interrupted()) {
player = new MediaPlayer();
try {
player.setDataSource(filename);
player.prepare();
player.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Я получаю Illegal State Exception | Start failed: -38
. Но я называю microphone.start
после microphone.prepare
... Какая проблема? Я искал другие темы, в которых говорилось, что с помощью микрофона могут быть другие фоновые приложения. Я искал свое устройство: Moto X Play (3rd Gen) и не нашел ни одного. (Я даже отключил распознавание голоса "ОК Google", но ошибка продолжалась).
ОШИБКА:
Вот лог-кота, показывающий самые последние ошибки:
01-31 09:37:21.064 344-3339/? E/MediaPlayerService: offset error
01-31 09:37:21.065 1835-1922/com.synerflow.testapp E/MediaPlayer: Unable to create media player
01-31 09:37:21.065 1835-1922/com.synerflow.testapp I/Player: player.prepare() has failed
01-31 09:37:21.065 1835-1922/com.synerflow.testapp W/System.err: java.io.IOException: setDataSourceFD failed.: status=0x80000000
Исключение IO похоже на player.setDataSource(filename)
, переменная filename представляет собой строку: Environment.getExternalStorageDirectory().getAbsolutePath() + "\voice.3gp"
Ответы
Ответ 1
Насколько я могу думать, это можно сделать очень простым способом. Я не пробовал, но вы это пробовали. Я думаю, это сработает:
Создайте два потока, один для записи другого для воспроизведения.
Скажем, что нитями являются TRecord и TPlay.
В методе прогона TRecord выполните следующее:
public void run(){
MediaRecorder mRecorder = null;
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile(mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
//todo
}
mRecorder.start();
}
И его метод запуска TPlay делает это:
public void run() {
MediaPlayer mPlayer = null;
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mFileName);
mPlayer.prepare();
mPlayer.start();
} catch (IOException e) {
//todo
}
}
Теперь на mainactivity просто создайте два потока. Сначала запустите поток TRecord, затем Tplay. Попробуйте.
вот код для расширения файла:
mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
mFileName += "/audiorecordtest.3gp";
Ответ 2
На самом деле это действительно сложно на Android. У Google есть очень хороший (но немного длинный) видео, объясняющий проблемы.
Они также имеют страницу, объясняющую методы тестирования и тесты времени ожидания для различных устройств.
По сути, Android Android не может делать звук с нулевой латентностью, однако нет ничего, что мешало бы аппаратным партнерам добавлять необходимые аппаратные средства и расширения платформы для этого.
Ответ 3
попробуйте это. Я не запускал это.
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING, bufferSize * BytesPerElement);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
public void run() {
try {
int intSize = android.media.AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_MONO , RECORDER_AUDIO_ENCODING);
byte[] sData = new byte[bufferSize];
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_MONO, RECORDER_AUDIO_ENCODING, intSize, AudioTrack.MODE_STREAM);
while(isRecording){
recorder.read(sData, 0, bufferSize); //isRecording = false; onStop button
if (at!=null) {
at.play();
// Write the byte array to the track
at.write(sData, 0, sData.length);
at.stop();
at.release();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, "AudioRecorder Thread");
recordingThread.start();