How to sample microphone on Android without recording to get live amplitude/level?
Asked Answered
G

5

24

I was trying to get the amplitude level of a microphone on Android like so:

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

Unfortunately, this only returns 0 all the time.

It appears that for this to work I have to actually start recording. Is that correct?

If so, do I need to record for 500ms, get amplitude, stop recording and repeat?

Finally, do I have to record to a file? I do not need to save this audio file, can't I just get the current amplitude or highest amplitude since last call of the current live microphone input without recording?

Any help is appreciated, thanks.

Ganda answered 23/1, 2011 at 22:42 Comment(0)
M
8

Yep you have to call recorder.start() first, and you must not forget to call recorder.stop() at the end too!

See http://code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/ for an example application, you may want to take a look at SoundMeter.java and NoiseAlert.java

Moonseed answered 5/2, 2011 at 15:30 Comment(2)
apparently one can use AudioRecord instead, no need to record a fileGanda
You can redirect audio/media output to /dev/null and prevent any actual recording from happening that way. Also make sure you use recorder.prepare(), it won't work otherwise.Kantianism
P
24

The solution from Toumal works, however I wasn't able to get a high enough refresh rate for my needs. So I ended up using the SoundMeter.java class that Toumal linked but modified it to use the code from this answer

Here is the code I used, which provides a much better refresh rate:

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

}
Pickup answered 30/10, 2014 at 4:26 Comment(2)
I see the only difference between the 2 codes is AudioFormat.CHANNEL_IN_MONO instead of AudioFormat.CHANNEL_CONFIGURATION_MONO. Is this what makes the refresh rate better ?Zobe
@Zobe I have no idea, I've not looked at this since I answered this question 7 years agoPickup
M
8

Yep you have to call recorder.start() first, and you must not forget to call recorder.stop() at the end too!

See http://code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/ for an example application, you may want to take a look at SoundMeter.java and NoiseAlert.java

Moonseed answered 5/2, 2011 at 15:30 Comment(2)
apparently one can use AudioRecord instead, no need to record a fileGanda
You can redirect audio/media output to /dev/null and prevent any actual recording from happening that way. Also make sure you use recorder.prepare(), it won't work otherwise.Kantianism
H
2

Use AudioRecord Class Instead of MediaRecorder

Check out this site: http://www.doepiccoding.com/blog/?p=195 , it gives a nice explanation and a working code :)

Hughie answered 31/5, 2016 at 10:46 Comment(0)
E
2

You can also use mediaRecoder class, to display real time data on UI you need to use 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();
}
}

This part show data on UI:

    private Runnable pollTask = new Runnable() {
    @Override
    public void run() {
        double amplitude = soundMeter.getAmplitude();
        amplitudeTextView.setText("Amplitude: " + amplitude);

        handler.postDelayed(pollTask, 500);
    }
};

Don't forget to call handler in onCreate method:

handler.postDelayed(pollTask, 500);

500 is delay in milliseconds which UI will updated

as you can see here you don't need to save output to file if you set output destination as below it won't save anywhere:

mediaRecorder.setOutputFile("/dev/null");
Ecliptic answered 10/8, 2017 at 5:49 Comment(0)
J
1

Based on Benjamin answer but updated to Kotlin:

class MicChecker @Inject constructor(@ApplicationContext val context: Context) {
    private var audioRecord: AudioRecord? = null
    private var minSize = 0
    val level: Int
        get() {
            val buffer = ShortArray(minSize)
            audioRecord?.read(buffer, 0, minSize)
            return buffer.max().toInt()
        }

    fun startCheck() {
        minSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)
        if (ActivityCompat.checkSelfPermission(context, RECORD_AUDIO) != PERMISSION_GRANTED) {
            Timber.d("==> record audio permission not granted")
            return
        }
        audioRecord = AudioRecord(
            MediaRecorder.AudioSource.MIC,
            8000,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            minSize
        )
        audioRecord?.startRecording()
    }

    fun stopCheck() {
        audioRecord?.stop()
    }
}
Jamshedpur answered 27/4, 2023 at 11:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.