每天两三小时的视频会议后,你记得谁承诺了什么吗?我不记得。试过Otter.ai、Fireflies、Granola这些云端转录服务,但公司安全策略不允许会议音频流出内网。
于是我做了Scripta:一款开源macOS应用,同时录制通话双方、实时转录、生成AI摘要——全部在本地运行。零云端请求,零订阅费,零数据外泄。
GitHub: github.com/thehwang/Scripta
双声道难题
多数转录应用只处理单路音频。播客没问题,但会议有两个独立音源:你的麦克风,以及系统音频里传出的远程参会者声音。混成一路,就无法区分谁说了什么。
如果尝试用Apple的SFSpeechRecognizer同时跑两个识别任务,系统会抛出一个有趣的错误:kAFAssistantErrorDomain Code=1101——苹果的语音框架静默拒绝并发执行。
我的解法是用两套完全不同的自动语音识别引擎:
麦克风 → whisper.cpp:Whisper模型本地运行,Metal加速。base模型仅142MB,在Apple Silicon上实现>15倍实时速度——5秒音频约0.3秒转录完成。
系统音频 → SFSpeechRecognizer:苹果的设备端语音识别处理远程音频,对压缩过的VoIP音频效果良好,且不与Whisper争抢GPU资源。
这种混合方案既避开了SFSpeechRecognizer的并发崩溃,又保持全流程本地执行。
用ScreenCaptureKit捕获系统音频
macOS 13之前,捕获特定应用系统音频需要各种hack:BlackHole等虚拟音频设备、聚合设备,或内核扩展。ScreenCaptureKit彻底改变了这一局面。
关键发现:ScreenCaptureKit可以只捕获音频——完全不需要录屏。把视频尺寸设为2×2像素,启用音频即可:
let config = SCStreamConfiguration()
config.capturesAudio = true
config.excludesCurrentProcessAudio = true // 防止反馈环路
config.sampleRate = 16_000
config.channelCount = 1
config.width = 2 // 最小视频——我们只要音频
config.height = 2
excludesCurrentProcessAudio = true至关重要。没有它,应用自身播放的任何声音都会被捕获,形成反馈环路。
热门跟贴