AudioKit中completionHandler与schedule buffer使用问题:回调未触发
问题分析与解决方案
你的代码能正常播放PCM buffer但completionHandler始终不触发,核心问题是线程阻塞导致RunLoop无法处理回调,同时存在冗余调用干扰播放流程,具体修正如下:
核心问题:阻塞RunLoop
你在player.play()后用while循环+sleep(3)阻塞了当前线程,而AudioKit的completionHandler依赖RunLoop(或音频线程的回调调度)才能触发。线程被阻塞后,回调事件无法被处理,自然不会执行。
冗余调用干扰
你已经通过AudioPlayer(buffer: buffer1!)初始化了携带目标buffer的播放器,后续重复设置player.buffer = buffer1!和调用player.schedule(at:...)属于冗余操作,反而可能打乱播放器的内部状态。
修正后的代码
import AudioKit let audioURL = URL(fileURLWithPath: "/Users/myuser/greeneggs.wav") let audioFile = try! AVAudioFile(forReading: audioURL) print("audioFile length is \(audioFile.length)") let format = audioFile.processingFormat let buffer1 = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(audioFile.length/8))! audioFile.framePosition = 0 try audioFile.read(into: buffer1, frameCount: AVAudioFrameCount(audioFile.length/8)) let audioEngine = AudioEngine() let player = AudioPlayer(buffer: buffer1)! audioEngine.output = player player.completionHandler = bufferCompletionHandler do { try audioEngine.start() print("Audio engine started successfully.") } catch { print("Error starting audio engine: \(error)") } player.play() // 保持RunLoop运行,避免程序直接退出,同时让回调能被正常处理 RunLoop.main.run(until: Date().addingTimeInterval(player.duration + 1)) print("Done!") func bufferCompletionHandler(){ print("!!!!!!+++++...Scheduled...+++++!!!!!!") }
关键修改说明
- 移除冗余的
player.buffer = buffer1!和player.schedule(at:...)调用,直接使用初始化时传入的buffer进行播放 - 替换
while循环+sleep为RunLoop.main.run(until:...),既保证程序运行到播放完成后再退出,又不会阻塞RunLoop,确保回调能被触发 - 修正
buffer1的强制解包(添加!),避免隐式解包的潜在风险
如果需要在播放过程中打印状态,建议使用定时器而非阻塞循环,示例如下:
// 播放开始后添加定时器,每隔3秒打印状态 let timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { timer in guard player.isPlaying else { timer.invalidate() return } print("Players gonna play") print("isBuffered \(player.isBuffered)") print("duration \(player.duration)") print("status \(player.status)") print("isLooping \(player.isLooping)") }
内容的提问来源于stack exchange,提问作者John Brown
相关产品推荐
相关产品推荐

