fix: fix the kvo compliance crash when rapidly switching source

This commit is contained in:
wood1986 2022-12-17 13:33:49 -08:00
parent a2cdf0f656
commit 1f27ffbc81

View File

@ -233,102 +233,92 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
} }
// MARK: - Player and source // MARK: - Player and source
@objc @objc
func setSrc(_ source:NSDictionary!) { func setSrc(_ source:NSDictionary!) {
_source = VideoSource(source) DispatchQueue.global(qos: .default).async {
if (_source?.uri == nil || _source?.uri == "") { _source = VideoSource(source)
DispatchQueue.global(qos: .default).async { if (_source?.uri == nil || _source?.uri == "") {
self._player?.replaceCurrentItem(with: nil) self._player?.replaceCurrentItem(with: nil)
return;
} }
return; removePlayerLayer()
} _playerObserver.player = nil
removePlayerLayer() _playerObserver.playerItem = nil
_playerObserver.player = nil
_playerObserver.playerItem = nil
// perform on next run loop, otherwise other passed react-props may not be set // perform on next run loop, otherwise other passed react-props may not be set
RCTVideoUtils.delay() RCTVideoUtils.delay()
.then{ [weak self] in .then{ [weak self] in
guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)} guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)}
guard let source = self._source else { guard let source = self._source else {
DebugLog("The source not exist") DebugLog("The source not exist")
throw NSError(domain: "", code: 0, userInfo: nil) throw NSError(domain: "", code: 0, userInfo: nil)
} }
if let uri = source.uri, uri.starts(with: "ph://") { if let uri = source.uri, uri.starts(with: "ph://") {
return Promise { return Promise {
RCTVideoUtils.preparePHAsset(uri: uri).then { asset in RCTVideoUtils.preparePHAsset(uri: uri).then { asset in
return self.playerItemPrepareText(asset:asset, assetOptions:nil) return self.playerItemPrepareText(asset:asset, assetOptions:nil)
}
} }
} }
} guard let assetResult = RCTVideoUtils.prepareAsset(source: source),
guard let assetResult = RCTVideoUtils.prepareAsset(source: source), let asset = assetResult.asset,
let asset = assetResult.asset, let assetOptions = assetResult.assetOptions else {
let assetOptions = assetResult.assetOptions else { DebugLog("Could not find video URL in source '\(self._source)'")
DebugLog("Could not find video URL in source '\(self._source)'") throw NSError(domain: "", code: 0, userInfo: nil)
throw NSError(domain: "", code: 0, userInfo: nil) }
}
#if canImport(RCTVideoCache) #if canImport(RCTVideoCache)
if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) { if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) {
return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions) return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions)
} }
#endif #endif
if self._drm != nil || self._localSourceEncryptionKeyScheme != nil { if self._drm != nil || self._localSourceEncryptionKeyScheme != nil {
self._resouceLoaderDelegate = RCTResourceLoaderDelegate( self._resouceLoaderDelegate = RCTResourceLoaderDelegate(
asset: asset, asset: asset,
drm: self._drm, drm: self._drm,
localSourceEncryptionKeyScheme: self._localSourceEncryptionKeyScheme, localSourceEncryptionKeyScheme: self._localSourceEncryptionKeyScheme,
onVideoError: self.onVideoError, onVideoError: self.onVideoError,
onGetLicense: self.onGetLicense, onGetLicense: self.onGetLicense,
reactTag: self.reactTag reactTag: self.reactTag
) )
} }
return Promise{self.playerItemPrepareText(asset: asset, assetOptions:assetOptions)} return Promise{self.playerItemPrepareText(asset: asset, assetOptions:assetOptions)}
}.then{[weak self] (playerItem:AVPlayerItem!) in }.then{[weak self] (playerItem:AVPlayerItem!) in
guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)} guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)}
self._player?.pause() self._player?.pause()
self._playerItem = playerItem self._playerItem = playerItem
self._playerObserver.playerItem = self._playerItem self._playerObserver.playerItem = self._playerItem
self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration) self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration)
self.setFilter(self._filterName) self.setFilter(self._filterName)
if let maxBitRate = self._maxBitRate { if let maxBitRate = self._maxBitRate {
self._playerItem?.preferredPeakBitRate = Double(maxBitRate) self._playerItem?.preferredPeakBitRate = Double(maxBitRate)
} }
self._player = self._player ?? AVPlayer() self._player = self._player ?? AVPlayer()
DispatchQueue.global(qos: .default).async { self._player.replaceCurrentItem(with: playerItem)
self._player?.replaceCurrentItem(with: playerItem) self._playerObserver.player = self._player
} self.applyModifiers()
self._playerObserver.player = self._player self._player?.actionAtItemEnd = .none
self.applyModifiers()
self._player?.actionAtItemEnd = .none
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
self.setAutomaticallyWaitsToMinimizeStalling(self._automaticallyWaitsToMinimizeStalling) self.setAutomaticallyWaitsToMinimizeStalling(self._automaticallyWaitsToMinimizeStalling)
} }
if self._adTagUrl != nil { //Perform on next run loop, otherwise onVideoLoadStart is nil
// Set up your content playhead and contentComplete callback. self.onVideoLoadStart?([
self._contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: self._player!) "src": [
"uri": self._source?.uri ?? NSNull(),
self._imaAdsManager.setUpAdsLoader() "type": self._source?.type ?? NSNull(),
} "isNetwork": NSNumber(value: self._source?.isNetwork ?? false)
],
//Perform on next run loop, otherwise onVideoLoadStart is nil "drm": self._drm?.json ?? NSNull(),
self.onVideoLoadStart?([ "target": self.reactTag
"src": [ ])
"uri": self._source?.uri ?? NSNull(), }.catch{_ in }
"type": self._source?.type ?? NSNull(), _videoLoadStarted = true
"isNetwork": NSNumber(value: self._source?.isNetwork ?? false) }
],
"drm": self._drm?.json ?? NSNull(),
"target": self.reactTag
])
}.catch{_ in }
_videoLoadStarted = true
} }
@objc @objc