追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述Android Mediarecorder setNextOutputFile IllegalStateException相关的知识,希望能为你提供帮助。
我试图将我的带有android mediarecorder的录音分成多个文件,但每当我设置下一个输出文件时,我都会遇到非法状态异常。
这是代码:
private void getMediaRecorderReady(String filePath, FileDescriptor nextFile) {
bufferSize = 88200;
recorder = new MediaRecorder();
recorder.setAudiosource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AAC_ADTS);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setAudioEncodingBitRate(64000);
recorder.setAudioSamplingRate(44100);
recorder.setAudioChannels(1);
recorder.setOutputFile(filePath);
recorder.setMaxDuration(1000);
recorder.setMaxFileSize(100000);
try {
recorder.prepare();
recorder.setNextOutputFile(nextFile);
} catch (IOException e) {
e.printStackTrace();
}
}
这是错误:
E/MediaRecorder: setNextOutputFile failed: -38
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.a49164.teachmi, PID: 31554
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:353)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.IllegalStateException
at android.media.MediaRecorder._setNextOutputFile(Native Method)
at android.media.MediaRecorder.setNextOutputFile(MediaRecorder.java:878)
at com.example.a49164.teachmi.ExComThread.getMediaRecorderReady(ExComThread.java:189)
at com.example.a49164.teachmi.ExComThread.soundTransfer(ExComThread.java:211)
at com.example.a49164.teachmi.ExComThread.doInBackground(ExComThread.java:82)
at com.example.a49164.teachmi.ExComThread.doInBackground(ExComThread.java:46)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
因此,在进行一些挖掘之后,错误-38等于“-ENOSYS”或“INVALID_OPERATION”,如果记录器为空或准备未被调用(但我先调用prepare()),这似乎就会发生。
这是一些原生的android代码:
enum {
OK= 0,// Everything's swell.
NO_ERROR= 0,// No errors.UNKNOWN_ERROR= 0x80000000,
NO_MEMORY= -ENOMEM,
INVALID_OPERATION= -ENOSYS,
BAD_VALUE= https://www.songbingjia.com/android/-EINVAL,
BAD_TYPE= 0x80000001,
NAME_NOT_FOUND= -ENOENT,
PERMISSION_DENIED= -EPERM,
NO_INIT= -ENODEV,
ALREADY_EXISTS= -EEXIST,
DEAD_OBJECT= -EPIPE,
FAILED_TRANSACTION= 0x80000002,
JPARKS_BROKE_IT= -EPIPE,
#if !defined(HAVE_MS_C_RUNTIME)
BAD_INDEX= -EOVERFLOW,
NOT_ENOUGH_DATA= -ENODATA,
WOULD_BLOCK= -EWOULDBLOCK,
TIMED_OUT= -ETIMEDOUT,
UNKNOWN_TRANSACTION = -EBADMSG,
#else
BAD_INDEX= -E2BIG,
NOT_ENOUGH_DATA= 0x80000003,
WOULD_BLOCK= 0x80000004,
TIMED_OUT= 0x80000005,
UNKNOWN_TRANSACTION = 0x80000006,
#endif
FDS_NOT_ALLOWED= 0x80000007,
};
原生nextoutputfile:
status_t MediaRecorder::setNextOutputFile(int fd)
{
ALOGV("setNextOutputFile(%d)", fd);
if (mMediaRecorder == NULL) {
ALOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
}
// It appears that if an invalid file descriptor is passed through
// binder calls, the server-side of the inter-process function call
// is skipped. As a result, the check at the server-side to catch
// the invalid file descritpor never gets invoked. This is to workaround
// this issue by checking the file descriptor first before passing
// it through binder call.
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
ALOGE("Fail to get File Status Flags err: %s", strerror(errno));
}
// fd must be in read-write mode or write-only mode.
if ((flags &
(O_RDWR | O_WRONLY)) == 0) {
ALOGE("File descriptor is not in read-write mode or write-only mode");
return BAD_VALUE;
}
status_t ret = mMediaRecorder->
setNextOutputFile(fd);
if (OK != ret) {
ALOGE("setNextOutputFile failed: %d", ret);
}
return ret;
}
我可能错了-38确实等于-ENOSYS的事实,但是,我仍然不知道为什么它不起作用,因为我传递文件描述符并在准备之后调用它,如android文档中所述。
我非常欢迎你的帮助,谢谢!
编辑:我试图在准备后立即删除setNextOutputFile(nextFile),只保留一个:
recorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int infoCode, int extra) {
System.out.println("----------------------------------------onMaxFileSizeApproaching " + infoCode);
if (infoCode == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
System.out.println("max sized reached");
String path = Environment.getExternalStorageDirectory().getPath() + "/dataSound" + currFile + ".aac";
File nextFile = new File(path);
try {
FileOutputStream fos = new FileOutputStream(nextFile);
recorder.setNextOutputFile(fos.getFD());
} catch (IOException e) {
e.printStackTrace();
}
String currPath = Environment.getExternalStorageDirectory().getPath() + "/dataSound" + (currFile - 1) + ".aac";
sendDataPath = currPath;
currFile++;
}
}
});
但无济于事......
答案这意味着
setNextOutputFile()
在prepare()
finish it's own work之前被召唤。因此,您应该等到documentation中讨论的文件准备好了。
在切换到该输出之前,不会使用该文件。申请将收到
MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED
您应该监听文件信息,如:
recorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mediaRecorder, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)
recorder.setNextOutputFile(nextFile);
}
});
此外,当使用下一个输出文件时。如果尚未使用前一个文件,应用程序将无法设置新的输出文件。应用程序负责在调用
stop()
后清理未使用的文件。另一答案【Android Mediarecorder setNextOutputFile IllegalStateException】根据文档,在MediaRecorder.OnInfoListener收到MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING的“什么”代码后,必须立即调用
setNextOutputFile
API。mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
Toast.makeText(RecordActivity.this, "MediaRecorder onInfo:"+what, Toast.LENGTH_LONG).show();
Log.w("RecordActivity","MediaRecorder onInfo:"+what);
if (what == MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING) {File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "MyRecordings");
if (!mediaStorageDir.exists()){
mediaStorageDir.mkdirs();
}
Date date= new java.util.Date();
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(date.getTime());
String mediaFilePath = mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4";
File mediaFile = new File(mediaFilePath);
Log.e("RecordActivity",mediaFilePath);
try {
RandomAccessFile f = new RandomAccessFile(mediaFile, "rw");
try {
mediaRecorder.setNextOutputFile(f.getFD());
} finally {
f.close();
}
} catch(Exception ex) {
Log.e("RecordActivity","",ex);
}
}
}});
推荐阅读
- App被杀死时的回调-React Native
- [Material appbar存在时,Android Studio布局预览不起作用
- 谁能建议如何在android Recycler View中按产品价格实现排序[关闭]
- 在表单提交中找不到错误类'AppModel'
- 错误的Android Studio预览行为
- 如何使用Android Studio解决抖动中的gradle错误()
- Ubuntu 19.10上的React Native Android模拟器设置
- 如何在Android模拟器中安装Google Fit应用()
- Azure App Services无法连接到Azure SQL数据库