diff --git a/docs/pages/component/events.md b/docs/pages/component/events.md index ffc44937..aa598c4d 100644 --- a/docs/pages/component/events.md +++ b/docs/pages/component/events.md @@ -86,14 +86,27 @@ Payload: Property | Type | Description --- | --- | --- bitrate | number | The estimated bitrate in bits/sec +width | number | The width of the video (android only) +height | number | The height of the video (android only) +trackId | string | The track ID of the video track (android only) -Example: +Example on iOS: ```javascript { bitrate: 1000000 } ``` +Example on Android: +```javascript +{ + bitrate: 1000000 + width: 1920 + height: 1080 + trackId: 'some-track-id' +} +``` + Note: On Android, you must set the [reportBandwidth](#reportbandwidth) prop to enable this event. This is due to the high volume of events generated. Platforms: Android diff --git a/ios/Video/Features/RCTPlayerObserver.swift b/ios/Video/Features/RCTPlayerObserver.swift index b08b187a..d5441409 100644 --- a/ios/Video/Features/RCTPlayerObserver.swift +++ b/ios/Video/Features/RCTPlayerObserver.swift @@ -7,8 +7,7 @@ protocol RCTPlayerObserverHandlerObjc { func handleDidFailToFinishPlaying(notification:NSNotification!) func handlePlaybackStalled(notification:NSNotification!) func handlePlayerItemDidReachEnd(notification:NSNotification!) - // unused -// func handleAVPlayerAccess(notification:NSNotification!) + func handleAVPlayerAccess(notification:NSNotification!) } protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc { @@ -25,7 +24,6 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc { } class RCTPlayerObserver: NSObject { - weak var _handlers: RCTPlayerObserverHandler? var player:AVPlayer? { @@ -108,7 +106,6 @@ class RCTPlayerObserver: NSObject { func addPlayerItemObservers() { guard let playerItem = playerItem, let _handlers = _handlers else { return } - _playerItemStatusObserver = playerItem.observe(\.status, options: [.new, .old], changeHandler: _handlers.handlePlayerItemStatusChange) _playerPlaybackBufferEmptyObserver = playerItem.observe(\.isPlaybackBufferEmpty, options: [.new, .old], changeHandler: _handlers.handlePlaybackBufferKeyEmpty) _playerPlaybackLikelyToKeepUpObserver = playerItem.observe(\.isPlaybackLikelyToKeepUp, options: [.new, .old], changeHandler: _handlers.handlePlaybackLikelyToKeepUp) @@ -121,7 +118,6 @@ class RCTPlayerObserver: NSObject { _playerPlaybackLikelyToKeepUpObserver?.invalidate() _playerTimedMetadataObserver?.invalidate() } - func addPlayerViewControllerObservers() { guard let playerViewController = playerViewController, let _handlers = _handlers else { return } @@ -182,10 +178,10 @@ class RCTPlayerObserver: NSObject { func attachPlayerEventListeners() { guard let _handlers = _handlers else {return} - NotificationCenter.default.removeObserver(_handlers, name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object:player?.currentItem) + NotificationCenter.default.addObserver(_handlers, selector:#selector(RCTPlayerObserverHandler.handlePlayerItemDidReachEnd(notification:)), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, @@ -194,17 +190,27 @@ class RCTPlayerObserver: NSObject { NotificationCenter.default.removeObserver(_handlers, name:NSNotification.Name.AVPlayerItemPlaybackStalled, object:nil) + NotificationCenter.default.addObserver(_handlers, selector:#selector(RCTPlayerObserverHandler.handlePlaybackStalled(notification:)), name:NSNotification.Name.AVPlayerItemPlaybackStalled, object:nil) + NotificationCenter.default.removeObserver(_handlers, name: NSNotification.Name.AVPlayerItemFailedToPlayToEndTime, object:nil) + NotificationCenter.default.addObserver(_handlers, selector:#selector(RCTPlayerObserverHandler.handleDidFailToFinishPlaying(notification:)), name: NSNotification.Name.AVPlayerItemFailedToPlayToEndTime, object:nil) + + NotificationCenter.default.removeObserver(_handlers, name: NSNotification.Name.AVPlayerItemNewAccessLogEntry, object: player?.currentItem) + + NotificationCenter.default.addObserver(_handlers, + selector:#selector(RCTPlayerObserverHandlerObjc.handleAVPlayerAccess(notification:)), + name: NSNotification.Name.AVPlayerItemNewAccessLogEntry, + object: player?.currentItem) } func clearPlayer() { diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index e195cbf4..6779dfae 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -94,7 +94,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH @objc var onVideoBuffer: RCTDirectEventBlock? @objc var onVideoError: RCTDirectEventBlock? @objc var onVideoProgress: RCTDirectEventBlock? - @objc var onBandwidthUpdate: RCTDirectEventBlock? + @objc var onVideoBandwidthUpdate: RCTDirectEventBlock? @objc var onVideoSeek: RCTDirectEventBlock? @objc var onVideoEnd: RCTDirectEventBlock? @objc var onTimedMetadata: RCTDirectEventBlock? @@ -1335,16 +1335,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _playerObserver.removePlayerTimeObserver() } } - - //unused - // @objc func handleAVPlayerAccess(notification:NSNotification!) { - // let accessLog:AVPlayerItemAccessLog! = (notification.object as! AVPlayerItem).accessLog() - // let lastEvent:AVPlayerItemAccessLogEvent! = accessLog.events.last - // - // /* TODO: get this working - // if (self.onBandwidthUpdate) { - // self.onBandwidthUpdate(@{@"bitrate": [NSNumber numberWithFloat:lastEvent.observedBitrate]}); - // } - // */ - // } + + @objc func handleAVPlayerAccess(notification:NSNotification!) { + let accessLog:AVPlayerItemAccessLog! = (notification.object as! AVPlayerItem).accessLog() + let lastEvent:AVPlayerItemAccessLogEvent! = accessLog.events.last + + onVideoBandwidthUpdate?(["bitrate": lastEvent.observedBitrate, "target": reactTag]) + } } diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index 96c9d0f4..291868eb 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -44,7 +44,7 @@ RCT_EXPORT_VIEW_PROPERTY(onVideoLoad, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoBuffer, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoError, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTDirectEventBlock); -RCT_EXPORT_VIEW_PROPERTY(onBandwidthUpdate, RCTDirectEventBlock); +RCT_EXPORT_VIEW_PROPERTY(onVideoBandwidthUpdate, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onTimedMetadata, RCTDirectEventBlock); diff --git a/src/VideoNativeComponent.ts b/src/VideoNativeComponent.ts index 5c98ab41..68c90268 100644 --- a/src/VideoNativeComponent.ts +++ b/src/VideoNativeComponent.ts @@ -150,9 +150,9 @@ export type OnProgressData = Readonly<{ export type OnBandwidthUpdateData = Readonly<{ bitrate: number; - width: number; - height: number; - trackId: number; + width?: number; + height?: number; + trackId?: number; }>; export type OnSeekData = Readonly<{ diff --git a/src/types/events.ts b/src/types/events.ts index 5cb71717..6da4856f 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -131,12 +131,15 @@ export type OnAudioFocusChangedData = Readonly<{ export type OnBufferData = Readonly<{isBuffering: boolean}>; -export type OnBandwidthUpdateData = Readonly<{ - bitrate: number; - width: number; - height: number; - trackId: number; -}>; +export type OnBandwidthUpdateData = Readonly< + | { + bitrate: number; + width: number; + height: number; + trackId: number; + } + | {bitrate: number} +>; export interface ReactVideoEvents { onAudioBecomingNoisy?: () => void; //Android, iOS