Android media recording and unhandled events

84 Views Asked by At

Hi I am using android with java. I have set up a very simple button which when held down records audio and when released stops recording. I have two questions:

When I run the following implementation of my idea, I get runtime a warning mediarecorder went away with unhandled events every time the button is released. I can't find what is causing this! I see that this has been answered previously on this forum many years ago with the suggestion to add mediaRecorder.update(), but this does not address why the warning is occurring. What does it mean by unhandled events and what could be causing it? I have done nothing different I can see than in the documentation, other than using an onTouchListener...

Second, should I be wary of user's being able to switch on and off the button very rapidly - could this cause runtime problems and should I take steps to guard against this?

The relevant code I use is more-or-less this:

public void set() {
View.OnTouchListener recordOnTouchListener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        if (requestMultiplePermissions(Permissions).granted) {
                            audioSetup();
                            recordAudio();
                        }
                        return true;
                    case MotionEvent.ACTION_UP:
                        stopAudio();
                        return true;
                    default:
                        return false;
                }
            }
binding.addnewvocabRecordVocab.setOnTouchListener(recordOnTouchListener)
}

where

private void audioSetup() {
        File filedir = new File(filepath);
        if (!filedir.exists()) {filedir.mkdirs();
        file = new File(filepath,filename);
        if (file.exists()) { file.delete();}
}

public void recordAudio () {
        isRecording = true;
        if (mediaRecorder != null) {
            mediaRecorder.stop();
            mediaRecorder.release();
            mediaRecorder = null;
        }
        try {
            mediaRecorder = new MediaRecorder();
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mediaRecorder.setOutputFile(file);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mediaRecorder.prepare();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mediaRecorder.start();
}

public void stopAudio () {
        if (isRecording) {
            mediaRecorder.stop();
            mediaRecorder.release();
            mediaRecorder = null;
            isRecording = false;
        }
}
1

There are 1 best solutions below

0
dlw On

This isn't a full answer to my own question, and the question still stands. But after playing with this a while, I have learnt a few lessons.

  • If the user taps the record button for a second, then mediarecorder.stop() will produce an error if there is not sufficient data recorded. See this. So if one wants to prevent the app from crashing, one needs to wrap mediarecorder.stop() in some catch - as the discussion in the link advises us. In fact, on some shortish taps, the stop method seems to take rather a long time (well over a second), so it might be worth considering disabling the button just before and after the stop method is called.
  • Another problem with fast repeated tapping is that it seems to keep adding to the main thread queue, which is probably inadvisable. I have found that using an executor thread with submit is a nice way of dealing with this. Schematically we can
public class audioLibrary() {
//or could go directly in main code

ExecutorService executor;

public void onStartRecord() {
   if (executor == null) {
      this.executor = Executors.newSingleThreadExecutor();
      executor.submit(() -> {
         //check isRecording and record stuff
      });
   }
}

public void onStopRecord() {
   if (executor != null) {
      executor.submit(() -> {
         //check isRecording and shut down mediarecorder
         //together with catch for onStop.
      });
      executor.shutdown();
   }
}

}

Clearly, one must be a little careful to make sure the thread really does always get shut down.

Curiously, I do not get the `unhandled events' when I do this now...

Maybe someone could expand on this and comment on my code above to see whether they agree with the gist of it, whether it is necessary and on possible improvements.