AudioRecord类管理Java应用程序的音频资源,以记录来自平台音频输入硬件的音频。这是通过“拉”(读取)来自AudioRecord对象的数据来实现的。该应用程序负责轮询使用以下三种方法之一AudioRecord对象在时间: read(byte[], int, int),read(short[], int, int) 或read(java.nio.ByteBuffer, int)。使用哪种方法的选择将基于对AudioRecord用户最方便的音频数据存储格式。
创建后,AudioRecord对象将初始化其关联的音频缓冲区,它将用新的音频数据填充。在构造期间指定的此缓冲区的大小确定AudioRecord在尚未读取的“超速运行”数据之前可以记录多长时间。应从音频硬件读取数据,其大小应小于总记录缓冲区的大小。
录音的完整过程分为以下部分:
1、调用AudioRecord类中的getMinBufferSize获取到最小的音频缓冲区。
2、初始化AudioRecord类,配置一些基本参数
3、初始化一个buffer,该buffer大于等于AudioRecord对象用于写声音数据的buffer大小。
4、开始录音
5、将录音写入数据流
6、关闭录音。
// 返回成功创建音频记录所需的最小缓冲区大小,以字节为单位。
//请注意,此大小不能保证在负载和更高的值下平稳录制
//应根据录音实例的预期频率选择
---getMinBufferSize
//@param sampleRateInHz以赫兹表示的采样率。(采样率,现在能够保证在所有设备上使用的采样率是44100Hz, 但是其他的采样率(22050, 16000, 11025)在一些设备上也可以使用。)
//@param channelConfig描述音频通道的配置。(声道数。CHANNEL_IN_MONO 、 CHANNEL_IN_STEREO等等. AudioFormat里面可以查看到所有支持的。其中CHANNEL_IN_MONO是可以保证在所有设备能够使用的。)
//@param audio format表示音频数据的格式。音频数据的采样精度,这里设置为AudioFormat.ENCODING_16BIT;也是通过AudioFormat去查看,还是有很多种,这里不一一介绍了。
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)
recordBufSize=AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)
---AudioRecord
//audioSource 定义音频源。麦克风音频源,除了这个还有其他的。
public static final int MIC = 1;
//bufferSizeInBytes 写入音频数据的缓冲区的总大小(字节),需大于等于getMinBufferSize,否则将导致初始化失败。
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes)
audioRecord= AudioRecord(MediaRecorder.AudioSource.MIC,44100,AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,recordBufSize)
---整个过程代码
private fun createAudioRecord() {
//audioRecord能接受的最小的buffer大小,
//sampleRateInHz:默认采样率,单位Hz,这里设置为44100,44100Hz是当前唯一能保证在所有设备上工作的采样率;
//channelConfig: 描述音频声道设置,这里设置为AudioFormat.CHANNEL_CONFIGURATION_MONO,CHANNEL_CONFIGURATION_MONO保证能在所有设备上工作;
//audioFormat:音频数据的采样精度,这里设置为AudioFormat.ENCODING_16BIT;
recordBufSize=AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)
print("recordBufSize-->$recordBufSize")
audioRecord= AudioRecord(MediaRecorder.AudioSource.MIC,44100,AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,recordBufSize)
audioRecord?.startRecording()
isRecording = true
var os:FileOutputStream?=null
val file = File(baseContext.externalCacheDir?.absolutePath, "AudioRecord/test.pcm")
Log.e("---", "filename"+file.absolutePath)
if (!file.mkdirs()) {
Log.e("---", "Directory not created")
}
if (file.exists()) {
file.delete()
}
var read: Int?=null
var data=ByteArray(recordBufSize)
try {
os = FileOutputStream(file)
} catch (e:Exception) {
e.printStackTrace()
}
if (null != os) {
while (isRecording) {
read = audioRecord?.read(data, 0, recordBufSize)
// 如果读取音频数据没有出现错误,就将数据写入到文件
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
os.write(data)
} catch (e:IOException) {
e.printStackTrace()
}
}
}
try {
os.close()
} catch (e:IOException) {
e.printStackTrace()
}
}
}而以上生成的文件,我们是播放不了的,还只是原始的音频数据,需要加文件头,否则播放器不晓得是什么内容。
/**
* pcm文件转wav文件
*
* @param inFilename 源文件路径
* @param outFilename 目标文件路径
*/
fun pcmToWav(inFilename: String, outFilename: String) {
val `in`: FileInputStream
val out: FileOutputStream
val totalAudioLen: Long
val totalDataLen: Long
val longSampleRate = mSampleRate.toLong()
val channels = if (mChannel == AudioFormat.CHANNEL_IN_MONO) 1 else 2
val byteRate = (16 * mSampleRate * channels / 8).toLong()
val data = ByteArray(mBufferSize)
try {
`in` = FileInputStream(inFilename)
out = FileOutputStream(outFilename)
totalAudioLen = `in`.channel.size()
totalDataLen = totalAudioLen + 36
writeWaveFileHeader(
out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate
)
while (`in`.read(data) !== -1) {
out.write(data)
}
`in`.close()
out.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
/**
* 加入wav文件头
*/
@Throws(IOException::class)
private fun writeWaveFileHeader(
out: FileOutputStream, totalAudioLen: Long,
totalDataLen: Long, longSampleRate: Long, channels: Int, byteRate: Long
) {
val header = ByteArray(44)
// RIFF/WAVE header
header[0] = 'R'.toByte()
header[1] = 'I'.toByte()
header[2] = 'F'.toByte()
header[3] = 'F'.toByte()
header[4] = (totalDataLen and 0xff).toByte()
header[5] = (totalDataLen shr 8 and 0xff).toByte()
header[6] = (totalDataLen shr 16 and 0xff).toByte()
header[7] = (totalDataLen shr 24 and 0xff).toByte()
//WAVE
header[8] = 'W'.toByte()
header[9] = 'A'.toByte()
header[10] = 'V'.toByte()
header[11] = 'E'.toByte()
// 'fmt ' chunk
header[12] = 'f'.toByte()
header[13] = 'm'.toByte()
header[14] = 't'.toByte()
header[15] = ' '.toByte()
// 4 bytes: size of 'fmt ' chunk
header[16] = 16
header[17] = 0
header[18] = 0
header[19] = 0
// format = 1
header[20] = 1
header[21] = 0
header[22] = channels.toByte()
header[23] = 0
header[24] = (longSampleRate and 0xff).toByte()
header[25] = (longSampleRate shr 8 and 0xff).toByte()
header[26] = (longSampleRate shr 16 and 0xff).toByte()
header[27] = (longSampleRate shr 24 and 0xff).toByte()
header[28] = (byteRate and 0xff).toByte()
header[29] = (byteRate shr 8 and 0xff).toByte()
header[30] = (byteRate shr 16 and 0xff).toByte()
header[31] = (byteRate shr 24 and 0xff).toByte()
// block align
header[32] = (2 * 16 / 8).toByte()
header[33] = 0
// bits per sample
header[34] = 16
header[35] = 0
//data
header[36] = 'd'.toByte()
header[37] = 'a'.toByte()
header[38] = 't'.toByte()
header[39] = 'a'.toByte()
header[40] = (totalAudioLen and 0xff).toByte()
header[41] = (totalAudioLen shr 8 and 0xff).toByte()
header[42] = (totalAudioLen shr 16 and 0xff).toByte()
header[43] = (totalAudioLen shr 24 and 0xff).toByte()
out.write(header, 0, 44)
}以上就是一个简单的录音过程,更多的技术细节,需要自己去实践操作。