У меня есть один основной AVAudioPlayerNode, который играет постоянно. И есть другие игроки, которые ставятся в очередь и играют, когда основной игрок достигает определенной точки.
Эти AVAudioPlayerNode должны быть синхронизированы с точностью до миллисекунды. Иногда можно запустить 4-10 штук одновременно.
Как это работает - я сохраняю lastRenderTime
основного игрока на момент, когда нужно запустить всех запланированных игроков, а затем запустить всех необходимых игроков с
player.start(at: lastRenderTime)
Обычно он работает хорошо и без задержки между звуками.
Но у меня есть задержка в этом случае:
- Работает на старых устройствах (iPad 2, iPhone 5 и т. Д.)
- ТОЛЬКО когда МНОГИЕ проигрыватели в первый раз после запуска приложения (например, на iPhone 7 я запускаю 8 проигрывателей одновременно после запуска приложения и слышу десинхронизацию между звуками), но все проигрыватели работают с одинаковым
player.start(at: lastRenderTime)
временем ,
Все действия игрока, которые я запускаю асинхронно с настраиваемой параллельной очередью.
Потратьте 3 дня, пытаясь это исправить. Я хотел бы за любые советы.
Код:
Вот как я начинаю основного игрока -
self.scheduleBuffer(audioFileBuffer, at: nil, options: [], completionHandler: {
lastRenderTime = lastRenderTime + audioBufferLength //Schematic showing logic that after each loop I calculate current render time value.
if self.isStopPressed == false { //Run fileEndCompletion only when player seek to end.
fileEndCompletionHandler() //here is callback that running all scheduled players.
if loop { // Recursive play this file again.
self.playAudioBuffer(audioFileBuffer: audioFileBuffer, loop: loop, fileEndCompletionHandler: fileEndCompletionHandler)
}
}
})
Пример кода, на котором запущены все запланированные проигрыватели.
AudioEnginePlayer.sharedInstance.audioQueue.async {
if !self.isPlaying {
self.volume = 1.0
self.audioFile.framePosition = frameCount.startingFrame
self.prepare(withFrameCount: frameCount.frameCount)
self.play(at: AudioEnginePlayer.sharedInstance.loopMsLastStartRenderTime) //Calculated lastRenderTime
}
self.scheduleSegment(self.audioFile, startingFrame: frameCount.startingFrame, frameCount: frameCount.frameCount, at: nil) {
//WARNING: COMPLETION HANDLER RUNNING EARLY THEN FILE IS COMPLETED
if self.isStopPressed == false { //Run fileEndCompletion only when player seek to end.
fileEndCompletionHandler()
if loop {
self.playAudioFile(loop: loop, startTime: 0, fileEndCompletionHandler: fileEndCompletionHandler)
}
}
}
}