Android Mediarecorder setNextOutputFile IllegalStateException

追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述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); } } }});


    推荐阅读