英文:
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("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
}
}
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论