iOS 12.4调用AVAudioRecorder.record()触发BogusAudioBufferList崩溃
崩溃触发原因
- 核心诱因是初始化
AVAudioRecorder时传入了空字典[:]作为录音配置参数。iOS 12.x 系统的AVFoundation框架不会在settings为空时自动补全合法的PCM录音参数,会生成格式非法的音频缓冲列表,直接触发CrashIfClientProvidedBogusAudioBufferList标识的崩溃。该问题在iOS 12.4 x86模拟器上100%复现,真机环境触发概率极低,但属于不符合API规范的写法。 - 代码调用顺序存在问题:当前实现先初始化AVAudioRecorder实例,再配置AVAudioSession的分类、激活状态,违反了AVFoundation录音接口的调用顺序要求,部分系统版本下会导致录音器读取到未就绪的音频会话状态,进一步提升崩溃概率。
- iOS 12.4模拟器本身存在音频栈实现bug,对非法音频缓冲的校验逻辑比真机/高版本系统更严格,会放大上述代码问题的影响。
修复方案
- 调整调用顺序:麦克风权限校验通过后,优先完成AVAudioSession的分类设置、激活操作,再初始化AVAudioRecorder实例。
- 禁止传入空配置:初始化AVAudioRecorder时显式指定和目标格式匹配的录音参数,以WAV格式为例,合法配置如下:
let recordSettings: [String: Any] = [ AVFormatIDKey: Int(kAudioFormatLinearPCM), AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 2, AVLinearPCMBitDepthKey: 16, AVLinearPCMIsBigEndianKey: false, AVLinearPCMIsFloatKey: false, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ]
- 修正后的完整录音启动代码参考:
func startRecording() { let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] let recordName = "record.wav" audioURL = URL(fileURLWithPath: dirPath + "/" + recordName) do { // 先配置并激活音频会话 try audioSession.setCategory(.playAndRecord, options: .defaultToSpeaker) try audioSession.setActive(true) // 传入显式配置的录音参数初始化录音器 let recordSettings: [String: Any] = [ AVFormatIDKey: Int(kAudioFormatLinearPCM), AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 2, AVLinearPCMBitDepthKey: 16, AVLinearPCMIsBigEndianKey: false, AVLinearPCMIsFloatKey: false, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ] let recorder = try AVAudioRecorder(url: self.audioURL, settings: recordSettings) audioRecorder = recorder audioRecorder.isMeteringEnabled = true audioRecorder.delegate = self audioRecorder.prepareToRecord() audioRecorder.record() } catch { self.finishRecording(success: false) print(error) } }
补充说明:完成上述修改后如果iOS 12.4模拟器仍存在偶发崩溃,属于模拟器自身的底层bug,不会在实体设备上复现,只要iOS 13及以上版本模拟器、全版本真机运行正常即可,不需要针对旧版模拟器做额外兼容。
内容的提问来源于stack exchange,提问作者Діма Комар
相关产品推荐
相关产品推荐

