expo-libvlc-player 6.1.16 → 6.1.18
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 +6 -8
- package/android/src/main/java/expo/modules/libvlcplayer/LibVlcPlayerView.kt +58 -66
- package/ios/LibVlcPlayerView.swift +25 -24
- package/ios/Utils/MediaPlayerDrawable.swift +2 -2
- package/ios/Utils/PictureInPictureDrawable.swift +0 -1
- package/package.json +2 -2
- package/tsconfig.json +1 -0
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<i>Screenshots taken from the <a href="example/App.tsx">Example App</a> on Android and iOS</i>
|
|
20
20
|
</p>
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
#### Supported versions
|
|
23
23
|
|
|
24
24
|
| Platform | Version |
|
|
25
25
|
| -------------------- | ------- |
|
|
@@ -27,9 +27,7 @@
|
|
|
27
27
|
| Android / Android TV | 7+ |
|
|
28
28
|
| iOS / Apple TV | 15.1+ |
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Add the package to your npm dependencies.
|
|
30
|
+
## Installation
|
|
33
31
|
|
|
34
32
|
```
|
|
35
33
|
npm install expo-libvlc-player
|
|
@@ -143,8 +141,8 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
|
|
|
143
141
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
|
144
142
|
| `source` | Sets the source of the media to be played. Set to `null` to release the player | |
|
|
145
143
|
| `options` | Sets the VLC options to initialize the player with. See the [VLC Wiki](https://wiki.videolan.org/VLC_command-line_help/) for more | `[]` |
|
|
146
|
-
| `tracks` | Sets the player audio, video and subtitle tracks
|
|
147
|
-
| `slaves` | Sets the player audio and subtitle slaves
|
|
144
|
+
| `tracks` | Sets the player audio, video and subtitle tracks. See [`Tracks`](#tracks) for more | `undefined` |
|
|
145
|
+
| `slaves` | Sets the player audio and subtitle slaves. See [`Slave`](#slave) for more | `[]` |
|
|
148
146
|
| `scale` | Sets the player scaling factor. Must be a float equal or greater than `0` | `0` |
|
|
149
147
|
| `aspectRatio` | Sets the container aspect ratio. Must be a valid ratio string, number or `"auto"` | `undefined` |
|
|
150
148
|
| `contentFit` | Sets how the video should be scaled to fit in the container | `"contain"` |
|
|
@@ -157,7 +155,7 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
|
|
|
157
155
|
| `autoplay` | Determines whether the media should autoplay once created | `true` |
|
|
158
156
|
| `pictureInPicture` | Determines whether the player should allow Picture-in-Picture (PiP) mode | `false` |
|
|
159
157
|
|
|
160
|
-
####
|
|
158
|
+
#### Callback props
|
|
161
159
|
|
|
162
160
|
| Prop | Description | Payload |
|
|
163
161
|
| ------------------------- | ------------------------------------------------------------ | ----------------------------- |
|
|
@@ -178,7 +176,7 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
|
|
|
178
176
|
| `onPictureInPictureStart` | Called after the player enters Picture-in-Picture (PiP) mode | |
|
|
179
177
|
| `onPictureInPictureStop` | Called after the player exits Picture-in-Picture (PiP) mode | |
|
|
180
178
|
|
|
181
|
-
###
|
|
179
|
+
### Module types
|
|
182
180
|
|
|
183
181
|
#### `Tracks`
|
|
184
182
|
|
|
@@ -112,48 +112,20 @@ class LibVlcPlayerView(
|
|
|
112
112
|
|
|
113
113
|
fun getTextureView(layout: VLCVideoLayout): TextureView? = layout.findViewById(org.videolan.R.id.texture_video)
|
|
114
114
|
|
|
115
|
-
fun
|
|
116
|
-
|
|
117
|
-
destroyPlayer()
|
|
115
|
+
fun addPlayerLayout(view: VLCVideoLayout) {
|
|
116
|
+
val parent = playerLayout.parent as? ViewGroup
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
118
|
+
if (parent == null) {
|
|
119
|
+
addView(view)
|
|
122
120
|
}
|
|
123
121
|
}
|
|
124
122
|
|
|
125
|
-
fun
|
|
126
|
-
|
|
127
|
-
args.toggleStartPausedOption(autoplay)
|
|
128
|
-
|
|
129
|
-
if (pictureInPicture) {
|
|
130
|
-
MediaPlayerManager.pictureInPictureManager.setupPipView(this)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
libVLC = LibVLC(context, args)
|
|
134
|
-
setDialogCallbacks(libVLC!!)
|
|
135
|
-
|
|
136
|
-
mediaPlayer = MediaPlayer(libVLC!!)
|
|
137
|
-
attachPlayerLayout(playerLayout)
|
|
138
|
-
setPlayerListener(mediaPlayer!!)
|
|
139
|
-
setupPlayer()
|
|
123
|
+
fun removePlayerLayout() {
|
|
124
|
+
val parent = playerLayout.parent as? ViewGroup
|
|
140
125
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
} catch (_: Exception) {
|
|
144
|
-
onEncounteredError(mapOf("error" to "Invalid source, media could not be set"))
|
|
145
|
-
return
|
|
126
|
+
if (parent != null) {
|
|
127
|
+
removeView(playerLayout)
|
|
146
128
|
}
|
|
147
|
-
|
|
148
|
-
val media = Media(libVLC!!, Uri.parse(source!!))
|
|
149
|
-
mediaPlayer!!.setMedia(media)
|
|
150
|
-
media.release()
|
|
151
|
-
mediaPlayer!!.play()
|
|
152
|
-
|
|
153
|
-
firstPlay = true
|
|
154
|
-
shouldInit = false
|
|
155
|
-
|
|
156
|
-
addPlayerLayout(playerLayout)
|
|
157
129
|
}
|
|
158
130
|
|
|
159
131
|
fun resetPlayer() {
|
|
@@ -191,20 +163,48 @@ class LibVlcPlayerView(
|
|
|
191
163
|
}
|
|
192
164
|
}
|
|
193
165
|
|
|
194
|
-
fun
|
|
195
|
-
|
|
166
|
+
fun initPlayer() {
|
|
167
|
+
if (shouldInit) {
|
|
168
|
+
destroyPlayer()
|
|
196
169
|
|
|
197
|
-
|
|
198
|
-
|
|
170
|
+
if (source != null) {
|
|
171
|
+
createPlayer()
|
|
172
|
+
}
|
|
199
173
|
}
|
|
200
174
|
}
|
|
201
175
|
|
|
202
|
-
fun
|
|
203
|
-
|
|
176
|
+
fun createPlayer() {
|
|
177
|
+
var args = options
|
|
178
|
+
args.toggleStartPausedOption(autoplay)
|
|
204
179
|
|
|
205
|
-
if (
|
|
206
|
-
|
|
180
|
+
if (pictureInPicture) {
|
|
181
|
+
MediaPlayerManager.pictureInPictureManager.setupPipView(this)
|
|
207
182
|
}
|
|
183
|
+
|
|
184
|
+
libVLC = LibVLC(context, args)
|
|
185
|
+
setDialogCallbacks(libVLC!!)
|
|
186
|
+
|
|
187
|
+
mediaPlayer = MediaPlayer(libVLC!!)
|
|
188
|
+
attachPlayerLayout(playerLayout)
|
|
189
|
+
setPlayerListener(mediaPlayer!!)
|
|
190
|
+
setupPlayer()
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
URI(source)
|
|
194
|
+
} catch (_: Exception) {
|
|
195
|
+
onEncounteredError(mapOf("error" to "Invalid source, media could not be set"))
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
val media = Media(libVLC!!, Uri.parse(source!!))
|
|
200
|
+
mediaPlayer!!.setMedia(media)
|
|
201
|
+
media.release()
|
|
202
|
+
mediaPlayer!!.play()
|
|
203
|
+
|
|
204
|
+
firstPlay = true
|
|
205
|
+
shouldInit = false
|
|
206
|
+
|
|
207
|
+
addPlayerLayout(playerLayout)
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
fun destroyPlayer() {
|
|
@@ -277,7 +277,7 @@ class LibVlcPlayerView(
|
|
|
277
277
|
try {
|
|
278
278
|
URI(source)
|
|
279
279
|
} catch (_: Exception) {
|
|
280
|
-
onEncounteredError(mapOf("error" to "Invalid
|
|
280
|
+
onEncounteredError(mapOf("error" to "Invalid source, $type could not be added"))
|
|
281
281
|
return@forEach
|
|
282
282
|
}
|
|
283
283
|
|
|
@@ -444,11 +444,7 @@ class LibVlcPlayerView(
|
|
|
444
444
|
|
|
445
445
|
fun getVideoSize(): Size {
|
|
446
446
|
val video = mediaPlayer?.getCurrentVideoTrack()
|
|
447
|
-
|
|
448
|
-
if (video != null) {
|
|
449
|
-
return Size(video.width, video.height)
|
|
450
|
-
}
|
|
451
|
-
|
|
447
|
+
if (video != null) return Size(video.width, video.height)
|
|
452
448
|
return Size(0, 0)
|
|
453
449
|
}
|
|
454
450
|
|
|
@@ -642,8 +638,6 @@ class LibVlcPlayerView(
|
|
|
642
638
|
|
|
643
639
|
if (!success) {
|
|
644
640
|
onEncounteredError(mapOf("error" to "Media could not be recorded"))
|
|
645
|
-
|
|
646
|
-
player.record(null)
|
|
647
641
|
}
|
|
648
642
|
} else {
|
|
649
643
|
player.record(null)
|
|
@@ -665,12 +659,9 @@ class LibVlcPlayerView(
|
|
|
665
659
|
surface,
|
|
666
660
|
bitmap,
|
|
667
661
|
{ copyResult ->
|
|
668
|
-
if (copyResult != PixelCopy.SUCCESS) {
|
|
669
|
-
onEncounteredError(mapOf("error" to "Snapshot could not be taken"))
|
|
670
|
-
return@request
|
|
671
|
-
}
|
|
672
|
-
|
|
673
662
|
try {
|
|
663
|
+
if (copyResult != PixelCopy.SUCCESS) throw Exception()
|
|
664
|
+
|
|
674
665
|
val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd-HH'h'mm'm'ss's'")
|
|
675
666
|
val timestamp = simpleDateFormat.format(Calendar.getInstance().time)
|
|
676
667
|
|
|
@@ -781,6 +772,14 @@ fun LibVlcPlayerView.setPlayerListener(mediaPlayer: MediaPlayer?) {
|
|
|
781
772
|
return@retryUntil hasVideoSize
|
|
782
773
|
}
|
|
783
774
|
|
|
775
|
+
retryUntil { isLastAttempt ->
|
|
776
|
+
if (hasAudioOut) {
|
|
777
|
+
MediaPlayerManager.audioFocusManager.updateAudioFocus()
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return@retryUntil hasAudioOut
|
|
781
|
+
}
|
|
782
|
+
|
|
784
783
|
firstPlay = false
|
|
785
784
|
}
|
|
786
785
|
}
|
|
@@ -801,16 +800,9 @@ fun LibVlcPlayerView.setPlayerListener(mediaPlayer: MediaPlayer?) {
|
|
|
801
800
|
}
|
|
802
801
|
}
|
|
803
802
|
|
|
804
|
-
MediaPlayerManager.pictureInPictureManager.setPipActions()
|
|
805
803
|
MediaPlayerManager.keepAwakeManager.toggleKeepAwake()
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (hasAudioOut) {
|
|
809
|
-
MediaPlayerManager.audioFocusManager.updateAudioFocus()
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
return@retryUntil hasAudioOut
|
|
813
|
-
}
|
|
804
|
+
MediaPlayerManager.audioFocusManager.updateAudioFocus()
|
|
805
|
+
MediaPlayerManager.pictureInPictureManager.setPipActions()
|
|
814
806
|
}
|
|
815
807
|
|
|
816
808
|
Event.EndReached -> {
|
|
@@ -167,7 +167,7 @@ class LibVlcPlayerView: ExpoView {
|
|
|
167
167
|
let selected = slave.selected ?? false
|
|
168
168
|
|
|
169
169
|
guard let url = URL(string: source) else {
|
|
170
|
-
onEncounteredError(["error": "Invalid
|
|
170
|
+
onEncounteredError(["error": "Invalid source, \(type) could not be added"])
|
|
171
171
|
continue
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -247,18 +247,6 @@ class LibVlcPlayerView: ExpoView {
|
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
func getMediaLength() -> Int32 {
|
|
251
|
-
var length: Int32 = 0
|
|
252
|
-
|
|
253
|
-
let duration = mediaPlayer?.media?.length.intValue ?? 0
|
|
254
|
-
|
|
255
|
-
if duration > 0 {
|
|
256
|
-
length = duration
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return length
|
|
260
|
-
}
|
|
261
|
-
|
|
262
250
|
func getMediaTracks() -> MediaTracks {
|
|
263
251
|
var mediaTracks = MediaTracks()
|
|
264
252
|
|
|
@@ -291,6 +279,18 @@ class LibVlcPlayerView: ExpoView {
|
|
|
291
279
|
return mediaTracks
|
|
292
280
|
}
|
|
293
281
|
|
|
282
|
+
func getMediaLength() -> Int32 {
|
|
283
|
+
var length: Int32 = 0
|
|
284
|
+
|
|
285
|
+
let duration = mediaPlayer?.media?.length.intValue ?? 0
|
|
286
|
+
|
|
287
|
+
if duration > 0 {
|
|
288
|
+
length = duration
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return length
|
|
292
|
+
}
|
|
293
|
+
|
|
294
294
|
func getMediaInfo() -> MediaInfo {
|
|
295
295
|
var mediaInfo = MediaInfo()
|
|
296
296
|
|
|
@@ -613,6 +613,16 @@ extension LibVlcPlayerView: VLCMediaPlayerDelegate {
|
|
|
613
613
|
return hasVideoSize
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
+
retryUntil { [weak self] _ in
|
|
617
|
+
guard let self else { return true }
|
|
618
|
+
|
|
619
|
+
if hasAudioOut {
|
|
620
|
+
MediaPlayerManager.shared.audioSessionManager.setAppropriateAudioSession()
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return hasAudioOut
|
|
624
|
+
}
|
|
625
|
+
|
|
616
626
|
firstPlay = false
|
|
617
627
|
}
|
|
618
628
|
}
|
|
@@ -631,18 +641,9 @@ extension LibVlcPlayerView: VLCMediaPlayerDelegate {
|
|
|
631
641
|
}
|
|
632
642
|
}
|
|
633
643
|
|
|
634
|
-
pictureDrawable.updatePipState()
|
|
635
644
|
MediaPlayerManager.shared.keepAwakeManager.toggleKeepAwake()
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
guard let self else { return true }
|
|
639
|
-
|
|
640
|
-
if hasAudioOut {
|
|
641
|
-
MediaPlayerManager.shared.audioSessionManager.setAppropriateAudioSession()
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
return hasAudioOut
|
|
645
|
-
}
|
|
645
|
+
MediaPlayerManager.shared.audioSessionManager.setAppropriateAudioSession()
|
|
646
|
+
pictureDrawable.updatePipState()
|
|
646
647
|
case .error:
|
|
647
648
|
onEncounteredError(["error": "Player encountered an error"])
|
|
648
649
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
class MediaPlayerDrawable: UIView {
|
|
2
2
|
init() {
|
|
3
3
|
super.init(frame: .zero)
|
|
4
|
-
isUserInteractionEnabled = false
|
|
5
|
-
autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
6
4
|
backgroundColor = .black
|
|
5
|
+
autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
6
|
+
isUserInteractionEnabled = false
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
@available(*, unavailable)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-libvlc-player",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.18",
|
|
4
4
|
"description": "LibVLC Player for Expo",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@eslint/js": "^9.39.4",
|
|
40
40
|
"@types/react": "~19.2.10",
|
|
41
41
|
"eslint": "^9.39.4",
|
|
42
|
-
"expo": "~55.0.
|
|
42
|
+
"expo": "~55.0.13",
|
|
43
43
|
"expo-module-scripts": "^55.0.2",
|
|
44
44
|
"globals": "^16.5.0",
|
|
45
45
|
"husky": "^9.1.7",
|