expo-libvlc-player 5.0.0 → 5.0.1

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.
@@ -42,6 +42,8 @@ private val DISPLAY_MANAGER: DisplayManager? = null
42
42
  private val ENABLE_SUBTITLES: Boolean = true
43
43
  private val USE_TEXTURE_VIEW: Boolean = true
44
44
 
45
+ private val MAX_RETRY_COUNT: Int = 10
46
+
45
47
  class LibVlcPlayerView(
46
48
  context: Context,
47
49
  appContext: AppContext,
@@ -53,9 +55,8 @@ class LibVlcPlayerView(
53
55
  var media: Media? = null
54
56
  var vlcDialog: VLCDialog? = null
55
57
 
56
- var mediaLength: Long? = null
57
58
  var firstPlay: Boolean = true
58
- var firstTime: Boolean = true
59
+ private var retryCount: Int = 0
59
60
  private var shouldInit: Boolean = true
60
61
 
61
62
  val onBuffering by EventDispatcher<Unit>()
@@ -137,7 +138,6 @@ class LibVlcPlayerView(
137
138
  }
138
139
 
139
140
  firstPlay = true
140
- firstTime = true
141
141
  shouldInit = false
142
142
  }
143
143
 
@@ -208,19 +208,20 @@ class LibVlcPlayerView(
208
208
 
209
209
  fun setContentFit() {
210
210
  post {
211
- val textureView = getTextureView() ?: return@post
212
-
211
+ val view = getTextureView() ?: return@post
213
212
  val matrix = Matrix()
214
213
 
215
214
  mediaPlayer?.let { player ->
216
215
  val video = player.getCurrentVideoTrack()
216
+ val width = video?.width ?: 0
217
+ val height = video?.height ?: 0
217
218
 
218
- if (video != null) {
219
- val viewWidth = playerView.width.toFloat()
220
- val viewHeight = playerView.height.toFloat()
219
+ if (width > 0 && height > 0) {
220
+ val viewWidth = view.width.toFloat()
221
+ val viewHeight = view.height.toFloat()
221
222
 
222
- val videoWidth = video.width.toFloat()
223
- val videoHeight = video.height.toFloat()
223
+ val videoWidth = width.toFloat()
224
+ val videoHeight = height.toFloat()
224
225
 
225
226
  val viewAspect = viewWidth / viewHeight
226
227
  val videoAspect = videoWidth / videoHeight
@@ -260,7 +261,7 @@ class LibVlcPlayerView(
260
261
  }
261
262
  }
262
263
 
263
- textureView.setTransform(matrix)
264
+ view.setTransform(matrix)
264
265
  }
265
266
  }
266
267
 
@@ -270,8 +271,6 @@ class LibVlcPlayerView(
270
271
 
271
272
  addPlayerSlaves()
272
273
 
273
- setContentFit()
274
-
275
274
  if (scale != MediaPlayerConstants.DEFAULT_PLAYER_SCALE) {
276
275
  player.setScale(scale)
277
276
  }
@@ -299,6 +298,32 @@ class LibVlcPlayerView(
299
298
  }
300
299
  }
301
300
 
301
+ fun setupFirstPlay() {
302
+ val tracks = getMediaTracks()
303
+ val media = getMediaInfo()
304
+ val length = getMediaLength()
305
+
306
+ val hasAudio = tracks.audio.any { track -> track.id != -1 }
307
+ val hasVideo = tracks.video.any { track -> track.id != -1 }
308
+
309
+ val hasAudioOnly = hasAudio && !hasVideo && length > 0L
310
+ val hasWidthAndHeight = media.width > 0 && media.height > 0
311
+ val hasAudioAndVideo = hasAudio && hasVideo && hasWidthAndHeight && length > 0L
312
+
313
+ val canFirstPlay = hasAudioOnly || hasAudioAndVideo || retryCount == MAX_RETRY_COUNT
314
+
315
+ if (!canFirstPlay && retryCount < MAX_RETRY_COUNT) {
316
+ retryCount++
317
+ postDelayed(::setupFirstPlay, 100L)
318
+ return
319
+ }
320
+
321
+ retryCount = 0
322
+ onFirstPlay(media)
323
+ setContentFit()
324
+ MediaPlayerManager.audioFocusManager.updateAudioFocus()
325
+ }
326
+
302
327
  fun getMediaTracks(): MediaTracks {
303
328
  var mediaTracks = MediaTracks()
304
329
 
@@ -338,18 +363,26 @@ class LibVlcPlayerView(
338
363
  return mediaTracks
339
364
  }
340
365
 
366
+ fun getMediaLength(): Long {
367
+ var length: Long = 0L
368
+
369
+ mediaPlayer?.let { player ->
370
+ val duration = player.getLength()
371
+
372
+ if (duration > 0L) {
373
+ length = duration
374
+ }
375
+ }
376
+
377
+ return length
378
+ }
379
+
341
380
  fun getMediaInfo(): MediaInfo {
342
381
  var mediaInfo = MediaInfo()
343
382
 
344
383
  mediaPlayer?.let { player ->
345
384
  val video = player.getCurrentVideoTrack()
346
- val duration = player.getLength()
347
- val length =
348
- if (duration != -1L) {
349
- duration
350
- } else {
351
- 0L
352
- }
385
+ val length = getMediaLength()
353
386
  val seekable = player.isSeekable()
354
387
 
355
388
  mediaInfo =
@@ -359,13 +392,6 @@ class LibVlcPlayerView(
359
392
  length = length.toDouble(),
360
393
  seekable = seekable,
361
394
  )
362
-
363
- mediaLength =
364
- if (length > 0L) {
365
- length
366
- } else {
367
- null
368
- }
369
395
  }
370
396
 
371
397
  return mediaInfo
@@ -490,8 +516,7 @@ class LibVlcPlayerView(
490
516
  }
491
517
  } else {
492
518
  if (type == "position") {
493
- val length = mediaLength ?: 0L
494
- time = (value * length.toDouble()).toInt()
519
+ time = (value * getMediaLength().toDouble()).toInt()
495
520
  } else {
496
521
  time = value.toInt()
497
522
  }
@@ -518,19 +543,20 @@ class LibVlcPlayerView(
518
543
  fun snapshot(path: String) {
519
544
  mediaPlayer?.let { player ->
520
545
  try {
521
- val textureView = getTextureView() ?: throw Exception()
546
+ val view = getTextureView() ?: throw Exception()
522
547
  val video = player.getCurrentVideoTrack() ?: throw Exception()
523
548
 
524
- val surface = Surface(textureView.surfaceTexture)
525
- val bitmap = Bitmap.createBitmap(video.width, video.height, Bitmap.Config.ARGB_8888)
549
+ val width = video.width?.takeIf { it > 0 } ?: throw Exception()
550
+ val height = video.height?.takeIf { it > 0 } ?: throw Exception()
551
+
552
+ val surface = Surface(view.surfaceTexture)
553
+ val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
526
554
 
527
555
  PixelCopy.request(
528
556
  surface,
529
557
  bitmap,
530
558
  { copyResult ->
531
- if (copyResult != PixelCopy.SUCCESS) {
532
- throw Exception()
533
- }
559
+ if (copyResult != PixelCopy.SUCCESS) throw Exception()
534
560
 
535
561
  val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd-HH'h'mm'm'ss's'")
536
562
  val timestamp = Calendar.getInstance().time
@@ -582,15 +608,15 @@ fun LibVlcPlayerView.setPlayerListener(player: MediaPlayer) {
582
608
  onPlaying(Unit)
583
609
 
584
610
  if (firstPlay) {
585
- onFirstPlay(getMediaInfo())
586
-
587
- attachPlayer()
611
+ setupFirstPlay()
588
612
 
589
613
  setupPlayer()
590
614
 
591
615
  firstPlay = false
592
616
  }
593
617
 
618
+ attachPlayer()
619
+
594
620
  MediaPlayerManager.keepAwakeManager.activateKeepAwake()
595
621
  MediaPlayerManager.audioFocusManager.updateAudioFocus()
596
622
  }
@@ -609,9 +635,6 @@ fun LibVlcPlayerView.setPlayerListener(player: MediaPlayer) {
609
635
 
610
636
  MediaPlayerManager.keepAwakeManager.deactivateKeepAwake()
611
637
  MediaPlayerManager.audioFocusManager.updateAudioFocus()
612
-
613
- firstPlay = true
614
- firstTime = true
615
638
  }
616
639
 
617
640
  Event.EndReached -> {
@@ -632,12 +655,6 @@ fun LibVlcPlayerView.setPlayerListener(player: MediaPlayer) {
632
655
 
633
656
  Event.TimeChanged -> {
634
657
  onTimeChanged(mapOf("time" to player.getTime().toInt()))
635
-
636
- if (firstTime) {
637
- MediaPlayerManager.audioFocusManager.updateAudioFocus()
638
-
639
- firstTime = false
640
- }
641
658
  }
642
659
 
643
660
  Event.PositionChanged -> {
@@ -8,6 +8,8 @@ import UIKit
8
8
 
9
9
  private let dialogCustomUI: Bool = true
10
10
 
11
+ private let maxRetryCount: Int = 10
12
+
11
13
  class LibVlcPlayerView: ExpoView {
12
14
  private let playerView = UIView()
13
15
 
@@ -15,10 +17,10 @@ class LibVlcPlayerView: ExpoView {
15
17
  var vlcDialog: VLCDialogProvider?
16
18
  var vlcDialogRef: NSValue?
17
19
 
18
- var mediaLength: Int32?
19
20
  var oldVolume: Int = MediaPlayerConstants.maxPlayerVolume
21
+
20
22
  var firstPlay: Bool = true
21
- var firstTime: Bool = true
23
+ private var retryCount: Int = 0
22
24
  private var shouldInit: Bool = true
23
25
 
24
26
  let onBuffering = EventDispatcher()
@@ -92,7 +94,6 @@ class LibVlcPlayerView: ExpoView {
92
94
  }
93
95
 
94
96
  firstPlay = true
95
- firstTime = true
96
97
  shouldInit = false
97
98
  }
98
99
 
@@ -137,16 +138,17 @@ class LibVlcPlayerView: ExpoView {
137
138
 
138
139
  func setContentFit() {
139
140
  DispatchQueue.main.async {
140
- let view = self.playerView.frame.size
141
-
141
+ let view = self.playerView
142
142
  var transform: CGAffineTransform = .identity
143
143
 
144
144
  if let player = self.mediaPlayer {
145
145
  let video = player.videoSize
146
+ let width = video.width
147
+ let height = video.height
146
148
 
147
- if video != .zero {
148
- let viewAspect = view.width / view.height
149
- let videoAspect = video.width / video.height
149
+ if width > 0, height > 0 {
150
+ let viewAspect = view.frame.size.width / view.frame.size.height
151
+ let videoAspect = width / height
150
152
 
151
153
  switch self.contentFit {
152
154
  case .contain:
@@ -173,7 +175,7 @@ class LibVlcPlayerView: ExpoView {
173
175
  }
174
176
  }
175
177
 
176
- self.playerView.transform = transform
178
+ view.transform = transform
177
179
  }
178
180
  }
179
181
 
@@ -183,8 +185,6 @@ class LibVlcPlayerView: ExpoView {
183
185
 
184
186
  addPlayerSlaves()
185
187
 
186
- setContentFit()
187
-
188
188
  if scale != MediaPlayerConstants.defaultPlayerScale {
189
189
  player.scaleFactor = scale
190
190
  }
@@ -209,6 +209,46 @@ class LibVlcPlayerView: ExpoView {
209
209
  }
210
210
  }
211
211
 
212
+ func setupFirstPlay() {
213
+ let tracks = getMediaTracks()
214
+ let media = getMediaInfo()
215
+ let length = getMediaLength()
216
+
217
+ let hasAudio = tracks.audio.contains { track in track.id != -1 }
218
+ let hasVideo = tracks.video.contains { track in track.id != -1 }
219
+
220
+ let hasAudioOnly = hasAudio && !hasVideo && length > 0
221
+ let hasWidthAndHeight = media.width > 0 && media.height > 0
222
+ let hasAudioAndVideo = hasAudio && hasVideo && hasWidthAndHeight && length > 0
223
+
224
+ let canFirstPlay = hasAudioOnly || hasAudioAndVideo || retryCount == maxRetryCount
225
+
226
+ if !canFirstPlay, retryCount < maxRetryCount {
227
+ retryCount += 1
228
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in self?.setupFirstPlay() }
229
+ return
230
+ }
231
+
232
+ retryCount = 0
233
+ onFirstPlay(media)
234
+ setContentFit()
235
+ MediaPlayerManager.shared.audioSessionManager.setAppropriateAudioSession()
236
+ }
237
+
238
+ func getMediaLength() -> Int32 {
239
+ var length: Int32 = 0
240
+
241
+ if let player = mediaPlayer, let media = player.media {
242
+ let duration = media.length.intValue
243
+
244
+ if duration > 0 {
245
+ length = duration
246
+ }
247
+ }
248
+
249
+ return length
250
+ }
251
+
212
252
  func getMediaTracks() -> MediaTracks {
213
253
  var mediaTracks = MediaTracks()
214
254
 
@@ -261,7 +301,7 @@ class LibVlcPlayerView: ExpoView {
261
301
 
262
302
  if let player = mediaPlayer {
263
303
  let video = player.videoSize
264
- let length = player.media?.length.intValue ?? 0
304
+ let length = getMediaLength()
265
305
  let seekable = player.isSeekable
266
306
 
267
307
  mediaInfo = MediaInfo(
@@ -270,10 +310,6 @@ class LibVlcPlayerView: ExpoView {
270
310
  length: Double(length),
271
311
  seekable: seekable,
272
312
  )
273
-
274
- mediaLength = length > 0 ?
275
- length :
276
- nil
277
313
  }
278
314
 
279
315
  return mediaInfo
@@ -387,8 +423,7 @@ class LibVlcPlayerView: ExpoView {
387
423
  }
388
424
  } else {
389
425
  if type == "position" {
390
- let length = mediaLength ?? 0
391
- time = Int(value * Double(length))
426
+ time = Int(value * Double(getMediaLength()))
392
427
  } else {
393
428
  time = Int(value)
394
429
  }
@@ -416,13 +451,15 @@ class LibVlcPlayerView: ExpoView {
416
451
  func snapshot(_ path: String) {
417
452
  if let player = mediaPlayer {
418
453
  let video = player.videoSize
454
+ let width = video.width
455
+ let height = video.height
419
456
 
420
- if video != .zero {
457
+ if width > 0, height > 0 {
421
458
  let dateFormatter = DateFormatter()
422
459
  dateFormatter.dateFormat = "yyyy-MM-dd-HH'h'mm'm'ss's'"
423
460
  let snapshotPath = path + "/vlc-snapshot-\(dateFormatter.string(from: Date())).jpg"
424
461
 
425
- player.saveVideoSnapshot(at: snapshotPath, withWidth: Int32(video.width), andHeight: Int32(video.height))
462
+ player.saveVideoSnapshot(at: snapshotPath, withWidth: Int32(width), andHeight: Int32(height))
426
463
 
427
464
  onSnapshotTaken(["path": snapshotPath])
428
465
  } else {
@@ -457,7 +494,7 @@ extension LibVlcPlayerView: VLCMediaPlayerDelegate {
457
494
  onPlaying()
458
495
 
459
496
  if firstPlay {
460
- onFirstPlay(getMediaInfo())
497
+ setupFirstPlay()
461
498
 
462
499
  setupPlayer()
463
500
 
@@ -476,9 +513,6 @@ extension LibVlcPlayerView: VLCMediaPlayerDelegate {
476
513
 
477
514
  MediaPlayerManager.shared.keepAwakeManager.deactivateKeepAwake()
478
515
  MediaPlayerManager.shared.audioSessionManager.setAppropriateAudioSession()
479
-
480
- firstPlay = true
481
- firstTime = true
482
516
  case .ended:
483
517
  onEndReached()
484
518
 
@@ -503,12 +537,6 @@ extension LibVlcPlayerView: VLCMediaPlayerDelegate {
503
537
  if let player = mediaPlayer {
504
538
  onTimeChanged(["time": player.time.intValue])
505
539
 
506
- if firstTime {
507
- MediaPlayerManager.shared.audioSessionManager.setAppropriateAudioSession()
508
-
509
- firstTime = false
510
- }
511
-
512
540
  onPositionChanged(["position": player.position])
513
541
  }
514
542
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-libvlc-player",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "LibVLC Player for Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",