I'm trying to record around 500 frames using AudioRecord, but it seems like AudioRecord's buffer initially gets partially filled with a number of 0s before capturing meaningful values.
I had to read the initial 10000 frames using an array in order to get to the actual values.
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
44100,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
2*44100);
audioRecord.startRecording();
audioRecord.read(new short[10000], 0, 10000); // have to include this to remove redundant values
audioRecord.read(audio, 0, 500);
audioRecord.stop();
If I omit the third line, I'll end up with 500 zeros. This solution isn't neat and I need to know if I'm doing something wrong. Also, it's important to note that before the read()
methods are called, the state
is STATE_INITIALIZED
and the recordingState
is RECORDSTATE_RECORDING
, also the read()
methods return exactly the number of frames that they're supposed to read, so no problem there.
You are using the AudioRecord
correctly. The issue seems to be some AGC on the mic; as you observed, the values read out of the buffer gradually become larger over the first few ms. It is likely this is a hardware AGC, perhaps added by the manufacturer to inhibit a sharp "crack" at the start of each new recording.
As an aside: I have an old RAZR with AGC that's so aggressive, if you snap your fingers near the mic, it'll go silent for a full second, and then slowly fade in.
One solution to this problem is just to leave the AudioRecord
recording on a long-term basis. Then, when you decide you need to grab your 500 frames, it'll already be "warmed up", and the values should be full-scale.
EDIT
I just unit-tested it, and it seems that AudioRecord
does not overwrite the data in its internal buffer if you neglect to read it out quickly enough. Or, at least, it's not clear exactly what's happening with that data. So, a more complicated solution is necessary.
In this case, it looks like you'll have to ensure the buffer never overflows. That means calling read()
at a fast enough rate. Depending on your architecture, you may find it easiest to dedicate a thread for this purpose.
If you simply use a 500 frame buffer in each of your reads, then when the time comes, you can just grab a copy of that buffer, which will be reasonably close to the "most recent possible" data streaming from the mic. This assumes you have been reading quickly enough such that your next read would block.
I say "reasonably close" because audio data is placed in the buffer in chunks of size getMinBufferSize()/2
, if I remember correctly, and this is also the limit of OnRecordPositionUpdateListener
resolution. So, you'll be somewhere close to the end, but it's hard to tell exactly how close.