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 => {
 | 
					                    {this.state.audioTracks.map(track => {
 | 
				
			||||||
 | 
					                      if (!track) {
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
                      return (
 | 
					                      return (
 | 
				
			||||||
                        <Picker.Item
 | 
					                        <Picker.Item
 | 
				
			||||||
                          label={track.language}
 | 
					                          label={track.language}
 | 
				
			||||||
@@ -720,13 +723,18 @@ class VideoPlayer extends Component {
 | 
				
			|||||||
                      });
 | 
					                      });
 | 
				
			||||||
                    }}>
 | 
					                    }}>
 | 
				
			||||||
                    <Picker.Item label={'none'} value={'none'} key={'none'} />
 | 
					                    <Picker.Item label={'none'} value={'none'} key={'none'} />
 | 
				
			||||||
                    {this.state.textTracks.map(track => (
 | 
					                    {this.state.textTracks.map(track => {
 | 
				
			||||||
 | 
					                      if (!track) {
 | 
				
			||||||
 | 
					                        return;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      return (
 | 
				
			||||||
                        <Picker.Item
 | 
					                        <Picker.Item
 | 
				
			||||||
                          label={track.language}
 | 
					                          label={track.language}
 | 
				
			||||||
                          value={track.language}
 | 
					                          value={track.language}
 | 
				
			||||||
                          key={track.language}
 | 
					                          key={track.language}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                    ))}
 | 
					                      );
 | 
				
			||||||
 | 
					                    })}
 | 
				
			||||||
                  </Picker>
 | 
					                  </Picker>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
              </View>
 | 
					              </View>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -364,7 +364,7 @@ enum RCTVideoUtils {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    static func delay(seconds: Int = 0) -> Promise<Void> {
 | 
					    static func delay(seconds: Int = 0) -> Promise<Void> {
 | 
				
			||||||
        return Promise<Void>(on: .global()) { fulfill, _ in
 | 
					        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(())
 | 
					                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
 | 
					    // MARK: - Player and source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @objc
 | 
					    @objc
 | 
				
			||||||
    func setSrc(_ source: NSDictionary!) {
 | 
					    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 = {
 | 
					        let dispatchClosure = {
 | 
				
			||||||
            self._source = VideoSource(source)
 | 
					            self._source = VideoSource(source)
 | 
				
			||||||
            if self._source?.uri == nil || self._source?.uri == "" {
 | 
					            if self._source?.uri == nil || self._source?.uri == "" {
 | 
				
			||||||
                self._player?.replaceCurrentItem(with: nil)
 | 
					                self._player?.replaceCurrentItem(with: nil)
 | 
				
			||||||
 | 
					                self.isSetSourceOngoing = false
 | 
				
			||||||
 | 
					                self.applyNextSource()
 | 
				
			||||||
 | 
					                DebugLog("setSrc Stopping playback")
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            self.removePlayerLayer()
 | 
					            self.removePlayerLayer()
 | 
				
			||||||
@@ -321,9 +345,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
 | 
				
			|||||||
                    guard let self else { throw NSError(domain: "", code: 0, userInfo: nil) }
 | 
					                    guard let 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")
 | 
				
			||||||
 | 
					                        self.isSetSourceOngoing = false
 | 
				
			||||||
 | 
					                        self.applyNextSource()
 | 
				
			||||||
                        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://") {
 | 
				
			||||||
 | 
					                        self.isSetSourceOngoing = false
 | 
				
			||||||
 | 
					                        self.applyNextSource()
 | 
				
			||||||
                        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, uri: source.uri ?? "")
 | 
					                                return self.playerItemPrepareText(asset: asset, assetOptions: nil, uri: source.uri ?? "")
 | 
				
			||||||
@@ -334,6 +362,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
 | 
				
			|||||||
                          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 '\(String(describing: self._source))'")
 | 
					                        DebugLog("Could not find video URL in source '\(String(describing: self._source))'")
 | 
				
			||||||
 | 
					                        self.isSetSourceOngoing = false
 | 
				
			||||||
 | 
					                        self.applyNextSource()
 | 
				
			||||||
                        throw NSError(domain: "", code: 0, userInfo: nil)
 | 
					                        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 ?? "")
 | 
					                    return self.playerItemPrepareText(asset: asset, assetOptions: assetOptions, uri: source.uri ?? "")
 | 
				
			||||||
                }.then { [weak self] (playerItem: AVPlayerItem!) in
 | 
					                }.then { [weak self] (playerItem: AVPlayerItem!) in
 | 
				
			||||||
                    guard let self else { throw NSError(domain: "", code: 0, userInfo: nil) }
 | 
					                    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._player?.pause()
 | 
				
			||||||
                    self._playerItem = playerItem
 | 
					                    self._playerItem = playerItem
 | 
				
			||||||
                    self._playerObserver.playerItem = self._playerItem
 | 
					                    self._playerObserver.playerItem = self._playerItem
 | 
				
			||||||
@@ -402,8 +435,16 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
 | 
				
			|||||||
                        "drm": self._drm?.json ?? NSNull(),
 | 
					                        "drm": self._drm?.json ?? NSNull(),
 | 
				
			||||||
                        "target": self.reactTag,
 | 
					                        "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._videoLoadStarted = true
 | 
				
			||||||
 | 
					            self.applyNextSource()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        DispatchQueue.global(qos: .default).async(execute: dispatchClosure)
 | 
					        DispatchQueue.global(qos: .default).async(execute: dispatchClosure)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user