I am trying to record audio from the device.
I created an AudioRecord object and manage it over the cycle of the activity.
When my app goes to background it stops, and when in foreground it continues.
When the recording is running, I want to get the samples from the recorder to a byte array
This is the code I use to do it:
private void startRecorder() {
Log.d(TAG, "before start recording");
myBuffer = new byte[2048];
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_DTMF, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
myRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 2048);
myThread = new Thread() {
public void run() {
while (true) {
if (myRecorder != null && myRecorder.getState() == AudioRecord.RECORDSTATE_RECORDING) {
myRecorder.read(myBuffer, 0, 2048);
recordingSampleNumber++;
if (recordingSampleNumber % 10 == 0) {
Log.d(TAG, "recording sample number:" + recordingSampleNumber);
}
}
}
}
};
myThread.setPriority(Thread.MAX_PRIORITY);
myRecorder.startRecording();
myThread.start();
Log.d(TAG, "after start recording");
}
My problem is: Every once in a while I get the following error :
06-22 11:44:21.057: E/AndroidRuntime(17776): Process: com.example.microphonetestproject2, PID: 17776
06-22 11:44:21.057: E/AndroidRuntime(17776): java.lang.NullPointerException: Attempt to invoke virtual method 'int android.media.AudioRecord.getState()' on a null object reference
06-22 11:44:21.057: E/AndroidRuntime(17776): at com.example.microphonetestproject2.MicrophoneTestApp$3.run(MicrophoneTestApp.java:108)
my question is: Why would I get an NPE on myRecorder.getState() when just half a line before that i wrote "if myRecorder!=null"
This looks like a concurrency problem.
It seems that after the check myRecorder != null, the variable is actually set to null in a different thread, which is possible because as you probably know threads run in parallel.
I'd recommend you lock on the object and execute your loop. Then, no one will access it out of place, i.e. unexpectedly.
Although this may fix your problem, you should deal with it with in other ways, e.g. instead of setting the variable to null to cancel the thread, use the built in
interrupt
andjoin
methods:interrupt() as you may have understood, interrupts the thread, but it does not kill it instantly. With the help of join() you can wait for the Thread to finish after you interrupted it.