if (!file.exists()) {
Toast.makeText(this, “请先进行录制PCM音频”, Toast.LENGTH_SHORT).show()
return
}
val fis = FileInputStream(file)
var read: Int
status = Status.STARTING
while ({ read = fis.read(byteArray);read }() > 0) {
var ret = audioTrack?.write(byteArray, 0, bufferSizeInBytes)!!
if (ret == AudioTrack.ERROR_BAD_VALUE || ret == AudioTrack.ERROR_INVALID_OPERATION || ret == AudioManager.ERROR_DEAD_OBJECT) {
break
}
}
fis.close()
}
释放资源
首先停止播放
if (audioTrack != null && audioTrack?.state != AudioTrack.STATE_UNINITIALIZED) {
audioTrack?.stop()
}
然后停止线程
if (thread!=null){
thread?.join()
thread =null
}
最后释放AudioTrack
if (audioTrack != null) {
audioTrack?.release()
audioTrack = null
}
经过这样几个步骤,我们就可以听到刚刚我们录制的PCM数据声音啦!这就是使用Android提供的AudioRecord
和AudioTrack
对PCM数据进行操作。
但是仅仅这样是不够的,因为我们生活中肯定不是使用PCM进行音乐播放,那么怎么才能让音频在主流播放器上播放呢?这就需要我们进行压缩编码了,比如mp3或aac压缩编码格式。
AAC
压缩编码是一种高压缩比的音频压缩算法,AAC压缩比通常为18:1;采样率范围通常是8KHz~96KHz,这个范围比MP3更广一些(MP3的范围一般是:16KHz~48KHz),所以在16bit的采样格式上比MP3更精细。
方便我们处理AAC编码,Android SDK中提供了MediaCodec
API,可以将PCM数据编码成AAC数据。大概需要以下几个步骤:
-
创建
MediaCodec
-
为
MediaCodec
配置音频参数 -
启动线程,循环往缓冲区送入数据
-
通过
MediaCodec
将缓冲区的数据进行编码并写入文件 -
释放资源
创建MediaCodec
通过MediaCodec.createEncoderByType
创建编码MediaCodec
mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC)
配置音频参数
// 配置采样率和声道数
mediaFormat = MediaFormat.createAudioFormat(MINE_TYPE,sampleRate,channel)
// 配置比特率
mediaFormat?.setInteger(MediaFormat.KEY_BIT_RATE,bitRate)
// 配置PROFILE,其中属AAC-LC兼容性最好
mediaFormat?.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC)
// 最大输入大小
mediaFormat?.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 10 * 1024)
mediaCodec!!.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE)
mediaCodec?.start()
inputBuffers = mediaCodec?.inputBuffers
outputBuffers = mediaCodec?.outputBuffers
启动线程
启动线程,循环读取PCM数据送入缓冲区
thread = Thread(Runnable {
val fis = FileInputStream(pcmFile)
fos = FileOutputStream(aacFile)
var read: Int
while ({ read = fis.read(byteArray);read }() > 0) {
encode(byteArray)
}
})
thread?.start()