mac电脑开发第二次1

This commit is contained in:
2026-02-12 17:27:59 +08:00
parent 67d8c4ec88
commit 13fcd674ad
@@ -3,10 +3,24 @@ import { StartAudioRecordFailImpl, AudioErrorCode } from '../unierror.uts';
import { UTSiOS } from "DCloudUTSFoundation"
import { AVAudioEngine, AVAudioSession, AVAudioFormat, AVAudioInputNode, AVAudioPCMBuffer } from "AVFoundation";
import { NSData, NSMutableData } from "Foundation";
// 线程安全的录制状态标识
// @argumentLabel("forBus")
/**
* 音频采集状态(全局变量,保证生命周期)
*/
let isRecording = false;
/**
* 音频引擎实例(全局变量,避免异步回调中被释放)
*/
let audioEngine: AVAudioEngine | null = null;
/**
* 音频输入节点(全局变量,避免被释放)
*/
let inputNode: AVAudioInputNode | null = null;
// 全局复用缓冲区(避免每次创建新数组)
let reuseInt32Array: Int32Array | null = new Int32Array(4800);
/**
* 启动音频采集(iOS端核心实现)
@@ -16,19 +30,83 @@ let isRecording = false;
export function startAudioRecord(options: StartAudioRecordOptions): void {
// 避免重复启动
console.log('避免重复启动', isRecording);
if (isRecording) return;
// if (isRecording) return;
try {
const audioSession = AVAudioSession.sharedInstance();
const authStatus = audioSession.recordPermission();
console.log('asaadda', authStatus);
UTSiOS.try(audioSession.setCategory(
AVAudioSession.Category.playAndRecord,
mode=AVAudioSession.Mode.spokenAudio,
options= AVAudioSession.CategoryOptions.duckOthers // 可选:其他音频静音
));
// UTSiOS.try(audioSession.setCategory(AVAudioSession.Category.playAndRecord));
// UTSiOS.try(audioSession.setMode(AVAudioSession.Mode.spokenAudio));
UTSiOS.try(audioSession.setActive(true));
audioSession.requestRecordPermission((granted: boolean) => {
// 闭包内处理权限结果(异步执行)
if (granted) {
// 权限通过:继续初始化采集逻辑
try {
// 创建音频引擎(移到闭包内,保证权限通过后才执行)
audioEngine = AVAudioEngine.init();
if (audioEngine === null) { // 解包:先判断是否为nil
throw new Error("音频输入节点为空,无法获取音频格式");
}
inputNode = audioEngine!.inputNode;
if (inputNode === null) { // 解包:先判断是否为nil
throw new Error("音频输入节点为空,无法获取音频格式");
}
const unwrappedInputNode = inputNode!;
const inputFormat = unwrappedInputNode.inputFormat(forBus= 0);
unwrappedInputNode.installTap(
onBus= 0, // 总线编号,通常传 0
bufferSize= 1024, // 缓冲区大小,常用 1024/2048
format= inputFormat, // 音频格式
block=(buffer: AVAudioPCMBuffer, time: any) => {
const floatData = buffer.floatChannelData;
const channelData = floatData![0];
const frameLength = buffer.frameLength as number;
const bytesPerSample = 2; // 16位整型=2字节/样本
const totalBytes = frameLength * bytesPerSample;
console.log(channelData);
console.log(totalBytes);
const pcmData = NSMutableData.dataWithCapacity(20); // 可变Data,支持写入
// const data = new Float32Array(int32Array.byteLength);
// data.set(int32Array.buffer, 1); // 内存块拷贝,替代逐字节写入
options.onFrame?.(pcmData);
// if (floatData !== null) {
// // 单声道取第0个通道(立体声可取[0]左声道、[1]右声道)
// const channelData = floatData[0];
// options.onFrame?.(channelData)
// }
}
);
UTSiOS.try(audioEngine!.start());
if (audioEngine!.isRunning) {
console.log("引擎确实处于运行状态");
isRecording = true;
} else {
console.error("调用 start() 但引擎未运行");
}
isRecording = true;
} catch (error) {
isRecording = false;
}
} else {
// 权限被拒绝:回调错误
isRecording = false;
}
});
isRecording = true;
} catch (error) {
// 初始化失败回调错误
const err = new StartAudioRecordFailImpl(AudioErrorCode.AUDIO_FORMAT_ILLEGAL);
const err = new StartAudioRecordFailImpl(9010002);
options.onError?.(err);
// 重置状态
return;
}
}
@@ -37,7 +115,34 @@ export function startAudioRecord(options: StartAudioRecordOptions): void {
* 停止音频采集(配套停止逻辑,保证功能完整)
* @param options 回调配置
*/
@UTSJS.keepAlive
export function stopAudioRecord(): void {
if (audioEngine === null) { // 解包:先判断是否为nil
isRecording = false;
return; // 直接返回,不执行后续逻辑
}
const _audioEngine = audioEngine!
if (_audioEngine.isRunning) {
_audioEngine.stop();
}
if (inputNode === null) { // 解包:先判断是否为nil
isRecording = false;
return; // 直接返回,不执行后续逻辑
}
const _inputNode = inputNode!
_inputNode.removeTap(onBus= 0); // 移除音频回调
// 停用音频会话
const audioSession = AVAudioSession.sharedInstance();
try {
UTSiOS.try(audioSession.setActive(false));
}catch (e) {
console.log(e)
}
inputNode = null;
audioEngine = null; // 释放全局引擎
isRecording = false;
}