Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

problem of read method in AudioRecord class

public int read (byte[] audioData, int offsetInBytes, int sizeInBytes).

This method reads audio data from the audio hardware for recording into a buffer.

Its Parameters are : audioData the array to which the recorded audio data is written. offsetInBytes index in audioData from which the data is written expressed in bytes. sizeInBytes the number of requested bytes.

It Returns the number of bytes that were read or or ERROR_INVALID_OPERATION if the object wasn't properly initialized, or ERROR_BAD_VALUE if the parameters don't resolve to valid data and indexes. The number of bytes will not exceed sizeInBytes.

I have written this method in my code like this : int num; byte[] buf = new byte[160]; num = record.read(buf, 0, 160);

The problem is that it always returns 160 (i.e. the requested byte to be read) not less than 160 even if the data is not available. what's the problem? help me. Thanks in advance.

like image 960
abc Avatar asked Dec 31 '10 10:12

abc


2 Answers

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.

like image 194
Jesse Gordon Avatar answered Oct 27 '22 10:10

Jesse Gordon


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).

AudioRecord being a continuous stream, the case of "no more data available" never applies.

like image 24
EboMike Avatar answered Oct 27 '22 11:10

EboMike