如何在不录制的情况下在 Android 上对麦克风进行采样以获得实时振幅/电平?

IT小君   2021-10-24T08:49:49

我试图在 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。

看来要让这个工作,我必须真正开始录音。那是对的吗?

如果是这样,我是否需要记录500ms,获取幅度,停止记录并重复?

最后,我必须记录到文件中吗?我不需要保存这个音频文件,难道我不能在不录音的情况下获取当前实时麦克风输入的当前振幅或自上次调用以来的最高振幅吗?

任何帮助表示赞赏,谢谢。

评论(4)
IT小君

Toumal 的解决方案有效,但是我无法获得足够高的刷新率以满足我的需求。所以我最终使用了Toumal 链接SoundMeter.java类,但对其进行了修改以使用此答案中的代码

这是我使用的代码,它提供了更好的刷新率:

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

}
2021-10-24T08:49:49   回复
IT小君

是的,你必须先调用 recorder.start() ,最后也不要忘记调用 recorder.stop() !

有关示例应用程序,请参阅http://code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/,您可能想看看 SoundMeter。 java 和 NoiseAlert.java

2021-10-24T08:49:49   回复
IT小君

使用 AudioRecord 类而不是 MediaRecorder

看看这个网站:http : //www.doepiccoding.com/blog/?p=195,它给出了一个很好的解释和一个工作代码:)

2021-10-24T08:49:49   回复
IT小君

您还可以使用 mediaRecoder 类,在需要使用 Handler 的 UI 上显示实时数据:

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

这部分在 UI 上显示数据:

    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 是 UI 将更新的延迟(以毫秒为单位)

正如您在此处看到的,如果您将输出目标设置为如下,则无需将输出保存到文件,它不会保存在任何地方:

mediaRecorder.setOutputFile("/dev/null");
2021-10-24T08:49:49   回复