You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

visionOS平台AVCaptureAudioDataOutput替代方案及AVAudioBuffer获取咨询

visionOS 下获取 AVAudioBuffer 的可行思路
  • 基于录制回调直接捕获
    既然已确认音频录制功能可用,可通过AVAudioRecorder结合自定义逻辑捕获AVAudioBuffer。先配置好音频会话和录制格式,再借助底层回调或引擎tap获取缓冲区:

    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(.record, mode: .default)
        try session.setActive(true)
        
        let settings: [String: Any] = [
            AVFormatIDKey: kAudioFormatLinearPCM,
            AVSampleRateKey: 44100.0,
            AVNumberOfChannelsKey: 1,
            AVLinearPCMBitDepthKey: 16,
            AVLinearPCMIsFloatKey: false,
            AVLinearPCMIsBigEndianKey: false
        ]
        
        let recorder = try AVAudioRecorder(url: temporaryFileURL, settings: settings)
        recorder.prepareToRecord()
        // 后续可结合AudioQueue或AVAudioEngine的tap逻辑获取buffer
    } catch {
        print("配置失败: \(error)")
    }
    
  • 尝试AVAudioEngine输入节点Tap
    尽管visionOS初期对AVAudioEngine支持有限,但输入节点tap是获取实时音频缓冲区的常规方案,可尝试如下实现:

    let engine = AVAudioEngine()
    let inputNode = engine.inputNode
    let inputFormat = inputNode.inputFormat(forBus: 0)
    
    inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { (buffer: AVAudioPCMBuffer, time: AVAudioTime) in
        // 此处直接拿到AVAudioPCMBuffer,可直接处理
        print("捕获缓冲区帧数: \(buffer.frameLength)")
    }
    
    do {
        try engine.start()
    } catch {
        print("引擎启动失败: \(error)")
    }
    

    注意:必须在Info.plist中添加NSMicrophoneUsageDescription字段申请麦克风权限,否则会无响应或崩溃。

  • 底层Core Audio API兜底
    如果高层API无法生效,可直接用Core Audio的AudioQueue录制并包装成AVAudioBuffer,兼容性更强:

    var audioFormat = AudioStreamBasicDescription()
    audioFormat.mSampleRate = 44100.0
    audioFormat.mFormatID = kAudioFormatLinearPCM
    audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked
    audioFormat.mChannelsPerFrame = 1
    audioFormat.mBitsPerChannel = 16
    audioFormat.mBytesPerPacket = 2
    audioFormat.mFramesPerPacket = 1
    audioFormat.mBytesPerFrame = 2
    
    func setupAudioQueue() {
        var queue: AudioQueueRef?
        AudioQueueNewInput(&audioFormat, audioQueueCallback, nil, nil, nil, 0, &queue)
        AudioQueueStart(queue!, nil)
    }
    
    func audioQueueCallback(queue: AudioQueueRef, buffer: AudioQueueBufferRef, startTime: UnsafePointer<AudioTimeStamp>, numPackets: UInt32, packetDescs: UnsafePointer<AudioStreamPacketDescription>?) {
        // 将AudioQueueBuffer数据拷贝到AVAudioPCMBuffer
        guard let pcmFormat = AVAudioFormat(streamDescription: &audioFormat) else { return }
        let pcmBuffer = AVAudioPCMBuffer(pcmFormat: pcmFormat, frameCapacity: AVAudioFrameCount(numPackets))
        pcmBuffer?.frameLength = AVAudioFrameCount(numPackets)
        memcpy(pcmBuffer?.int16ChannelData?[0], buffer.pointee.mAudioData, Int(buffer.pointee.mAudioDataBytesCapacity))
        
        // 处理pcmBuffer
        AudioQueueEnqueueBuffer(queue, buffer, 0, nil)
    }
    
  • 检查会话配置与权限
    所有音频操作的前提是正确配置会话并获取权限:

    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(.playAndRecord, options: .mixWithOthers)
        try session.setActive(true)
        let hasPermission = await session.requestRecordPermission()
        guard hasPermission else {
            print("未获取麦克风权限")
            return
        }
    } catch {
        print("会话配置失败: \(error)")
    }
    

内容的提问来源于stack exchange,提问作者Pietro Messineo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 02:14:56