Android设备麦克风输入ADC的RMS值无文件测量方案咨询
方案推荐:使用Android原生
AudioRecord类 你的需求完全可以通过Android原生的AudioRecord类实现,无需依赖Oboe库——Oboe更适合对延迟要求极致(如亚10ms)的场景,而100-200ms的测量周期用原生API足够简单高效。
核心步骤说明
1. 申请麦克风权限
麦克风属于危险权限,需在AndroidManifest.xml中声明静态权限,同时在代码中动态申请(Android 6.0+):
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-feature android:name="android.hardware.microphone" android:required="true" />
2. 配置AudioRecord参数
选择适合的音频参数,以16位单声道PCM为例(计算RMS最方便):
- 采样率:44100Hz(通用兼容值)
- 声道:
CHANNEL_IN_MONO(单声道减少计算量) - 格式:
ENCODING_PCM_16BIT(16位线性PCM,直接映射ADC采样值)
通过AudioRecord.getMinBufferSize()获取系统要求的最小缓冲区大小,避免初始化失败。
3. 实现RMS测量逻辑
启动后台线程循环读取PCM数据,按100-200ms的周期计算RMS:
- 将读取到的字节数组转换为短数组(16位PCM每个采样占2字节)
- 计算周期内所有采样值的平方和,再求平均值的平方根(即RMS)
Kotlin代码示例
import android.Manifest import android.content.pm.PackageManager import android.media.AudioFormat import android.media.AudioRecord import android.media.MediaRecorder import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlin.math.sqrt class MainActivity : AppCompatActivity() { private val RECORD_AUDIO_PERMISSION_REQUEST = 1001 private lateinit var audioRecord: AudioRecord private var isRecording = false // 配置参数 private val sampleRate = 44100 private val channelConfig = AudioFormat.CHANNEL_IN_MONO private val audioFormat = AudioFormat.ENCODING_PCM_16BIT // 测量周期:150ms(可在100-200ms之间调整) private val measurementPeriodMs = 150 // 每个周期的采样数 = 采样率 * 周期(秒) private val samplesPerPeriod = (sampleRate * measurementPeriodMs / 1000).toInt() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), RECORD_AUDIO_PERMISSION_REQUEST) return } initAudioRecord() startRecording() } private fun initAudioRecord() { val minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) // 确保缓冲区大小至少能容纳一个周期的采样数据 val bufferSize = maxOf(minBufferSize, samplesPerPeriod * 2) // 16位PCM每个采样2字节 audioRecord = AudioRecord( MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize ) } private fun startRecording() { isRecording = true audioRecord.startRecording() // 用协程在后台线程处理音频数据 CoroutineScope(Dispatchers.IO).launch { val buffer = ShortArray(samplesPerPeriod) // 存储一个周期的采样数据 while (isRecording) { val readCount = audioRecord.read(buffer, 0, samplesPerPeriod) if (readCount > 0) { val rms = calculateRms(buffer, readCount) // 在这里处理RMS值,比如更新UI(需切换到主线程) runOnUiThread { // 示例:打印RMS值 println("当前RMS值:$rms") } } } audioRecord.stop() audioRecord.release() } } // 计算RMS值:sqrt(Σ(x²)/n) private fun calculateRms(samples: ShortArray, count: Int): Double { var sum = 0.0 for (i in 0 until count) { val sample = samples[i].toDouble() sum += sample * sample } val mean = sum / count return sqrt(mean) } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == RECORD_AUDIO_PERMISSION_REQUEST) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initAudioRecord() startRecording() } } } override fun onDestroy() { super.onDestroy() isRecording = false } }
关键注意事项
- 权限处理:必须确保用户授予录音权限,否则
AudioRecord无法初始化 - 线程安全:音频数据读取必须在后台线程进行,避免阻塞UI线程
- 资源释放:在Activity销毁时停止录音并释放
AudioRecord资源,防止内存泄漏 - RMS计算:直接使用ADC采样的原始PCM值计算,不会引入噪声过滤逻辑,完全符合你“获取ADC的RMS值而非噪声水平”的需求
内容的提问来源于stack exchange,提问作者Ivan Vashchenko
相关产品推荐
相关产品推荐

