UPDATE: This bug in Android got fixed somewhere after 4.2.2 and before 5.01. On 5.01, the callbacks work exactly like the documents say they should.
It looks like read
is blocking due to some shortsightedness of the developers.
Basically, when a audio recorder is initialized it allocates a sort of ring buffer, and when its told to .start()
, it begins recording to that buffer.
Then when .read()
is called, it reads up to half of the buffer size (or the requested size, whichever is less) and returns.
If it wants to read 1000 samples and there are only 900 available, it has to wait for 100 more samples before returning. If, however, there are more than 1000 samples, it reads those instantly and then returns right away.
Ideally, they would either provide a non-blocking read so that whatever is available is returned, or provide a way to know when a full read's worth of data is available so a non-blocking read can be performed.
I don't think they support the first. They appear to attempt to support the second by using the set period callback method, but so far I can't get that call back at the correct time to do a quick non-blocking read.
I've cloned the full source (8.5G bytes) of the native C++ source code and I'm trying to follow the functionality through all the layers to see how it's supposed to work.
The trick for non-blocking .read(0)
ing is to only read when there's a full read's worth of samples ready. But determining when that condition is true is what I haven't figure out yet.
References:
Here's the java code for .read() which calls a native C++ function:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.4_r1/android/media/AudioRecord.java#AudioRecord.read%28java.nio.ByteBuffer%2Cint%29
The above read() method calls the native native_read_in_direct_buffer()
which is found in:
http://pdroid.googlecode.com/svn/android-2.3.4_r1/trunk/frameworks/base/core/jni/android_media_AudioRecord.cpp
which calls or points to android_media_AudioRecord_readInByteArray()
which in turn calls AudioRecord.read()
in frameworks/base/media/libmedia/frameworks/base/media/libmedia/AudioRecord.cpp
(as best as I can tell) and it looks like in this function there's a do/while loop which essentially blocks until the desired number of bytes have been read (or half of the buffersize, whichever is smaller.)
I have tried to get the callbacks to function nicely but they seem to only call back at a time when read() has to wait for the audio buffer to be filled before it can return -- so what's the point.
My next goal is to try to track down the notify callback source code so I can get a guess on exactly what that's supposed to do and when.
read
is a blocking method. It will only return after it has read as many bytes you told it to read, or if the stream is closed, or if the stream indicates there is no more data available (for example when reading a file). – Skin