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:
Olivier Bouillet 2024-03-14 11:46:45 +01:00 committed by GitHub
parent f4cce2ecdb
commit 429fddf3b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 10 deletions

View File

@ -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 => {
<Picker.Item if (!track) {
label={track.language} return;
value={track.language} }
key={track.language} return (
/> <Picker.Item
))} label={track.language}
value={track.language}
key={track.language}
/>
);
})}
</Picker> </Picker>
)} )}
</View> </View>

View File

@ -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(())
} }
} }

View File

@ -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)
} }