Android: выбор микрофона без записи, чтобы получить живую амплитуду/уровень?
Я пытался получить амплитудный уровень микрофона на Android, например:
MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new RecorderTask(recorder), 0, 1000);
private class RecorderTask extends TimerTask {
private MediaRecorder recorder;
public RecorderTask(MediaRecorder recorder) {
this.recorder = recorder;
}
public void run() {
Log.v("MicInfoService", "amplitude: " + recorder.getMaxAmplitude());
}
}
К сожалению, это возвращает только 0.
Похоже, что для этого я должен начать запись. Это правильно?
Если да, нужно ли записывать за 500 мс, получать амплитуду, останавливать запись и повторять?
Наконец, мне нужно записать в файл? Мне не нужно сохранять этот аудиофайл, не могу ли я получить текущую амплитуду или самую высокую амплитуду после последнего вызова текущего живого микрофона без записи?
Любая помощь приветствуется, спасибо.
Ответы
Ответ 1
Да, сначала нужно вызвать recorder.start(), и вы также не должны забывать вызывать recorder.stop() в конце!
См. http://code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/ для примера приложения, вы можете взглянуть на SoundMeter.java и NoiseAlert.java
Ответ 2
Решение от Toumal работает, однако мне не удалось получить достаточно высокую частоту обновления для моих нужд. Поэтому я закончил использование класса SoundMeter.java, который связал Toumal, но изменил его, чтобы использовать код из этого ответ
Вот код, который я использовал, который обеспечивает гораздо лучшую частоту обновления:
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
public class SoundMeter {
private AudioRecord ar = null;
private int minSize;
public void start() {
minSize= AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
ar = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000,AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,minSize);
ar.startRecording();
}
public void stop() {
if (ar != null) {
ar.stop();
}
}
public double getAmplitude() {
short[] buffer = new short[minSize];
ar.read(buffer, 0, minSize);
int max = 0;
for (short s : buffer)
{
if (Math.abs(s) > max)
{
max = Math.abs(s);
}
}
return max;
}
}
Ответ 3
Использовать класс AudioRecord вместо MediaRecorder
Посмотрите на этом сайте: http://www.doepiccoding.com/blog/?p=195, это дает хорошее объяснение и рабочий код:)
Ответ 4
Вы также можете использовать класс mediaRecoder для отображения данных в режиме реального времени в пользовательском интерфейсе, который вам нужен для использования Handler:
public class SoundMeter {
private MediaRecorder mediaRecorder;
public void start(){
if(started){
return;
}
if (mediaRecorder == null){
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(
MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(
MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(
MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setOutputFile("/dev/null");
try{
mediaRecorder.prepare();
}catch (IllegalStateException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
mediaRecorder.start();
started = true;
}
}
}
public double getAmplitude(){
return mediaRecorder.getMaxAmplitude();
}
}
В этой части приведены данные по пользовательскому интерфейсу:
private Runnable pollTask = new Runnable() {
@Override
public void run() {
double amplitude = soundMeter.getAmplitude();
amplitudeTextView.setText("Amplitude: " + amplitude);
handler.postDelayed(pollTask, 500);
}
};
Не забудьте вызвать обработчик в методе onCreate:
handler.postDelayed(pollTask, 500);
500 - это задержка в миллисекундах, которые обновит пользовательский интерфейс
как вы можете видеть здесь, вам не нужно сохранять вывод в файл, если вы задаете выходной адрес назначения, как показано ниже:
mediaRecorder.setOutputFile("/dev/null");