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:
Krzysztof Moch 2024-01-04 14:14:51 +01:00 committed by GitHub
parent 51828f350f
commit 481cc71eda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 19 deletions

View File

@ -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)
} }
} }

View File

@ -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