diff --git a/Classes/Player/AVPlayerEngine/AVPlayerEngine+Observation.swift b/Classes/Player/AVPlayerEngine/AVPlayerEngine+Observation.swift index 2d26d625..8fb40a78 100644 --- a/Classes/Player/AVPlayerEngine/AVPlayerEngine+Observation.swift +++ b/Classes/Player/AVPlayerEngine/AVPlayerEngine+Observation.swift @@ -205,13 +205,18 @@ extension AVPlayerEngine { @objc func timebaseChanged(notification: Notification) { // For some reason timebase rate changed is received on a background thread. // in order to check self.rate we must make sure we are on the main thread. + DispatchQueue.main.async { guard let timebase = self.currentItem?.timebase else { return } PKLog.verbose("timebase changed, current timebase: \(String(describing: timebase))") let timebaseRate = CMTimebaseGetRate(timebase) if timebaseRate > 0 && self.lastTimebaseRate != timebaseRate { + PKLog.verbose("timebaseChanged->PlayerEvent.Playing") + self.post(event: PlayerEvent.Playing()) } else if timebaseRate == 0 && self.rate == 0 && self.lastTimebaseRate != timebaseRate { + PKLog.verbose("timebaseChanged->PlayerEvent.Pause") + self.post(event: PlayerEvent.Pause()) } // Make sure to save the last value so we could only post events only when currentTimebase != lastTimebase @@ -219,15 +224,34 @@ extension AVPlayerEngine { } } + /* When setting automaticallyWaitsToMinimizeStalling and shouldPlayImmediately, the player may be stalled and the rate will be changed to 0, player paused, by the AVPlayer. Therefor we are sending a paused event. + */ /// Handles changes in player rate private func handleRate() { - PKLog.debug("player rate was changed, now: \(self.rate)") - // When setting automaticallyWaitsToMinimizeStalling and shouldPlayImmediately, the player may be stalled and the rate will be changed to 0, player paused, by the AVPlayer. Therefor we are sending a paused event. + PKLog.verbose("player rate was changed, now: \(self.rate)") + if let isPlaybackLikelyToKeepUp = self.currentItem?.isPlaybackLikelyToKeepUp, isPlaybackLikelyToKeepUp == false { if self.rate == 0, self.currentState == .buffering || self.currentState == .ready { self.post(event: PlayerEvent.Pause()) } } + + // In all other cases, the player manages pause in the timebaseChanged event! + //This is only when the user clicks the pause button on the exteranl TV remote control, and the app needs refreshing UI in sender device. + PKLog.debug("isAppInBackground = \(isAppInBackground)") + if isAppInBackground{ + + let isPaused = self.rate == 0 + PKLog.debug("isPaused = \(isPaused)") + + if isPaused{ + if self.currentState != .idle && self.currentState != .ended && self.currentState != .error { + PKLog.debug("player send pause event!!!") + self.lastTimebaseRate = 0 + self.post(event: PlayerEvent.Pause()) + } + } + } } /// Handle changes in Audio/Video tracks codecs. diff --git a/Classes/Player/AVPlayerEngine/AVPlayerEngine.swift b/Classes/Player/AVPlayerEngine/AVPlayerEngine.swift index 34a941b5..e20a5185 100644 --- a/Classes/Player/AVPlayerEngine/AVPlayerEngine.swift +++ b/Classes/Player/AVPlayerEngine/AVPlayerEngine.swift @@ -55,6 +55,20 @@ public class AVPlayerEngine: AVPlayer { var onEventBlock: ((PKEvent) -> Void)? + var isAppInBackground: Bool{ + switch UIApplication.shared.applicationState { + case .active: + return false + case .inactive: + return true + case .background: + return true + @unknown default: + return false + } + } + + public weak var view: PlayerView? { didSet { view?.player = self @@ -458,8 +472,9 @@ extension AVPlayerEngine: AppStateObservable { }), NotificationObservation(name: UIApplication.didEnterBackgroundNotification, onObserve: { [weak self] in guard let self = self else { return } - + PKLog.debug("player: \(self)\n Did enter background, finishing up...") + self.startBackgroundTask() if self.allowAudioFromVideoAssetInBackground { @@ -470,12 +485,28 @@ extension AVPlayerEngine: AppStateObservable { guard let self = self else { return } PKLog.debug("player: \(self)\n Will enter foreground...") + self.endBackgroundTask() if self.playerLayer?.player == nil { self.playerLayer?.player = self } + }), + + NotificationObservation(name: UIApplication.willResignActiveNotification, onObserve: { + [weak self] in + guard let self = self else { return } + PKLog.debug("player: \(self)\n app is no longer active and loses focus...") + + }), + + NotificationObservation(name: UIApplication.didBecomeActiveNotification, onObserve: { + [weak self] in + guard let self = self else { return } + PKLog.debug("player: \(self)\n app becomes active (fcused)...") + }) + ] } diff --git a/PlayKit.podspec b/PlayKit.podspec index 31e1e455..d947b852 100644 --- a/PlayKit.podspec +++ b/PlayKit.podspec @@ -4,7 +4,7 @@ suffix = '.0000' # Dev mode Pod::Spec.new do |s| s.name = 'PlayKit' -s.version = '3.30.2' + suffix +s.version = '3.30.3' + suffix s.summary = 'PlayKit: Kaltura Mobile Player SDK - iOS' s.homepage = 'https://github.com/kaltura/playkit-ios' s.license = { :type => 'AGPLv3', :text => 'AGPLv3' }