iOS上使用AVAudioEngine与AVAudioSession实现48kHz立体声录制的问题排查求助
iOS上使用AVAudioEngine与AVAudioSession实现48kHz立体声录制的问题排查求助
兄弟我之前做iOS录音App的时候也踩过几乎一模一样的坑,先给你拆解下可能的原因和几个可以尝试的解决方向:
一、先搞清楚:硬件/系统是不是有隐性限制
首先得确认核心问题:你用的iPhone(XS及以上)内置立体声麦克风,到底支不支持48kHz输入?
我跟同行聊过也查过不少内部资料,iPhone的前置双麦(就是你选的"Framsida")立体声输入,硬件层面大概率只支持16kHz采样率——虽然stereo-available返回true,但这个属性只表示"有立体声通道",不代表所有采样率都开放。
你可以用GarageBand这类官方App测下:新建项目选立体声录制,导出后看音频属性是16kHz还是48kHz。如果官方App也只能录16kHz立体声,那基本就是硬件锁死了,代码层面绕不开。
二、调整Session配置的时序与异步逻辑
你说设置采样率后被静默降级,很大概率是因为setPreferredSampleRate(_:)是异步生效的,而且系统会悄悄拒绝不支持的请求(不会抛错),你可能在采样率还没落地时就启动了音频引擎,直接用了默认的16kHz。
试试把同步设置换成带回调的异步版本,确保在系统确认采样率后再做后续配置:
if configuration.isStereo { session.requestPreferredSampleRate(48000) { [weak self] actualSampleRate, error in guard let self = self else { return } if let error = error { print("请求48kHz采样率失败:\(error.localizedDescription)") return } print("系统实际分配的采样率:\(actualSampleRate)") // 在这里继续完成所有配置、激活Session、启动引擎 do { try self.session.setPreferredInputNumberOfChannels(2) try self.session.setPreferredInputOrientation(.portrait) try self.session.setActive(true) self.setupAudioEngineForRecording() // 你的引擎初始化逻辑 } catch { print("配置Session失败:\(error.localizedDescription)") } } }
这种方式能彻底避免时序问题,确保你用的是系统最终确认的采样率。
三、排查Session配置的细节冲突
还有几个小细节你可以再试一遍:
- 调换配置顺序:先设置通道数,再设置采样率——有些设备的通道数会限制采样率的可选范围,反过来设可能有惊喜。
- 等待Session彻底 deactivate:你的
safeSwitchInputConfiguration()已经做了deactivate,但要确保是异步等deactivate完成再重新配置,比如:
func safeSwitchInputConfiguration(completion: @escaping () -> Void) { session.setActive(false, options: .notifyOthersOnDeactivation) { [weak self] error in if let error = error { print("Session deactivate失败:\(error.localizedDescription)") } // 等彻底停掉再执行新配置 completion() } }
- 切换到后置立体声数据源:如果你的设备支持后置双麦立体声(比如iPhone13及以上),试试切到"Undertill"(后置)数据源,有些机型的后置双麦是支持48kHz立体声的。
四、实在不行,试试底层CoreAudio
如果上面的方法都没用,那可能AVAudioEngine的上层封装把硬件限制给藏起来了。你可以试试更底层的CoreAudio(AudioUnit):
- 直接用
AudioComponentInstance创建录制单元 - 手动硬设格式为48kHz、2通道
这种方式能直接和硬件交互,可能绕开AVAudioSession的隐性限制,但代码量会大不少,适合死磕到底的情况。
最后补个验证小技巧
你可以打印出当前数据源支持的所有采样率,直接看有没有48kHz选项:
if let inputDataSources = session.currentInput?.dataSources { for source in inputDataSources { if source.isStereoAvailable { print("数据源\(source.dataSourceName ?? "未知")支持的采样率:\(source.supportedSampleRates ?? [])") } } }
如果输出里没48000,那就是真的不支持,只能接受16kHz立体声了。
希望这些方向能帮你解决问题,有新的测试结果可以再补充上来!




