feat(ios): update timed metadata handler (#3449)
* feat(ios): update timedmetadata handler * chore: move metadata output delegate to main queue * code clean * apply code review nit
This commit is contained in:
		| @@ -17,7 +17,7 @@ protocol RCTPlayerObserverHandlerObjc { | |||||||
| protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc { | protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc { | ||||||
|     func handleTimeUpdate(time: CMTime) |     func handleTimeUpdate(time: CMTime) | ||||||
|     func handleReadyForDisplay(changeObject: Any, change: NSKeyValueObservedChange<Bool>) |     func handleReadyForDisplay(changeObject: Any, change: NSKeyValueObservedChange<Bool>) | ||||||
|     func handleTimeMetadataChange(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<[AVMetadataItem]?>) |     func handleTimeMetadataChange(timedMetadata: [AVMetadataItem]) | ||||||
|     func handlePlayerItemStatusChange(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<AVPlayerItem.Status>) |     func handlePlayerItemStatusChange(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<AVPlayerItem.Status>) | ||||||
|     func handlePlaybackBufferKeyEmpty(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<Bool>) |     func handlePlaybackBufferKeyEmpty(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<Bool>) | ||||||
|     func handlePlaybackLikelyToKeepUp(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<Bool>) |     func handlePlaybackLikelyToKeepUp(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<Bool>) | ||||||
| @@ -29,7 +29,7 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc { | |||||||
|  |  | ||||||
| // MARK: - RCTPlayerObserver | // MARK: - RCTPlayerObserver | ||||||
|  |  | ||||||
| class RCTPlayerObserver: NSObject { | class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate { | ||||||
|     weak var _handlers: RCTPlayerObserverHandler? |     weak var _handlers: RCTPlayerObserverHandler? | ||||||
|  |  | ||||||
|     var player: AVPlayer? { |     var player: AVPlayer? { | ||||||
| @@ -50,9 +50,14 @@ class RCTPlayerObserver: NSObject { | |||||||
|             removePlayerItemObservers() |             removePlayerItemObservers() | ||||||
|         } |         } | ||||||
|         didSet { |         didSet { | ||||||
|             if playerItem != nil { |             guard let playerItem else { return } | ||||||
|  |  | ||||||
|             addPlayerItemObservers() |             addPlayerItemObservers() | ||||||
|             } |  | ||||||
|  |             // handle timedMetadata | ||||||
|  |             let metadataOutput = AVPlayerItemMetadataOutput() | ||||||
|  |             playerItem.add(metadataOutput) | ||||||
|  |             metadataOutput.setDelegate(self, queue: .main) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -98,8 +103,16 @@ class RCTPlayerObserver: NSObject { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     func metadataOutput(_: AVPlayerItemMetadataOutput, didOutputTimedMetadataGroups groups: [AVTimedMetadataGroup], from _: AVPlayerItemTrack?) { | ||||||
|  |         guard let _handlers else { return } | ||||||
|  |  | ||||||
|  |         for metadataGroup in groups { | ||||||
|  |             _handlers.handleTimeMetadataChange(timedMetadata: metadataGroup.items) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     func addPlayerObservers() { |     func addPlayerObservers() { | ||||||
|         guard let player = player, let _handlers = _handlers else { |         guard let player, let _handlers else { | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -114,7 +127,7 @@ class RCTPlayerObserver: NSObject { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     func addPlayerItemObservers() { |     func addPlayerItemObservers() { | ||||||
|         guard let playerItem = playerItem, let _handlers = _handlers else { return } |         guard let playerItem, let _handlers else { return } | ||||||
|         _playerItemStatusObserver = playerItem.observe(\.status, options: [.new, .old], changeHandler: _handlers.handlePlayerItemStatusChange) |         _playerItemStatusObserver = playerItem.observe(\.status, options: [.new, .old], changeHandler: _handlers.handlePlayerItemStatusChange) | ||||||
|         _playerPlaybackBufferEmptyObserver = playerItem.observe( |         _playerPlaybackBufferEmptyObserver = playerItem.observe( | ||||||
|             \.isPlaybackBufferEmpty, |             \.isPlaybackBufferEmpty, | ||||||
| @@ -126,7 +139,6 @@ class RCTPlayerObserver: NSObject { | |||||||
|             options: [.new, .old], |             options: [.new, .old], | ||||||
|             changeHandler: _handlers.handlePlaybackLikelyToKeepUp |             changeHandler: _handlers.handlePlaybackLikelyToKeepUp | ||||||
|         ) |         ) | ||||||
|         _playerTimedMetadataObserver = playerItem.observe(\.timedMetadata, options: [.new], changeHandler: _handlers.handleTimeMetadataChange) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     func removePlayerItemObservers() { |     func removePlayerItemObservers() { | ||||||
| @@ -137,7 +149,7 @@ class RCTPlayerObserver: NSObject { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     func addPlayerViewControllerObservers() { |     func addPlayerViewControllerObservers() { | ||||||
|         guard let playerViewController = playerViewController, let _handlers = _handlers else { return } |         guard let playerViewController, let _handlers else { return } | ||||||
|  |  | ||||||
|         _playerViewControllerReadyForDisplayObserver = playerViewController.observe( |         _playerViewControllerReadyForDisplayObserver = playerViewController.observe( | ||||||
|             \.isReadyForDisplay, |             \.isReadyForDisplay, | ||||||
| @@ -158,7 +170,7 @@ class RCTPlayerObserver: NSObject { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     func addPlayerLayerObserver() { |     func addPlayerLayerObserver() { | ||||||
|         guard let _handlers = _handlers else { return } |         guard let _handlers else { return } | ||||||
|         _playerLayerReadyForDisplayObserver = playerLayer?.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay) |         _playerLayerReadyForDisplayObserver = playerLayer?.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -167,7 +179,7 @@ class RCTPlayerObserver: NSObject { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     func addPlayerTimeObserver() { |     func addPlayerTimeObserver() { | ||||||
|         guard let _handlers = _handlers else { return } |         guard let _handlers else { return } | ||||||
|         removePlayerTimeObserver() |         removePlayerTimeObserver() | ||||||
|         let progressUpdateIntervalMS: Float64 = _progressUpdateInterval / 1000 |         let progressUpdateIntervalMS: Float64 = _progressUpdateInterval / 1000 | ||||||
|         // @see endScrubbing in AVPlayerDemoPlaybackViewController.m |         // @see endScrubbing in AVPlayerDemoPlaybackViewController.m | ||||||
| @@ -203,7 +215,7 @@ class RCTPlayerObserver: NSObject { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     func attachPlayerEventListeners() { |     func attachPlayerEventListeners() { | ||||||
|         guard let _handlers = _handlers else { return } |         guard let _handlers else { return } | ||||||
|         NotificationCenter.default.removeObserver(_handlers, |         NotificationCenter.default.removeObserver(_handlers, | ||||||
|                                                   name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, |                                                   name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, | ||||||
|                                                   object: player?.currentItem) |                                                   object: player?.currentItem) | ||||||
| @@ -242,7 +254,7 @@ class RCTPlayerObserver: NSObject { | |||||||
|     func clearPlayer() { |     func clearPlayer() { | ||||||
|         player = nil |         player = nil | ||||||
|         playerItem = nil |         playerItem = nil | ||||||
|         if let _handlers = _handlers { |         if let _handlers { | ||||||
|             NotificationCenter.default.removeObserver(_handlers) |             NotificationCenter.default.removeObserver(_handlers) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1114,13 +1114,9 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // When timeMetadata is read the event onTimedMetadata is triggered |     // When timeMetadata is read the event onTimedMetadata is triggered | ||||||
|     func handleTimeMetadataChange(playerItem _: AVPlayerItem, change: NSKeyValueObservedChange<[AVMetadataItem]?>) { |     func handleTimeMetadataChange(timedMetadata: [AVMetadataItem]) { | ||||||
|         guard let newValue = change.newValue, let _items = newValue, !_items.isEmpty else { |  | ||||||
|             return |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         var metadata: [[String: String?]?] = [] |         var metadata: [[String: String?]?] = [] | ||||||
|         for item in _items { |         for item in timedMetadata { | ||||||
|             let value = item.value as? String |             let value = item.value as? String | ||||||
|             let identifier = item.identifier?.rawValue |             let identifier = item.identifier?.rawValue | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user