AudioRecord是安卓多媒体框架中用于录制音频的工具。它支持录制原始音频数据,即PCM数据,PCM数据不能被播放器直接播放,需要编码压缩成常见音频格式才能被播放器识别。而原生api也提供了AudioTrack播放PCM数据。
AudioRecord是通过read方式不断读取来自音源输入的数据流(字节流),进而把数据流保存成PCM数据。
开始录音的时候,AudioRecord需要创建一个缓冲区, 这个缓冲区主要是用来保存新的音频数据,它用于标识一个AudioRecord对象还没有被读取(同步)声音数据前能录多长的音(即一次可以录制的声音容量)。声音数据不断从音频硬件中被读出,每次读取的数据大小不超过初始化缓冲区的容量(录音数据的大小)。
流程如下:
构造一个AudioRecord对象。其中最小录音数据缓存的缓冲区大小可以通过getMinBufferSize方法得到,如果缓冲区容量过小,将导致对象构造的失败。
初始化一个缓冲区,该缓冲区大小大于等于AudioRecord对象用于写声音数据的缓冲区大小,用于缓存读取的音频数据。
startRecording开始录音
创建一个数据流,不断地从AudioRecord中读取声音数据到初始化的缓冲区,然后将缓冲区中的数据输出。
关闭数据流
停止录音
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
示例
下面使用Kotlin代码展示AudioRecord如何录制音频数据:
- class AudioActivity : AppCompatActivity() {
- //音频录制
- private var audioRecord: AudioRecord? = null
- //缓冲区大小,缓冲区用于保存音频数据流
- private var bufferSize: Int = 0
- //记录是否正在录制音频
- @Volatile private var isRecording = false
- //录音线程
- private var recordThread: Thread? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_media)
- initRecoder()
- }
-
- /**
- * 初始化
- */
- private fun initRecoder() {
- /*
- getMinBufferSize用于获取成功创建AudioRecord对象所需的最小缓冲区大小,
- 此大小不能保证在负载下能顺利录制,应根据预期的频率选择更高的值,
- 在该频率下,将对AudioRecord实例进行轮询以获取新数据
- 参数介绍:(具体看官网api介绍)
- sampleRateInHz:采样率,以赫兹为单位
- channelConfig:音频通道的配置
- audioFormat:音频数据的格式
- */
- bufferSize = AudioRecord.getMinBufferSize(
- 44100,
- AudioFormat.CHANNEL_IN_MONO,
- AudioFormat.ENCODING_PCM_16BIT
- )
-
- /*
- 构建AudioRecord对象。
- 参数介绍:
- audioSource:音频来源
- sampleRateInHz:采样率,以赫兹为单位。目前,只有44100Hz是保证在所有设备上都可以使用的速率(最适合人耳的),但是其他速率(例如22050、16000和11025)可能在某些设备上可以使用
- channelConfig:音频通道的配置
- audioFormat:音频数据的格式
- bufferSizeInBytes:在录制期间写入音频数据的缓冲区的总大小(以字节为单位)
- */
- audioRecord = AudioRecord(
- MediaRecorder.AudioSource.MIC,
- 44100,
- AudioFormat.CHANNEL_IN_MONO,
- AudioFormat.ENCODING_PCM_16BIT,
- bufferSize * 2
- )
- }
-
- /**
- * 开始录制
- */
- fun startRecord(view: View) {
- if (isRecording) {
- return
- }
- isRecording = true
- if (recordThread == null) {
- recordThread = Thread(recordRunnable)
- }
- recordThread!!.start()
- }
-
- /**
- * 停止录制
- */
- fun stopRecord(view: View) {
- //置为false,表示线程循环就结束了,线程也执行完毕了
- //也可以直接中断线程
- isRecording = false
- audioRecord = null
- recordThread = null
- }
-
- /**
- * 录音线程
- *
- * 由于需要不断读取音频数据,所以放在子线程操作
- */
- private val recordRunnable = Runnable {
- //设置线程优先级
- android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO)
- //创建文件
- val tmpFile: File? = FileUtil.createFile("${System.currentTimeMillis()}.pcm")
- //文件输出流
- var fos: FileOutputStream = FileOutputStream(tmpFile?.getAbsoluteFile())
- try {
-
- if (audioRecord?.getState() !== AudioRecord.STATE_INITIALIZED) {
- //没有初始化成功
- return@Runnable
- }
- //开始录制
- audioRecord?.startRecording()
-
- var buffer = 0
- val bytes = ByteArray(bufferSize)
- //轮询读取数据
- while (isRecording) {
- if (audioRecord != null) {
- buffer = audioRecord!!.read(bytes, 0, bufferSize)
- if (buffer == AudioRecord.ERROR_INVALID_OPERATION || buffer == AudioRecord.ERROR_BAD_VALUE) {
- continue
- }
- if (buffer == 0 || buffer == -1) {
- break
- }
- //在此可以对录制音频的数据进行二次处理 如变声,压缩,降噪等操作
- //也可以直接发送至服务器(实时语音传输) 对方可采用AudioTrack进行播放
- //这里直接将pcm音频数据写入文件
- fos.write(bytes)
- }
- }
- } catch (e: Exception) {
- Log.e("Test", "出错了", e)
- } finally {
- try {
- fos?.close()
- } catch (ex: IOException) {
- }
- audioRecord?.stop()
- audioRecord?.release()
- }
- }
- }
如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓