Подтвердить что ты не робот

AVAudioPlayer производит лаг, несмотря на то, что prepareToPlay() в Swift

Воспроизведение очень короткого звука (~ 0,5 с) вызывает икоту (например, отставание) в моей игре IIS SpriteKit, запрограммированной в Swift. В других вопросах я читал, что должен prepareToPlay() звук, который я сделал.

Я даже использовал переменную (soundReady), чтобы проверить, подготовлен ли звук до ее воспроизведения. Я также перерабатываю звук, когда он заканчивается (audioPlayerDidFinishPlaying()). Вот соответствующие части кода:

class GameScene: SKScene, AVAudioPlayerDelegate {

   var splashSound = NSURL()
   var audioPlayer = AVAudioPlayer()
   var soundReady = false

   override func didMoveToView(view: SKView) {
      let path = NSBundle.mainBundle().pathForResource("plopSound", ofType: "m4a")
      splashSound = NSURL(fileURLWithPath: path)
      audioPlayer = AVAudioPlayer(contentsOfURL: splashSound, error: nil)
      audioPlayer.delegate = self
      soundReady = audioPlayer.prepareToPlay()
   }

   func playSound(){
      if(soundReady){
         audioPlayer.play()
         soundReady = false
      }
   }

   func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool){
      //Prepare to play after Sound finished playing
      soundReady = audioPlayer.prepareToPlay()
   }
}

Я понятия не имею, где я ошибся в этом. Я чувствую, что я пробовал все (включая, но не ограничиваясь: только готовить один раз, готовить сразу после игры, не использовать переменную, а просто подготовитьToPlay()).

Дополнительная информация:

  • Звук воспроизводится без задержек.
  • Как быстро звук воспроизводится после последнего финиша, похоже, не влияет на задержку.
4b9b3361

Ответ 1

Я столкнулся с этой проблемой и воспроизвел звук в backgroundQueue.

Это хороший пример: fooobar.com/questions/31332/....

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    audioPlayer.play()
})

Ответ 2

Просто добавив версию Swift 3 от @brilliantairic.

DispatchQueue.global().async {
    audioPlayer.play()
}

Ответ 3

Когда я звонил play несколько раз, это вызывало бы плохой доступ. Я считаю, что игрок освобождается, так как это не безопасно для потоков. Я создал последовательную очередь, чтобы облегчить эту проблему.

class SoundManager {

    static let shared = SoundManager()

    private init() {
        try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try? AVAudioSession.sharedInstance().setActive(true)
    }

    private let serialQueue = DispatchQueue(label: "SoundQueue", qos: .userInitiated)
    private var player: AVAudioPlayer?

    static func play(_ sound: Sound) {
        shared.play(sound)
    }

    func play(_ sound: Sound) {
        guard let url = Bundle.main.url(forResource: sound.fileName, withExtension: "mp3")
            else { return }

        do {
            try serialQueue.sync {
                self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
                DispatchQueue.main.async {
                    self.player?.play()
                }
            }
        } catch let error as NSError {
            print("error: \(error.localizedDescription)")
        }
    }

}