问题
I need your help. I'm trying to record some audio with Androids AudioRecord class. Most time this works very well but sometimes I get a SIGSEGV error.
Here is the code which runs in a seperate Thread while recording audio:
private void startRecording() {
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
@Override
public void run() {
writeAudioDataToFile();
}
}, "AudioRecorder Thread");
recordingThread.start();
}
private void writeAudioDataToFile() {
byte data[] = new byte[bufferSize];
String filename = getTempFilename();
FileOutputStream os = null;
try {
os = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int read = 0;
if (null != os) {
while (isRecording) {
read = recorder.read(data, 0, bufferSize);
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
os.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
os.close();
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here is what I do, when the recording stops:
public void stopRecording() {
if (null != recorder) {
isRecording = false;
mRecordingBlocked = true;
mProgressDialog = RecorderDialog.newInstance();
mProgressDialog.show(getFragmentManager(), "progressDialog");
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
new Thread(new Runnable() {
@Override
public void run() {
String fileName = getFilename();
copyWaveFile(getTempFilename(), fileName);
final TelephonyManager tm = (TelephonyManager) getActivity().getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();
App.db.insertEntry(deviceId, "Song title", fileName);
deleteTempFile();
if (cbox_overdub.isChecked()) {
phrases.add(playAudio(fileName, true));
}
}
}).start();
}
}
private void copyWaveFile(String inFilename, String outFilename) {
FileInputStream in;
FileOutputStream out;
long totalAudioLen = 0;
long totalDataLen;
long longSampleRate = RECORDER_SAMPLERATE;
int channels = 2;
long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels / 8;
try {
AppLog.logString("begin copyWaveFile try{}");
File file = new File(inFilename);
in = new FileInputStream(file);
byte[] bytes = new byte[(int) file.length()];
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
in.read(bytes);
in.close();
out = new FileOutputStream(outFilename);
AppLog.logString("fos created");
WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
AppLog.logString("wave header written");
int bufferLength = 1024;
publishProgress(0);
for (int i = 0; i < bytes.length; i += bufferLength) {
int progress = (int) ((i / (float) bytes.length) * 100);
publishProgress(progress);
if (bytes.length - i >= bufferLength) {
out.write(bytes, i, bufferLength);
} else {
out.write(bytes, i, bytes.length - i);
}
}
publishProgress(100);
AppLog.logString("progress complete");
mRecordingBlocked = false;
mProgressDialog.dismiss();
out.close();
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
It seems this error occurs after the instance of AudioRecord has already been stopped. Then I copy the contents of my temporary temp_record.wav (SD Card) to the destination (SD Card) with setting a proper wave file header.
I'm not able to filter any useful information out of the following debug information. I hope someone has an idea. Thank you!
Here's the Logcat output:
06-30 14:47:53.311: INFO/DEBUG(9381): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
06-30 14:47:53.311: INFO/DEBUG(9381): Build fingerprint: 'otorola/RTGB/umts_milestone2:2.3.4/MILS2_U6_4.1-22/1317097892:user/release-keys'
06-30 14:47:53.311: INFO/DEBUG(9381): pid: 9459, tid: 9525 >>> de.intermeco.android.apps.ilaugh <<<
06-30 14:47:53.311: INFO/DEBUG(9381): signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 4640e000
06-30 14:47:53.311: INFO/DEBUG(9381): r0 4640e000 r1 00000000 r2 fffffd49 r3 4670da18
06-30 14:47:53.311: INFO/DEBUG(9381): r4 4640e000 r5 4640e000 r6 fffffd49 r7 4670da18
06-30 14:47:53.311: INFO/DEBUG(9381): r8 a904cf6a r9 0000000a 10 a904cfad fp a904cff0
06-30 14:47:53.311: INFO/DEBUG(9381): ip a9060074 sp 4670d9e0 lr afd11704 pc afd113dc cpsr 20000050
06-30 14:47:53.311: INFO/DEBUG(9381): d0 6472656767756265 d1 0037fff00020000c
06-30 14:47:53.311: INFO/DEBUG(9381): d2 fff5ffd8fff5ffdb d3 ffe0ffd8ffd9ffd8
06-30 14:47:53.311: INFO/DEBUG(9381): d4 fff2ffe50008ffd4 d5 ffdafffafff20000
06-30 14:47:53.311: INFO/DEBUG(9381): d6 fff40003ffcf0003 d7 ffe30013ffe1fffd
06-30 14:47:53.311: INFO/DEBUG(9381): d8 0000000000989680 d9 0000000000000000
06-30 14:47:53.311: INFO/DEBUG(9381): d10 0000000000000000 d11 0000000000000000
06-30 14:47:53.311: INFO/DEBUG(9381): d12 0000000000000000 d13 0000000000000000
06-30 14:47:53.311: INFO/DEBUG(9381): d14 0000000000000000 d15 0000000000000000
06-30 14:47:53.311: INFO/DEBUG(9381): d16 000000c24003a7e0 d17 4000000000000000
06-30 14:47:53.311: INFO/DEBUG(9381): d18 3ff0000000000000 d19 0000000000000000
06-30 14:47:53.311: INFO/DEBUG(9381): d20 b96377ce858a5d48 d21 3929f5135cb87c55
06-30 14:47:53.311: INFO/DEBUG(9381): d22 3e21ee9ebdb4b1c4 d23 bda8fae9be8838d4
06-30 14:47:53.319: INFO/DEBUG(9381): d24 0000000000000000 d25 0000000000000000
06-30 14:47:53.319: INFO/DEBUG(9381): d26 0000000000000000 d27 ffffffffffffffff
06-30 14:47:53.319: INFO/DEBUG(9381): d28 0100010001000100 d29 0100010001000100
06-30 14:47:53.319: INFO/DEBUG(9381): d30 4086800000000000 d31 3ff0000000000000
06-30 14:47:53.319: INFO/DEBUG(9381): scr 60000010
06-30 14:47:53.483: INFO/DEBUG(9381): #00 pc 000113dc /system/lib/libc.so (pthread_mutex_lock)
06-30 14:47:53.483: INFO/DEBUG(9381): #01 pc 00011700 /system/lib/libc.so (__pthread_cond_timedwait_relative)
06-30 14:47:53.483: INFO/DEBUG(9381): #02 pc 0002d658 /system/lib/libmedia.so
06-30 14:47:53.483: INFO/DEBUG(9381): code around pc:
06-30 14:47:53.483: INFO/DEBUG(9381): afd113bc e3a02001 ebfffe82 e1a00005 e8bd87f0
06-30 14:47:53.483: INFO/DEBUG(9381): afd113cc 00036024 e92d47f0 e2504000 0a000019
06-30 14:47:53.483: INFO/DEBUG(9381): afd113dc e5946000 e5947000 e2166903 1a000017
06-30 14:47:53.483: INFO/DEBUG(9381): afd113ec e5945000 e1a02004 e2055a02 e1a00005
06-30 14:47:53.483: INFO/DEBUG(9381): afd113fc e3851001 ebffed7f e3500000 13856002
06-30 14:47:53.483: INFO/DEBUG(9381): code around lr:
06-30 14:47:53.483: INFO/DEBUG(9381): afd116e4 e1a03007 e1a02006 e2011001 e1a00004
06-30 14:47:53.483: INFO/DEBUG(9381): afd116f4 ebfffd9a e1a04000 e1a00005 ebffff32
06-30 14:47:53.483: INFO/DEBUG(9381): afd11704 e374006e 03a0006e 13a00000 e8bd81f0
06-30 14:47:53.483: INFO/DEBUG(9381): afd11714 e304cdd3 e3043240 e92d4010 e341c062
06-30 14:47:53.483: INFO/DEBUG(9381): afd11724 e1a0e002 e24dd008 e340300f e1a0200d
06-30 14:47:53.483: INFO/DEBUG(9381): stack:
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9a0 04000804
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9a4 00000001
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9a8 001c6b58
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9ac 00000262
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9b0 0000ee6b
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9b4 afd0fe34 /system/lib/libc.so
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9b8 001edbb0
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9bc afd13bc1 /system/lib/libc.so
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9c0 001b0470
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9c4 001c6b58
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9c8 00000241
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9cc 3b9aca00
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9d0 00000000
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9d4 00989680
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9d8 df002777
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9dc e3a070ad
06-30 14:47:53.483: INFO/DEBUG(9381): #00 4670d9e0 00000000
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9e4 4640e000
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9e8 fffffd49
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9ec 4670da18
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9f0 a904cf6a /system/lib/libmedia.so
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9f4 0000000a
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9f8 a904cfad /system/lib/libmedia.so
06-30 14:47:53.483: INFO/DEBUG(9381): 4670d9fc afd11704 /system/lib/libc.so
06-30 14:47:53.483: INFO/DEBUG(9381): #01 4670da00 4640e000
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da04 4640e004
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da08 4670da98
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da0c 000000c8
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da10 a904cf6a /system/lib/libmedia.so
06-30 14:47:53.483: INFO/DEBUG(9381): 4670da14 a902d65b /system/lib/libmedia.so
回答1:
Thanks for pointing out SIGSEV again, i over read it a little because i didn't know its meaning. Now i do :) I agree with CommonsWare that you should inform the manufacturer/modder of the firmware. But i also think it does not help you further in a useful time span. Maybe we find a way to modify your code in a way not to provoke the error anymore.
Generally your code looks quite good. What i think is not totally safe and proper is the way you are stopping the recorder.
- Instead of using the isRecording flag i'd use a isCancelled flag. So you record while(!isCancelled). And when you want to stop recording you just set isCancelled to true and call recorder.stop().
- After recording stopped you can call, right after writeAudioDataToFile() in the audio recorder thread, your logic for display the progress dialog and for copy the file. I would not use an additional thread for these things since we are still in the audio recorder thread and your UI is not blocked.
- When to call recorder.release(), it releases memory... The docs "Releases the native AudioRecord resources." I don' know exactly, if this has an influence on the problem. In the current code you provided, you call recorder.release() while theoretically the recorder could reading (without knowing if the class is threadsafe). Maybe you could also try to call it after you copied all your files, even i think it should be fine after the recorder really stopped and your outputstream is closed.
Hope i could help a little and you are able to find a way.
回答2:
Thank you for your proposals. I rebuild the code a little bit and now it seems to work. At least I did not get the error for about one day (longer than before :D).
I changed the method writeAudioDataToFile() so that now releasing and so on is done there, too (after isRecording is set to false in the stopRecording() method). I do also not create a second Thread anymore, but handle all things in the RecorderThread.
So this seems to work for me now:
private void writeAudioDataToFile() {
byte data[] = new byte[bufferSize];
String filename = getTempFilename();
FileOutputStream os = null;
try {
os = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int read = 0;
if (null != os) {
while (isRecording) {
read = recorder.read(data, 0, bufferSize);
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
os.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
os.close();
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
recorder.stop();
recorder.release();
recorder = null;
String fileName = getFilename();
copyWaveFile(getTempFilename(), fileName);
final TelephonyManager tm = (TelephonyManager) getActivity().getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getActivity().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();
App.db.insertEntry(deviceId, "Song title", fileName);
deleteTempFile();
if (cbox_overdub.isChecked()) {
phrases.add(playAudio(fileName, true));
}
}
}
public void stopRecording() {
if (null != recorder) {
Toast.makeText(getActivity(), "Stop Recording", Toast.LENGTH_SHORT).show();
((ImageView) getActivity().findViewById(R.id.btnMic)).setImageDrawable(getActivity().getResources().getDrawable(R.drawable.btn_mic));
isRecording = false;
mRecordingBlocked = true;
mProgressDialog = RecorderDialog.newInstance();
mProgressDialog.show(getFragmentManager(), "progressDialog");
}
}
private void publishProgress(int progress) {
ProgressDialog pd = ((ProgressDialog) mProgressDialog.getDialog());
if (pd != null) pd.setProgress(progress);
}
Thank you for now!
回答3:
A SIGSEGV should not be possible from Java code. Unless this was your JNI code, this would indicate a flaw in the firmware.
If you are running modded firmware, please pass this information along to the firmware modders.
If you are running the original firmware that came with your device, and this only occurs on one device, you can try to contact the device manufacturer.
If you are seeing this on more than one device with original firmware, and you can create a sample project that reproduces the error, post the project and the stack trace on the Android issue tracker, assuming this issue is not already reported there.
回答4:
The documentation states:
In order to receive the respective callback associated with these listeners, applications are required to create MediaRecorder objects on threads with a Looper running (the main UI thread by default already has a Looper running).
Make sure you create the recorder on the UI thread. Perhaps also call its methods on the UI thread.
回答5:
None of the above solutions worked for me. Instead I increased the buffer in the constructor of the AudioRecord.
The minimum buffersize recommends something between 1k and 4k depending on the parameters and device. It seems my algorithm is too slow to read the data from the buffer before the buffer is full so I got the segv (to be honest I am just guessing the consequences).
After I enhanced the buffer to a value twice as much as I need data from the AudioRecord it works like a charm.
bufferSize = AudioRecord.getMinBufferSize(sampleAudioBitRate,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
if (bufferSize < sampleSize * 2)
bufferSize = sampleSize * 2;
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleAudioBitRate,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.w(TAG, "audioRecord not initialized");
return;
}
来源:https://stackoverflow.com/questions/11274341/android-sigsegv-error-when-recording-audio