Advertisement
Guest User

Untitled

a guest
Oct 20th, 2019
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.83 KB | None | 0 0
  1. import AVFoundation
  2.  
  3. private let notificationNames: [Notification.Name] = [.AVPlayerItemTimeJumped,
  4. .AVPlayerItemPlaybackStalled,
  5. .AVPlayerItemDidPlayToEndTime,
  6. .AVPlayerItemFailedToPlayToEndTime]
  7. extension AVPlayer {
  8.  
  9. private struct AssociatedKey {
  10. static var stateHandlerKey: UInt8 = 0
  11. static var currentItem: UInt8 = 0
  12. static var rate: UInt8 = 0
  13. }
  14.  
  15. public enum PlayerNotifications {
  16. case DidStartPlayback
  17. case DidPausePlayback
  18. case DidChangeCurrentItem(item: AVPlayerItem?)
  19. case ItemTimeJumped(item: AVPlayerItem)
  20. case ItemPlaybackStalled(item: AVPlayerItem)
  21. case ItemDidPlayToEndTime(item: AVPlayerItem)
  22. case ItemPlayToEndTimeFailed(item: AVPlayerItem)
  23. }
  24.  
  25. var stateHandler: ((PlayerNotifications) -> ())? {
  26. get {
  27. return objc_getAssociatedObject(self, &AssociatedKey.stateHandlerKey) as? ((PlayerNotifications) -> ())
  28. }
  29. set {
  30. objc_setAssociatedObject(self, &AssociatedKey.stateHandlerKey, newValue, .OBJC_ASSOCIATION_RETAIN)
  31. }
  32. }
  33.  
  34. public convenience init(url URL: URL, _ stateHandler:@escaping (PlayerNotifications)->()) {
  35. self.init(url: URL)
  36. self.stateHandler = stateHandler
  37. setupObservers()
  38. }
  39.  
  40. public convenience init(playerItem item: AVPlayerItem?, _ stateHandler:@escaping (PlayerNotifications)->()) {
  41. self.init(playerItem: item)
  42. self.stateHandler = stateHandler
  43. setupObservers()
  44. }
  45.  
  46. private func setupObservers() {
  47. let notificationCenter = NotificationCenter.default
  48. notificationNames.forEach {
  49. guard stateHandler != nil else {
  50. notificationCenter.removeObserver(self, name: $0, object: nil)
  51. return
  52. }
  53. notificationCenter.addObserver(self,
  54. selector: #selector(handleNotification(_:)),
  55. name: $0,
  56. object: nil)
  57. }
  58. switch stateHandler {
  59. case .some:
  60. currentItemObserver = observe(\.currentItem, options: [.new]) { [weak self] _, change in
  61. guard let item = change.newValue else { return }
  62. self?.stateHandler?(PlayerNotifications.DidChangeCurrentItem(item: item))
  63. }
  64. rateObserver = observe(\.rate, options: [.old, .new]) { [weak self] _, change in
  65. guard let oldRate = change.oldValue else { return }
  66. guard let newRate = change.newValue else { return }
  67. if oldRate != 0 && newRate == 0 {
  68. self?.stateHandler?(PlayerNotifications.DidPausePlayback)
  69. } else if oldRate == 0 && newRate != 0 {
  70. self?.stateHandler?(PlayerNotifications.DidStartPlayback)
  71. }
  72. }
  73. case .none:
  74. currentItemObserver = nil
  75. rateObserver = nil
  76. }
  77. }
  78.  
  79. private var currentItemObserver: NSKeyValueObservation? {
  80. get {
  81. return objc_getAssociatedObject(self, &AssociatedKey.currentItem) as? NSKeyValueObservation
  82. }
  83. set {
  84. currentItemObserver.flatMap { $0.invalidate() }
  85. objc_setAssociatedObject(self, &AssociatedKey.currentItem, newValue, .OBJC_ASSOCIATION_RETAIN)
  86. }
  87. }
  88.  
  89. private var rateObserver: NSKeyValueObservation? {
  90. get {
  91. return objc_getAssociatedObject(self, &AssociatedKey.rate) as? NSKeyValueObservation
  92. }
  93. set {
  94. rateObserver.flatMap { $0.invalidate() }
  95. objc_setAssociatedObject(self, &AssociatedKey.rate, newValue, .OBJC_ASSOCIATION_RETAIN)
  96. }
  97. }
  98.  
  99. @objc private func handleNotification(_ notification: Notification) {
  100. guard let item = notification.object as? AVPlayerItem else { return }
  101. guard item == currentItem else { return }
  102. switch notification.name {
  103. case .AVPlayerItemTimeJumped:
  104. stateHandler?(PlayerNotifications.ItemTimeJumped(item: item))
  105. case .AVPlayerItemPlaybackStalled:
  106. stateHandler?(PlayerNotifications.ItemPlaybackStalled(item: item))
  107. case .AVPlayerItemDidPlayToEndTime:
  108. stateHandler?(PlayerNotifications.ItemDidPlayToEndTime(item: item))
  109. case .AVPlayerItemFailedToPlayToEndTime:
  110. stateHandler?(PlayerNotifications.ItemPlayToEndTimeFailed(item: item))
  111. default:
  112. return
  113. }
  114. }
  115.  
  116. func cleanupObservers() {
  117. notificationNames.forEach { name in
  118. NotificationCenter.default.removeObserver(self, name: name, object: nil)
  119. }
  120. currentItemObserver = nil
  121. rateObserver = nil
  122. }
  123. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement