diff --git a/ios/App/Shared/player/AudioPlayer.swift b/ios/App/Shared/player/AudioPlayer.swift index 3ffe4259..bc69f9fb 100644 --- a/ios/App/Shared/player/AudioPlayer.swift +++ b/ios/App/Shared/player/AudioPlayer.swift @@ -63,15 +63,22 @@ class AudioPlayer: NSObject { initAudioSession() setupRemoteTransportControls() - let playbackSession = Database.shared.getPlaybackSession(id: self.sessionId)! + let playbackSession = self.getPlaybackSession() + guard let playbackSession = playbackSession else { + NSLog("Failed to fetch playback session. Player will not initialize") + NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.failed.rawValue), object: nil) + return + } // Listen to player events self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.rate), options: .new, context: &playerContext) self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem), options: .new, context: &playerContext) for track in playbackSession.audioTracks { - let playerItem = AVPlayerItem(asset: createAsset(itemId: playbackSession.libraryItemId!, track: track)) - self.allPlayerItems.append(playerItem) + if let playerAsset = createAsset(itemId: playbackSession.libraryItemId!, track: track) { + let playerItem = AVPlayerItem(asset: playerAsset) + self.allPlayerItems.append(playerItem) + } } self.currentTrackIndex = getItemIndexForTime(time: playbackSession.currentTime) @@ -118,12 +125,16 @@ class AudioPlayer: NSObject { NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.closed.rawValue), object: nil) } - func isInitialized() -> Bool { + public func isInitialized() -> Bool { return self.status != -1 } - func getItemIndexForTime(time:Double) -> Int { - let playbackSession = Database.shared.getPlaybackSession(id: self.sessionId)! + public func getPlaybackSession() -> PlaybackSession? { + return Database.shared.getPlaybackSession(id: self.sessionId) + } + + private func getItemIndexForTime(time:Double) -> Int { + guard let playbackSession = self.getPlaybackSession() else { return 0 } for index in 0.. currentTime { self.setSleepTime(stopAt: newSleepTimerPosition, scaleBasedOnSpeed: true) @@ -464,8 +492,7 @@ class AudioPlayer: NSObject { } public func decreaseSleepTime(removeTimeInSeconds: Double) { - if let sleepTime = PlayerHandler.remainingSleepTime { - let currentTime = getCurrentTime() + if let sleepTime = PlayerHandler.remainingSleepTime, let currentTime = getCurrentTime() { let newSleepTimerPosition = currentTime + Double(sleepTime) - removeTimeInSeconds guard newSleepTimerPosition > currentTime else { return } if newSleepTimerPosition > currentTime { @@ -486,16 +513,16 @@ class AudioPlayer: NSObject { NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.sleepEnded.rawValue), object: self) } - public func getCurrentTime() -> Double { - let playbackSession = Database.shared.getPlaybackSession(id: self.sessionId)! + public func getCurrentTime() -> Double? { + guard let playbackSession = self.getPlaybackSession() else { return nil } let currentTrackTime = self.audioPlayer.currentTime().seconds let audioTrack = playbackSession.audioTracks[currentTrackIndex] let startOffset = audioTrack.startOffset ?? 0.0 return startOffset + currentTrackTime } - public func getPlayMethod() -> Int { - let playbackSession = Database.shared.getPlaybackSession(id: self.sessionId)! + public func getPlayMethod() -> Int? { + guard let playbackSession = self.getPlaybackSession() else { return nil } return playbackSession.playMethod } @@ -503,8 +530,8 @@ class AudioPlayer: NSObject { return self.sessionId } - public func getDuration() -> Double { - let playbackSession = Database.shared.getPlaybackSession(id: self.sessionId)! + public func getDuration() -> Double? { + guard let playbackSession = self.getPlaybackSession() else { return nil } return playbackSession.duration } @@ -513,8 +540,9 @@ class AudioPlayer: NSObject { } // MARK: - Private - private func createAsset(itemId:String, track:AudioTrack) -> AVAsset { - let playbackSession = Database.shared.getPlaybackSession(id: self.sessionId)! + private func createAsset(itemId:String, track:AudioTrack) -> AVAsset? { + guard let playbackSession = self.getPlaybackSession() else { return nil } + if (playbackSession.playMethod == PlayMethod.directplay.rawValue) { // The only reason this is separate is because the filename needs to be encoded let filename = track.metadata?.filename ?? "" @@ -576,8 +604,10 @@ class AudioPlayer: NSObject { guard let command = event.command as? MPSkipIntervalCommand else { return .noSuchContent } - - seek(getCurrentTime() + command.preferredIntervals[0].doubleValue, from: "remote") + guard let currentTime = self.getCurrentTime() else { + return .commandFailed + } + seek(currentTime + command.preferredIntervals[0].doubleValue, from: "remote") return .success } commandCenter.skipBackwardCommand.isEnabled = true @@ -586,8 +616,10 @@ class AudioPlayer: NSObject { guard let command = event.command as? MPSkipIntervalCommand else { return .noSuchContent } - - seek(getCurrentTime() - command.preferredIntervals[0].doubleValue, from: "remote") + guard let currentTime = self.getCurrentTime() else { + return .commandFailed + } + seek(currentTime - command.preferredIntervals[0].doubleValue, from: "remote") return .success } @@ -614,7 +646,9 @@ class AudioPlayer: NSObject { } private func updateNowPlaying() { NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.update.rawValue), object: nil) - NowPlayingInfo.shared.update(duration: getDuration(), currentTime: getCurrentTime(), rate: rate) + if let duration = self.getDuration(), let currentTime = self.getCurrentTime() { + NowPlayingInfo.shared.update(duration: duration, currentTime: currentTime, rate: rate) + } } // MARK: - Observer diff --git a/ios/App/Shared/player/PlayerHandler.swift b/ios/App/Shared/player/PlayerHandler.swift index c565690d..b2f49587 100644 --- a/ios/App/Shared/player/PlayerHandler.swift +++ b/ios/App/Shared/player/PlayerHandler.swift @@ -62,13 +62,14 @@ class PlayerHandler { public static var remainingSleepTime: Int? { get { guard let player = player else { return nil } + guard let currentTime = player.getCurrentTime() else { return nil } // Return the player time until sleep var timeUntilSleep: Double? = nil if let sleepTimerChapterStopTime = sleepTimerChapterStopTime { - timeUntilSleep = Double(sleepTimerChapterStopTime) - player.getCurrentTime() + timeUntilSleep = Double(sleepTimerChapterStopTime) - currentTime } else if let stopAt = player.getSleepStopAt() { - timeUntilSleep = stopAt - player.getCurrentTime() + timeUntilSleep = stopAt - currentTime } // Scale the time until sleep based on the playback rate @@ -96,7 +97,8 @@ class PlayerHandler { public static func setSleepTime(secondsUntilSleep: Double) { guard let player = player else { return } - let stopAt = secondsUntilSleep + player.getCurrentTime() + guard let currentTime = player.getCurrentTime() else { return } + let stopAt = secondsUntilSleep + currentTime player.setSleepTime(stopAt: stopAt, scaleBasedOnSpeed: true) } @@ -134,15 +136,17 @@ class PlayerHandler { public static func seekForward(amount: Double) { guard let player = player else { return } + guard let currentTime = player.getCurrentTime() else { return } - let destinationTime = player.getCurrentTime() + amount + let destinationTime = currentTime + amount player.seek(destinationTime, from: "handler") } public static func seekBackward(amount: Double) { guard let player = player else { return } + guard let currentTime = player.getCurrentTime() else { return } - let destinationTime = player.getCurrentTime() - amount + let destinationTime = currentTime - amount player.seek(destinationTime, from: "handler") }