diff --git a/examples/basic/src/VideoPlayer.tsx b/examples/basic/src/VideoPlayer.tsx index 3fc1f150ce..4b657c1b22 100644 --- a/examples/basic/src/VideoPlayer.tsx +++ b/examples/basic/src/VideoPlayer.tsx @@ -693,6 +693,9 @@ class VideoPlayer extends Component { }); }}> {this.state.audioTracks.map(track => { + if (!track) { + return; + } return ( - {this.state.textTracks.map(track => ( - - ))} + {this.state.textTracks.map(track => { + if (!track) { + return; + } + return ( + + ); + })} )} diff --git a/ios/Video/Features/RCTVideoUtils.swift b/ios/Video/Features/RCTVideoUtils.swift index 9fd6bec82d..9d4e6f66a8 100644 --- a/ios/Video/Features/RCTVideoUtils.swift +++ b/ios/Video/Features/RCTVideoUtils.swift @@ -364,7 +364,7 @@ enum RCTVideoUtils { static func delay(seconds: Int = 0) -> Promise { return Promise(on: .global()) { fulfill, _ in - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(seconds)) / Double(NSEC_PER_SEC)) { + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(seconds)) { fulfill(()) } } diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 7ff053eb56..24e051ae3f 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -300,14 +300,38 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH } } + var isSetSourceOngoing = false + var nextSource: NSDictionary? + + func applyNextSource() { + if self.nextSource != nil { + DebugLog("apply next source") + self.isSetSourceOngoing = false + let nextSrc = self.nextSource + self.nextSource = nil + self.setSrc(nextSrc) + } + } + // MARK: - Player and source @objc func setSrc(_ source: NSDictionary!) { + if self.isSetSourceOngoing || self.nextSource != nil { + DebugLog("setSrc buffer request") + self._player?.replaceCurrentItem(with: nil) + nextSource = source + return + } + self.isSetSourceOngoing = true + let dispatchClosure = { self._source = VideoSource(source) if self._source?.uri == nil || self._source?.uri == "" { self._player?.replaceCurrentItem(with: nil) + self.isSetSourceOngoing = false + self.applyNextSource() + DebugLog("setSrc Stopping playback") return } self.removePlayerLayer() @@ -321,9 +345,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH guard let self else { throw NSError(domain: "", code: 0, userInfo: nil) } guard let source = self._source else { DebugLog("The source not exist") + self.isSetSourceOngoing = false + self.applyNextSource() throw NSError(domain: "", code: 0, userInfo: nil) } if let uri = source.uri, uri.starts(with: "ph://") { + self.isSetSourceOngoing = false + self.applyNextSource() return Promise { RCTVideoUtils.preparePHAsset(uri: uri).then { asset in return self.playerItemPrepareText(asset: asset, assetOptions: nil, uri: source.uri ?? "") @@ -334,6 +362,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH let asset = assetResult.asset, let assetOptions = assetResult.assetOptions else { DebugLog("Could not find video URL in source '\(String(describing: self._source))'") + self.isSetSourceOngoing = false + self.applyNextSource() throw NSError(domain: "", code: 0, userInfo: nil) } @@ -361,7 +391,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH return self.playerItemPrepareText(asset: asset, assetOptions: assetOptions, uri: source.uri ?? "") }.then { [weak self] (playerItem: AVPlayerItem!) in guard let self else { throw NSError(domain: "", code: 0, userInfo: nil) } - + if !self.isSetSourceOngoing { + DebugLog("setSrc has been canceled last step") + return + } self._player?.pause() self._playerItem = playerItem self._playerObserver.playerItem = self._playerItem @@ -402,8 +435,16 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH "drm": self._drm?.json ?? NSNull(), "target": self.reactTag, ]) - }.catch { _ in } + self.isSetSourceOngoing = false + self.applyNextSource() + }.catch { error in + DebugLog("An error occurred: \(error.localizedDescription)") + self.onVideoError?(["error": error.localizedDescription]) + self.isSetSourceOngoing = false + self.applyNextSource() + } self._videoLoadStarted = true + self.applyNextSource() } DispatchQueue.global(qos: .default).async(execute: dispatchClosure) }