/* eslint-disable */ // @ts-nocheck // @ts-ignore-start import 'android.media.AudioRecord' import 'android.media.MediaRecorder' import 'android.media.AudioFormat' import 'android.media.MediaSyncEvent' import 'android.media.MediaCodec' import 'android.media.MediaCodecInfo' import 'android.media.MediaFormat' import 'java.lang.Thread' import { UTSAndroid } from 'io.dcloud.uts' import { Result } from '../interface.uts' import { FLVPacker, FLVListener } from 'com.tencent.iot.thirdparty.flv' let recorder: AudioRecord | null = null let aacEncoder: MediaCodec | null = null let flvPacker: FLVPacker | null = null let recordThread: Thread | null = null let isRecording: boolean = false let bufferSizeInBytes: Int = 0 class MyFLVListener extends FLVListener { private callback: (data: Array) => void constructor(callback: (data: Array) => void) { super() this.callback = callback } override onFLV(data: ByteArray) { if (isRecording) { const numberArray: Array = [] for (let i: Int = 0; i < data.size; i++) { numberArray.push(data[i].toInt()) } UTSAndroid.getUniActivity()?.runOnUiThread(() => { this.callback(numberArray) }) } } } function addADTStoPacket(packet: ByteArray, packetLen: Int) { const profile = 2 const freqIdx = 8 const chanCfg = 1 packet[0] = (0xff).toByte() packet[1] = (0xf9).toByte() packet[2] = (((profile - 1) << 6) | (freqIdx << 2) | (chanCfg >> 2)).toByte() packet[3] = (((chanCfg & 3) << 6) | (packetLen >> 11)).toByte() packet[4] = ((packetLen & 0x7ff) >> 3).toByte() packet[5] = (((packetLen & 7) << 5) | 0x1f).toByte() packet[6] = (0xfc).toByte() } export const requestPermission = async function (): Promise { return new Promise(resolve => { try { const permissionNeed = ['android.permission.RECORD_AUDIO'] UTSAndroid.requestSystemPermission( UTSAndroid.getUniActivity()!, permissionNeed, (allRight: boolean, _: string[]) => { if (allRight) { resolve({ code: 0, data: {}, message: '成功' }) } else { resolve({ code: -1, data: {}, message: '失败' }) } }, (_: boolean, _: string[]) => { resolve({ code: -1, data: {}, message: '失败' }) } ) } catch (error) { resolve({ code: -1, data: {}, message: error.toString() }) } }) } export const initAudio = async function (): Promise { try { const audioSource = MediaRecorder.AudioSource.MIC const sampleRateInHz = 16000 const channelConfig = AudioFormat.CHANNEL_IN_MONO const audioFormat = AudioFormat.ENCODING_PCM_16BIT bufferSizeInBytes = AudioRecord.getMinBufferSize( sampleRateInHz.toInt(), channelConfig, audioFormat ) recorder = new AudioRecord( audioSource, sampleRateInHz.toInt(), channelConfig, audioFormat, bufferSizeInBytes ) if (recorder?.getState() == AudioRecord.STATE_INITIALIZED) { return { code: 0, data: {}, message: '成功' } } else { return { code: -1, data: {}, message: '初始化录音失败' } } } catch (error) { return { code: -1, data: {}, message: error.toString() } } } export function onStartRecord(callback: (data: Array) => void) { stopRecord() .then(() => { const currentRecorder = recorder if (currentRecorder == null) { return } const listener = new MyFLVListener(callback) flvPacker = new FLVPacker(listener, true, false) const sampleRateInHz = 16000 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) 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) { 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 ) } } 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 } }) recordThread!!.start() }) .catch(error => { console.log('Error in stopRecord(): ' + error.toString()) }) } export const stopRecord = async function (): Promise { try { if (isRecording) { isRecording = false if (recordThread != null) { try { recordThread!!.join(1000) } catch (e) { console.log('recordThread.join error: ' + e.toString()) } recordThread = null } return { code: 0, data: {}, message: '成功' } } return { code: 0, data: {}, message: '录音未开始' } } catch (error) { isRecording = false recordThread = null return { code: -1, data: {}, message: error.toString() } } } export const releaseRecord = async function (): Promise { try { await stopRecord() const currentRecorder = recorder if (currentRecorder != null) { try { if (currentRecorder.getState() == AudioRecord.STATE_INITIALIZED) { currentRecorder.release() } } catch (e) {} recorder = null } return { code: 0, data: {}, message: '成功' } } catch (error) { return { code: -1, data: {}, message: error.toString() } } } // @ts-ignore-end