expo-libvlc-player 7.0.12 → 7.0.13
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 +53 -53
- package/android/src/main/java/expo/modules/libvlcplayer/LibVlcPlayerView.kt +6 -5
- package/android/src/main/java/expo/modules/libvlcplayer/constants/MediaPlayerConstants.kt +2 -1
- package/ios/Constants/MediaPlayerConstants.swift +2 -1
- package/ios/LibVlcPlayerView.swift +12 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -120,19 +120,19 @@ See the [Example App](example/App.tsx) for additional usage.
|
|
|
120
120
|
|
|
121
121
|
### View methods
|
|
122
122
|
|
|
123
|
-
| Method | Description
|
|
124
|
-
| ---------------------------------------------------------------- |
|
|
125
|
-
| `play()` | Starts playback of the current player
|
|
126
|
-
| `pause()` | Pauses playback of the current player
|
|
127
|
-
| `stop()` | Stops playback of the current player
|
|
128
|
-
| `seek(value: number, type?: "time" \| "position")` | Sets the time or position of the current player. Value must be a number equal or greater than `0` and type defaults to `"time"`
|
|
129
|
-
| `record(path?: string)` | Starts or stops recording the current media. Path must be a valid directory or `undefined` to stop recording
|
|
130
|
-
| `snapshot(path: string)` | Takes a snapshot of the current media. Path must be a valid directory
|
|
131
|
-
| `postAction(action: 1 \| 2)` | Posts an answer to a
|
|
132
|
-
| `postLogin(username: string, password: string, store?: boolean)` | Posts a username and password to a login
|
|
133
|
-
| `dismiss()` | Dismisses a
|
|
134
|
-
| `startPictureInPicture()` | Enters Picture-in-Picture (PiP) mode. Config plugin has to be configured for Picture-in-Picture (PiP) to work
|
|
135
|
-
| `stopPictureInPicture()` | Exits Picture-in-Picture (PiP) mode on iOS
|
|
123
|
+
| Method | Description | Returns |
|
|
124
|
+
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | --------------- |
|
|
125
|
+
| `play()` | Starts playback of the current player | `Promise<void>` |
|
|
126
|
+
| `pause()` | Pauses playback of the current player | `Promise<void>` |
|
|
127
|
+
| `stop()` | Stops playback of the current player | `Promise<void>` |
|
|
128
|
+
| `seek(value: number, type?: "time" \| "position")` | Sets the time or position of the current player. Value must be a number equal or greater than `0` and type defaults to `"time"` | `Promise<void>` |
|
|
129
|
+
| `record(path?: string)` | Starts or stops recording the current media. Path must be a valid directory or `undefined` to stop recording | `Promise<void>` |
|
|
130
|
+
| `snapshot(path: string)` | Takes a snapshot of the current media. Path must be a valid directory | `Promise<void>` |
|
|
131
|
+
| `postAction(action: 1 \| 2)` | Posts an answer to a dialog. Action must be either `1` or `2` | `Promise<void>` |
|
|
132
|
+
| `postLogin(username: string, password: string, store?: boolean)` | Posts a username and password to a login dialog. Username can't be empty, password can be empty and if `true`, store the credentials | `Promise<void>` |
|
|
133
|
+
| `dismiss()` | Dismisses a dialog | `Promise<void>` |
|
|
134
|
+
| `startPictureInPicture()` | Enters Picture-in-Picture (PiP) mode. Config plugin has to be configured for Picture-in-Picture (PiP) to work | `Promise<void>` |
|
|
135
|
+
| `stopPictureInPicture()` | Exits Picture-in-Picture (PiP) mode on iOS | `Promise<void>` |
|
|
136
136
|
|
|
137
137
|
### View props
|
|
138
138
|
|
|
@@ -165,7 +165,7 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
|
|
|
165
165
|
| `onPaused` | Called after the `Paused` player event | |
|
|
166
166
|
| `onStopped` | Called after the `Stopped` player event | |
|
|
167
167
|
| `onEncounteredError` | Called after the `EncounteredError` player event | [`Error`](#error) |
|
|
168
|
-
| `onDialogDisplay` | Called after a
|
|
168
|
+
| `onDialogDisplay` | Called after a dialog needs to be displayed | [`Dialog`](#dialog) |
|
|
169
169
|
| `onTimeChanged` | Called after the `TimeChanged` player event | [`Time`](#time) |
|
|
170
170
|
| `onPositionChanged` | Called after the `PositionChanged` player event | [`Position`](#position) |
|
|
171
171
|
| `onESAdded` | Called after the `ESAdded` player event | [`MediaTracks`](#mediatracks) |
|
|
@@ -179,38 +179,6 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
|
|
|
179
179
|
|
|
180
180
|
### Module types
|
|
181
181
|
|
|
182
|
-
#### `Error`
|
|
183
|
-
|
|
184
|
-
```ts
|
|
185
|
-
interface Error {
|
|
186
|
-
message: string;
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
#### `Time`
|
|
191
|
-
|
|
192
|
-
```ts
|
|
193
|
-
interface Time {
|
|
194
|
-
value: number;
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
#### `Position`
|
|
199
|
-
|
|
200
|
-
```ts
|
|
201
|
-
interface Position {
|
|
202
|
-
value: number;
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
#### `Snapshot`
|
|
207
|
-
|
|
208
|
-
```ts
|
|
209
|
-
interface Snapshot {
|
|
210
|
-
path: string;
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
182
|
#### `Tracks`
|
|
215
183
|
|
|
216
184
|
```ts
|
|
@@ -231,6 +199,14 @@ interface Slave {
|
|
|
231
199
|
}
|
|
232
200
|
```
|
|
233
201
|
|
|
202
|
+
#### `Error`
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
interface Error {
|
|
206
|
+
message: string;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
234
210
|
#### `Dialog`
|
|
235
211
|
|
|
236
212
|
```ts
|
|
@@ -244,12 +220,19 @@ interface Dialog {
|
|
|
244
220
|
}
|
|
245
221
|
```
|
|
246
222
|
|
|
247
|
-
#### `
|
|
223
|
+
#### `Time`
|
|
248
224
|
|
|
249
225
|
```ts
|
|
250
|
-
interface
|
|
251
|
-
|
|
252
|
-
|
|
226
|
+
interface Time {
|
|
227
|
+
value: number;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### `Position`
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
interface Position {
|
|
235
|
+
value: number;
|
|
253
236
|
}
|
|
254
237
|
```
|
|
255
238
|
|
|
@@ -272,6 +255,23 @@ interface MediaTracks {
|
|
|
272
255
|
}
|
|
273
256
|
```
|
|
274
257
|
|
|
258
|
+
#### `Recording`
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
interface Recording {
|
|
262
|
+
path: string | null;
|
|
263
|
+
isRecording: boolean;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### `Snapshot`
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
interface Snapshot {
|
|
271
|
+
path: string;
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
275
|
#### `MediaInfo`
|
|
276
276
|
|
|
277
277
|
```ts
|
|
@@ -317,7 +317,7 @@ https://developer.apple.com/documentation/technotes/tn3179-understanding-local-n
|
|
|
317
317
|
|
|
318
318
|
## Disclaimer
|
|
319
319
|
|
|
320
|
-
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
|
|
320
|
+
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:
|
|
321
321
|
|
|
322
322
|
- `libvlcjni` for Android / Android TV
|
|
323
323
|
- `VLCKit` for iOS / Apple TV
|
|
@@ -326,11 +326,11 @@ For official VLC products and support, please visit [videolan.org](https://www.v
|
|
|
326
326
|
|
|
327
327
|
## Credits
|
|
328
328
|
|
|
329
|
-
This library is inspired by existing projects such as [
|
|
329
|
+
This library is inspired by existing projects such as [react-native-vlc-media-player](https://github.com/razorRun/react-native-vlc-media-player) and [expo-video](https://github.com/expo/expo/tree/main/packages/expo-video).
|
|
330
330
|
|
|
331
331
|
## Contributing
|
|
332
332
|
|
|
333
|
-
Contributions are always welcome. Please raise any issues
|
|
333
|
+
Contributions are always welcome. Please raise any issues or fix them by creating a pull request.
|
|
334
334
|
|
|
335
335
|
## License
|
|
336
336
|
|
|
@@ -722,18 +722,19 @@ class LibVlcPlayerView(
|
|
|
722
722
|
fun retryUntil(
|
|
723
723
|
maxRetries: Int = MediaPlayerConstants.MAX_RETRY_COUNT,
|
|
724
724
|
retry: Int = 0,
|
|
725
|
-
delay:
|
|
725
|
+
delay: Double = MediaPlayerConstants.RETRY_DELAY_MS,
|
|
726
726
|
block: (isLastAttempt: Boolean) -> Boolean,
|
|
727
727
|
) {
|
|
728
728
|
val isLastAttempt = retry >= maxRetries
|
|
729
729
|
|
|
730
730
|
if (block(isLastAttempt) || isLastAttempt) return
|
|
731
731
|
|
|
732
|
-
val expDelay =
|
|
732
|
+
val expDelay = delay * MediaPlayerConstants.EXP_DELAY_MULTIPLIER
|
|
733
|
+
val postDelay = delay.toLong()
|
|
733
734
|
|
|
734
735
|
postDelayed({
|
|
735
736
|
retryUntil(maxRetries, retry + 1, expDelay, block)
|
|
736
|
-
},
|
|
737
|
+
}, postDelay)
|
|
737
738
|
}
|
|
738
739
|
}
|
|
739
740
|
|
|
@@ -766,7 +767,7 @@ fun LibVlcPlayerView.setPlayerListener(mediaPlayer: MediaPlayer?) {
|
|
|
766
767
|
return@retryUntil hasVideoOut
|
|
767
768
|
}
|
|
768
769
|
|
|
769
|
-
retryUntil {
|
|
770
|
+
retryUntil {
|
|
770
771
|
if (hasVideoSize) {
|
|
771
772
|
setContentFit(layout = playerLayout)
|
|
772
773
|
setContentFit(layout = pictureLayout)
|
|
@@ -775,7 +776,7 @@ fun LibVlcPlayerView.setPlayerListener(mediaPlayer: MediaPlayer?) {
|
|
|
775
776
|
return@retryUntil hasVideoSize
|
|
776
777
|
}
|
|
777
778
|
|
|
778
|
-
retryUntil {
|
|
779
|
+
retryUntil {
|
|
779
780
|
if (hasAudioOut) {
|
|
780
781
|
MediaPlayerManager.audioFocusManager.updateAudioFocus()
|
|
781
782
|
}
|
|
@@ -16,6 +16,7 @@ object MediaPlayerConstants {
|
|
|
16
16
|
const val SEEK_STEP_MS: Long = 10_000L
|
|
17
17
|
|
|
18
18
|
const val COROUTINE_DELAY_MS: Long = 1_000L
|
|
19
|
-
const val
|
|
19
|
+
const val EXP_DELAY_MULTIPLIER: Double = 1.5
|
|
20
|
+
const val RETRY_DELAY_MS: Double = 200.0
|
|
20
21
|
const val MAX_RETRY_COUNT: Int = 5
|
|
21
22
|
}
|
|
@@ -5,6 +5,7 @@ enum MediaPlayerConstants {
|
|
|
5
5
|
static let minPlayerVolume: Int = 0
|
|
6
6
|
static let maxPlayerVolume: Int = 100
|
|
7
7
|
|
|
8
|
-
static let
|
|
8
|
+
static let expDelayMultiplier: Double = 1.5
|
|
9
|
+
static let retryDelayMs: Double = 200.0
|
|
9
10
|
static let maxRetryCount: Int = 5
|
|
10
11
|
}
|
|
@@ -224,7 +224,7 @@ class LibVlcPlayerView: ExpoView {
|
|
|
224
224
|
|
|
225
225
|
if volume != MediaPlayerConstants.maxPlayerVolume || mute {
|
|
226
226
|
// Audio instance not ready, try again
|
|
227
|
-
retryUntil { [weak self]
|
|
227
|
+
retryUntil { [weak self] _ in
|
|
228
228
|
guard let self else { return true }
|
|
229
229
|
|
|
230
230
|
let newVolume = mute ?
|
|
@@ -233,7 +233,7 @@ class LibVlcPlayerView: ExpoView {
|
|
|
233
233
|
|
|
234
234
|
player.audio?.volume = Int32(newVolume)
|
|
235
235
|
|
|
236
|
-
return
|
|
236
|
+
return false
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -480,10 +480,6 @@ class LibVlcPlayerView: ExpoView {
|
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
-
private func snapshotExists(_ path: String) -> Bool {
|
|
484
|
-
FileManager.default.fileExists(atPath: path)
|
|
485
|
-
}
|
|
486
|
-
|
|
487
483
|
func snapshot(_ path: String) {
|
|
488
484
|
if hasVideoSize {
|
|
489
485
|
let dateFormatter = DateFormatter()
|
|
@@ -491,24 +487,16 @@ class LibVlcPlayerView: ExpoView {
|
|
|
491
487
|
let timestamp = dateFormatter.string(from: Date())
|
|
492
488
|
|
|
493
489
|
let snapshotPath = path + "/vlc-snapshot-\(timestamp).jpg"
|
|
494
|
-
let video =
|
|
490
|
+
let video = CGSize(width: 0, height: 0) // Use original window size
|
|
495
491
|
|
|
496
492
|
mediaPlayer?.saveVideoSnapshot(at: snapshotPath, withWidth: Int32(video.width), andHeight: Int32(video.height))
|
|
497
493
|
|
|
498
|
-
|
|
499
|
-
guard let self else { return true }
|
|
500
|
-
|
|
501
|
-
let hasSnapshot = snapshotExists(snapshotPath)
|
|
494
|
+
let fileExists = FileManager.default.fileExists(atPath: snapshotPath)
|
|
502
495
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
} else {
|
|
508
|
-
onEncounteredError(["message": "Snapshot could not be taken"])
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
return hasSnapshot
|
|
496
|
+
if fileExists {
|
|
497
|
+
onSnapshotTaken(["path": snapshotPath])
|
|
498
|
+
} else {
|
|
499
|
+
onEncounteredError(["message": "Snapshot could not be taken"])
|
|
512
500
|
}
|
|
513
501
|
} else {
|
|
514
502
|
onEncounteredError(["message": "Snapshot could not be taken"])
|
|
@@ -566,16 +554,17 @@ class LibVlcPlayerView: ExpoView {
|
|
|
566
554
|
func retryUntil(
|
|
567
555
|
maxRetries: Int = MediaPlayerConstants.maxRetryCount,
|
|
568
556
|
retry: Int = 0,
|
|
569
|
-
delay:
|
|
557
|
+
delay: Double = MediaPlayerConstants.retryDelayMs,
|
|
570
558
|
block: @escaping (_ isLastAttempt: Bool) -> Bool
|
|
571
559
|
) {
|
|
572
560
|
let isLastAttempt = retry >= maxRetries
|
|
573
561
|
|
|
574
562
|
if block(isLastAttempt) || isLastAttempt { return }
|
|
575
563
|
|
|
576
|
-
let
|
|
564
|
+
let deadline = DispatchTime.now() + .milliseconds(Int(delay))
|
|
565
|
+
let expDelay = delay * MediaPlayerConstants.expDelayMultiplier
|
|
577
566
|
|
|
578
|
-
DispatchQueue.main.asyncAfter(deadline:
|
|
567
|
+
DispatchQueue.main.asyncAfter(deadline: deadline) { [weak self] in
|
|
579
568
|
self?.retryUntil(maxRetries: maxRetries, retry: retry + 1, delay: expDelay, block: block)
|
|
580
569
|
}
|
|
581
570
|
}
|