expo-libvlc-player 3.2.3 → 3.2.5

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/README.md CHANGED
@@ -43,34 +43,10 @@ For bare React Native projects, you must ensure that you have [installed and con
43
43
 
44
44
  No additional configuration necessary.
45
45
 
46
- #### Black screen issue
47
-
48
- On Android, the `libvlcjni` player detaches from the View when surfaces are destroyed after switching screens.
49
-
50
- The current workaround attaches the View once surfaces are created but this results in a brief black screen.
51
-
52
- https://code.videolan.org/videolan/vlc-android/-/issues/1495
53
-
54
46
  ### Configure for iOS
55
47
 
56
48
  Run `npx pod-install` after installing the npm package.
57
49
 
58
- #### Local network privacy
59
-
60
- On iOS, the `VLCKit` player seems to interact with the local network when playing media from external sources.
61
-
62
- Starting in iOS 14, a clear message must be provided to the `NSLocalNetworkUsageDescription` key in the Info.plist file.
63
-
64
- https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy
65
-
66
- #### Audio playback issue
67
-
68
- On iOS, the `VLCKit` player experiences a small audio delay when resuming or muting media playback.
69
-
70
- This might be related to the internal clock used by the library core causing inaccurate time values.
71
-
72
- https://code.videolan.org/videolan/VLCKit/-/issues/233
73
-
74
50
  ### Configure for TV
75
51
 
76
52
  Set the `EXPO_TV` environment variable, and run prebuild to make the TV modifications to the project.
@@ -268,6 +244,32 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
268
244
  }
269
245
  ```
270
246
 
247
+ ## Known issues
248
+
249
+ #### Black screen
250
+
251
+ On Android, the `libvlcjni` player detaches from the View when its surface is destroyed after switching screens.
252
+
253
+ The current workaround attaches the View once a surface is created but this causes a brief black screen.
254
+
255
+ https://code.videolan.org/videolan/vlc-android/-/issues/1495
256
+
257
+ #### Local network
258
+
259
+ On iOS, the `VLCKit` player seems to interact with the local network when playing media from external sources.
260
+
261
+ A clear message must be provided to the `NSLocalNetworkUsageDescription` key in the Info.plist file.
262
+
263
+ https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy
264
+
265
+ #### Audio delay
266
+
267
+ On iOS, the `VLCKit` player experiences a small audio delay when resuming or muting media playback.
268
+
269
+ This might be related to the internal clock used by the library core causing inaccurate time values.
270
+
271
+ https://code.videolan.org/videolan/VLCKit/-/issues/233
272
+
271
273
  ## Disclaimer
272
274
 
273
275
  This project is not affiliated with, endorsed by, or officially supported by VideoLAN. The VLC icon is trademark of VideoLAN and is used here solely to indicate compatibility with the following **LibVLC** bindings:
@@ -1,7 +1,7 @@
1
1
  apply plugin: "com.android.library"
2
2
 
3
3
  group = "expo.modules.libvlcplayer"
4
- version = "3.2.3"
4
+ version = "3.2.5"
5
5
 
6
6
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
7
  apply from: expoModulesCorePlugin
@@ -27,7 +27,7 @@ android {
27
27
  namespace "expo.modules.libvlcplayer"
28
28
  defaultConfig {
29
29
  versionCode 1
30
- versionName "3.2.3"
30
+ versionName "3.2.5"
31
31
  consumerProguardFiles("proguard-rules.pro")
32
32
  }
33
33
  lintOptions {
@@ -55,33 +55,33 @@ class LibVlcPlayerView(
55
55
  addView(it)
56
56
  }
57
57
 
58
- internal var libVLC: LibVLC? = null
59
- internal var mediaPlayer: MediaPlayer? = null
58
+ var libVLC: LibVLC? = null
59
+ var mediaPlayer: MediaPlayer? = null
60
60
  private var media: Media? = null
61
- internal var vlcDialog: VLCDialog? = null
61
+ var vlcDialog: VLCDialog? = null
62
62
 
63
- internal var mediaLength: Long = 0L
64
- internal var oldVolume: Int = MAX_PLAYER_VOLUME
63
+ var mediaLength: Long = 0L
64
+ var oldVolume: Int = MAX_PLAYER_VOLUME
65
65
 
66
66
  private var shouldCreate: Boolean = false
67
- internal var firstPlay: Boolean = false
68
- internal var firstTime: Boolean = false
69
-
70
- internal val onBuffering by EventDispatcher<Unit>()
71
- internal val onPlaying by EventDispatcher<Unit>()
72
- internal val onPaused by EventDispatcher<Unit>()
73
- internal val onStopped by EventDispatcher<Unit>()
74
- internal val onEndReached by EventDispatcher<Unit>()
75
- internal val onEncounteredError by EventDispatcher()
76
- internal val onDialogDisplay by EventDispatcher<Dialog>()
77
- internal val onTimeChanged by EventDispatcher()
78
- internal val onPositionChanged by EventDispatcher()
79
- internal val onESAdded by EventDispatcher<MediaTracks>()
80
- internal val onRecordChanged by EventDispatcher<Recording>()
81
- internal val onSnapshotTaken by EventDispatcher()
82
- internal val onFirstPlay by EventDispatcher<MediaInfo>()
83
- internal val onForeground by EventDispatcher<Unit>()
84
- internal val onBackground by EventDispatcher<Unit>()
67
+ var firstPlay: Boolean = false
68
+ var firstTime: Boolean = false
69
+
70
+ val onBuffering by EventDispatcher<Unit>()
71
+ val onPlaying by EventDispatcher<Unit>()
72
+ val onPaused by EventDispatcher<Unit>()
73
+ val onStopped by EventDispatcher<Unit>()
74
+ val onEndReached by EventDispatcher<Unit>()
75
+ val onEncounteredError by EventDispatcher()
76
+ val onDialogDisplay by EventDispatcher<Dialog>()
77
+ val onTimeChanged by EventDispatcher()
78
+ val onPositionChanged by EventDispatcher()
79
+ val onESAdded by EventDispatcher<MediaTracks>()
80
+ val onRecordChanged by EventDispatcher<Recording>()
81
+ val onSnapshotTaken by EventDispatcher()
82
+ val onFirstPlay by EventDispatcher<MediaInfo>()
83
+ val onForeground by EventDispatcher<Unit>()
84
+ val onBackground by EventDispatcher<Unit>()
85
85
 
86
86
  init {
87
87
  MediaPlayerManager.registerPlayerView(this)
@@ -99,6 +99,8 @@ class LibVlcPlayerView(
99
99
  detachPlayer()
100
100
  }
101
101
 
102
+ fun getTextureView(): TextureView? = playerView.findViewById(org.videolan.R.id.texture_video)
103
+
102
104
  fun createPlayer() {
103
105
  if (!shouldCreate) {
104
106
  return
@@ -205,50 +207,53 @@ class LibVlcPlayerView(
205
207
 
206
208
  fun setContentFit() {
207
209
  mediaPlayer?.let { player ->
208
- val textureView = playerView.findViewById<TextureView>(org.videolan.R.id.texture_video) ?: return
209
- val video = player.getCurrentVideoTrack() ?: return
210
+ val textureView = getTextureView() ?: return
210
211
 
211
- val viewWidth = playerView.width.toFloat()
212
- val viewHeight = playerView.height.toFloat()
212
+ val matrix = Matrix()
213
213
 
214
- val videoWidth = video.width.toFloat()
215
- val videoHeight = video.height.toFloat()
214
+ val video = player.getCurrentVideoTrack()
216
215
 
217
- val viewAspect = viewWidth / viewHeight
218
- val videoAspect = videoWidth / videoHeight
216
+ if (video != null) {
217
+ val viewWidth = playerView.width.toFloat()
218
+ val viewHeight = playerView.height.toFloat()
219
219
 
220
- val pivotX = viewWidth / 2f
221
- val pivotY = viewHeight / 2f
220
+ val videoWidth = video.width.toFloat()
221
+ val videoHeight = video.height.toFloat()
222
222
 
223
- val matrix = Matrix()
223
+ val viewAspect = viewWidth / viewHeight
224
+ val videoAspect = videoWidth / videoHeight
224
225
 
225
- when (contentFit) {
226
- VideoContentFit.CONTAIN -> {
227
- // No scale required
228
- }
226
+ val pivotX = viewWidth / 2f
227
+ val pivotY = viewHeight / 2f
228
+
229
+ when (contentFit) {
230
+ VideoContentFit.CONTAIN -> {
231
+ // No scale required
232
+ }
233
+
234
+ VideoContentFit.COVER -> {
235
+ val scale =
236
+ if (videoAspect > viewAspect) {
237
+ videoAspect / viewAspect
238
+ } else {
239
+ viewAspect / videoAspect
240
+ }
241
+
242
+ matrix.setScale(scale, scale, pivotX, pivotY)
243
+ }
244
+
245
+ VideoContentFit.FILL -> {
246
+ var scaleX = 1f
247
+ var scaleY = 1f
229
248
 
230
- VideoContentFit.COVER -> {
231
- val scale =
232
249
  if (videoAspect > viewAspect) {
233
- videoAspect / viewAspect
250
+ scaleY = videoAspect / viewAspect
234
251
  } else {
235
- viewAspect / videoAspect
252
+ scaleX = viewAspect / videoAspect
236
253
  }
237
254
 
238
- matrix.setScale(scale, scale, pivotX, pivotY)
239
- }
240
-
241
- VideoContentFit.FILL -> {
242
- var scaleX = 1f
243
- var scaleY = 1f
244
-
245
- if (videoAspect > viewAspect) {
246
- scaleY = videoAspect / viewAspect
247
- } else {
248
- scaleX = viewAspect / videoAspect
255
+ matrix.setScale(scaleX, scaleY, pivotX, pivotY)
249
256
  }
250
-
251
- matrix.setScale(scaleX, scaleY, pivotX, pivotY)
252
257
  }
253
258
  }
254
259
 
@@ -556,7 +561,7 @@ class LibVlcPlayerView(
556
561
  fun snapshot(path: String) {
557
562
  mediaPlayer?.let { player ->
558
563
  try {
559
- val textureView = playerView.findViewById<TextureView>(org.videolan.R.id.texture_video) ?: throw Exception()
564
+ val textureView = getTextureView() ?: throw Exception()
560
565
  val video = player.getCurrentVideoTrack() ?: throw Exception()
561
566
 
562
567
  val surface = Surface(textureView.surfaceTexture)
@@ -620,7 +625,7 @@ class LibVlcPlayerView(
620
625
  return this.any { option -> option in options }
621
626
  }
622
627
 
623
- internal fun ArrayList<String>.hasRepeatOption(): Boolean {
628
+ fun ArrayList<String>.hasRepeatOption(): Boolean {
624
629
  val options =
625
630
  setOf(
626
631
  "--input-repeat=",
@@ -635,7 +640,7 @@ class LibVlcPlayerView(
635
640
  }
636
641
  }
637
642
 
638
- internal fun ArrayList<String>.hasStartPausedOption(): Boolean {
643
+ private fun ArrayList<String>.hasStartPausedOption(): Boolean {
639
644
  val options =
640
645
  setOf(
641
646
  "--start-paused",
@@ -646,7 +651,7 @@ class LibVlcPlayerView(
646
651
  return this.any { option -> option in options }
647
652
  }
648
653
 
649
- internal fun ArrayList<String>.removeStartPausedOption() {
654
+ private fun ArrayList<String>.removeStartPausedOption() {
650
655
  val options =
651
656
  setOf(
652
657
  "--start-paused",
@@ -7,7 +7,7 @@ import java.lang.ref.WeakReference
7
7
  object MediaPlayerManager {
8
8
  lateinit var audioFocusManager: AudioFocusManager
9
9
 
10
- internal var playerViews: MutableList<WeakReference<LibVlcPlayerView>> = mutableListOf()
10
+ var playerViews: MutableList<WeakReference<LibVlcPlayerView>> = mutableListOf()
11
11
 
12
12
  fun registerPlayerView(view: LibVlcPlayerView) {
13
13
  playerViews.find { it.get() == view } ?: run { playerViews.add(WeakReference(view)) }
@@ -145,35 +145,37 @@ class LibVlcPlayerView: ExpoView {
145
145
 
146
146
  func setContentFit() {
147
147
  if let player = mediaPlayer {
148
+ var transform: CGAffineTransform = .identity
149
+
148
150
  let view = playerView.bounds.size
149
151
  let video = player.videoSize
150
152
 
151
- let viewAspect = view.width / view.height
152
- let videoAspect = video.width / video.height
153
-
154
- var transform: CGAffineTransform = .identity
153
+ if video != .zero {
154
+ let viewAspect = view.width / view.height
155
+ let videoAspect = video.width / video.height
156
+
157
+ switch contentFit {
158
+ case .contain:
159
+ // No transform required
160
+ break
161
+ case .cover:
162
+ let scale = videoAspect > viewAspect ?
163
+ videoAspect / viewAspect :
164
+ viewAspect / videoAspect
165
+
166
+ transform = CGAffineTransform(scaleX: scale, y: scale)
167
+ case .fill:
168
+ var scaleX = 1.0
169
+ var scaleY = 1.0
170
+
171
+ if videoAspect > viewAspect {
172
+ scaleY = videoAspect / viewAspect
173
+ } else {
174
+ scaleX = viewAspect / videoAspect
175
+ }
155
176
 
156
- switch contentFit {
157
- case .contain:
158
- // No transform required
159
- break
160
- case .cover:
161
- var scale = videoAspect > viewAspect ?
162
- videoAspect / viewAspect :
163
- viewAspect / videoAspect
164
-
165
- transform = CGAffineTransform(scaleX: scale, y: scale)
166
- case .fill:
167
- var scaleX = 1.0
168
- var scaleY = 1.0
169
-
170
- if videoAspect > viewAspect {
171
- scaleY = videoAspect / viewAspect
172
- } else {
173
- scaleX = viewAspect / videoAspect
177
+ transform = CGAffineTransform(scaleX: scaleX, y: scaleY)
174
178
  }
175
-
176
- transform = CGAffineTransform(scaleX: scaleX, y: scaleY)
177
179
  }
178
180
 
179
181
  playerView.transform = transform
@@ -188,9 +190,8 @@ class LibVlcPlayerView: ExpoView {
188
190
 
189
191
  if let audios = player.audioTrackNames as? [String] {
190
192
  if let audioIndexes = player.audioTrackIndexes as? [NSNumber] {
191
- for (index, trackName) in audios.enumerated() {
192
- let trackId = audioIndexes[index].intValue
193
- let track = Track(id: trackId, name: trackName)
193
+ for (index, trackName) in zip(audioIndexes, audios) {
194
+ let track = Track(id: index.intValue, name: trackName)
194
195
  audioTracks.append(track)
195
196
  }
196
197
  }
@@ -200,9 +201,8 @@ class LibVlcPlayerView: ExpoView {
200
201
 
201
202
  if let videos = player.videoTrackNames as? [String] {
202
203
  if let videoIndexes = player.videoTrackIndexes as? [NSNumber] {
203
- for (index, trackName) in videos.enumerated() {
204
- let trackId = videoIndexes[index].intValue
205
- let track = Track(id: trackId, name: trackName)
204
+ for (index, trackName) in zip(videoIndexes, videos) {
205
+ let track = Track(id: index.intValue, name: trackName)
206
206
  videoTracks.append(track)
207
207
  }
208
208
  }
@@ -212,9 +212,8 @@ class LibVlcPlayerView: ExpoView {
212
212
 
213
213
  if let subtitles = player.videoSubTitlesNames as? [String] {
214
214
  if let subtitleIndexes = player.videoSubTitlesIndexes as? [NSNumber] {
215
- for (index, trackName) in subtitles.enumerated() {
216
- let trackId = subtitleIndexes[index].intValue
217
- let track = Track(id: trackId, name: trackName)
215
+ for (index, trackName) in zip(subtitleIndexes, subtitles) {
216
+ let track = Track(id: index.intValue, name: trackName)
218
217
  subtitleTracks.append(track)
219
218
  }
220
219
  }
@@ -536,7 +535,7 @@ extension Array where Element == String {
536
535
  }
537
536
  }
538
537
 
539
- extension Array where Element == String {
538
+ private extension Array where Element == String {
540
539
  func hasStartPausedOption() -> Bool {
541
540
  let options = [
542
541
  "--start-paused",
@@ -548,7 +547,7 @@ extension Array where Element == String {
548
547
  }
549
548
  }
550
549
 
551
- extension Array where Element == String {
550
+ private extension Array where Element == String {
552
551
  mutating func removeStartPausedOption() {
553
552
  let options = [
554
553
  "--start-paused",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-libvlc-player",
3
- "version": "3.2.3",
3
+ "version": "3.2.5",
4
4
  "description": "LibVLC Player for Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  "@eslint/js": "^9.30.0",
36
36
  "@types/react": "~19.0.0",
37
37
  "eslint": "^9.30.0",
38
- "expo": "~53.0.26",
38
+ "expo": "~53.0.27",
39
39
  "expo-module-scripts": "^4.1.6",
40
40
  "globals": "^16.2.0",
41
41
  "husky": "^9.1.7",