Skip to content

Commit

Permalink
observing empty buffer to handle replay on network lost
Browse files Browse the repository at this point in the history
  • Loading branch information
NullIsOne committed Jun 24, 2024
1 parent a0d1fc5 commit 0dfbb08
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 1 deletion.
1 change: 1 addition & 0 deletions Sources/KinescopeSDK/Bags/KVO/KVOSubKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation
enum KVOSubKey {
case playerStatus
case playerItem
case playerItemBufferEmpty
case playerItemStatus
case playerTimeControlStatus
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum NotificationSubKey {
case appDidEnterBackground
case deviceOrientationChanged
case itemDidPlayToEnd
case itemFailedToPlayToEndTime

var notificationName: NSNotification.Name {
switch self {
Expand All @@ -26,6 +27,8 @@ enum NotificationSubKey {
return UIDevice.orientationDidChangeNotification
case .itemDidPlayToEnd:
return AVPlayerItem.didPlayToEndTimeNotification
case .itemFailedToPlayToEndTime:
return AVPlayerItem.failedToPlayToEndTimeNotification
}
}

Expand Down
14 changes: 14 additions & 0 deletions Sources/KinescopeSDK/Player/KinescopeVideoPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,19 @@ private extension KinescopeVideoPlayer {
let observerFactory = CurrentItemObserver(playerBody: self, currentItemChanged: {
[weak self] item in
self?.kvoBag.removeObserver(for: .playerItemStatus)
self?.kvoBag.removeObserver(for: .playerItemBufferEmpty)
if let item {
self?.addPlayerItemStatusObserver()
self?.addPlayerItemBufferIsEmptyObserver()
}
})
kvoBag.addObserver(for: .playerItem, using: .init(wrappedFactory: observerFactory))
}

func addPlayerItemBufferIsEmptyObserver() {
let observerFactory = EmptyBufferObserver(playerBody: self, repeater: $playRepeater)
kvoBag.addObserver(for: .playerItemBufferEmpty, using: .init(wrappedFactory: observerFactory))
}

func addPlayerItemStatusObserver() {
let observerFactory = CurrentItemStatusObserver(playerBody: self,
Expand Down Expand Up @@ -368,6 +375,8 @@ private extension KinescopeVideoPlayer {
using: .init(selector: #selector(changeOrientation)))
notificationsBag.addObserver(for: .itemDidPlayToEnd,
using: .init(selector: #selector(itemDidPlayToEnd)))
notificationsBag.addObserver(for: .itemFailedToPlayToEndTime,
using: .init(selector: #selector(itemFailedToPlayeToEndTime)))
}

func configureAnalytic() {
Expand Down Expand Up @@ -435,6 +444,11 @@ private extension KinescopeVideoPlayer {
analytic?.send(event: .end)
}

@objc func itemFailedToPlayeToEndTime(_ notification: Notification) {
let error = notification.userInfo?[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error
Kinescope.shared.logger?.log(error: error, level: KinescopeLoggerLevel.player)
}

func restoreView() {
view?.showOverlay(isOverlayed)
isPlaying ? play() : pause()
Expand Down
41 changes: 41 additions & 0 deletions Sources/KinescopeSDK/Player/Observers/EmptyBufferObserver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// EmptyBufferObserver.swift
// KinescopeSDK
//
// Created by Nikita Korobeinikov on 24.06.2024.
//

import Foundation
import AVFoundation

final class EmptyBufferObserver: KVOObserverFactory {

private weak var playerBody: KinescopePlayerBody?
private weak var repeater: Repeater?

init(playerBody: KinescopePlayerBody,
repeater: Repeater) {
self.repeater = repeater
self.playerBody = playerBody
}

func provide() -> NSKeyValueObservation? {
playerBody?.strategy.player.currentItem?.observe(
\.isPlaybackBufferEmpty,
options: [.new, .old],
changeHandler: { [weak self] item, value in
let isBufferEmpty = value.newValue ?? item.isPlaybackBufferEmpty
if isBufferEmpty {
self?.repeater?.start()
}

Kinescope.shared.logger?.log(
message: "AVPlayer.isPlaybackBufferEmpty – \(isBufferEmpty)",
level: KinescopeLoggerLevel.player
)
}
)
}

}

5 changes: 4 additions & 1 deletion Sources/KinescopeSDK/View/Player/KinescopePlayerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,11 @@ public class KinescopePlayerView: UIView {
overlay?.isHidden = false
overlay?.set(playing: true)
progressView.showVideoProgress(isLoading: false)
case .paused, .waitingToPlayAtSpecifiedRate:
case .paused:
overlay?.set(playing: false)
case .waitingToPlayAtSpecifiedRate:
overlay?.set(playing: false)
progressView.showVideoProgress(isLoading: true)
@unknown default:
break
}
Expand Down

0 comments on commit 0dfbb08

Please sign in to comment.