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

能否在ScreenCaptureKit录屏时用AVAudioEngine处理音频并停止录屏后恢复原音?

解决ScreenCaptureKit录屏时音频效果处理问题

你的核心需求是录屏时捕获系统音频并添加效果播放,停止录屏后恢复原音。现有代码仅做了buffer传递,缺少AVAudioEngine链路配置、音频会话管理和原音频静音处理,导致无法正常工作。以下是完整解决方案:

1. 初始化音频处理组件

提前创建AVAudioEngine相关实例,搭建好包含效果器的音频链路:

import AVFoundation
import ScreenCaptureKit

class ScreenRecorder: NSObject, SCStreamOutput {
    private let audioEngine = AVAudioEngine()
    private let playerNode = AVAudioPlayerNode()
    private let pitchEffect = AVAudioUnitTimePitch()
    private var originalAudioSessionConfig: (category: AVAudioSession.Category, options: AVAudioSession.CategoryOptions)?
    
    override init() {
        super.init()
        // 配置变调效果(示例:升高200音分,约2个半音)
        pitchEffect.pitch = 200
        // 搭建音频链路:playerNode → 变调效果器 → 引擎主混音器
        audioEngine.attach(playerNode)
        audioEngine.attach(pitchEffect)
        audioEngine.connect(playerNode, to: pitchEffect, format: nil)
        audioEngine.connect(pitchEffect, to: audioEngine.mainMixerNode, format: nil)
    }
}

2. 录屏启动前配置音频会话

启动录屏前修改音频会话,避免原音频与处理后的音频重叠,同时确保ScreenCaptureKit能正常捕获音频:

func startRecording() async throws {
    let audioSession = AVAudioSession.sharedInstance()
    // 保存原音频会话配置,用于停止时恢复
    originalAudioSessionConfig = (audioSession.category, audioSession.categoryOptions)
    
    // 设置音频会话为播放+录制模式,静音原系统输出,只播放处理后的音频
    try audioSession.setCategory(.playAndRecord, options: [.mixWithOthers, .defaultToSpeaker])
    try audioSession.activate()
    
    // 启动音频引擎
    try audioEngine.start()
    
    // 配置SCStream(仅展示音频相关配置)
    let streamConfig = SCStreamConfiguration()
    streamConfig.capturesAudio = true
    // 匹配音频引擎的采样率,避免格式不兼容
    streamConfig.audioSampleRate = audioEngine.inputNode.inputFormat(forBus: 0).sampleRate
    
    // 后续SCStream初始化、启动逻辑...
}

3. 修正音频SampleBuffer处理逻辑

在stream(_:didOutputSampleBuffer:of:)中正确转换并播放音频buffer:

func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of outputType: SCStreamOutputType) {
    guard sampleBuffer.isValid else { return }
    
    switch outputType {
    case .screen:
        // 屏幕帧处理逻辑...
    case .audio:
        guard let pcmBuffer = convertCMSampleBufferToPCMBuffer(sampleBuffer) else { return }
        // 确保playerNode处于播放状态
        if !playerNode.isPlaying {
            playerNode.play()
        }
        playerNode.scheduleBuffer(pcmBuffer, completionHandler: nil)
    default:
        break
    }
}

// 工具方法:将CMSampleBuffer转换为AVAudioPCMBuffer
private func convertCMSampleBufferToPCMBuffer(_ sampleBuffer: CMSampleBuffer) -> AVAudioPCMBuffer? {
    guard let formatDesc = CMSampleBufferGetFormatDescription(sampleBuffer),
          let audioFormat = AVAudioFormat(cmAudioFormatDescription: formatDesc),
          let pcmBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: AVAudioFrameCount(CMSampleBufferGetNumSamples(sampleBuffer))) else {
        return nil
    }
    
    pcmBuffer.frameLength = pcmBuffer.frameCapacity
    guard CMSampleBufferCopyPCMDataIntoAudioBufferList(sampleBuffer, at: 0, frameCount: Int(pcmBuffer.frameLength), into: pcmBuffer.mutableAudioBufferList) else {
        return nil
    }
    return pcmBuffer
}

4. 停止录屏时恢复原音频状态

停止录屏后清理音频组件,恢复系统原音频配置:

func stopRecording() {
    // 停止音频播放并重置引擎
    playerNode.stop()
    audioEngine.stop()
    audioEngine.reset()
    
    // 恢复原音频会话配置
    guard let originalConfig = originalAudioSessionConfig else { return }
    
    Task {
        let audioSession = AVAudioSession.sharedInstance()
        try? audioSession.setCategory(originalConfig.category, options: originalConfig.options)
        try? audioSession.deactivate(options: .notifyOthersOnDeactivation)
    }
    
    // 停止SCStream逻辑...
}

关键注意点

  • 格式匹配:SCStream的音频采样率必须与AVAudioEngine的格式一致,否则会出现播放卡顿或无声问题。
  • 音频会话冲突:必须通过playAndRecord类别配合defaultToSpeaker选项,实现原音频静音、仅播放处理后音频的效果。
  • 资源清理:停止录屏时务必重置音频引擎并恢复原会话,避免影响后续系统音频播放。

内容的提问来源于stack exchange,提问作者Babitha shetty k

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:07:45