【问题标题】:MediaRecorder Android 11 start failed -1004MediaRecorder Android 11 启动失败-1004
【发布时间】:2021-02-26 23:28:39
【问题描述】:

在 Android 11 上,我的 MediaRecorder 无法初始化。我怀疑这个问题与范围存储有关,但我一直无法找出原因。我正在使用 MediaRecorder 从麦克风录制音频。我从音频中提取幅度,所以我无意保留文件,这就是为什么路径是 /dev/null

 var mRecorder: MediaRecorder? = null


 if (mRecorder == null) {
        mRecorder = MediaRecorder()
        mRecorder!!.setAudioSource(MediaRecorder.AudioSource.MIC)
        mRecorder!!.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
        mRecorder!!.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
        mRecorder!!.setOutputFile("/dev/null")
        try {
            mRecorder!!.prepare()
        } catch (ioe: IOException) {
            Log.e("[Monkey]", "IOException: " + Log.getStackTraceString(ioe))
        } catch (e: SecurityException) {
            Log.e("[Monkey]", "SecurityException: " + Log.getStackTraceString(e))
        }
        try {
            mRecorder!!.start()
        } catch (e: SecurityException) {
            Log.e("[Monkey]", "SecurityException: " + Log.getStackTraceString(e))
        }

崩溃发生在 MediaRecorded.start()。 /dev/null 在 Android 11 上不是有效路径吗?

Logcat:

start failed: -1004
2020-11-15 10:51:41.827 11836-11836/= E/AndroidRuntime: FATAL EXCEPTION: main
    Process: c=, PID: 11836
    java.lang.RuntimeException: start failed.
        at android.media.MediaRecorder.start(Native Method)
 

【问题讨论】:

    标签: android kotlin mediastore


    【解决方案1】:

    用正确的文件路径“${externalCacheDir.absolutePath}/test.3gp”替换“/dev/null”,它应该可以工作。

    【讨论】:

    • 感谢您的回复。我很惊讶我没有想到如此明显的事情。非常感谢您的帮助。
    • 感谢您的提示!这似乎解决了这个问题,但是我想知道当应用程序运行很长时间时它的行为如何? “test.3gp”文件会不断增长并使用设备上的所有可用空间吗?应用关闭时会自动删除吗?谢谢!
    • 我看不出这是一个可以接受的答案...问题明确说不需要输出,这就是使用/dev/null的原因,这将保存一个可能很大的持久文件...
    • @mivola 每次运行 MediaRecorder 时,都会覆盖“test.3gp”文件。因此,它的大小不会增加。
    • @CruzJean MediaRecorder 在不保存文件的情况下无法工作。文件“test.3gp”每次都会被覆盖,大小不会增加。
    【解决方案2】:

    由于某种原因,设置 "/dev/null" 路径以防止 MediaRecorder 存储导致 Android 11 版本到此日期的崩溃,通过设置它得到的实际路径得到修复,就像是在另一个答案中提到,但在我的应用程序中,我只需要注册来自麦克风的幅度级别,因此为了防止不确定地存储在输出文件中,我每分钟刷新一次 MediaRecorder 对象。

    这是一个完整但简化的示例:

    class MainActivity : AppCompatActivity() {
    
        private lateinit var mediaRecorder: MediaRecorder
        private var handler: Handler = Handler()
    
        private var fakeOutput = ""
        private var needsFlush = false
        private var flushCounter = 300
    
        private val runnable = object : Runnable {
            override fun run() {
                Log.d("AudioAmplitude: ", mediaRecorder.maxAmplitude.toString())
                if (needsFlush) {
                    if (flushCounter == 0) {
                        mediaRecorder.stop()
                        mediaRecorder.release()
                        initMediaRecorder()
                        flushCounter = 300
                    }
                    flushCounter--
                }
                handler.postDelayed(this, 200)
            }
        }
    
        private val requestedPermissions = arrayOf(
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.CAMERA
        )
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            requestedPermissions.forEach {
                ContextCompat.checkSelfPermission(
                    this,
                    it
                )
            }
    
            if (ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.RECORD_AUDIO
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(
                        (this as Activity?)!!,
                        Manifest.permission.RECORD_AUDIO
                    )
                ) {
                } else {
                    ActivityCompat.requestPermissions(
                        (this as Activity?)!!, arrayOf(Manifest.permission.RECORD_AUDIO),
                        0
                    )
                }
            }
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                fakeOutput = "${externalCacheDir?.absolutePath}/temp.3gp"
                needsFlush = true
            } else {
                fakeOutput = "/dev/null"
            }
    
            initMediaRecorder()
        }
    
        private fun initMediaRecorder() {
            mediaRecorder = MediaRecorder().apply {
                setAudioSource(MediaRecorder.AudioSource.MIC)
                setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
                setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
                setOutputFile(fakeOutput)
                prepare()
                start()
            }
        }
    
        @RequiresApi(Build.VERSION_CODES.N)
        override fun onResume() {
            super.onResume()
            mediaRecorder.resume()
            handler.post(runnable)
        }
    
        @RequiresApi(Build.VERSION_CODES.N)
        override fun onPause() {
            super.onPause()
            mediaRecorder.pause()
            handler.removeCallbacks(runnable)
        }
    }
    

    请注意,我使用处理程序(可能不是最佳做法)打印出 ma​​xAmplitude,这是我进行此工作的主要原因,我使用它每 60 秒刷新一次(计数器是 300 减去处理程序每​​ 200 毫秒调用一次)。

    【讨论】:

      猜你喜欢
      • 2016-07-12
      • 1970-01-01
      • 2015-07-30
      • 1970-01-01
      • 1970-01-01
      • 2016-12-30
      • 2012-07-30
      • 2012-06-30
      • 1970-01-01
      相关资源
      最近更新 更多