feat: 优化音频录制功能,调整onStartRecord函数以支持Promise,增强错误处理和日志记录
This commit is contained in:
parent
601bfb1e16
commit
6d538569f7
@ -11,7 +11,6 @@ import 'android.media.MediaFormat'
|
|||||||
import 'java.lang.Thread'
|
import 'java.lang.Thread'
|
||||||
import { UTSAndroid } from 'io.dcloud.uts'
|
import { UTSAndroid } from 'io.dcloud.uts'
|
||||||
import { Result } from '../interface.uts'
|
import { Result } from '../interface.uts'
|
||||||
// @ts-ignore-end
|
|
||||||
import { FLVPacker, FLVListener } from 'com.tencent.iot.thirdparty.flv'
|
import { FLVPacker, FLVListener } from 'com.tencent.iot.thirdparty.flv'
|
||||||
|
|
||||||
let recorder: AudioRecord | null = null
|
let recorder: AudioRecord | null = null
|
||||||
@ -142,121 +141,115 @@ export const initAudio = async function (): Promise<Result> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function onStartRecord(callback: (data: Array<number>) => void): Promise<Result> {
|
// Final version based on the naming convention from the documentation.
|
||||||
try {
|
// This function intentionally returns void. The caller on the JS side
|
||||||
await stopRecord()
|
// must NOT use `await` on it, otherwise a ClassCastException will occur.
|
||||||
|
export function onStartRecord(callback: (data: Array<number>) => void) {
|
||||||
|
stopRecord()
|
||||||
|
.then(() => {
|
||||||
|
const currentRecorder = recorder
|
||||||
|
if (currentRecorder == null) {
|
||||||
|
console.log('Error: Recorder not initialized.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const currentRecorder = recorder
|
const listener = new MyFLVListener(callback)
|
||||||
if (currentRecorder == null) {
|
flvPacker = new FLVPacker(listener, true, false)
|
||||||
return { code: -1, data: {}, message: '录音尚未初始化' }
|
|
||||||
}
|
|
||||||
|
|
||||||
const listener = new MyFLVListener(callback)
|
const sampleRateInHz = 16000
|
||||||
flvPacker = new FLVPacker(listener, true, false)
|
const channelCount = 1
|
||||||
|
const bitRate = 96000
|
||||||
|
aacEncoder = MediaCodec.createEncoderByType('audio/mp4a-latm')
|
||||||
|
const mediaFormat = MediaFormat.createAudioFormat(
|
||||||
|
'audio/mp4a-latm',
|
||||||
|
sampleRateInHz.toInt(),
|
||||||
|
channelCount.toInt()
|
||||||
|
)
|
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate.toInt())
|
||||||
|
mediaFormat.setInteger(
|
||||||
|
MediaFormat.KEY_AAC_PROFILE,
|
||||||
|
MediaCodecInfo.CodecProfileLevel.AACObjectLC
|
||||||
|
)
|
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1024 * 1024)
|
||||||
|
aacEncoder!!.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
|
||||||
|
|
||||||
const sampleRateInHz = 16000
|
recordThread = new Thread(() => {
|
||||||
const channelCount = 1
|
try {
|
||||||
const bitRate = 96000
|
if (aacEncoder == null || currentRecorder == null || flvPacker == null) {
|
||||||
aacEncoder = MediaCodec.createEncoderByType('audio/mp4a-latm')
|
return
|
||||||
const mediaFormat = MediaFormat.createAudioFormat(
|
|
||||||
'audio/mp4a-latm',
|
|
||||||
sampleRateInHz.toInt(),
|
|
||||||
channelCount.toInt()
|
|
||||||
)
|
|
||||||
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate.toInt())
|
|
||||||
mediaFormat.setInteger(
|
|
||||||
MediaFormat.KEY_AAC_PROFILE,
|
|
||||||
MediaCodecInfo.CodecProfileLevel.AACObjectLC
|
|
||||||
)
|
|
||||||
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1024 * 1024)
|
|
||||||
aacEncoder!!.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
|
|
||||||
|
|
||||||
recordThread = new Thread(() => {
|
|
||||||
try {
|
|
||||||
if (aacEncoder == null || currentRecorder == null || flvPacker == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
currentRecorder.startRecording()
|
|
||||||
aacEncoder!!.start()
|
|
||||||
isRecording = true
|
|
||||||
|
|
||||||
const audioInfo = new MediaCodec.BufferInfo()
|
|
||||||
while (isRecording) {
|
|
||||||
// Feed encoder
|
|
||||||
const inputBufferId = aacEncoder!!.dequeueInputBuffer(10000)
|
|
||||||
if (inputBufferId >= 0) {
|
|
||||||
const inputBuffer = aacEncoder!!.getInputBuffer(inputBufferId)!!
|
|
||||||
const readSize = currentRecorder.read(inputBuffer, bufferSizeInBytes)
|
|
||||||
if (readSize > 0 && isRecording) {
|
|
||||||
aacEncoder!!.queueInputBuffer(
|
|
||||||
inputBufferId,
|
|
||||||
0,
|
|
||||||
readSize,
|
|
||||||
(Date.now() * 1000).toLong(),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain encoder
|
currentRecorder.startRecording()
|
||||||
var outputBufferId = aacEncoder!!.dequeueOutputBuffer(audioInfo, 10000)
|
aacEncoder!!.start()
|
||||||
while (outputBufferId >= 0 && isRecording) {
|
isRecording = true
|
||||||
const outputBuffer = aacEncoder!!.getOutputBuffer(outputBufferId)!!
|
|
||||||
if (audioInfo.size > 0 && flvPacker != null) {
|
|
||||||
const outDataSize = audioInfo.size
|
|
||||||
const packetLen = outDataSize + 7
|
|
||||||
const aacPacket = ByteArray(packetLen)
|
|
||||||
|
|
||||||
addADTStoPacket(aacPacket, packetLen)
|
const audioInfo = new MediaCodec.BufferInfo()
|
||||||
|
while (isRecording) {
|
||||||
outputBuffer.position(audioInfo.offset)
|
const inputBufferId = aacEncoder!!.dequeueInputBuffer(10000)
|
||||||
outputBuffer.limit(audioInfo.offset + outDataSize)
|
if (inputBufferId >= 0) {
|
||||||
outputBuffer.get(aacPacket, 7, outDataSize)
|
const inputBuffer = aacEncoder!!.getInputBuffer(inputBufferId)!!
|
||||||
outputBuffer.position(audioInfo.offset)
|
const readSize = currentRecorder.read(inputBuffer, bufferSizeInBytes)
|
||||||
|
if (readSize > 0 && isRecording) {
|
||||||
if (flvPacker != null && isRecording) {
|
aacEncoder!!.queueInputBuffer(
|
||||||
flvPacker!!.encodeFlv(aacPacket, FLVPacker.TYPE_AUDIO, Date.now().toLong())
|
inputBufferId,
|
||||||
|
0,
|
||||||
|
readSize,
|
||||||
|
(Date.now() * 1000).toLong(),
|
||||||
|
0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aacEncoder!!.releaseOutputBuffer(outputBufferId, false)
|
|
||||||
outputBufferId = aacEncoder!!.dequeueOutputBuffer(audioInfo, 0)
|
var outputBufferId = aacEncoder!!.dequeueOutputBuffer(audioInfo, 10000)
|
||||||
|
while (outputBufferId >= 0 && isRecording) {
|
||||||
|
const outputBuffer = aacEncoder!!.getOutputBuffer(outputBufferId)!!
|
||||||
|
if (audioInfo.size > 0 && flvPacker != null) {
|
||||||
|
const outDataSize = audioInfo.size
|
||||||
|
const aacPacketWithAdts = ByteArray(outDataSize + 7)
|
||||||
|
|
||||||
|
addADTStoPacket(aacPacketWithAdts, outDataSize + 7)
|
||||||
|
|
||||||
|
outputBuffer.position(audioInfo.offset)
|
||||||
|
outputBuffer.limit(audioInfo.offset + outDataSize)
|
||||||
|
outputBuffer.get(aacPacketWithAdts, 7, outDataSize)
|
||||||
|
|
||||||
|
if (flvPacker != null && isRecording) {
|
||||||
|
flvPacker!!.encodeFlv(
|
||||||
|
aacPacketWithAdts,
|
||||||
|
FLVPacker.TYPE_AUDIO,
|
||||||
|
Date.now().toLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aacEncoder!!.releaseOutputBuffer(outputBufferId, false)
|
||||||
|
outputBufferId = aacEncoder!!.dequeueOutputBuffer(audioInfo, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Record thread error: ' + error.toString())
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
currentRecorder?.stop()
|
||||||
|
} catch (e) {}
|
||||||
|
try {
|
||||||
|
aacEncoder?.stop()
|
||||||
|
aacEncoder?.release()
|
||||||
|
} catch (e) {}
|
||||||
|
try {
|
||||||
|
flvPacker?.release()
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
aacEncoder = null
|
||||||
|
flvPacker = null
|
||||||
|
isRecording = false
|
||||||
}
|
}
|
||||||
} catch (error) {
|
})
|
||||||
// Log error
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
currentRecorder?.stop()
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
aacEncoder?.stop()
|
|
||||||
aacEncoder?.release()
|
|
||||||
} catch (e) {}
|
|
||||||
try {
|
|
||||||
flvPacker?.release()
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
aacEncoder = null
|
recordThread!!.start()
|
||||||
flvPacker = null
|
})
|
||||||
isRecording = false
|
.catch(error => {
|
||||||
}
|
console.log('Error in stopRecord(): ' + error.toString())
|
||||||
})
|
})
|
||||||
|
|
||||||
recordThread!!.start()
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
data: {},
|
|
||||||
message: '成功'
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
code: -1,
|
|
||||||
data: {},
|
|
||||||
message: error.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const stopRecord = async function (): Promise<Result> {
|
export const stopRecord = async function (): Promise<Result> {
|
||||||
@ -322,5 +315,3 @@ export const releaseRecord = async function (): Promise<Result> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore-end
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user