I am building an app that records and plays audio. I use a touch button to record. Audio is recorded successfully on prolonged touch, but if i tap the button without holding my finger on it for more than one second, my app crashes.
mRecordBtn.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
startRecording();
mRecordLabel.setText("Recording...");
}
else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
stopRecording();
mRecordLabel.setText("Recording stopped");
}
return false;
}
});
private void startRecording() {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
try {
recorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
recorder.start();
}
private void stopRecording() {
recorder.stop();
recorder.release();
recorder = null;
}
Logcat when prolonged touching (no error):
D/ViewRootImpl@406d73a[MainActivity]: ViewPostIme pointer 0
I/MediaRecorderJNI: setup
I/MediaRecorderJNI: setAudioSource(1)
I/MediaRecorderJNI: setAudioEncoder(3)
I/MediaRecorderJNI: setOutputFile
I/MediaRecorderJNI: prepare
I/MediaRecorderJNI: start
D/ViewRootImpl@406d73a[MainActivity]: ViewPostIme pointer 1
I/MediaRecorderJNI: stop
I/MediaRecorderJNI: release
W/MediaRecorder: mediarecorder went away with unhandled events
Logcat when tapping:
D/ViewRootImpl@d597feb[MainActivity]: ViewPostIme pointer 0
I/MediaRecorderJNI: setup
I/MediaRecorderJNI: setAudioSource(1)
I/MediaRecorderJNI: setAudioEncoder(3)
I/MediaRecorderJNI: setOutputFile
I/MediaRecorderJNI: prepare
I/MediaRecorderJNI: start
D/ViewRootImpl@d597feb[MainActivity]: ViewPostIme pointer 1
I/MediaRecorderJNI: stop
E/MediaRecorder: stop failed: -1007
E/InputEventReceiver: Exception dispatching input event.
E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
E/MessageQueue-JNI: java.lang.RuntimeException: stop failed.
at android.media.MediaRecorder._stop(Native Method)
at android.media.MediaRecorder.stop(MediaRecorder.java:1340)
at tk.gandriks.gaaudiotransform.MainActivity.stopRecording(MainActivity.java:162)
at tk.gandriks.gaaudiotransform.MainActivity.access$200(MainActivity.java:34)
at tk.gandriks.gaaudiotransform.MainActivity$1.onTouch(MainActivity.java:78)
at android.view.View.dispatchTouchEvent(View.java:12536)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:601)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)
at android.app.Activity.dispatchTouchEvent(Activity.java:3384)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:563)
at android.view.View.dispatchPointerEvent(View.java:12788)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5670)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5465)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5114)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5171)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7736)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7676)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7637)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7847)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:197)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:325)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: tk.gandriks.gaaudiotransform, PID: 20802
java.lang.RuntimeException: stop failed.
at android.media.MediaRecorder._stop(Native Method)
at android.media.MediaRecorder.stop(MediaRecorder.java:1340)
at tk.gandriks.gaaudiotransform.MainActivity.stopRecording(MainActivity.java:162)
at tk.gandriks.gaaudiotransform.MainActivity.access$200(MainActivity.java:34)
at tk.gandriks.gaaudiotransform.MainActivity$1.onTouch(MainActivity.java:78)
at android.view.View.dispatchTouchEvent(View.java:12536)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3159)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2844)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:601)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1871)
at android.app.Activity.dispatchTouchEvent(Activity.java:3384)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:563)
at android.view.View.dispatchPointerEvent(View.java:12788)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5670)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5465)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5114)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5171)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4977)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4985)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4958)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7736)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7676)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7637)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7847)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:197)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:325)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
I/zygote64: Do partial code cache collection, code=29KB, data=20KB
After code cache collection, code=28KB, data=20KB
Increasing code cache capacity to 128KB
I/MediaRecorderJNI: finalize
release
Application terminated.
I can tell there is something wrong when stopping the recording process, but i can't seem to fix it on my own...
The prepare needs some time to be executed, so when tapping you are trying to stop the recorder but you are not sure that it has already started, you can have a variable isStarted
to check or surround the stop with a try catch.
Solution 1
private void startRecording() {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setOutputFile(fileName);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
try {
recorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
recorder.start();
isStarted = true;
}
private void stopRecording() {
if(isStarted) {
recorder.stop();
recorder.release();
recorder = null;
isStarted = false;
}
}
Solution 2
private void stopRecording() {
try {
recorder.stop();
recorder.release();
recorder = null;
} catch(Exception e) {}
}