spactureai-mobile-player 1.0.31 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ios/hybrids/VideoPlayer/HybridVideoPlayer.swift +229 -39
- package/lib/module/core/video-view/VideoView.js +65 -5
- package/lib/module/core/video-view/VideoView.js.map +1 -1
- package/lib/typescript/src/core/types/BufferConfig.d.ts +11 -1
- package/lib/typescript/src/core/types/BufferConfig.d.ts.map +1 -1
- package/lib/typescript/src/core/video-view/VideoView.d.ts +10 -0
- package/lib/typescript/src/core/video-view/VideoView.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/types/BufferConfig.ts +11 -1
- package/src/core/video-view/VideoView.tsx +93 -5
|
@@ -11,18 +11,53 @@ import Foundation
|
|
|
11
11
|
import MobileVLCKit
|
|
12
12
|
import NitroModules
|
|
13
13
|
|
|
14
|
-
// MARK: - HLS / network tuning (
|
|
14
|
+
// MARK: - HLS / network tuning (libvlc `network-caching` / `live-caching`)
|
|
15
15
|
|
|
16
|
+
/// libvlc `network-caching` is a **single** input-side budget (ms). Setting it
|
|
17
|
+
/// to many minutes makes VLC stay in `opening` / `buffering` for a long time
|
|
18
|
+
/// before first frame — the default must stay small for CCTV/HLS. Opt into a
|
|
19
|
+
/// larger window only via `VideoConfig.bufferConfig` (forward + back sum).
|
|
16
20
|
private enum VLCHLSDefaults {
|
|
17
|
-
|
|
18
|
-
///
|
|
19
|
-
|
|
20
|
-
///
|
|
21
|
-
static let
|
|
22
|
-
|
|
23
|
-
///
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
static let floorMs = 300
|
|
22
|
+
/// Default total when JS omits `bufferConfig` — prioritises time-to-first-frame.
|
|
23
|
+
static let defaultRemoteTotalMs = 4_000
|
|
24
|
+
/// Per-side fallback when `bufferConfig` is present but a field is nil (1 min).
|
|
25
|
+
static let bufferConfigSideFallbackMs = 60_000
|
|
26
|
+
static let hardCapMs = 2 * 3600 * 1_000
|
|
27
|
+
/// First-frame watchdog: if we never leave loading, surface `error` to JS.
|
|
28
|
+
static let firstFrameTimeoutSeconds: TimeInterval = 45
|
|
29
|
+
|
|
30
|
+
static func networkCachingMs(for config: NativeVideoConfig, sourceURL: URL) -> Int {
|
|
31
|
+
let scheme = sourceURL.scheme?.lowercased() ?? ""
|
|
32
|
+
let isRemote =
|
|
33
|
+
scheme == "http" || scheme == "https" || scheme == "rtsp" || scheme == "rtsps"
|
|
34
|
+
guard isRemote else { return floorMs }
|
|
35
|
+
|
|
36
|
+
guard let b = config.bufferConfig else {
|
|
37
|
+
return min(max(floorMs, defaultRemoteTotalMs), hardCapMs)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let side = Double(bufferConfigSideFallbackMs)
|
|
41
|
+
let forward = Int(b.preferredForwardBufferDurationMs ?? b.maxBufferMs ?? side)
|
|
42
|
+
let back = Int(b.backBufferDurationMs ?? b.minBufferMs ?? side)
|
|
43
|
+
let total = max(floorMs, forward + back)
|
|
44
|
+
return min(total, hardCapMs)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static func liveCachingMs(for config: NativeVideoConfig, networkCachingMs: Int) -> Int {
|
|
48
|
+
if let target = config.bufferConfig?.livePlayback?.targetOffsetMs, target > 0 {
|
|
49
|
+
return max(floorMs, min(Int(target), networkCachingMs))
|
|
50
|
+
}
|
|
51
|
+
return networkCachingMs
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#if DEBUG
|
|
55
|
+
static func log(_ message: String) {
|
|
56
|
+
print("[UnifiedPlayer/VLC] \(message)")
|
|
57
|
+
}
|
|
58
|
+
#else
|
|
59
|
+
static func log(_ message: String) {}
|
|
60
|
+
#endif
|
|
26
61
|
}
|
|
27
62
|
|
|
28
63
|
final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
@@ -60,6 +95,28 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
60
95
|
/// from `VideoComponentView` when the surface attaches.
|
|
61
96
|
private var wantsPlaybackWhenDrawableReady: Bool = false
|
|
62
97
|
|
|
98
|
+
private var loadTimeoutWorkItem: DispatchWorkItem?
|
|
99
|
+
|
|
100
|
+
/// Marshal a closure onto the main thread, executing inline if we're
|
|
101
|
+
/// already there. VLC's renderer (`VLCOpenGLES2VideoView`) reaches into
|
|
102
|
+
/// `CAEAGLLayer` to manage its OpenGL renderbuffer when the active
|
|
103
|
+
/// media changes (`mediaPlayer.media = ...`), the player stops, or the
|
|
104
|
+
/// drawable is reattached. Those CALayer mutations must happen on the
|
|
105
|
+
/// main thread; otherwise iOS raises
|
|
106
|
+
/// `_raiseExceptionForBackgroundThreadLayerPropertyModification`.
|
|
107
|
+
/// JS-driven lifecycle calls (release / replaceSourceAsync /
|
|
108
|
+
/// constructor) can land on Nitro's worker thread, so we must hop
|
|
109
|
+
/// before touching any `mediaPlayer.*` setter that triggers a render
|
|
110
|
+
/// reset.
|
|
111
|
+
@inline(__always)
|
|
112
|
+
private static func runOnMain(_ block: @escaping () -> Void) {
|
|
113
|
+
if Thread.isMainThread {
|
|
114
|
+
block()
|
|
115
|
+
} else {
|
|
116
|
+
DispatchQueue.main.async(execute: block)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
63
120
|
init(source: (any HybridVideoPlayerSourceSpec)) throws {
|
|
64
121
|
self.source = source
|
|
65
122
|
self.eventEmitter = HybridVideoPlayerEventEmitter()
|
|
@@ -199,17 +256,21 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
199
256
|
}
|
|
200
257
|
|
|
201
258
|
func release() {
|
|
259
|
+
cancelLoadTimeout()
|
|
202
260
|
invalidateStallWatchdog()
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
261
|
+
|
|
262
|
+
// Capture the VLC objects so they survive past `self` being
|
|
263
|
+
// deallocated — `release()` may be called from `deinit` on a
|
|
264
|
+
// background thread, and the closure below has to outlive the
|
|
265
|
+
// `HybridVideoPlayer` instance.
|
|
266
|
+
let mp = mediaPlayer
|
|
267
|
+
let m = media
|
|
268
|
+
let proxy = authProxy
|
|
269
|
+
|
|
270
|
+
// Clear JS-side bookkeeping first; it doesn't touch any UIKit
|
|
271
|
+
// layer state and can safely run on whatever thread we're on.
|
|
207
272
|
media = nil
|
|
208
|
-
mediaPlayer.media = nil
|
|
209
|
-
mediaPlayer.delegate = nil
|
|
210
273
|
vlcDelegates = nil
|
|
211
|
-
|
|
212
|
-
authProxy?.stop()
|
|
213
274
|
authProxy = nil
|
|
214
275
|
|
|
215
276
|
try? _eventEmitter?.clearAllListeners()
|
|
@@ -224,6 +285,21 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
224
285
|
lastProgressTimeSeconds = 0
|
|
225
286
|
lastProgressTickMonotonic = 0
|
|
226
287
|
|
|
288
|
+
// Tear down VLC on the main thread. `mp.stop()` and
|
|
289
|
+
// `mp.media = nil` cause `VLCOpenGLES2VideoView` to reset its
|
|
290
|
+
// OpenGL renderbuffer, which mutates `CAEAGLLayer.contents` —
|
|
291
|
+
// strictly main-thread-only. Without this hop, iOS raises
|
|
292
|
+
// `_raiseExceptionForBackgroundThreadLayerPropertyModification`
|
|
293
|
+
// whenever a player is released from a non-main queue (typical
|
|
294
|
+
// when the JS owner is dropped from a Nitro worker thread).
|
|
295
|
+
Self.runOnMain {
|
|
296
|
+
if mp.isPlaying { mp.stop() }
|
|
297
|
+
m?.delegate = nil
|
|
298
|
+
mp.media = nil
|
|
299
|
+
mp.delegate = nil
|
|
300
|
+
proxy?.stop()
|
|
301
|
+
}
|
|
302
|
+
|
|
227
303
|
VideoManager.shared.unregister(player: self)
|
|
228
304
|
}
|
|
229
305
|
|
|
@@ -238,26 +314,38 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
238
314
|
|
|
239
315
|
func play() throws {
|
|
240
316
|
wantsPlaybackWhenDrawableReady = true
|
|
241
|
-
mediaPlayer
|
|
317
|
+
let mp = mediaPlayer
|
|
318
|
+
Self.runOnMain { mp.play() }
|
|
242
319
|
VideoManager.shared.requestAudioSessionUpdate()
|
|
243
320
|
}
|
|
244
321
|
|
|
245
322
|
func pause() throws {
|
|
246
323
|
wantsPlaybackWhenDrawableReady = false
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
324
|
+
let mp = mediaPlayer
|
|
325
|
+
// VLC's `stop()` (the not-canPause fallback) tears down the
|
|
326
|
+
// renderbuffer; must be on main. Even `pause()` proper sometimes
|
|
327
|
+
// touches the GL view on first call after attach, so keep both
|
|
328
|
+
// branches on main for symmetry.
|
|
329
|
+
Self.runOnMain {
|
|
330
|
+
if mp.canPause {
|
|
331
|
+
mp.pause()
|
|
332
|
+
} else {
|
|
333
|
+
mp.stop()
|
|
334
|
+
}
|
|
251
335
|
}
|
|
252
336
|
VideoManager.shared.requestAudioSessionUpdate()
|
|
253
337
|
}
|
|
254
338
|
|
|
255
339
|
/// Called from `VideoComponentView` after `mediaPlayer.drawable` is set.
|
|
256
340
|
func notifyVideoHostViewAttached() {
|
|
341
|
+
VLCHLSDefaults.log(
|
|
342
|
+
"drawable attached; wantsPlayback=\(wantsPlaybackWhenDrawableReady) state=\(String(describing: mediaPlayer.state))"
|
|
343
|
+
)
|
|
257
344
|
if wantsPlaybackWhenDrawableReady, media != nil {
|
|
258
345
|
mediaPlayer.play()
|
|
259
346
|
}
|
|
260
347
|
maybeFireOnLoad()
|
|
348
|
+
emitPlaybackState()
|
|
261
349
|
}
|
|
262
350
|
|
|
263
351
|
func seekBy(time: Double) throws {
|
|
@@ -293,15 +381,22 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
293
381
|
promise.resolve(withResult: ())
|
|
294
382
|
case .second(let newSource):
|
|
295
383
|
wantsPlaybackWhenDrawableReady = false
|
|
384
|
+
cancelLoadTimeout()
|
|
296
385
|
invalidateStallWatchdog()
|
|
297
|
-
|
|
298
|
-
|
|
386
|
+
|
|
387
|
+
// Tear down the previous VLC media on main — same reasoning as
|
|
388
|
+
// `release()`. `mediaPlayer.stop()` and `mediaPlayer.media = nil`
|
|
389
|
+
// both poke `VLCOpenGLES2VideoView`'s renderbuffer.
|
|
390
|
+
let mp = mediaPlayer
|
|
391
|
+
let oldMedia = media
|
|
392
|
+
let oldProxy = authProxy
|
|
393
|
+
Self.runOnMain {
|
|
394
|
+
if mp.isPlaying { mp.stop() }
|
|
395
|
+
oldMedia?.delegate = nil
|
|
396
|
+
mp.media = nil
|
|
397
|
+
oldProxy?.stop()
|
|
299
398
|
}
|
|
300
|
-
media?.delegate = nil
|
|
301
399
|
media = nil
|
|
302
|
-
mediaPlayer.media = nil
|
|
303
|
-
|
|
304
|
-
authProxy?.stop()
|
|
305
400
|
authProxy = nil
|
|
306
401
|
|
|
307
402
|
self.source = newSource
|
|
@@ -415,7 +510,11 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
415
510
|
|
|
416
511
|
let media = VLCMedia(url: mediaURL)
|
|
417
512
|
|
|
418
|
-
applyHlsNetworkOptions(
|
|
513
|
+
applyHlsNetworkOptions(
|
|
514
|
+
to: media,
|
|
515
|
+
sourceURL: hybridSource.url,
|
|
516
|
+
videoConfig: hybridSource.config
|
|
517
|
+
)
|
|
419
518
|
|
|
420
519
|
for (key, value) in residualHeaders {
|
|
421
520
|
switch key.lowercased() {
|
|
@@ -432,7 +531,17 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
432
531
|
|
|
433
532
|
media.delegate = vlcDelegates
|
|
434
533
|
self.media = media
|
|
435
|
-
mediaPlayer.media
|
|
534
|
+
// Assigning `mediaPlayer.media` causes VLC to swap the active
|
|
535
|
+
// `VLCOpenGLES2VideoView` renderbuffer, which mutates
|
|
536
|
+
// `CAEAGLLayer.contents`. Hop to main so the layer write is on
|
|
537
|
+
// the main thread. We capture `mediaPlayer` and the new `media`
|
|
538
|
+
// by value so the assignment is safe even if `self` is dropped
|
|
539
|
+
// before the dispatched block runs.
|
|
540
|
+
let mp = mediaPlayer
|
|
541
|
+
let mediaToAttach = media
|
|
542
|
+
Self.runOnMain {
|
|
543
|
+
mp.media = mediaToAttach
|
|
544
|
+
}
|
|
436
545
|
|
|
437
546
|
if !hasFiredOnLoadStart {
|
|
438
547
|
hasFiredOnLoadStart = true
|
|
@@ -450,6 +559,8 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
450
559
|
status = .loading
|
|
451
560
|
setBuffering(true)
|
|
452
561
|
hasEmittedEndForCurrentItem = false
|
|
562
|
+
emitPlaybackState()
|
|
563
|
+
scheduleLoadTimeout()
|
|
453
564
|
}
|
|
454
565
|
|
|
455
566
|
/// Rewrite an http(s) URL to point at the local auth proxy on
|
|
@@ -467,11 +578,68 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
467
578
|
return components.url
|
|
468
579
|
}
|
|
469
580
|
|
|
470
|
-
private func applyHlsNetworkOptions(
|
|
471
|
-
media
|
|
472
|
-
|
|
581
|
+
private func applyHlsNetworkOptions(
|
|
582
|
+
to media: VLCMedia,
|
|
583
|
+
sourceURL: URL,
|
|
584
|
+
videoConfig: NativeVideoConfig
|
|
585
|
+
) {
|
|
586
|
+
let scheme = sourceURL.scheme?.lowercased() ?? ""
|
|
587
|
+
let networkMs = VLCHLSDefaults.networkCachingMs(for: videoConfig, sourceURL: sourceURL)
|
|
588
|
+
let liveMs = VLCHLSDefaults.liveCachingMs(for: videoConfig, networkCachingMs: networkMs)
|
|
589
|
+
media.addOption(":network-caching=\(networkMs)")
|
|
590
|
+
media.addOption(":live-caching=\(liveMs)")
|
|
473
591
|
// HLS over HTTP benefits from reconnect; harmless for file URLs.
|
|
474
592
|
media.addOption(":http-reconnect=true")
|
|
593
|
+
|
|
594
|
+
// RTSP: UDP can be blocked on cellular / Wi‑Fi guest; TCP interleaved is
|
|
595
|
+
// the reliable default for CCTV / NVR streams.
|
|
596
|
+
if scheme == "rtsp" || scheme == "rtsps" {
|
|
597
|
+
media.addOption(":rtsp-tcp")
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// HLS: libvlc may issue many small GETs (master + variant index.m3u8).
|
|
601
|
+
// Keep-alive amortizes TLS/TCP handshakes. Parallel segment threads help
|
|
602
|
+
// time-to-first-frame once a variant is selected. (Master still lists
|
|
603
|
+
// every variant; fastest fix for huge masters is pointing the URI at a
|
|
604
|
+
// single media playlist from the app.)
|
|
605
|
+
let path = sourceURL.absoluteString.lowercased()
|
|
606
|
+
if path.contains(".m3u8") {
|
|
607
|
+
media.addOption(":http-keep-alive=true")
|
|
608
|
+
media.addOption(":hls-segment-threads=2")
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
VLCHLSDefaults.log(
|
|
612
|
+
"options url=\(sourceURL.absoluteString) scheme=\(scheme) network-caching=\(networkMs) live-caching=\(liveMs)"
|
|
613
|
+
)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
private func scheduleLoadTimeout() {
|
|
617
|
+
cancelLoadTimeout()
|
|
618
|
+
let item = DispatchWorkItem { [weak self] in
|
|
619
|
+
guard let self else { return }
|
|
620
|
+
guard self.media != nil else { return }
|
|
621
|
+
guard !self.hasFiredOnLoad else { return }
|
|
622
|
+
let vlcState = self.mediaPlayer.state
|
|
623
|
+
if vlcState == .playing || vlcState == .paused {
|
|
624
|
+
return
|
|
625
|
+
}
|
|
626
|
+
VLCHLSDefaults.log(
|
|
627
|
+
"first-frame timeout (state=\(String(describing: vlcState)) isPlaying=\(self.mediaPlayer.isPlaying))"
|
|
628
|
+
)
|
|
629
|
+
self.setBuffering(false)
|
|
630
|
+
self.status = .error
|
|
631
|
+
self.emitPlaybackState()
|
|
632
|
+
}
|
|
633
|
+
loadTimeoutWorkItem = item
|
|
634
|
+
DispatchQueue.main.asyncAfter(
|
|
635
|
+
deadline: .now() + VLCHLSDefaults.firstFrameTimeoutSeconds,
|
|
636
|
+
execute: item
|
|
637
|
+
)
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private func cancelLoadTimeout() {
|
|
641
|
+
loadTimeoutWorkItem?.cancel()
|
|
642
|
+
loadTimeoutWorkItem = nil
|
|
475
643
|
}
|
|
476
644
|
|
|
477
645
|
/// Resets stall-watchdog liveness so a long seek / buffer gap is not mistaken for a dead stream.
|
|
@@ -482,17 +650,26 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
482
650
|
private func applySeek(seconds target: Double) {
|
|
483
651
|
let ms = Int32(min(Double(Int32.max), max(0, target * 1000.0)))
|
|
484
652
|
|
|
485
|
-
|
|
486
|
-
|
|
653
|
+
// VLC's seek can prompt the demuxer to re-attach segments and
|
|
654
|
+
// refresh the renderbuffer (especially for HLS where a seek
|
|
655
|
+
// jumps to a different .ts segment). Marshal onto main so any
|
|
656
|
+
// resulting CALayer write happens there. We capture the player
|
|
657
|
+
// by value so the dispatch is safe even if the JS owner is
|
|
658
|
+
// released before the block fires.
|
|
659
|
+
let mp = mediaPlayer
|
|
660
|
+
let totalMs = Double(media?.length.intValue ?? 0)
|
|
661
|
+
let isSeekable = mediaPlayer.isSeekable
|
|
662
|
+
|
|
663
|
+
if isSeekable {
|
|
487
664
|
pendingSeekSeconds = nil
|
|
665
|
+
Self.runOnMain { mp.time = VLCTime(int: ms) }
|
|
488
666
|
return
|
|
489
667
|
}
|
|
490
668
|
|
|
491
|
-
let totalMs = Double(media?.length.intValue ?? 0)
|
|
492
669
|
if totalMs > 0 {
|
|
493
670
|
let position = Float(min(1.0, (Double(ms)) / totalMs))
|
|
494
|
-
mediaPlayer.position = position
|
|
495
671
|
pendingSeekSeconds = nil
|
|
672
|
+
Self.runOnMain { mp.position = position }
|
|
496
673
|
} else {
|
|
497
674
|
pendingSeekSeconds = target
|
|
498
675
|
}
|
|
@@ -500,6 +677,7 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
500
677
|
|
|
501
678
|
private func handleStateChange() {
|
|
502
679
|
let state = mediaPlayer.state
|
|
680
|
+
VLCHLSDefaults.log("stateChange -> \(String(describing: state))")
|
|
503
681
|
switch state {
|
|
504
682
|
case .opening:
|
|
505
683
|
status = .loading
|
|
@@ -513,6 +691,7 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
513
691
|
}
|
|
514
692
|
|
|
515
693
|
case .playing:
|
|
694
|
+
cancelLoadTimeout()
|
|
516
695
|
setBuffering(false)
|
|
517
696
|
status = .readytoplay
|
|
518
697
|
maybeFireOnLoad()
|
|
@@ -523,6 +702,7 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
523
702
|
case .paused:
|
|
524
703
|
setBuffering(false)
|
|
525
704
|
if status == .loading { status = .readytoplay }
|
|
705
|
+
maybeFireOnLoad()
|
|
526
706
|
VideoManager.shared.requestAudioSessionUpdate()
|
|
527
707
|
|
|
528
708
|
case .stopped, .ended:
|
|
@@ -538,6 +718,7 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
538
718
|
}
|
|
539
719
|
|
|
540
720
|
case .error:
|
|
721
|
+
cancelLoadTimeout()
|
|
541
722
|
setBuffering(false)
|
|
542
723
|
status = .error
|
|
543
724
|
// JS layer maps `error` status → `onError` (see VideoPlayer.ts).
|
|
@@ -590,13 +771,22 @@ final class HybridVideoPlayer: HybridVideoPlayerSpec, VLCPlaybackDelegateOwner {
|
|
|
590
771
|
let hasDuration = dur.isFinite && dur > 0
|
|
591
772
|
let size = mediaPlayer.videoSize
|
|
592
773
|
let hasVideo = size.width > 0 && size.height > 0
|
|
774
|
+
let state = mediaPlayer.state
|
|
593
775
|
// VOD HLS from MediaMTX may keep length at 0 until the playlist is fully
|
|
594
776
|
// parsed; still emit onLoad once we are playing or have decoded dimensions
|
|
595
777
|
// so JS overlays (e.g. preroll spinner) can clear.
|
|
596
|
-
|
|
778
|
+
let hasBasicReadiness =
|
|
779
|
+
hasDuration || mediaPlayer.isPlaying || hasVideo
|
|
780
|
+
// First paint: VLC can report 0×0 video size and unknown duration while
|
|
781
|
+
// already past demux (paused autoplay, or drawable attached a frame late).
|
|
782
|
+
let demuxPastOpen =
|
|
783
|
+
state == .playing || state == .paused || state == .buffering
|
|
784
|
+
let relaxedReadiness = (media?.isParsed == true) && demuxPastOpen
|
|
785
|
+
if !hasBasicReadiness && !relaxedReadiness {
|
|
597
786
|
return
|
|
598
787
|
}
|
|
599
788
|
hasFiredOnLoad = true
|
|
789
|
+
cancelLoadTimeout()
|
|
600
790
|
let width = Double(size.width)
|
|
601
791
|
let height = Double(size.height)
|
|
602
792
|
let orientation: VideoOrientation =
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
|
+
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
|
4
5
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
5
6
|
import { tryParseNativeVideoError, VideoComponentError, VideoError } from "../types/VideoError.js";
|
|
6
7
|
import { NativeVideoView } from './NativeVideoView';
|
|
7
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
9
|
let nitroIdCounter = 1;
|
|
9
10
|
const VideoViewViewManagerFactory = NitroModules.createHybridObject('VideoViewViewManagerFactory');
|
|
10
11
|
const wrapNativeViewManagerFunction = (manager, func) => {
|
|
@@ -50,6 +51,8 @@ const VideoView = /*#__PURE__*/React.forwardRef(({
|
|
|
50
51
|
fullscreen = false,
|
|
51
52
|
paused,
|
|
52
53
|
speed,
|
|
54
|
+
showLoadingIndicator = false,
|
|
55
|
+
loadingIndicatorColor,
|
|
53
56
|
onPictureInPictureChange,
|
|
54
57
|
onFullscreenChange,
|
|
55
58
|
willEnterFullscreen,
|
|
@@ -61,6 +64,37 @@ const VideoView = /*#__PURE__*/React.forwardRef(({
|
|
|
61
64
|
const nitroId = React.useMemo(() => nitroIdCounter++, []);
|
|
62
65
|
const nitroViewManager = React.useRef(null);
|
|
63
66
|
const [isManagerReady, setIsManagerReady] = React.useState(false);
|
|
67
|
+
const [hasLoadedMedia, setHasLoadedMedia] = React.useState(false);
|
|
68
|
+
const [isBuffering, setIsBuffering] = React.useState(false);
|
|
69
|
+
const [playerStatus, setPlayerStatus] = React.useState(player.status);
|
|
70
|
+
React.useEffect(() => {
|
|
71
|
+
if (!showLoadingIndicator) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
setPlayerStatus(player.status);
|
|
75
|
+
setHasLoadedMedia(player.status === 'readyToPlay');
|
|
76
|
+
const onLoadStart = () => {
|
|
77
|
+
setHasLoadedMedia(false);
|
|
78
|
+
setIsBuffering(true);
|
|
79
|
+
};
|
|
80
|
+
const onLoad = () => {
|
|
81
|
+
setHasLoadedMedia(true);
|
|
82
|
+
setIsBuffering(false);
|
|
83
|
+
};
|
|
84
|
+
const onBuffer = buffering => setIsBuffering(buffering);
|
|
85
|
+
const onStatus = status => setPlayerStatus(status);
|
|
86
|
+
const subLoadStart = player.addEventListener('onLoadStart', onLoadStart);
|
|
87
|
+
const subLoad = player.addEventListener('onLoad', onLoad);
|
|
88
|
+
const subBuffer = player.addEventListener('onBuffer', onBuffer);
|
|
89
|
+
const subStatus = player.addEventListener('onStatusChange', onStatus);
|
|
90
|
+
return () => {
|
|
91
|
+
subLoadStart.remove();
|
|
92
|
+
subLoad.remove();
|
|
93
|
+
subBuffer.remove();
|
|
94
|
+
subStatus.remove();
|
|
95
|
+
};
|
|
96
|
+
}, [player, showLoadingIndicator]);
|
|
97
|
+
const showNativeSpinner = showLoadingIndicator && playerStatus !== 'error' && playerStatus !== 'idle' && (!hasLoadedMedia || isBuffering);
|
|
64
98
|
const setupViewManager = React.useCallback(id => {
|
|
65
99
|
try {
|
|
66
100
|
if (nitroViewManager.current === null) {
|
|
@@ -250,12 +284,38 @@ const VideoView = /*#__PURE__*/React.forwardRef(({
|
|
|
250
284
|
console.warn('[UnifiedPlayer] Failed to change fullscreen state:', error);
|
|
251
285
|
}
|
|
252
286
|
}, [fullscreen, isManagerReady]);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
287
|
+
if (!showLoadingIndicator) {
|
|
288
|
+
return /*#__PURE__*/_jsx(NativeVideoView, {
|
|
289
|
+
nitroId: nitroId,
|
|
290
|
+
onNitroIdChange: onNitroIdChange,
|
|
291
|
+
...props
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
295
|
+
style: props.style,
|
|
296
|
+
collapsable: false,
|
|
297
|
+
children: [/*#__PURE__*/_jsx(NativeVideoView, {
|
|
298
|
+
nitroId: nitroId,
|
|
299
|
+
onNitroIdChange: onNitroIdChange,
|
|
300
|
+
...props,
|
|
301
|
+
style: StyleSheet.absoluteFill
|
|
302
|
+
}), showNativeSpinner ? /*#__PURE__*/_jsx(View, {
|
|
303
|
+
style: styles.loadingOverlay,
|
|
304
|
+
pointerEvents: "none",
|
|
305
|
+
children: /*#__PURE__*/_jsx(ActivityIndicator, {
|
|
306
|
+
size: "large",
|
|
307
|
+
color: loadingIndicatorColor
|
|
308
|
+
})
|
|
309
|
+
}) : null]
|
|
257
310
|
});
|
|
258
311
|
});
|
|
312
|
+
const styles = StyleSheet.create({
|
|
313
|
+
loadingOverlay: {
|
|
314
|
+
...StyleSheet.absoluteFillObject,
|
|
315
|
+
alignItems: 'center',
|
|
316
|
+
justifyContent: 'center'
|
|
317
|
+
}
|
|
318
|
+
});
|
|
259
319
|
VideoView.displayName = 'VideoView';
|
|
260
320
|
export default /*#__PURE__*/React.memo(VideoView);
|
|
261
321
|
//# sourceMappingURL=VideoView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","NitroModules","tryParseNativeVideoError","VideoComponentError","VideoError","NativeVideoView","jsx","_jsx","nitroIdCounter","VideoViewViewManagerFactory","createHybridObject","wrapNativeViewManagerFunction","manager","func","error","updateProps","props","player","__getNativePlayer","controls","pictureInPicture","autoEnterPictureInPicture","resizeMode","keepScreenAwake","surfaceType","VideoView","forwardRef","autoplay","fullscreen","paused","speed","onPictureInPictureChange","onFullscreenChange","willEnterFullscreen","willExitFullscreen","willEnterPictureInPicture","willExitPictureInPicture","ref","nitroId","useMemo","nitroViewManager","useRef","isManagerReady","setIsManagerReady","useState","setupViewManager","useCallback","id","current","createViewManager","parsedError","code","console","warn","onNitroIdChange","event","nativeEvent","useImperativeHandle","enterFullscreen","exitFullscreen","enterPictureInPicture","exitPictureInPicture","canEnterPictureInPicture","addEventListener","callback","addOnPictureInPictureChangeListener","addOnFullscreenChangeListener","addWillEnterFullscreenListener","addWillExitFullscreenListener","addWillEnterPictureInPictureListener","addWillExitPictureInPictureListener","Error","useEffect","clearAllListeners","subscriptions","push","forEach","sub","remove","undefined","pause","play","rate","hasAutoplayedRef","prevFullscreenRef","prev","displayName","memo"],"sourceRoot":"../../../../src","sources":["core/video-view/VideoView.tsx"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["React","ActivityIndicator","StyleSheet","View","NitroModules","tryParseNativeVideoError","VideoComponentError","VideoError","NativeVideoView","jsx","_jsx","jsxs","_jsxs","nitroIdCounter","VideoViewViewManagerFactory","createHybridObject","wrapNativeViewManagerFunction","manager","func","error","updateProps","props","player","__getNativePlayer","controls","pictureInPicture","autoEnterPictureInPicture","resizeMode","keepScreenAwake","surfaceType","VideoView","forwardRef","autoplay","fullscreen","paused","speed","showLoadingIndicator","loadingIndicatorColor","onPictureInPictureChange","onFullscreenChange","willEnterFullscreen","willExitFullscreen","willEnterPictureInPicture","willExitPictureInPicture","ref","nitroId","useMemo","nitroViewManager","useRef","isManagerReady","setIsManagerReady","useState","hasLoadedMedia","setHasLoadedMedia","isBuffering","setIsBuffering","playerStatus","setPlayerStatus","status","useEffect","onLoadStart","onLoad","onBuffer","buffering","onStatus","subLoadStart","addEventListener","subLoad","subBuffer","subStatus","remove","showNativeSpinner","setupViewManager","useCallback","id","current","createViewManager","parsedError","code","console","warn","onNitroIdChange","event","nativeEvent","useImperativeHandle","enterFullscreen","exitFullscreen","enterPictureInPicture","exitPictureInPicture","canEnterPictureInPicture","callback","addOnPictureInPictureChangeListener","addOnFullscreenChangeListener","addWillEnterFullscreenListener","addWillExitFullscreenListener","addWillEnterPictureInPictureListener","addWillExitPictureInPictureListener","Error","clearAllListeners","subscriptions","push","forEach","sub","undefined","pause","play","rate","hasAutoplayedRef","prevFullscreenRef","prev","style","collapsable","children","absoluteFill","styles","loadingOverlay","pointerEvents","size","color","create","absoluteFillObject","alignItems","justifyContent","displayName","memo"],"sourceRoot":"../../../../src","sources":["core/video-view/VideoView.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -38,12 +38,17 @@ export interface BufferConfig {
|
|
|
38
38
|
* Minimum duration (ms) the player will attempt to keep buffered.
|
|
39
39
|
* @default 5000
|
|
40
40
|
* @platform android
|
|
41
|
+
* @platform ios (VLC) Back portion of `network-caching` when set; if omitted
|
|
42
|
+
* alongside the other buffer fields, defaults to 60s for that side. Large
|
|
43
|
+
* values delay first frame — prefer explicit tuning over huge defaults.
|
|
41
44
|
*/
|
|
42
45
|
minBufferMs?: number;
|
|
43
46
|
/**
|
|
44
47
|
* Maximum duration (ms) the player will attempt to keep buffered.
|
|
45
48
|
* @default 10000
|
|
46
49
|
* @platform android
|
|
50
|
+
* @platform ios (VLC) Fallback for the **forward** half when
|
|
51
|
+
* `preferredForwardBufferDurationMs` is omitted.
|
|
47
52
|
*/
|
|
48
53
|
maxBufferMs?: number;
|
|
49
54
|
/**
|
|
@@ -61,11 +66,16 @@ export interface BufferConfig {
|
|
|
61
66
|
/**
|
|
62
67
|
* Duration (ms) of media that must be buffered before it can be played from the back buffer.
|
|
63
68
|
* @platform android
|
|
69
|
+
* @platform ios (VLC) Back portion of libvlc `network-caching`; if omitted
|
|
70
|
+
* defaults to 60s when any `bufferConfig` field is set.
|
|
64
71
|
*/
|
|
65
72
|
backBufferDurationMs?: number;
|
|
66
73
|
/**
|
|
67
74
|
* The preferred duration (ms) of media that the player will attempt to retain in the buffer.
|
|
68
|
-
* @platform ios, visionOS, tvOS
|
|
75
|
+
* @platform ios, visionOS, tvOS — AVKit semantics where applicable.
|
|
76
|
+
* @platform ios (VLC / unified-player) Forward portion of libvlc `network-caching`
|
|
77
|
+
* (combined with `backBufferDurationMs` / `minBufferMs`). Omit all fields to use
|
|
78
|
+
* a small default (~4s total) for fast first frame.
|
|
69
79
|
*/
|
|
70
80
|
preferredForwardBufferDurationMs?: number;
|
|
71
81
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BufferConfig.d.ts","sourceRoot":"","sources":["../../../../../src/core/types/BufferConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAIlC
|
|
1
|
+
{"version":3,"file":"BufferConfig.d.ts","sourceRoot":"","sources":["../../../../../src/core/types/BufferConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAIlC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAI9B;;;;;;OAMG;IACH,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,0BAA0B,CAAC,EAAE,UAAU,CAAC;IACxC;;;OAGG;IACH,wCAAwC,CAAC,EAAE,MAAM,CAAC;IAClD;;;OAGG;IACH,8CAA8C,CAAC,EAAE,UAAU,CAAC;CAC7D"}
|
|
@@ -68,6 +68,16 @@ export interface VideoViewProps extends Partial<VideoViewEvents>, ViewProps {
|
|
|
68
68
|
* The playback speed of the video. Defaults to 1.0.
|
|
69
69
|
*/
|
|
70
70
|
speed?: number;
|
|
71
|
+
/**
|
|
72
|
+
* When true, shows a centered activity indicator while the source is
|
|
73
|
+
* loading or the native player reports buffering (initial load and rebuffer).
|
|
74
|
+
* @default false
|
|
75
|
+
*/
|
|
76
|
+
showLoadingIndicator?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* @platform ios
|
|
79
|
+
*/
|
|
80
|
+
loadingIndicatorColor?: string;
|
|
71
81
|
}
|
|
72
82
|
export interface VideoViewRef {
|
|
73
83
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoView.d.ts","sourceRoot":"","sources":["../../../../../src/core/video-view/VideoView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"VideoView.d.ts","sourceRoot":"","sources":["../../../../../src/core/video-view/VideoView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AAC3F,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,eAAe,CAAC,EAAE,SAAS;IACzE;;OAEG;IACH,MAAM,EAAE,WAAW,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;OAEG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B;;OAEG;IACH,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B;;OAEG;IACH,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC;;OAEG;IACH,oBAAoB,EAAE,MAAM,IAAI,CAAC;IACjC;;;OAGG;IACH,wBAAwB,EAAE,MAAM,OAAO,CAAC;IACxC;;;;;OAKG;IACH,gBAAgB,EAAE,CAAC,KAAK,SAAS,MAAM,eAAe,EACpD,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,KAC7B,oBAAoB,CAAC;CAC3B;;AA8bD,wBAAqC"}
|
package/package.json
CHANGED
|
@@ -43,12 +43,17 @@ export interface BufferConfig {
|
|
|
43
43
|
* Minimum duration (ms) the player will attempt to keep buffered.
|
|
44
44
|
* @default 5000
|
|
45
45
|
* @platform android
|
|
46
|
+
* @platform ios (VLC) Back portion of `network-caching` when set; if omitted
|
|
47
|
+
* alongside the other buffer fields, defaults to 60s for that side. Large
|
|
48
|
+
* values delay first frame — prefer explicit tuning over huge defaults.
|
|
46
49
|
*/
|
|
47
50
|
minBufferMs?: number;
|
|
48
51
|
/**
|
|
49
52
|
* Maximum duration (ms) the player will attempt to keep buffered.
|
|
50
53
|
* @default 10000
|
|
51
54
|
* @platform android
|
|
55
|
+
* @platform ios (VLC) Fallback for the **forward** half when
|
|
56
|
+
* `preferredForwardBufferDurationMs` is omitted.
|
|
52
57
|
*/
|
|
53
58
|
maxBufferMs?: number;
|
|
54
59
|
/**
|
|
@@ -66,6 +71,8 @@ export interface BufferConfig {
|
|
|
66
71
|
/**
|
|
67
72
|
* Duration (ms) of media that must be buffered before it can be played from the back buffer.
|
|
68
73
|
* @platform android
|
|
74
|
+
* @platform ios (VLC) Back portion of libvlc `network-caching`; if omitted
|
|
75
|
+
* defaults to 60s when any `bufferConfig` field is set.
|
|
69
76
|
*/
|
|
70
77
|
backBufferDurationMs?: number;
|
|
71
78
|
|
|
@@ -73,7 +80,10 @@ export interface BufferConfig {
|
|
|
73
80
|
|
|
74
81
|
/**
|
|
75
82
|
* The preferred duration (ms) of media that the player will attempt to retain in the buffer.
|
|
76
|
-
* @platform ios, visionOS, tvOS
|
|
83
|
+
* @platform ios, visionOS, tvOS — AVKit semantics where applicable.
|
|
84
|
+
* @platform ios (VLC / unified-player) Forward portion of libvlc `network-caching`
|
|
85
|
+
* (combined with `backBufferDurationMs` / `minBufferMs`). Omit all fields to use
|
|
86
|
+
* a small default (~4s total) for fast first frame.
|
|
77
87
|
*/
|
|
78
88
|
preferredForwardBufferDurationMs?: number;
|
|
79
89
|
/**
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { ViewProps, ViewStyle } from 'react-native';
|
|
3
|
+
import {
|
|
4
|
+
ActivityIndicator,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
View,
|
|
7
|
+
} from 'react-native';
|
|
3
8
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
9
|
import type { ListenerSubscription } from '../../spec/nitro/VideoPlayerEventEmitter.nitro';
|
|
5
10
|
import type {
|
|
@@ -14,6 +19,7 @@ import {
|
|
|
14
19
|
VideoComponentError,
|
|
15
20
|
VideoError,
|
|
16
21
|
} from '../types/VideoError';
|
|
22
|
+
import type { VideoPlayerStatus } from '../types/VideoPlayerStatus';
|
|
17
23
|
import type { VideoPlayer } from '../VideoPlayer';
|
|
18
24
|
import { NativeVideoView } from './NativeVideoView';
|
|
19
25
|
|
|
@@ -81,6 +87,16 @@ export interface VideoViewProps extends Partial<VideoViewEvents>, ViewProps {
|
|
|
81
87
|
* The playback speed of the video. Defaults to 1.0.
|
|
82
88
|
*/
|
|
83
89
|
speed?: number;
|
|
90
|
+
/**
|
|
91
|
+
* When true, shows a centered activity indicator while the source is
|
|
92
|
+
* loading or the native player reports buffering (initial load and rebuffer).
|
|
93
|
+
* @default false
|
|
94
|
+
*/
|
|
95
|
+
showLoadingIndicator?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* @platform ios
|
|
98
|
+
*/
|
|
99
|
+
loadingIndicatorColor?: string;
|
|
84
100
|
}
|
|
85
101
|
|
|
86
102
|
export interface VideoViewRef {
|
|
@@ -173,6 +189,8 @@ const VideoView = React.forwardRef<VideoViewRef, VideoViewProps>(
|
|
|
173
189
|
fullscreen = false,
|
|
174
190
|
paused,
|
|
175
191
|
speed,
|
|
192
|
+
showLoadingIndicator = false,
|
|
193
|
+
loadingIndicatorColor,
|
|
176
194
|
onPictureInPictureChange,
|
|
177
195
|
onFullscreenChange,
|
|
178
196
|
willEnterFullscreen,
|
|
@@ -187,6 +205,47 @@ const VideoView = React.forwardRef<VideoViewRef, VideoViewProps>(
|
|
|
187
205
|
const nitroViewManager = React.useRef<VideoViewViewManager | null>(null);
|
|
188
206
|
const [isManagerReady, setIsManagerReady] = React.useState(false);
|
|
189
207
|
|
|
208
|
+
const [hasLoadedMedia, setHasLoadedMedia] = React.useState(false);
|
|
209
|
+
const [isBuffering, setIsBuffering] = React.useState(false);
|
|
210
|
+
const [playerStatus, setPlayerStatus] =
|
|
211
|
+
React.useState<VideoPlayerStatus>(player.status);
|
|
212
|
+
|
|
213
|
+
React.useEffect(() => {
|
|
214
|
+
if (!showLoadingIndicator) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
setPlayerStatus(player.status);
|
|
218
|
+
setHasLoadedMedia(player.status === 'readyToPlay');
|
|
219
|
+
const onLoadStart = () => {
|
|
220
|
+
setHasLoadedMedia(false);
|
|
221
|
+
setIsBuffering(true);
|
|
222
|
+
};
|
|
223
|
+
const onLoad = () => {
|
|
224
|
+
setHasLoadedMedia(true);
|
|
225
|
+
setIsBuffering(false);
|
|
226
|
+
};
|
|
227
|
+
const onBuffer = (buffering: boolean) => setIsBuffering(buffering);
|
|
228
|
+
const onStatus = (status: VideoPlayerStatus) => setPlayerStatus(status);
|
|
229
|
+
|
|
230
|
+
const subLoadStart = player.addEventListener('onLoadStart', onLoadStart);
|
|
231
|
+
const subLoad = player.addEventListener('onLoad', onLoad);
|
|
232
|
+
const subBuffer = player.addEventListener('onBuffer', onBuffer);
|
|
233
|
+
const subStatus = player.addEventListener('onStatusChange', onStatus);
|
|
234
|
+
|
|
235
|
+
return () => {
|
|
236
|
+
subLoadStart.remove();
|
|
237
|
+
subLoad.remove();
|
|
238
|
+
subBuffer.remove();
|
|
239
|
+
subStatus.remove();
|
|
240
|
+
};
|
|
241
|
+
}, [player, showLoadingIndicator]);
|
|
242
|
+
|
|
243
|
+
const showNativeSpinner =
|
|
244
|
+
showLoadingIndicator &&
|
|
245
|
+
playerStatus !== 'error' &&
|
|
246
|
+
playerStatus !== 'idle' &&
|
|
247
|
+
(!hasLoadedMedia || isBuffering);
|
|
248
|
+
|
|
190
249
|
const setupViewManager = React.useCallback(
|
|
191
250
|
(id: number) => {
|
|
192
251
|
try {
|
|
@@ -477,16 +536,45 @@ const VideoView = React.forwardRef<VideoViewRef, VideoViewProps>(
|
|
|
477
536
|
}
|
|
478
537
|
}, [fullscreen, isManagerReady]);
|
|
479
538
|
|
|
539
|
+
if (!showLoadingIndicator) {
|
|
540
|
+
return (
|
|
541
|
+
<NativeVideoView
|
|
542
|
+
nitroId={nitroId}
|
|
543
|
+
onNitroIdChange={onNitroIdChange}
|
|
544
|
+
{...props}
|
|
545
|
+
/>
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
480
549
|
return (
|
|
481
|
-
<
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
550
|
+
<View style={props.style} collapsable={false}>
|
|
551
|
+
<NativeVideoView
|
|
552
|
+
nitroId={nitroId}
|
|
553
|
+
onNitroIdChange={onNitroIdChange}
|
|
554
|
+
{...props}
|
|
555
|
+
style={StyleSheet.absoluteFill}
|
|
556
|
+
/>
|
|
557
|
+
{showNativeSpinner ? (
|
|
558
|
+
<View style={styles.loadingOverlay} pointerEvents="none">
|
|
559
|
+
<ActivityIndicator
|
|
560
|
+
size="large"
|
|
561
|
+
color={loadingIndicatorColor}
|
|
562
|
+
/>
|
|
563
|
+
</View>
|
|
564
|
+
) : null}
|
|
565
|
+
</View>
|
|
486
566
|
);
|
|
487
567
|
}
|
|
488
568
|
);
|
|
489
569
|
|
|
570
|
+
const styles = StyleSheet.create({
|
|
571
|
+
loadingOverlay: {
|
|
572
|
+
...StyleSheet.absoluteFillObject,
|
|
573
|
+
alignItems: 'center',
|
|
574
|
+
justifyContent: 'center',
|
|
575
|
+
},
|
|
576
|
+
});
|
|
577
|
+
|
|
490
578
|
VideoView.displayName = 'VideoView';
|
|
491
579
|
|
|
492
580
|
export default React.memo(VideoView);
|