Ritu
Ritu

Reputation: 666

MediaRecorder prepare() failed /storage/emulated/0/: open failed: EPERM (Operation not permitted)

I am trying to record audio on my Android 12 Device with File and Media Permission granted but recorder.prepare(); throws

prepare() failed /storage/emulated/0/Music/Exotel/Media/Exotel Audio/Voice Messages/Exotel Temp/Exotel_Voice1658709937668.3gpp: open failed: EPERM (Operation not permitted)

I am using official documentation but they are saving recording into app specific storage(getExternalCacheDir().getAbsolutePath();) and i am saving on external public storage String TempPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath()+ "/" + subfolder; . No matter what i try i still get the same error whenever i tried to save into external shared storage.

Here is my code:

String subfolder = "Exotel/Media/Exotel Audio/Voice Messages/Exotel Temp";
String time = new SimpleDateFormat("yyyyMMddhhmmss", Locale.US).format(new Date());
String filename = Session.getUserFname()+"_Voice"+time+".3gp";
String TempPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath()+ "/" + subfolder;
File dir = new File(TempPath);

if (!dir.exists()){
    dir.mkdirs();
}

TempPath = TempPath+"/"+filename;
Log.d(TAG, "onTouch: Temp Path "+TempPath);

recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(TempPath);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

try {
    recorder.prepare();
    recorder.start();
} catch (IOException | IllegalStateException e) {
    Log.e(TAG, "prepare() failed "+e.getMessage());
}

Upvotes: 1

Views: 1125

Answers (1)

Vadik Sirekanyan
Vadik Sirekanyan

Reputation: 4652

The getExternalStoragePublicDirectory() method is deprecated in API level 29 (Android 10).

If you want to save a file into a public shareable directory you have to use MediaStore API. I also recommend taking a look at all options for storing files on Android.

If you have no problems with saving your recordings into a cache directory (by using the code from the official docs). Then you can copy the file from the cache to the public directory using MediaStore API:

private void copyToPublicDirectory(String filename) throws IOException {
    InputStream inputStream = createInputStream(filename);
    OutputStream outputStream = createOutputStream(filename);
    copy(inputStream, outputStream);
}

private InputStream createInputStream(String filename) throws IOException {
    File cacheDirectory = getExternalCacheDir();
    if (cacheDirectory == null)
        throw new RuntimeException("Cache is not currently available");
    return new FileInputStream(new File(cacheDirectory, filename));
}

private OutputStream createOutputStream(String filename) throws IOException {
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, filename);
    Uri contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
    Uri uri = getContentResolver().insert(contentUri, contentValues);
    if (uri == null)
        throw new RuntimeException("Cannot insert file: " + filename);
    OutputStream outputStream = getContentResolver().openOutputStream(uri);
    if (outputStream == null)
        throw new RuntimeException("Cannot open uri: " + uri);
    return outputStream;
}

private void copy(InputStream source, OutputStream target) throws IOException {
    byte[] buffer = new byte[8192];
    int length;
    while ((length = source.read(buffer)) != -1) {
        target.write(buffer, 0, length);
    }
}

Note: 3gp recordings have video/3gpp mime type. And it will be saved into the Movies directory (as @blackapps already said). If you want to record a file in audio format and save it into the Music directory, then do the following:

  1. Change content uri from MediaStore.Video.Media.EXTERNAL_CONTENT_URI to MediaStore.Audio.Media.EXTERNAL_CONTENT_URI in the code above.

  2. Use OGG format in your MediaRecorder setup (OGG format is available only for Android API 29 and higher):

    setOutputFormat(MediaRecorder.OutputFormat.OGG)
    setAudioEncoder(MediaRecorder.AudioEncoder.OPUS)
    

PS: don't forget to add all necessary permissions to make things work.

Upvotes: 2

Related Questions