Fix(ios): fix real time issue when fast zapping (#3582)
* fix(ios): fix real time issue when doing fast zapping * fix(ios): fix delay implementation (timing was not applied correctly) * chore: fix random crash in sample * chore: fix linter
This commit is contained in:
		@@ -693,6 +693,9 @@ class VideoPlayer extends Component {
 | 
			
		||||
                      });
 | 
			
		||||
                    }}>
 | 
			
		||||
                    {this.state.audioTracks.map(track => {
 | 
			
		||||
                      if (!track) {
 | 
			
		||||
                        return;
 | 
			
		||||
                      }
 | 
			
		||||
                      return (
 | 
			
		||||
                        <Picker.Item
 | 
			
		||||
                          label={track.language}
 | 
			
		||||
@@ -720,13 +723,18 @@ class VideoPlayer extends Component {
 | 
			
		||||
                      });
 | 
			
		||||
                    }}>
 | 
			
		||||
                    <Picker.Item label={'none'} value={'none'} key={'none'} />
 | 
			
		||||
                    {this.state.textTracks.map(track => (
 | 
			
		||||
                    {this.state.textTracks.map(track => {
 | 
			
		||||
                      if (!track) {
 | 
			
		||||
                        return;
 | 
			
		||||
                      }
 | 
			
		||||
                      return (
 | 
			
		||||
                        <Picker.Item
 | 
			
		||||
                          label={track.language}
 | 
			
		||||
                          value={track.language}
 | 
			
		||||
                          key={track.language}
 | 
			
		||||
                        />
 | 
			
		||||
                    ))}
 | 
			
		||||
                      );
 | 
			
		||||
                    })}
 | 
			
		||||
                  </Picker>
 | 
			
		||||
                )}
 | 
			
		||||
              </View>
 | 
			
		||||
 
 | 
			
		||||
@@ -364,7 +364,7 @@ enum RCTVideoUtils {
 | 
			
		||||
 | 
			
		||||
    static func delay(seconds: Int = 0) -> Promise<Void> {
 | 
			
		||||
        return Promise<Void>(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(())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user