3

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

Greg
  • 357
  • 1
  • 11
  • It is very strange. What code is at these line mentioned in error stack trace. @Greg – Pie May 21 '19 at 18:03
  • 1
    Not sure i understand what you mean. Do you mean the entire logcat? – Greg May 21 '19 at 18:05
  • At line no 162 @greg – Pie May 21 '19 at 18:08
  • 1
    I assume this is line 162 of the Java file, then that would be the "recorder.stop();" line of the stopRecording method. – Greg May 21 '19 at 18:10
  • I would surround your "recorder.stop()" with a try catch, and Explicitly output the Caught RuntimeException; I'm leaning toward in the quicktap, the recorder object is not properly initialized or used... Attempting to stop it results in the exception. – Akin Okegbile May 21 '19 at 18:25

1 Answers1

1

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) {}
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Kou Peto
  • 237
  • 2
  • 7
  • I tried the code, i tried setting the boolean as default value both "false" and "true" and nothing changes. App still works as it did before, still crashes on tap. – Greg May 21 '19 at 18:31
  • 1
    Solution 2 works!!!!!!! I have lost a week's worth of sleep on this... You have my eternal gratitude dude – Greg May 21 '19 at 18:38