javaandroidandroidxandroid-mediarecorderandroid-audiorecord

MediaRecorder start called in invalid state: 4 || E/AudioRecording: prepare() failed


I'm with a big problem in my Record Audio App, and I read every post related to it in this site, and tryied every solution suggested, but didn't solved my problem. My app works fine in all Android versions from AndroidQ 10.0(SDK29) and bellow, and this problems only appears at version 10.0+, specifically in SDK30. Does anyone knows how to solve it, or maybe, have any idea about what is causing this bug?
Here is a print of the log: https://imgur.com/a/xSATHSp
The Manifest: https://imgur.com/a/T6eEGmb
The Code(line76): https://imgur.com/a/lrmlB58
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
I also tryied other solutions from another foruns, like this one, in the section "What could go wrong?" at subtopic "java.lang.IllegalStateException": https://www.grokkingandroid.com/recording-audio-using-androids-mediarecorder-framework/

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

My log exception:

E/AudioRecording: prepare() failed
E/MediaRecorder: start called in an invalid state: 4
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myfetus, PID: 17985
    java.lang.IllegalStateException
        at android.media.MediaRecorder.start(Native Method)
        at com.example.myfetus.MainActivity$1.onClick(MainActivity.java:81)
        at android.view.View.performClick(View.java:7448)
        at android.view.View.performClickInternal(View.java:7425)
        at android.view.View.access$3600(View.java:810)
        at android.view.View$PerformClick.run(View.java:28305)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)


My ActivityMain code:


public class MainActivity extends AppCompatActivity{
    private ImageButton recordbtn, stopbtn, playbtn, stopplay, pausebtn;
    private MediaRecorder mRecorder;
    private MediaPlayer mPlayer;
    private static final String LOG_TAG = "AudioRecording";
    private static String mFileName = null;
    public static final int REQUEST_AUDIO_PERMISSION_CODE = 1;
    private int buttonState = 0;
    private EditText editsenha1;
    private TextView test1;
    private ImageView editImagem;
    private int i=0;
    Date createdTime = new Date();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recordbtn = (ImageButton)findViewById(R.id.record);
        stopbtn = (ImageButton)findViewById(R.id.stopRecord);
        playbtn = (ImageButton)findViewById(R.id.play);
        stopplay = (ImageButton)findViewById(R.id.stopplay);
        pausebtn = (ImageButton)findViewById(R.id.pause);
        stopbtn.setEnabled(false);
        playbtn.setEnabled(false);
        stopplay.setEnabled(false);

        mFileName = (Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "MyFetus" +createdTime + "Audio.m4a").replaceAll(" ", "_").replaceAll(":", "-");
        test1 = findViewById(R.id.texto2);
         editImagem = findViewById(R.id.imageView4);

        recordbtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                    if (CheckPermissions()) {
                        stopbtn.setEnabled(true);
                        recordbtn.setEnabled(false);
                        playbtn.setEnabled(false);
                        stopplay.setEnabled(false);
                        pausebtn.setEnabled(false);
                        mRecorder = new MediaRecorder();
                        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                        mRecorder.setAudioEncodingBitRate(128000);
                        mRecorder.setAudioSamplingRate(44100);
                        mRecorder.setOutputFile(mFileName);
                        try {
                            mRecorder.prepare();

                        } catch (IOException e) {
                            Log.e(LOG_TAG, "prepare() failed");
                        }
                        mRecorder.start();
                        Toast.makeText(getApplicationContext(), "Recording Started", Toast.LENGTH_LONG).show();
                        test1.setText("Gravando...");
                        test1.setTextColor(Color.parseColor("#0af263"));
                    } else {
                        RequestPermissions();
                    }
                    recordbtn.setVisibility(View.INVISIBLE);
                    stopbtn.setVisibility(View.VISIBLE);
                }


        });
        stopbtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopbtn.setEnabled(false);
                recordbtn.setEnabled(true);
                playbtn.setEnabled(true);
                stopplay.setEnabled(true);
                pausebtn.setEnabled(true);
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;
                Toast.makeText(getApplicationContext(), "Recording Stopped", Toast.LENGTH_LONG).show();
                test1.setText("Aperte para gravar");
                test1.setTextColor(Color.parseColor("#FADCEE"));
                stopbtn.setVisibility(View.INVISIBLE);
                recordbtn.setVisibility(View.VISIBLE);
            }
        });
        playbtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopbtn.setEnabled(false);
                recordbtn.setEnabled(true);
                playbtn.setEnabled(false);
                stopplay.setEnabled(true);
                pausebtn.setEnabled(true);
                mPlayer = new MediaPlayer();
                try {
                    mPlayer.setDataSource(mFileName);
                    mPlayer.prepare();
                    mPlayer.start();
                    Toast.makeText(getApplicationContext(), "Recording Started Playing", Toast.LENGTH_LONG).show();
                } catch (IOException e) {
                    Log.e(LOG_TAG, "prepare() failed");
                }
            }
        });
        pausebtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mPlayer!=null){
                mPlayer.pause();
                stopbtn.setEnabled(true);
                recordbtn.setEnabled(true);
                playbtn.setEnabled(true);
                stopplay.setEnabled(true);
                pausebtn.setEnabled(false);
                Toast.makeText(getApplicationContext(),"Audio Paused", Toast.LENGTH_SHORT).show();}
            }
        });
        stopplay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPlayer.release();
                mPlayer = null;
                stopbtn.setEnabled(false);
                recordbtn.setEnabled(true);
                playbtn.setEnabled(true);
                stopplay.setEnabled(false);
                pausebtn.setEnabled(true);
                Toast.makeText(getApplicationContext(),"Audio Stopped", Toast.LENGTH_SHORT).show();
            }
        });


    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_AUDIO_PERMISSION_CODE:
                if (grantResults.length> 0) {
                    boolean permissionToRecord = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    boolean permissionToStore = grantResults[1] ==  PackageManager.PERMISSION_GRANTED;
                    if (permissionToRecord && permissionToStore) {
                        Toast.makeText(getApplicationContext(), "Permission Granted", Toast.LENGTH_LONG).show();
                    } else {
                        Toast.makeText(getApplicationContext(),"Permission Denied",Toast.LENGTH_LONG).show();
                    }
                }
                break;
        }
    }
    public boolean CheckPermissions() {
        int result = ContextCompat.checkSelfPermission(getApplicationContext(), WRITE_EXTERNAL_STORAGE);
        int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), RECORD_AUDIO);
        return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
    }
    private void RequestPermissions() {
        ActivityCompat.requestPermissions(MainActivity.this, new String[]{RECORD_AUDIO, WRITE_EXTERNAL_STORAGE}, REQUEST_AUDIO_PERMISSION_CODE);
    }
}


Solution

  • The problem you are facing with Android 10 upwards is, that you cannot access files on the external SD card anymore. You have to use either the Storage Access Framework to create a file first and then use it as a base for storing, or you only use app private storage.

    Or - IMHO better in this case - you use the MediaStore content provider. See the official docs for more details about how to add files to MediaStore.

    If you use MediaStore you canot use setOutputfile() anymore. Use setOutputFileDescriptor()instead with the FileDescriptor you can get from the MediaStore content provider.