Reputation: 666
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
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:
Change content uri from MediaStore.Video.Media.EXTERNAL_CONTENT_URI
to MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
in the code above.
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