我正在使用 AudioRecord 录制音频。我需要的是以可播放格式 (wav) 将录制的音频保存为一个数组/变量。 我需要使用 AudioRecord,因为在获取音频的同时我还运行了一个语音识别器。所以 MediaRecorder 是别无选择的。 我实际上得到了一个可行的解决方案。唯一的问题是音频被写入文件。另外,我将 wav 标头添加到 pcm 的功能需要一个文件并将其再次存储在一个文件中。
我在寻找什么:在不将音频保存到文件的情况下完成所有这些。最后,我希望将音频放入数组或类似的东西中,以将此音频发送到 Flutter 并在那里使用它。
我的工作解决方案(with 将音频保存到文件):
private fun record() {
val sampleRate = 16000
val frameLength = 512
val bufferSize = (sampleRate / 2).coerceAtLeast(minBufferSize)
var audioRecord: AudioRecord? = null
var buffer = ShortArray(frameLength)
var bufferByte: ByteArray
var fileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + "/audio" + ".pcm"
audioRecord = AudioRecord(
MediaRecorder.AudioSource.MIC,
sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize)
audioRecord.startRecording()
var outputStream: FileOutputStream?
try {
outputStream = FileOutputStream(fileName)
} catch (e: FileNotFoundException) {
return
}
while (!stop.get()) {
var readBufferShortLength = audioRecord.read(buffer, 0, buffer.size)
bufferByte = getBytes(buffer)
try {
outputStream!!.write(bufferByte, 0, bufferByte.size)
// clean up file writing operations
} catch (e: IOException) {
e.printStackTrace()
}
}
outputStream.flush()
outputStream.close()
}
对于语音识别,它需要一个 ShortArray。要添加 wav 标头,它需要 ByteArray。 将 ShortArray 转换为 ByteArray:
fun shortToByte(shortArray: ShortArray): ByteArray {
val buffer = ByteBuffer.allocate(shortArray.size * 2)
buffer.order(ByteOrder.LITTLE_ENDIAN)
buffer.asShortBuffer().put(shortArray)
val bytes = buffer.array()
return bytes
}
转换添加wav标头:
@Throws(IOException::class)
private fun rawToWave(rawFile: File, waveFile: File, sampleRate: Int) {
val rawData = ByteArray(rawFile.length().toInt())
var input: DataInputStream? = null
try {
input = DataInputStream(FileInputStream(rawFile))
input.read(rawData)
} finally {
input?.close()
}
var output: DataOutputStream? = null
try {
output = DataOutputStream(FileOutputStream(waveFile))
// WAVE header
// see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
writeString(output, "RIFF") // chunk id
writeInt(output, 36 + rawData.size) // chunk size
writeString(output, "WAVE") // format
writeString(output, "fmt ") // subchunk 1 id
writeInt(output, 16) // subchunk 1 size
writeShort(output, 1.toShort()) // audio format (1 = PCM)
writeShort(output, 1.toShort()) // number of channels
writeInt(output, sampleRate) // sample rate
writeInt(output, sampleRate * 2) // byte rate --------- Here changen maybe
writeShort(output, 2.toShort()) // block align
writeShort(output, 16.toShort()) // bits per sample
writeString(output, "data") // subchunk 2 id
writeInt(output, rawData.size) // subchunk 2 size
// Audio data (conversion big endian -> little endian)
val shorts = ShortArray(rawData.size / 2)
ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts)
val bytes: ByteBuffer = ByteBuffer.allocate(shorts.size * 2)
for (s in shorts) {
bytes.putShort(s)
}
output.write(fullyReadFileToBytes(rawFile))
} finally {
output?.close()
}
}
@Throws(IOException::class)
fun fullyReadFileToBytes(f: File): ByteArray? {
val size = f.length().toInt()
val bytes = ByteArray(size)
val tmpBuff = ByteArray(size)
val fis = FileInputStream(f)
try {
var read = fis.read(bytes, 0, size)
if (read < size) {
var remain = size - read
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain)
System.arraycopy(tmpBuff, 0, bytes, size - remain, read)
remain -= read
}
}
} catch (e: IOException) {
throw e
} finally {
fis.close()
}
return bytes
}
@Throws(IOException::class)
private fun writeInt(output: DataOutputStream, value: Int) {
output.write(value shr 0)
output.write(value shr 8)
output.write(value shr 16)
output.write(value shr 24)
}
@Throws(IOException::class)
private fun writeShort(output: DataOutputStream, value: Short) {
var v = value.toInt()
output.write(v shr 0)
output.write(v shr 8)
}
@Throws(IOException::class)
private fun writeString(output: DataOutputStream, value: String) {
for (i in 0 until value.length) {
output.write(value[i].code) // ------ Here changen maybe
}
}
非常感谢您的支持。