views:

83

answers:

1

I'm having troubles using AudioRecord.

An example using some of the code derived from the splmeter project:

private static final int FREQUENCY = 8000;
private static final int CHANNEL = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private int BUFFSIZE = 50;
private AudioRecord recordInstance = null;

...

android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, CHANNEL, ENCODING, 8000);
recordInstance.startRecording();
short[] tempBuffer = new short[BUFFSIZE];
int retval = 0;

while (this.isRunning) {
   for (int i = 0; i < BUFFSIZE - 1; i++) {
      tempBuffer[i] = 0;
   }

   retval = recordInstance.read(tempBuffer, 0, BUFFSIZE);
   ... // process the data
}

This works on the HTC Dream and the HTC Magic perfectly without any log warnings/errors, but causes problems on the emulators and Nexus One device.

On the Nexus one, it simply never returns useful data. I cannot provide any other useful information as I'm having a remote friend do the testing.

On the emulators (Android 1.5, 2.1 and 2.2), I get weird errors from the AudioFlinger and Buffer overflows with the AudioRecordThread. I also get a major slowdown in UI responsiveness (even though the recording takes place in a separate thread than the UI).

Is there something apparent that I'm doing incorrectly? Do I have to do anything special for the Nexus One hardware?

EDIT

I've partially solved the problem... The Documentation for AudioRecord says:

public static int getMinBufferSize (int sampleRateInHz, int channelConfig, int audioFormat)

Returns the minimum buffer size required for the successful creation of an AudioRecord object. Note that this size doesn't guarantee a smooth recording under load, and higher values should be chosen according to the expected frequency at which the AudioRecord instance will be polled for new data.for new data.

So I changed the buffer length to

private static final int BUFFSIZE = AudioRecord.getMinBufferSize(FREQUENCY, CHANNEL, ENCODING);

And now the Emulators run well.

But

Hardware doesn't. While the emulators return a value of 640 from that call (giving 12.5 polls per second) based on 8khz, the HTC hardware returns 4096! Meaning roughly 2 polls per second and an audio delay of half a second! Furthermore, that same call on the Nexus One returns 8192! So a full second delay!

I wish it ended at that, but the nexus one still doesn't return any audio (still don't have one myself, so I can't get proper debugging information from one), even though the HTC devices and all emulators now work (even if some are more laggy than others).

Am I doing something horribly wrong here?

A: 

I solved it!

I (wrongfully) assumed that the magic 8000 number used in the constructor of the AudioRecord class was a duplicate of the frequency variable. It's actually supposed to be the buffer size that you'll be using.

Unfortunately, not only is this different from the splmeter's buffer length (default 320 - which I modified to 50 in my first code block), but the minimum buffer size acceptable for the Nexus One is 8192, so the AudioRecord instance must not have been created properly.

So when I had my modified buffer length (from getMinBufferSize), replaced the magic 8000 with it, and increased my Frequency variable to the suggested 44100, everything works perfectly across all platforms/emulators.

So if you plan on using the splmeter code base before it gets patched, take these three things into account.

To be honest, the splmeter code shouldn't even work on the HTC devices. I guess that's why my dev device is named the HTC Magic =P

Marc