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

Posted

技术标签:

【中文标题】如何在不录制的情况下在 Android 上对麦克风进行采样以获得实时幅度/电平?【英文标题】:How to sample microphone on Android without recording to get live amplitude/level? 【发布时间】:2011-06-14 04:56:54 【问题描述】:

我试图像这样在 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,获取幅度,停止记录并重复吗?

最后,我必须记录到文件吗?我不需要保存这个音频文件,我不能只获取当前的实时麦克风输入的当前振幅或自上次呼叫以来的最高振幅而不进行录音吗?

感谢您的帮助。

【问题讨论】:

【参考方案1】:

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

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

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;
    


【讨论】:

我看到这两个代码之间的唯一区别是 AudioFormat.CHANNEL_IN_MONO 而不是 AudioFormat.CHANNEL_CONFIGURATION_MONO。这是使刷新率更好的原因吗? @YoussefDir 我不知道,自从我 7 年前回答这个问题后我就没有看过这个【参考方案2】:

是的,你必须先调用recorder.start(),而且你一定不要忘记在最后调用recorder.stop()!

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

【讨论】:

显然可以使用 AudioRecord 代替,不需要录制文件 您可以将音频/媒体输出重定向到 /dev/null 并防止任何实际录制以这种方式发生。还要确保你使用了 recorder.prepare(),否则它不会工作。【参考方案3】:

使用 AudioRecord 类代替 MediaRecorder

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

【讨论】:

【参考方案4】:

您也可以使用 mediaRecoder 类,在 UI 上显示实时数据,您需要使用 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();


这部分在 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");

【讨论】:

以上是关于如何在不录制的情况下在 Android 上对麦克风进行采样以获得实时幅度/电平?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在不使用 AVFoundation 框架的情况下在 iOS 中录制音频?

在不录制的情况下监控 iPhone 上的音频输入?

如何在不使用模拟位置的情况下在 android 上欺骗位置?

如何在不先保存的情况下在 Android 中发送 zip 文件?

如何在不登录的情况下在 Android 中发布到 Facebook Wall?

如何在不使用 Eclipse 的情况下在 Android 上安装/替换