如何使用Swift结合AudioKit同时播放两个音频文件
问题分析与代码修正
针对你的双音频同步播放需求,代码里存在几处需要修正的问题,同时可以优化实现逻辑:
核心问题与优化点
- 变量名笔误:类中定义的播放器实例是
player,但调用时错误使用了player2,会直接导致编译失败,需统一变量名。 - 音频会话类别错误:仅播放场景无需使用
.playAndRecord类别,改用.playback更合理,避免不必要的录音权限申请;同时调整会话选项适配外放需求。 - 命名规范问题:Swift中结构体名称需遵循大驼峰命名,将
segment改为Segment。 - 时长计算冗余:
AVAudioFile自带duration属性,无需手动通过采样率和样本数计算音频时长,直接调用即可简化代码。 - 错误处理不当:
error.localizedDescription.debugDescription是错误的用法,直接输出error或error.localizedDescription即可清晰展示错误信息。 - 资源生命周期缺失:类销毁时需停止AudioEngine并取消激活音频会话,避免内存泄漏和后台音频占用。
修正后的完整代码
import AudioKit import AVFoundation import Combine class AudioPlayClass: ObservableObject { var player = MultiSegmentAudioPlayer() let engine = AudioEngine() deinit { // 清理音频资源 engine.stop() do { try AVAudioSession.sharedInstance().setActive(false) } catch { print("Failed to deactivate audio session: \(error)") } } func playFiles() { // 连接播放器到引擎输出 engine.output = player do { // 配置音频会话为仅播放模式 try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: .defaultToSpeaker) try AVAudioSession.sharedInstance().setActive(true) // 读取音频文件 guard let url = Bundle.main.url(forResource: "note1", withExtension: "wav", subdirectory: "instrumentDirectory") else { print("note1.wav not found") return } guard let url2 = Bundle.main.url(forResource: "note2", withExtension: "wav", subdirectory: "instrumentDirectory") else { print("note2.wav not found") return } let audioFile = try AVAudioFile(forReading: url) let audioFile2 = try AVAudioFile(forReading: url2) // 创建同步播放的音频片段 let segment1 = Segment( audioFile: audioFile, playbackStartTime: 0.0, fileStartTime: 0, fileEndTime: audioFile.duration ) let segment2 = Segment( audioFile: audioFile2, playbackStartTime: 0.0, fileStartTime: 0, fileEndTime: audioFile2.duration ) // 调度片段并播放 player.scheduleSegments(audioSegments: [segment1, segment2]) try engine.start() player.play() } catch { print("Audio playback error: \(error.localizedDescription)") } } } // 遵循Swift命名规范的音频片段结构体 public struct Segment: StreamableAudioSegment { public var audioFile: AVAudioFile public var playbackStartTime: TimeInterval public var fileStartTime: TimeInterval public var fileEndTime: TimeInterval public var completionHandler: AVAudioNodeCompletionHandler? // 简化初始化(可选,提升代码可读性) public init(audioFile: AVAudioFile, playbackStartTime: TimeInterval, fileStartTime: TimeInterval, fileEndTime: TimeInterval, completionHandler: AVAudioNodeCompletionHandler? = nil) { self.audioFile = audioFile self.playbackStartTime = playbackStartTime self.fileStartTime = fileStartTime self.fileEndTime = fileEndTime self.completionHandler = completionHandler } }
关键说明
- 同步播放实现:只要两个
Segment的playbackStartTime都设置为0.0,MultiSegmentAudioPlayer会自动处理同步播放逻辑,无需额外的时间同步代码。 - 音频会话配置:
.playback类别专注于播放场景,配合.defaultToSpeaker选项确保音频从扬声器输出,避免使用听筒。 - 资源清理:
deinit方法中停止引擎并取消激活会话,是iOS音频开发的最佳实践,避免后台资源占用。
内容的提问来源于stack exchange,提问作者TrappinNachos
相关产品推荐
相关产品推荐

