使用AVAudioPlayer播放音频:真机报错及改格式后无声问题求助
问题分析与修复方案
错误原因拆解
- 格式不匹配:代码里加载的是
.m4a文件,但fileTypeHint指定为caf,真机对音频格式校验更严格,直接导致文件打开失败(错误码1685348671对应音频格式不支持/文件无法识别)。后续改后缀为caf后,代码里的文件名后缀没同步修改,实际加载的文件不存在,自然没有声音。 - 音频会话管理不当:每次播放都激活会话,但播放完成后未停用,多次调用会导致会话冲突,占用系统音频资源。
- 播放器实例生命周期问题:如果
player是类的弱引用或局部变量,会被ARC提前释放,导致播放中断或无声音。
具体修复步骤
1. 统一音频文件格式与参数
确保文件名后缀和fileTypeHint完全一致,以caf格式为例:
func playByUrl(url: String) { // 统一文件后缀为caf let audioFilename = getDocumentsDirectory().appendingPathComponent("\(url).caf") do { // 配置音频会话,添加混音选项避免和其他音频冲突 try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers]) try AVAudioSession.sharedInstance().setActive(true) // fileTypeHint与文件格式保持一致 player = try AVAudioPlayer(contentsOf: audioFilename, fileTypeHint: AVFileType.caf.rawValue) guard let player = player else { return } // 设置代理监听播放完成,及时释放资源 player.delegate = self player.prepareToPlay() player.play() } catch let error { print("播放失败:\(error.localizedDescription)") // 激活失败时强制停用会话,避免资源占用 try? AVAudioSession.sharedInstance().setActive(false) } }
2. 固定播放器实例生命周期
在类中声明强引用的player属性,防止被提前释放:
class YourAudioManager: NSObject, AVAudioPlayerDelegate { var player: AVAudioPlayer? // 强引用存储播放器实例 // ... 其他业务代码 }
3. 播放完成后释放资源
实现AVAudioPlayerDelegate回调,完成后清理会话和播放器:
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { // 停用音频会话并通知其他应用 try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation) // 重置播放器,释放资源 self.player = nil }
4. 录制阶段同步格式
如果是自行录制音频,录制时也要指定caf格式的参数,确保文件可用:
let recordSettings: [String: Any] = [ AVFormatIDKey: kAudioFormatLinearPCM, AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ] // 录制文件后缀统一为caf let recordUrl = getDocumentsDirectory().appendingPathComponent("\(url).caf") let recorder = try AVAudioRecorder(url: recordUrl, settings: recordSettings)
额外注意事项
- 真机测试时,确认设备未静音、音量已开启。
- 每次播放前检查旧播放器状态,避免资源冲突:
if let existingPlayer = player, existingPlayer.isPlaying { existingPlayer.stop() existingPlayer.delegate = nil } player = nil
内容的提问来源于stack exchange,提问作者Миша Гарлинский
相关产品推荐
相关产品推荐

