Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Craig Martin
2023-07-27 16:24:11 -04:00
18 changed files with 212 additions and 111 deletions

View File

@@ -6,6 +6,8 @@ struct VideoSource {
let isAsset: Bool
let shouldCache: Bool
let requestHeaders: Dictionary<String,Any>?
let startTime: Int64?
let endTime: Int64?
let json: NSDictionary?
@@ -18,6 +20,8 @@ struct VideoSource {
self.isAsset = false
self.shouldCache = false
self.requestHeaders = nil
self.startTime = nil
self.endTime = nil
return
}
self.json = json
@@ -27,5 +31,7 @@ struct VideoSource {
self.isAsset = json["isAsset"] as? Bool ?? false
self.shouldCache = json["shouldCache"] as? Bool ?? false
self.requestHeaders = json["requestHeaders"] as? Dictionary<String,Any>
self.startTime = json["startTime"] as? Int64
self.endTime = json["endTime"] as? Int64
}
}

View File

@@ -4,7 +4,7 @@ import GoogleInteractiveMediaAds
class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
private var _video:RCTVideo
private weak var _video: RCTVideo?
/* Entry point for the SDK. Used to make ad requests. */
private var adsLoader: IMAAdsLoader!
@@ -23,6 +23,7 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
}
func requestAds() {
guard let _video = _video else {return}
// Create ad display container for ad rendering.
let adDisplayContainer = IMAAdDisplayContainer(adContainer: _video, viewController: _video.reactViewController())
@@ -54,6 +55,7 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
// MARK: - IMAAdsLoaderDelegate
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
guard let _video = _video else {return}
// Grab the instance of the IMAAdsManager and set yourself as the delegate.
adsManager = adsLoadedData.adsManager
adsManager?.delegate = self
@@ -71,12 +73,17 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
print("Error loading ads: " + adErrorData.adError.message!)
}
_video.setPaused(false)
_video?.setPaused(false)
}
// MARK: - IMAAdsManagerDelegate
func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
guard let _video = _video else {return}
// Mute ad if the main player is muted
if (_video.isMuted()) {
adsManager.volume = 0;
}
// Play each ad once it has been loaded
if event.type == IMAAdEventType.LOADED {
adsManager.start()
@@ -98,19 +105,19 @@ class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
}
// Fall back to playing content
_video.setPaused(false)
_video?.setPaused(false)
}
func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) {
// Pause the content for the SDK to play ads.
_video.setPaused(true)
_video.setAdPlaying(true)
_video?.setPaused(true)
_video?.setAdPlaying(true)
}
func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
// Resume the content since the SDK is done playing ads (at least for now).
_video.setAdPlaying(false)
_video.setPaused(false)
_video?.setAdPlaying(false)
_video?.setPaused(false)
}
// MARK: - Helpers

View File

@@ -25,7 +25,7 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc {
class RCTPlayerObserver: NSObject {
var _handlers: RCTPlayerObserverHandler!
weak var _handlers: RCTPlayerObserverHandler?
var player:AVPlayer? {
willSet {
@@ -84,11 +84,13 @@ class RCTPlayerObserver: NSObject {
private var _playerViewControllerOverlayFrameObserver:NSKeyValueObservation?
deinit {
NotificationCenter.default.removeObserver(_handlers)
if let _handlers = _handlers {
NotificationCenter.default.removeObserver(_handlers)
}
}
func addPlayerObservers() {
guard let player = player else {
guard let player = player, let _handlers = _handlers else {
return
}
@@ -102,7 +104,7 @@ class RCTPlayerObserver: NSObject {
}
func addPlayerItemObservers() {
guard let playerItem = playerItem else { return }
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)
@@ -118,7 +120,7 @@ class RCTPlayerObserver: NSObject {
}
func addPlayerViewControllerObservers() {
guard let playerViewController = playerViewController else { return }
guard let playerViewController = playerViewController, let _handlers = _handlers else { return }
_playerViewControllerReadyForDisplayObserver = playerViewController.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay)
@@ -131,6 +133,7 @@ class RCTPlayerObserver: NSObject {
}
func addPlayerLayerObserver() {
guard let _handlers = _handlers else {return}
_playerLayerReadyForDisplayObserver = playerLayer?.observe(\.isReadyForDisplay, options: [.new], changeHandler: _handlers.handleReadyForDisplay)
}
@@ -139,6 +142,7 @@ class RCTPlayerObserver: NSObject {
}
func addPlayerTimeObserver() {
guard let _handlers = _handlers else {return}
removePlayerTimeObserver()
let progressUpdateIntervalMS:Float64 = _progressUpdateInterval / 1000
// @see endScrubbing in AVPlayerDemoPlaybackViewController.m
@@ -174,6 +178,7 @@ class RCTPlayerObserver: NSObject {
}
func attachPlayerEventListeners() {
guard let _handlers = _handlers else {return}
NotificationCenter.default.removeObserver(_handlers,
name:NSNotification.Name.AVPlayerItemDidPlayToEndTime,
@@ -202,6 +207,8 @@ class RCTPlayerObserver: NSObject {
func clearPlayer() {
player = nil
playerItem = nil
NotificationCenter.default.removeObserver(_handlers)
if let _handlers = _handlers {
NotificationCenter.default.removeObserver(_handlers)
}
}
}

View File

@@ -192,36 +192,51 @@ enum RCTPlayerOperations {
}
static func configureAudio(ignoreSilentSwitch:String, mixWithOthers:String) {
let session:AVAudioSession! = AVAudioSession.sharedInstance()
let audioSession:AVAudioSession! = AVAudioSession.sharedInstance()
var category:AVAudioSession.Category? = nil
var options:AVAudioSession.CategoryOptions? = nil
if (ignoreSilentSwitch == "ignore") {
category = AVAudioSession.Category.playAndRecord
} else if (ignoreSilentSwitch == "obey") {
category = AVAudioSession.Category.ambient
}
if (mixWithOthers == "mix") {
options = .mixWithOthers
} else if (mixWithOthers == "duck") {
options = .duckOthers
}
if let category = category, let options = options {
do {
try session.setCategory(category, options: options)
try audioSession.setCategory(category, options: options)
} catch {
debugPrint("[RCTPlayerOperations] Problem setting up AVAudioSession category and options. Error: \(error).")
// Handle specific set category and option combination error
// setCategory:AVAudioSessionCategoryPlayback withOptions:mixWithOthers || duckOthers
// Failed to set category, error: 'what' Error Domain=NSOSStatusErrorDomain
// https://developer.apple.com/forums/thread/714598
if #available(iOS 16.0, *) {
do {
debugPrint("[RCTPlayerOperations] Reseting AVAudioSession category to playAndRecord with defaultToSpeaker options.")
try audioSession.setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
} catch {
debugPrint("[RCTPlayerOperations] Reseting AVAudioSession category and options problem. Error: \(error).")
}
}
}
} else if let category = category, options == nil {
do {
try session.setCategory(category)
try audioSession.setCategory(category)
} catch {
debugPrint("[RCTPlayerOperations] Problem setting up AVAudioSession category. Error: \(error).")
}
} else if category == nil, let options = options {
do {
try session.setCategory(session.category, options: options)
try audioSession.setCategory(audioSession.category, options: options)
} catch {
debugPrint("[RCTPlayerOperations] Problem setting up AVAudioSession options. Error: \(error).")
}
}
}

View File

@@ -12,13 +12,17 @@ enum RCTVideoUtils {
*
* \returns The playable duration of the current player item in seconds.
*/
static func calculatePlayableDuration(_ player:AVPlayer?) -> NSNumber {
static func calculatePlayableDuration(_ player:AVPlayer?, withSource source:VideoSource?) -> NSNumber {
guard let player = player,
let video:AVPlayerItem = player.currentItem,
video.status == AVPlayerItem.Status.readyToPlay else {
return 0
}
if (source?.startTime != nil && source?.endTime != nil) {
return NSNumber(value: (Float64(source?.endTime ?? 0) - Float64(source?.startTime ?? 0)) / 1000)
}
var effectiveTimeRange:CMTimeRange?
for (_, value) in video.loadedTimeRanges.enumerated() {
let timeRange:CMTimeRange = value.timeRangeValue
@@ -31,6 +35,10 @@ enum RCTVideoUtils {
if let effectiveTimeRange = effectiveTimeRange {
let playableDuration:Float64 = CMTimeGetSeconds(CMTimeRangeGetEnd(effectiveTimeRange))
if playableDuration > 0 {
if (source?.startTime != nil) {
return NSNumber(value: (playableDuration - Float64(source?.startTime ?? 0) / 1000))
}
return playableDuration as NSNumber
}
}

View File

@@ -1,5 +1,6 @@
#import <React/RCTViewManager.h>
#import "RCTVideoSwiftLog.h"
#import "RCTEventDispatcher.h"
#if __has_include(<react-native-video/RCTVideoCache.h>)
#import "RCTVideoCache.h"

View File

@@ -60,6 +60,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
private var _fullscreenAutorotate:Bool = true
private var _fullscreenOrientation:String! = "all"
private var _fullscreenPlayerPresented:Bool = false
private var _fullscreenUncontrolPlayerPresented:Bool = false // to call events switching full screen mode from player controls
private var _filterName:String!
private var _filterEnabled:Bool = false
private var _presentingViewController:UIViewController?
@@ -214,7 +215,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
return
}
let currentTime = _player?.currentTime()
var currentTime = _player?.currentTime()
if (currentTime != nil && _source?.startTime != nil) {
currentTime = CMTimeSubtract(currentTime!, CMTimeMake(value: _source?.startTime ?? 0, timescale: 1000))
}
let currentPlaybackTime = _player?.currentItem?.currentDate()
let duration = CMTimeGetSeconds(playerDuration)
let currentTimeSecs = CMTimeGetSeconds(currentTime ?? .zero)
@@ -232,7 +236,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
#endif
onVideoProgress?([
"currentTime": NSNumber(value: Float(currentTimeSecs)),
"playableDuration": RCTVideoUtils.calculatePlayableDuration(_player),
"playableDuration": RCTVideoUtils.calculatePlayableDuration(_player, withSource: _source),
"atValue": NSNumber(value: currentTime?.value ?? .zero),
"currentPlaybackTime": NSNumber(value: NSNumber(value: floor(currentPlaybackTime?.timeIntervalSince1970 ?? 0 * 1000)).int64Value),
"target": reactTag,
@@ -244,7 +248,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
// MARK: - Player and source
@objc
func setSrc(_ source:NSDictionary!) {
DispatchQueue.global(qos: .default).async {
DispatchQueue.global(qos: .default).async { [weak self] in
guard let self = self else {return}
self._source = VideoSource(source)
if (self._source?.uri == nil || self._source?.uri == "") {
self._player?.replaceCurrentItem(with: nil)
@@ -301,6 +306,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
self._playerItem = playerItem
self._playerObserver.playerItem = self._playerItem
self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration)
self.setPlaybackRange(playerItem, withVideoStart: self._source?.startTime, withVideoEnd: self._source?.endTime)
self.setFilter(self._filterName)
if let maxBitRate = self._maxBitRate {
self._playerItem?.preferredPeakBitRate = Double(maxBitRate)
@@ -462,15 +468,6 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
_paused = paused
}
@objc
func setCurrentTime(_ currentTime:Float) {
let info:NSDictionary = [
"time": NSNumber(value: currentTime),
"tolerance": NSNumber(value: 100)
]
setSeek(info)
}
@objc
func setSeek(_ info:NSDictionary!) {
let seekTime:NSNumber! = info["time"] as! NSNumber
@@ -510,6 +507,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
applyModifiers()
}
@objc
func isMuted() -> Bool {
return _muted
}
@objc
func setMuted(_ muted:Bool) {
_muted = muted
@@ -561,6 +563,18 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
// Fallback on earlier versions
}
}
func setPlaybackRange(_ item:AVPlayerItem!, withVideoStart videoStart:Int64?, withVideoEnd videoEnd:Int64?) {
if (videoStart != nil) {
let start = CMTimeMake(value: videoStart!, timescale: 1000)
item.reversePlaybackEndTime = start
_pendingSeekTime = Float(CMTimeGetSeconds(start))
_pendingSeek = true
}
if (videoEnd != nil) {
item.forwardPlaybackEndTime = CMTimeMake(value: videoEnd!, timescale: 1000)
}
}
func applyModifiers() {
@@ -666,7 +680,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
self.onVideoFullscreenPlayerWillPresent?(["target": reactTag as Any])
if let playerViewController = _playerViewController {
viewController.present(playerViewController, animated:true, completion:{
if(_controls) {
// prevents crash https://github.com/react-native-video/react-native-video/issues/3040
self._playerViewController?.removeFromParent()
}
viewController.present(playerViewController, animated:true, completion:{ [weak self] in
guard let self = self else {return}
self._playerViewController?.showsPlaybackControls = self._controls
self._fullscreenPlayerPresented = fullscreen
self._playerViewController?.autorotate = self._fullscreenAutorotate
@@ -678,8 +698,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
}
} else if !fullscreen && _fullscreenPlayerPresented, let _playerViewController = _playerViewController {
self.videoPlayerViewControllerWillDismiss(playerViewController: _playerViewController)
_presentingViewController?.dismiss(animated: true, completion:{
self.videoPlayerViewControllerDidDismiss(playerViewController: _playerViewController)
_presentingViewController?.dismiss(animated: true, completion:{[weak self] in
self?.videoPlayerViewControllerDidDismiss(playerViewController: _playerViewController)
})
}
}
@@ -1025,7 +1045,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
}
if _pendingSeek {
setCurrentTime(_pendingSeekTime)
setSeek([
"time": NSNumber(value: _pendingSeekTime),
"tolerance": NSNumber(value: 100)
])
_pendingSeek = false
}
@@ -1104,12 +1127,27 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
let oldRect = change.oldValue
let newRect = change.newValue
if !oldRect!.equalTo(newRect!) {
// https://github.com/react-native-video/react-native-video/issues/3085#issuecomment-1557293391
if newRect!.equalTo(UIScreen.main.bounds) {
RCTLog("in fullscreen")
if (!_fullscreenUncontrolPlayerPresented) {
_fullscreenUncontrolPlayerPresented = true;
self.reactViewController().view.frame = UIScreen.main.bounds
self.reactViewController().view.setNeedsLayout()
} else {NSLog("not fullscreen")}
self.onVideoFullscreenPlayerWillPresent?(["target": self.reactTag as Any])
self.onVideoFullscreenPlayerDidPresent?(["target": self.reactTag as Any])
}
} else {
NSLog("not fullscreen")
if (_fullscreenUncontrolPlayerPresented) {
_fullscreenUncontrolPlayerPresented = false;
self.onVideoFullscreenPlayerWillDismiss?(["target": self.reactTag as Any])
self.onVideoFullscreenPlayerDidDismiss?(["target": self.reactTag as Any])
}
}
self.reactViewController().view.frame = UIScreen.main.bounds
self.reactViewController().view.setNeedsLayout()
}
}

View File

@@ -28,7 +28,6 @@ RCT_EXPORT_VIEW_PROPERTY(ignoreSilentSwitch, NSString);
RCT_EXPORT_VIEW_PROPERTY(mixWithOthers, NSString);
RCT_EXPORT_VIEW_PROPERTY(rate, float);
RCT_EXPORT_VIEW_PROPERTY(seek, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
RCT_EXPORT_VIEW_PROPERTY(fullscreenAutorotate, BOOL);
RCT_EXPORT_VIEW_PROPERTY(fullscreenOrientation, NSString);

View File

@@ -2,7 +2,7 @@ import AVKit
class RCTVideoPlayerViewController: AVPlayerViewController {
var rctDelegate:RCTVideoPlayerViewControllerDelegate!
weak var rctDelegate: RCTVideoPlayerViewControllerDelegate?
// Optional paramters
var preferredOrientation:String?
@@ -19,11 +19,9 @@ class RCTVideoPlayerViewController: AVPlayerViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if rctDelegate != nil {
rctDelegate.videoPlayerViewControllerWillDismiss(playerViewController: self)
rctDelegate.videoPlayerViewControllerDidDismiss(playerViewController: self)
}
rctDelegate?.videoPlayerViewControllerWillDismiss(playerViewController: self)
rctDelegate?.videoPlayerViewControllerDidDismiss(playerViewController: self)
}
#if !TARGET_OS_TV