AAC硬件编码文章有几篇,但是都是同步实现,这里采用异步实现,代码Kotlin。
虽然代码是kotlin写的,但是思路上面的按照java能复制出来
最后我会把代码上传到github,可以查看完整过程,为了方便查看,所以代码都写在
Activity中
录音和编码都设置在子线程
采取的是边录制边编码边写入文件
6.0注意动态权限问题,录音,读写文件
示例使用的5.0以上的API
上面是官方的一张原理图,我就先说下基本原理
MediaCodec给我们提供了一组InputBuffer和一组outputBuffer,我们通过手段获取到空的InputBuffer,装填原始音频数据,然后把装填后的buffer还给Codec让他去编码,他编码
后会把编码后文件放在outputBuffer中,我们获取outputBuffer读取数据保存到文件就好,
然后循环这个过程,完成所有文件的编码和保存。
这里注意并不是一个inputBuffer对应一个outputBuffer,一个输入buffer可以对应多个输出
buffer,比如你往inputBuffer添加1000个字节数据,他可能编码后放入了多个outputBuffer
中,一个outputBuffer可能就200或者300个字节。
下面就是实际操作过程
1.完成AudioRecord配置
/**
* 初始化音频采集
*/
private fun initAudioRecorder() {
//设置最小缓冲区大小 根据系统提供的方法计算
minBufferSize = AudioRecord.getMinBufferSize(
AudioConfig.SAMPLE_RATE,
AudioConfig.CHANNEL_CONFIG, AudioConfig.AUDIO_FORMAT
)
//创建音频记录器对象
audioRecorder = AudioRecord(
MediaRecorder.AudioSource.MIC,
AudioConfig.SAMPLE_RATE, AudioConfig.CHANNEL_CONFIG, AudioConfig.AUDIO_FORMAT,
minBufferSize
)
}
上面的AudioConfig配置文件如下
const val SAMPLE_RATE = 44100 //采样率
/**
* CHANNEL_IN_MONO 单声道 能够保证所有设备都支持
* CHANNEL_IN_STEREO 立体声
*/
const val CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO
/**
* 返回的音频数据格式
*/
const val AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT
/**
* 输出的音频声道
*/
const val CHANNEL_OUT_CONFIG = AudioFormat.CHANNEL_OUT_MONO
2.创建LinkedBlockingQeque准备保存录音数据
因为录音和编码都放在子线程去做,所以数据难以传递,通过同步队列保存来保证
正确读取数据,保存的数据类型是字节数组
private var audioList: LinkedBlockingDeque<ByteArray>? = LinkedBlockingDeque()
3,开始录音并保存
//开启线程启动录音
thread(priority = android.os.Process.THREAD_PRIORITY_URGENT_AUDIO) {
try {
//判断AudioRecord是否初始化成功
if (AudioRecord.STATE_INITIALIZED == audioRecorder.state) {