“AudioRecord.startRecording() 在应用程序处于后台时返回错误。”

huangapple go评论62阅读模式
英文:

AudioRecord.startRecording() returns error when app is in background

问题

I'm developing an wearOS app to record the surrounding audio and generate decibel from the recored audio. I'm using AudioRecord class from android.media to record the audio. The app works as expected while on foreground. However, while the app is switched to background, the startRecording() function returns some error without crashing the application. The AUDIO_RECORD permission is granted to the app on it's first start up. What could be the issue?

audioRunnable = object : Runnable {
            override fun run() {
                Log.i("Test", "Inside audio thread.")

                if (::soundMeter.isInitialized) {
                    soundMeter.startRecording()
                    Thread.sleep(4000)//wait time for soundMeter to get value
                    soundLevel = soundMeter.getDecibelValue()//get soundMeter value
                    Log.d(TAG, "dB2 update: $soundLevel")
                    soundMeter.stopRecording()//stop soundMeter

                    runOnUiThread { // UI code goes here
                        val floatTextView = findViewById<TextView>(R.id.soundValue)
                        floatTextView.text = soundLevel.roundToInt().toString()

                        when {
                            soundLevel > 60 -> {
                                floatTextView.setTextColor(Color.RED)
                            } else -> {
                                floatTextView.setTextColor(Color.GREEN)
                            }
                        }
                    }
                }

                audioHandler.postDelayed(this, 1000)//repeat every 10 seconds
            }
        }


    fun startRecording() { //needs to have permission check before call, which is done in MainActivity
        Log.i("AudioRecord", "Recording about to start.")

        if (Objects.nonNull(audioRecord) && audioRecord.state != AudioRecord.STATE_UNINITIALIZED)
            audioRecord.startRecording()

        Log.i("AudioRecord", "Recording completed.")
    }

    fun stopRecording() { //needs to be called after 10 second collecting period to get most recent max value
        if (Objects.nonNull(audioRecord) && audioRecord.state != AudioRecord.STATE_UNINITIALIZED)
            audioRecord.stop()
    }

    fun getDecibelValue(): Float { //returns the max amplitude in decibels
        return if (Objects.nonNull(audioRecord) && audioRecord.state != AudioRecord.STATE_UNINITIALIZED) {
            val buffer = ShortArray(bufferSize)
            audioRecord.read(buffer, 0, bufferSize)
            var maxAmplitude = 0 //max amplitude in the buffer
            for (i in buffer.indices) { //finds the max amplitude in the buffer by iterating through the buffer
                maxAmplitude = maxAmplitude.coerceAtLeast(kotlin.math.abs(buffer[i].toInt()))
            }

            20 * log10(maxAmplitude.toDouble()).toFloat() //math to be changed for calibration(to nearest whole number)

        } else {
            0f
        }
    }
英文:

I'm developing an wearOS app to record the surrounding audio and generate decibel from the recored audio. I'm using AudioRecord class from android.media to record the audio. The app works as expected while on foreground. However, while the app is switched to background, the startRecording() function returns some error without crashing the application. The AUDIO_RECORD permission is granted to the app on it's first start up. What could be the issue?

audioRunnable = object : Runnable {
            override fun run() {
                Log.i(&quot;Test&quot;, &quot;Inside audio thread.&quot;)

                if (::soundMeter.isInitialized) {
                    soundMeter.startRecording()
                    Thread.sleep(4000)//wait time for soundMeter to get value
                    soundLevel = soundMeter.getDecibelValue()//get soundMeter value
                    Log.d(TAG, &quot;dB2 update: $soundLevel&quot;)
                    soundMeter.stopRecording()//stop soundMeter

                    runOnUiThread { // UI code goes here
                        val floatTextView = findViewById&lt;TextView&gt;(R.id.soundValue)
                        floatTextView.text = soundLevel.roundToInt().toString()

                        when {
                            soundLevel &gt; 60 -&gt; {
                                floatTextView.setTextColor(Color.RED)
                            } else -&gt; {
                                floatTextView.setTextColor(Color.GREEN)
                            }
                        }
                    }
                }

                audioHandler.postDelayed(this, 1000)//repeat every 10 seconds
            }
        }


    fun startRecording() { //needs to have permission check before call, which is done in MainActivity
        Log.i(&quot;AudioRecord&quot;, &quot;Recording about to start.&quot;)

        if (Objects.nonNull(audioRecord) &amp;&amp; audioRecord.state != AudioRecord.STATE_UNINITIALIZED)
            audioRecord.startRecording()

        Log.i(&quot;AudioRecord&quot;, &quot;Recording completed.&quot;)
    }

    fun stopRecording() { //needs to be called after 10 second collecting period to get most recent max value
        if (Objects.nonNull(audioRecord) &amp;&amp; audioRecord.state != AudioRecord.STATE_UNINITIALIZED)
            audioRecord.stop()
    }

    fun getDecibelValue(): Float { //returns the max amplitude in decibels
        return if (Objects.nonNull(audioRecord) &amp;&amp; audioRecord.state != AudioRecord.STATE_UNINITIALIZED) {
            val buffer = ShortArray(bufferSize)
            audioRecord.read(buffer, 0, bufferSize)
            var maxAmplitude = 0 //max amplitude in the buffer
            for (i in buffer.indices) { //finds the max amplitude in the buffer by iterating through the buffer
                maxAmplitude = maxAmplitude.coerceAtLeast(kotlin.math.abs(buffer[i].toInt()))
            }

            20 * log10(maxAmplitude.toDouble()).toFloat() //math to be changed for calibration(to nearest whole number)

        } else {
            0f
        }
    }

答案1

得分: 1

来自文档:

> 注意:在运行Android 9(API级别28)或更高版本的设备上,后台运行的应用无法访问麦克风。因此,您的应用程序应仅在前台或在前台服务中包含MediaRecorder实例时记录音频。

你不能在后台这样做,这就是为什么会出现问题。假设这是一个服务,它需要成为一个前台服务。这样做的原因是保护隐私,操作系统希望用户知道他们的设备是否在录音。

英文:

From the docs:

> Note: On devices running Android 9 (API level 28) or higher, apps
> running in the background cannot access the microphone. Therefore,
> your app should record audio only when it's in the foreground or when
> you include an instance of MediaRecorder in a foreground service.

You can't do it in the background, which is why it's causing problems. Assuming this is a service, it needs to be a foreground service. The reason for this is privacy, the OS wants a user to know if their device is recording.

huangapple
  • 本文由 发表于 2023年6月6日 03:52:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76409594.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定