• Android音视频开发:AudioRecord录制音频


    简介

    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如何录制音频数据:

    1. class AudioActivity : AppCompatActivity() {
    2. //音频录制
    3. private var audioRecord: AudioRecord? = null
    4. //缓冲区大小,缓冲区用于保存音频数据流
    5. private var bufferSize: Int = 0
    6. //记录是否正在录制音频
    7. @Volatile private var isRecording = false
    8. //录音线程
    9. private var recordThread: Thread? = null
    10. override fun onCreate(savedInstanceState: Bundle?) {
    11. super.onCreate(savedInstanceState)
    12. setContentView(R.layout.activity_media)
    13. initRecoder()
    14. }
    15. /**
    16. * 初始化
    17. */
    18. private fun initRecoder() {
    19. /*
    20. getMinBufferSize用于获取成功创建AudioRecord对象所需的最小缓冲区大小,
    21. 此大小不能保证在负载下能顺利录制,应根据预期的频率选择更高的值,
    22. 在该频率下,将对AudioRecord实例进行轮询以获取新数据
    23. 参数介绍:(具体看官网api介绍)
    24. sampleRateInHz:采样率,以赫兹为单位
    25. channelConfig:音频通道的配置
    26. audioFormat:音频数据的格式
    27. */
    28. bufferSize = AudioRecord.getMinBufferSize(
    29. 44100,
    30. AudioFormat.CHANNEL_IN_MONO,
    31. AudioFormat.ENCODING_PCM_16BIT
    32. )
    33. /*
    34. 构建AudioRecord对象。
    35. 参数介绍:
    36. audioSource:音频来源
    37. sampleRateInHz:采样率,以赫兹为单位。目前,只有44100Hz是保证在所有设备上都可以使用的速率(最适合人耳的),但是其他速率(例如220501600011025)可能在某些设备上可以使用
    38. channelConfig:音频通道的配置
    39. audioFormat:音频数据的格式
    40. bufferSizeInBytes:在录制期间写入音频数据的缓冲区的总大小(以字节为单位)
    41. */
    42. audioRecord = AudioRecord(
    43. MediaRecorder.AudioSource.MIC,
    44. 44100,
    45. AudioFormat.CHANNEL_IN_MONO,
    46. AudioFormat.ENCODING_PCM_16BIT,
    47. bufferSize * 2
    48. )
    49. }
    50. /**
    51. * 开始录制
    52. */
    53. fun startRecord(view: View) {
    54. if (isRecording) {
    55. return
    56. }
    57. isRecording = true
    58. if (recordThread == null) {
    59. recordThread = Thread(recordRunnable)
    60. }
    61. recordThread!!.start()
    62. }
    63. /**
    64. * 停止录制
    65. */
    66. fun stopRecord(view: View) {
    67. //置为false,表示线程循环就结束了,线程也执行完毕了
    68. //也可以直接中断线程
    69. isRecording = false
    70. audioRecord = null
    71. recordThread = null
    72. }
    73. /**
    74. * 录音线程
    75. *
    76. * 由于需要不断读取音频数据,所以放在子线程操作
    77. */
    78. private val recordRunnable = Runnable {
    79. //设置线程优先级
    80. android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO)
    81. //创建文件
    82. val tmpFile: File? = FileUtil.createFile("${System.currentTimeMillis()}.pcm")
    83. //文件输出流
    84. var fos: FileOutputStream = FileOutputStream(tmpFile?.getAbsoluteFile())
    85. try {
    86. if (audioRecord?.getState() !== AudioRecord.STATE_INITIALIZED) {
    87. //没有初始化成功
    88. return@Runnable
    89. }
    90. //开始录制
    91. audioRecord?.startRecording()
    92. var buffer = 0
    93. val bytes = ByteArray(bufferSize)
    94. //轮询读取数据
    95. while (isRecording) {
    96. if (audioRecord != null) {
    97. buffer = audioRecord!!.read(bytes, 0, bufferSize)
    98. if (buffer == AudioRecord.ERROR_INVALID_OPERATION || buffer == AudioRecord.ERROR_BAD_VALUE) {
    99. continue
    100. }
    101. if (buffer == 0 || buffer == -1) {
    102. break
    103. }
    104. //在此可以对录制音频的数据进行二次处理 如变声,压缩,降噪等操作
    105. //也可以直接发送至服务器(实时语音传输) 对方可采用AudioTrack进行播放
    106. //这里直接将pcm音频数据写入文件
    107. fos.write(bytes)
    108. }
    109. }
    110. } catch (e: Exception) {
    111. Log.e("Test", "出错了", e)
    112. } finally {
    113. try {
    114. fos?.close()
    115. } catch (ex: IOException) {
    116. }
    117. audioRecord?.stop()
    118. audioRecord?.release()
    119. }
    120. }
    121. }

    如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

  • 相关阅读:
    基于VectorGrid加载GeoServer发布的矢量瓦片实例
    Java线程池的知识
    低代码技术这么香,如何把它的开发特点发挥到极致?
    Kubernetes的原理及应用详解(一)
    适用于嵌入式单片机的差分升级通用库
    django restframework 中使用throttle进行限流
    【Royalty in Wind 2.0.0】个人体测计算、资料分享小程序
    HTML5期末大作业:游戏网站设计与实现——基于bootstrap响应式游戏资讯网站制作HTML+CSS+JavaScript
    Linux篇-善用威胁情报
    Discrete Mathematics and Its Applications 8th Edition 目录
  • 原文地址:https://blog.csdn.net/m0_60259116/article/details/127428924