expo-libvlc-player 6.0.1 → 6.1.0
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 +61 -39
- package/android/src/main/java/expo/modules/libvlcplayer/LibVlcPlayerModule.kt +23 -0
- package/android/src/main/java/expo/modules/libvlcplayer/LibVlcPlayerView.kt +60 -15
- package/android/src/main/java/expo/modules/libvlcplayer/constants/MediaPlayerConstants.kt +9 -0
- package/android/src/main/java/expo/modules/libvlcplayer/managers/MediaPlayerManager.kt +8 -0
- package/android/src/main/java/expo/modules/libvlcplayer/managers/PictureInPictureManager.kt +335 -0
- package/android/src/main/java/expo/modules/libvlcplayer/utils/PictureInPictureFragment.kt +27 -0
- package/android/src/main/res/drawable/fast_forward_24px.xml +10 -0
- package/android/src/main/res/drawable/fast_rewind_24px.xml +10 -0
- package/android/src/main/res/drawable/pause_24px.xml +10 -0
- package/android/src/main/res/drawable/play_arrow_24px.xml +10 -0
- package/build/LibVlcPlayer.types.d.ts +41 -0
- package/build/LibVlcPlayer.types.d.ts.map +1 -1
- package/build/LibVlcPlayer.types.js.map +1 -1
- package/build/LibVlcPlayerModule.d.ts +6 -0
- package/build/LibVlcPlayerModule.d.ts.map +1 -1
- package/build/LibVlcPlayerModule.js.map +1 -1
- package/ios/LibVlcPlayerModule.swift +19 -0
- package/ios/LibVlcPlayerView.swift +74 -28
- package/ios/Managers/MediaPlayerManager.swift +3 -1
- package/ios/Utils/MediaPlayerDrawable.swift +12 -0
- package/ios/Utils/PictureInPictureDrawable.swift +111 -0
- package/package.json +1 -1
- package/plugin/build/withExpoLibVlcPlayer.d.ts +1 -0
- package/plugin/build/withExpoLibVlcPlayer.js +28 -1
- package/plugin/src/withExpoLibVlcPlayer.ts +44 -2
- package/src/LibVlcPlayer.types.ts +43 -0
- package/src/LibVlcPlayerModule.ts +6 -0
package/README.md
CHANGED
|
@@ -68,7 +68,8 @@ You can configure `expo-libvlc-player` using its built-in config plugin if you u
|
|
|
68
68
|
[
|
|
69
69
|
"expo-libvlc-player",
|
|
70
70
|
{
|
|
71
|
-
"localNetworkPermission": "Allow $(PRODUCT_NAME) to access your local network"
|
|
71
|
+
"localNetworkPermission": "Allow $(PRODUCT_NAME) to access your local network",
|
|
72
|
+
"supportsPictureInPicture": true
|
|
72
73
|
}
|
|
73
74
|
]
|
|
74
75
|
]
|
|
@@ -78,9 +79,10 @@ You can configure `expo-libvlc-player` using its built-in config plugin if you u
|
|
|
78
79
|
|
|
79
80
|
#### Configurable properties
|
|
80
81
|
|
|
81
|
-
| Name
|
|
82
|
-
|
|
|
83
|
-
| `localNetworkPermission`
|
|
82
|
+
| Name | Description | Default |
|
|
83
|
+
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
84
|
+
| `localNetworkPermission` | A string to set the `NSLocalNetworkUsageDescription` permission message on iOS | `"Allow $(PRODUCT_NAME) to access your local network"` |
|
|
85
|
+
| `supportsPictureInPicture` | A boolean value to enable Picture-in-Picture (PiP) on Android and iOS. If `true`, it adds the `android:supportsPictureInPicture` property on Android and the `audio` key to the `UIBackgroundModes` array in the Info.plist file on iOS. If `false`, it removes the property on Android and the key on iOS. When `undefined`, the configuration is not modified | `undefined` |
|
|
84
86
|
|
|
85
87
|
## Usage
|
|
86
88
|
|
|
@@ -101,13 +103,22 @@ import LibVlcPlayerModule from "expo-libvlc-player";
|
|
|
101
103
|
await LibVlcPlayerModule.triggerNetworkAlert();
|
|
102
104
|
```
|
|
103
105
|
|
|
106
|
+
Check for Picture-in-Picture (PiP) support:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import LibVlcPlayerModule from "expo-libvlc-player";
|
|
110
|
+
|
|
111
|
+
await LibVlcPlayerModule.isPictureInPictureSupported();
|
|
112
|
+
```
|
|
113
|
+
|
|
104
114
|
See the [Example App](example/App.tsx) for additional usage.
|
|
105
115
|
|
|
106
116
|
### Module methods
|
|
107
117
|
|
|
108
|
-
| Method
|
|
109
|
-
|
|
|
110
|
-
| `triggerNetworkAlert()`
|
|
118
|
+
| Method | Description | Returns |
|
|
119
|
+
| ------------------------------- | ----------------------------------------------------------- | --------------- |
|
|
120
|
+
| `triggerNetworkAlert()` | Attempts to trigger the local network privacy alert on iOS | `Promise<void>` |
|
|
121
|
+
| `isPictureInPictureSupported()` | Checks whether the device supports Picture-in-Picture (PiP) | `boolean` |
|
|
111
122
|
|
|
112
123
|
### View methods
|
|
113
124
|
|
|
@@ -121,46 +132,51 @@ See the [Example App](example/App.tsx) for additional usage.
|
|
|
121
132
|
| `snapshot(path: string)` | Takes a snapshot of the current media. Must be a valid path string | `Promise<void>` |
|
|
122
133
|
| `postAction(action: number)` | Posts an answer to a [`Dialog`](#dialog). Must be an integer of `1` or `2` | `Promise<void>` |
|
|
123
134
|
| `dismiss()` | Dismisses a [`Dialog`](#dialog) | `Promise<void>` |
|
|
135
|
+
| `startPictureInPicture()` | Enters Picture-in-Picture (PiP) mode. Config plugin has to be configured for Picture-in-Picture (PiP) to work | `Promise<void>` |
|
|
136
|
+
| `stopPictureInPicture()` | Exits Picture-in-Picture (PiP) mode on iOS | `Promise<void>` |
|
|
124
137
|
|
|
125
138
|
### View props
|
|
126
139
|
|
|
127
140
|
The `LibVlcPlayerView` extends React Native `ViewProps` and implements the following:
|
|
128
141
|
|
|
129
|
-
| Prop
|
|
130
|
-
|
|
|
131
|
-
| `source`
|
|
132
|
-
| `options`
|
|
133
|
-
| `tracks`
|
|
134
|
-
| `slaves`
|
|
135
|
-
| `scale`
|
|
136
|
-
| `aspectRatio`
|
|
137
|
-
| `contentFit`
|
|
138
|
-
| `rate`
|
|
139
|
-
| `time`
|
|
140
|
-
| `volume`
|
|
141
|
-
| `mute`
|
|
142
|
-
| `audioMixingMode`
|
|
143
|
-
| `repeat`
|
|
144
|
-
| `autoplay`
|
|
142
|
+
| Prop | Description | Default |
|
|
143
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
|
144
|
+
| `source` | Sets the source of the media to be played. Set to `null` to release the player | |
|
|
145
|
+
| `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 object. See [`Tracks`](#tracks) for more | `undefined` |
|
|
147
|
+
| `slaves` | Sets the player audio and subtitle slaves array. See [`Slave`](#slave) for more | `[]` |
|
|
148
|
+
| `scale` | Sets the player scaling factor. Must be a float equal or greater than `0` | `0` |
|
|
149
|
+
| `aspectRatio` | Sets the container aspect ratio. Must be a valid ratio string, number or `"auto"` | `undefined` |
|
|
150
|
+
| `contentFit` | Sets how the video should be scaled to fit in the container | `"contain"` |
|
|
151
|
+
| `rate` | Sets the player rate. Must be a float equal or greater than `1` | `1` |
|
|
152
|
+
| `time` | Sets the initial player time. Must be an integer in milliseconds | `0` |
|
|
153
|
+
| `volume` | Sets the player volume. Must be an integer between `0` and `100` | `100` |
|
|
154
|
+
| `mute` | Sets the player volume to `0` when `true`. Previous value is set when `false` | `false` |
|
|
155
|
+
| `audioMixingMode` | Determines how the player will interact with other audio in the system | `"auto"` |
|
|
156
|
+
| `repeat` | Determines whether the media should repeat once ended | `false` |
|
|
157
|
+
| `autoplay` | Determines whether the media should autoplay once created | `true` |
|
|
158
|
+
| `pictureInPicture` | Determines whether the player should allow Picture-in-Picture (PiP) mode | `false` |
|
|
145
159
|
|
|
146
160
|
#### Callbacks
|
|
147
161
|
|
|
148
|
-
| Prop
|
|
149
|
-
|
|
|
150
|
-
| `onBuffering`
|
|
151
|
-
| `onPlaying`
|
|
152
|
-
| `onPaused`
|
|
153
|
-
| `onStopped`
|
|
154
|
-
| `onEncounteredError`
|
|
155
|
-
| `onDialogDisplay`
|
|
156
|
-
| `onTimeChanged`
|
|
157
|
-
| `onPositionChanged`
|
|
158
|
-
| `onESAdded`
|
|
159
|
-
| `onRecordChanged`
|
|
160
|
-
| `onSnapshotTaken`
|
|
161
|
-
| `onFirstPlay`
|
|
162
|
-
| `onForeground`
|
|
163
|
-
| `onBackground`
|
|
162
|
+
| Prop | Description | Payload |
|
|
163
|
+
| ------------------------- | ------------------------------------------------------------ | ----------------------------- |
|
|
164
|
+
| `onBuffering` | Called after the `Buffering` player event | |
|
|
165
|
+
| `onPlaying` | Called after the `Playing` player event | |
|
|
166
|
+
| `onPaused` | Called after the `Paused` player event | |
|
|
167
|
+
| `onStopped` | Called after the `Stopped` player event | |
|
|
168
|
+
| `onEncounteredError` | Called after the `EncounteredError` player event | `{ error: string }` |
|
|
169
|
+
| `onDialogDisplay` | Called after a `Dialog` needs to be displayed | [`Dialog`](#dialog) |
|
|
170
|
+
| `onTimeChanged` | Called after the `TimeChanged` player event | `{ time: number }` |
|
|
171
|
+
| `onPositionChanged` | Called after the `PositionChanged` player event | `{ position: number }` |
|
|
172
|
+
| `onESAdded` | Called after the `ESAdded` player event | [`MediaTracks`](#mediatracks) |
|
|
173
|
+
| `onRecordChanged` | Called after the `RecordChanged` player event | [`Recording`](#recording) |
|
|
174
|
+
| `onSnapshotTaken` | Called after a media snapshot is taken | `{ path: string }` |
|
|
175
|
+
| `onFirstPlay` | Called after the player first playing event | [`MediaInfo`](#mediainfo) |
|
|
176
|
+
| `onForeground` | Called after the player enters the foreground | |
|
|
177
|
+
| `onBackground` | Called after the player enters the background | |
|
|
178
|
+
| `onStartPictureInPicture` | Called after the player enters Picture-in-Picture (PiP) mode | |
|
|
179
|
+
| `onStopPictureInPicture` | Called after the player exits Picture-in-Picture (PiP) mode | |
|
|
164
180
|
|
|
165
181
|
### Types
|
|
166
182
|
|
|
@@ -245,6 +261,12 @@ The current workaround attaches the View once a surface is created but this caus
|
|
|
245
261
|
|
|
246
262
|
https://code.videolan.org/videolan/vlc-android/-/issues/1495
|
|
247
263
|
|
|
264
|
+
On iOS, the `VLCKit` player deallocates from the UIView when closing the Picture-in-Picture (PiP) window.
|
|
265
|
+
|
|
266
|
+
The current workaround exclusively selects the current video track but this causes a brief black screen.
|
|
267
|
+
|
|
268
|
+
https://code.videolan.org/videolan/VLCKit/-/issues/743
|
|
269
|
+
|
|
248
270
|
#### Audio delay
|
|
249
271
|
|
|
250
272
|
On iOS, the `VLCKit` player experiences a small audio delay when resuming or muting media playback.
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
package expo.modules.libvlcplayer
|
|
2
2
|
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import expo.modules.kotlin.exception.Exceptions
|
|
3
6
|
import expo.modules.kotlin.modules.Module
|
|
4
7
|
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
8
|
import expo.modules.libvlcplayer.constants.MediaPlayerConstants
|
|
@@ -25,13 +28,25 @@ private val PLAYER_EVENTS =
|
|
|
25
28
|
"onFirstPlay",
|
|
26
29
|
"onForeground",
|
|
27
30
|
"onBackground",
|
|
31
|
+
"onPictureInPictureStart",
|
|
32
|
+
"onPictureInPictureStop",
|
|
28
33
|
)
|
|
29
34
|
|
|
30
35
|
class LibVlcPlayerModule : Module() {
|
|
36
|
+
private val activity: Activity
|
|
37
|
+
get() = appContext.currentActivity ?: throw Exceptions.MissingActivity()
|
|
38
|
+
|
|
31
39
|
override fun definition() =
|
|
32
40
|
ModuleDefinition {
|
|
33
41
|
Name("ExpoLibVlcPlayer")
|
|
34
42
|
|
|
43
|
+
Function("isPictureInPictureSupported") {
|
|
44
|
+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
|
45
|
+
activity.packageManager.hasSystemFeature(
|
|
46
|
+
android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE,
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
35
50
|
OnCreate {
|
|
36
51
|
MediaPlayerManager.onModuleCreate(appContext)
|
|
37
52
|
}
|
|
@@ -105,6 +120,10 @@ class LibVlcPlayerModule : Module() {
|
|
|
105
120
|
view.autoplay = autoplay
|
|
106
121
|
}
|
|
107
122
|
|
|
123
|
+
Prop("pictureInPicture", false) { view: LibVlcPlayerView, pictureInPicture: Boolean ->
|
|
124
|
+
view.pictureInPicture = pictureInPicture
|
|
125
|
+
}
|
|
126
|
+
|
|
108
127
|
OnViewDidUpdateProps { view: LibVlcPlayerView ->
|
|
109
128
|
view.initPlayer()
|
|
110
129
|
}
|
|
@@ -145,6 +164,10 @@ class LibVlcPlayerModule : Module() {
|
|
|
145
164
|
AsyncFunction("dismiss") { view: LibVlcPlayerView ->
|
|
146
165
|
view.dismiss()
|
|
147
166
|
}
|
|
167
|
+
|
|
168
|
+
AsyncFunction("startPictureInPicture") { view: LibVlcPlayerView ->
|
|
169
|
+
view.startPictureInPicture()
|
|
170
|
+
}
|
|
148
171
|
}
|
|
149
172
|
}
|
|
150
173
|
}
|
|
@@ -25,6 +25,11 @@ import expo.modules.libvlcplayer.records.Recording
|
|
|
25
25
|
import expo.modules.libvlcplayer.records.Slave
|
|
26
26
|
import expo.modules.libvlcplayer.records.Track
|
|
27
27
|
import expo.modules.libvlcplayer.records.Tracks
|
|
28
|
+
import kotlinx.coroutines.CoroutineScope
|
|
29
|
+
import kotlinx.coroutines.Dispatchers
|
|
30
|
+
import kotlinx.coroutines.Job
|
|
31
|
+
import kotlinx.coroutines.delay
|
|
32
|
+
import kotlinx.coroutines.launch
|
|
28
33
|
import org.videolan.libvlc.LibVLC
|
|
29
34
|
import org.videolan.libvlc.Media
|
|
30
35
|
import org.videolan.libvlc.MediaPlayer
|
|
@@ -48,7 +53,9 @@ class LibVlcPlayerView(
|
|
|
48
53
|
context: Context,
|
|
49
54
|
appContext: AppContext,
|
|
50
55
|
) : ExpoView(context, appContext) {
|
|
51
|
-
|
|
56
|
+
val playerView: VLCVideoLayout = VLCVideoLayout(context)
|
|
57
|
+
val pictureView: VLCVideoLayout = VLCVideoLayout(context)
|
|
58
|
+
private var pauseIfJob: Job? = null
|
|
52
59
|
|
|
53
60
|
var libVLC: LibVLC? = null
|
|
54
61
|
var mediaPlayer: MediaPlayer? = null
|
|
@@ -56,6 +63,7 @@ class LibVlcPlayerView(
|
|
|
56
63
|
|
|
57
64
|
var firstPlay: Boolean = true
|
|
58
65
|
private var shouldInit: Boolean = true
|
|
66
|
+
var isInBackground: Boolean = false
|
|
59
67
|
|
|
60
68
|
val onBuffering by EventDispatcher<Unit>()
|
|
61
69
|
val onPlaying by EventDispatcher<Unit>()
|
|
@@ -71,22 +79,23 @@ class LibVlcPlayerView(
|
|
|
71
79
|
val onFirstPlay by EventDispatcher<MediaInfo>()
|
|
72
80
|
val onForeground by EventDispatcher<Unit>()
|
|
73
81
|
val onBackground by EventDispatcher<Unit>()
|
|
82
|
+
val onPictureInPictureStart by EventDispatcher<Unit>()
|
|
83
|
+
val onPictureInPictureStop by EventDispatcher<Unit>()
|
|
74
84
|
|
|
75
85
|
init {
|
|
76
86
|
MediaPlayerManager.registerExpoView(this)
|
|
77
|
-
addPlayerView()
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
override fun onAttachedToWindow() {
|
|
81
90
|
super.onAttachedToWindow()
|
|
82
91
|
|
|
83
|
-
|
|
92
|
+
attachPlayerView(playerView)
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
override fun onDetachedFromWindow() {
|
|
87
96
|
super.onDetachedFromWindow()
|
|
88
97
|
|
|
89
|
-
|
|
98
|
+
detachPlayerView()
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
override fun onSizeChanged(
|
|
@@ -116,12 +125,14 @@ class LibVlcPlayerView(
|
|
|
116
125
|
var args = options
|
|
117
126
|
args.toggleStartPausedOption(autoplay)
|
|
118
127
|
|
|
128
|
+
MediaPlayerManager.pictureInPictureManager.setupPipManager(this)
|
|
129
|
+
|
|
119
130
|
libVLC = LibVLC(context, args)
|
|
120
131
|
setDialogCallbacks(libVLC!!)
|
|
121
132
|
|
|
122
133
|
mediaPlayer = MediaPlayer(libVLC!!)
|
|
123
134
|
setPlayerListener(mediaPlayer!!)
|
|
124
|
-
attachPlayerView()
|
|
135
|
+
attachPlayerView(playerView)
|
|
125
136
|
|
|
126
137
|
try {
|
|
127
138
|
URI(source)
|
|
@@ -137,6 +148,8 @@ class LibVlcPlayerView(
|
|
|
137
148
|
|
|
138
149
|
firstPlay = true
|
|
139
150
|
shouldInit = false
|
|
151
|
+
|
|
152
|
+
addPlayerView(playerView)
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
fun resetPlayer() {
|
|
@@ -145,8 +158,8 @@ class LibVlcPlayerView(
|
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
fun attachPlayer() {
|
|
148
|
-
attachPlayerView()
|
|
149
|
-
addPlayerView()
|
|
161
|
+
attachPlayerView(playerView)
|
|
162
|
+
addPlayerView(playerView)
|
|
150
163
|
}
|
|
151
164
|
|
|
152
165
|
fun detachPlayer() {
|
|
@@ -154,12 +167,12 @@ class LibVlcPlayerView(
|
|
|
154
167
|
removePlayerView()
|
|
155
168
|
}
|
|
156
169
|
|
|
157
|
-
fun attachPlayerView() {
|
|
170
|
+
fun attachPlayerView(view: VLCVideoLayout) {
|
|
158
171
|
mediaPlayer?.let { player ->
|
|
159
172
|
val attached = player.getVLCVout().areViewsAttached()
|
|
160
173
|
|
|
161
174
|
if (!attached) {
|
|
162
|
-
player.attachViews(
|
|
175
|
+
player.attachViews(view, DISPLAY_MANAGER, ENABLE_SUBTITLES, USE_TEXTURE_VIEW)
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
178
|
}
|
|
@@ -174,11 +187,11 @@ class LibVlcPlayerView(
|
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
|
|
177
|
-
fun addPlayerView() {
|
|
190
|
+
fun addPlayerView(view: VLCVideoLayout) {
|
|
178
191
|
val parent = playerView.parent as? ViewGroup
|
|
179
192
|
|
|
180
193
|
if (parent == null) {
|
|
181
|
-
addView(
|
|
194
|
+
addView(view)
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
|
|
@@ -514,6 +527,12 @@ class LibVlcPlayerView(
|
|
|
514
527
|
field = value
|
|
515
528
|
}
|
|
516
529
|
|
|
530
|
+
var pictureInPicture: Boolean = false
|
|
531
|
+
set(value) {
|
|
532
|
+
field = value
|
|
533
|
+
shouldInit = true
|
|
534
|
+
}
|
|
535
|
+
|
|
517
536
|
fun play() {
|
|
518
537
|
mediaPlayer?.let { player ->
|
|
519
538
|
if (!autoplay) {
|
|
@@ -529,10 +548,21 @@ class LibVlcPlayerView(
|
|
|
529
548
|
}
|
|
530
549
|
|
|
531
550
|
fun pauseIf(condition: Boolean? = true) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
551
|
+
cancelPauseIf()
|
|
552
|
+
|
|
553
|
+
pauseIfJob =
|
|
554
|
+
CoroutineScope(Dispatchers.Main).launch {
|
|
555
|
+
delay(MediaPlayerConstants.COROUTINE_DELAY_MS)
|
|
556
|
+
|
|
557
|
+
mediaPlayer?.let { player ->
|
|
558
|
+
val shouldPause = condition == true && player.isPlaying()
|
|
559
|
+
if (shouldPause) player.pause()
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
fun cancelPauseIf() {
|
|
565
|
+
pauseIfJob?.cancel()
|
|
536
566
|
}
|
|
537
567
|
|
|
538
568
|
fun stop() {
|
|
@@ -630,6 +660,20 @@ class LibVlcPlayerView(
|
|
|
630
660
|
}
|
|
631
661
|
}
|
|
632
662
|
|
|
663
|
+
fun startPictureInPicture() {
|
|
664
|
+
MediaPlayerManager.pictureInPictureManager.startPictureInPicture(this)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
fun onStartPictureInPicture() {
|
|
668
|
+
MediaPlayerManager.pictureInPictureManager.layoutForPipEnter()
|
|
669
|
+
onPictureInPictureStart(Unit)
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
fun onStopPictureInPicture() {
|
|
673
|
+
MediaPlayerManager.pictureInPictureManager.layoutForPipExit()
|
|
674
|
+
onPictureInPictureStop(Unit)
|
|
675
|
+
}
|
|
676
|
+
|
|
633
677
|
fun retryUntil(
|
|
634
678
|
maxRetries: Int = MediaPlayerConstants.MAX_RETRY_COUNT,
|
|
635
679
|
retry: Int = 0,
|
|
@@ -707,6 +751,7 @@ fun LibVlcPlayerView.setPlayerListener(mediaPlayer: MediaPlayer?) {
|
|
|
707
751
|
}
|
|
708
752
|
}
|
|
709
753
|
|
|
754
|
+
MediaPlayerManager.pictureInPictureManager.setPipActions()
|
|
710
755
|
MediaPlayerManager.keepAwakeManager.toggleKeepAwake()
|
|
711
756
|
|
|
712
757
|
retryUntil { isLastAttempt ->
|
|
@@ -7,6 +7,15 @@ object MediaPlayerConstants {
|
|
|
7
7
|
const val MIN_PLAYER_VOLUME: Int = 0
|
|
8
8
|
const val MAX_PLAYER_VOLUME: Int = 100
|
|
9
9
|
|
|
10
|
+
const val ACTION_PIP_CONTROL: String = "pip_control"
|
|
11
|
+
const val EXTRA_CONTROL_TYPE: String = "control_type"
|
|
12
|
+
const val EXTRA_CONTROL_REWIND: Int = 1
|
|
13
|
+
const val EXTRA_CONTROL_PLAY: Int = 2
|
|
14
|
+
const val EXTRA_CONTROL_PAUSE: Int = 3
|
|
15
|
+
const val EXTRA_CONTROL_FORWARD: Int = 4
|
|
16
|
+
const val SEEK_STEP_MS: Long = 10_000L
|
|
17
|
+
|
|
18
|
+
const val COROUTINE_DELAY_MS: Long = 1_000L
|
|
10
19
|
const val RETRY_DELAY_MS: Long = 200L
|
|
11
20
|
const val MAX_RETRY_COUNT: Int = 5
|
|
12
21
|
}
|
|
@@ -8,6 +8,7 @@ import java.util.WeakHashMap
|
|
|
8
8
|
object MediaPlayerManager {
|
|
9
9
|
lateinit var audioFocusManager: AudioFocusManager
|
|
10
10
|
lateinit var keepAwakeManager: KeepAwakeManager
|
|
11
|
+
lateinit var pictureInPictureManager: PictureInPictureManager
|
|
11
12
|
|
|
12
13
|
val expoViews: MutableSet<LibVlcPlayerView> = Collections.newSetFromMap(WeakHashMap())
|
|
13
14
|
|
|
@@ -27,6 +28,10 @@ object MediaPlayerManager {
|
|
|
27
28
|
if (!this::keepAwakeManager.isInitialized) {
|
|
28
29
|
keepAwakeManager = KeepAwakeManager(appContext)
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
if (!this::pictureInPictureManager.isInitialized) {
|
|
33
|
+
pictureInPictureManager = PictureInPictureManager(appContext)
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
fun onModuleDestroy() {
|
|
@@ -38,6 +43,8 @@ object MediaPlayerManager {
|
|
|
38
43
|
fun onModuleForeground() {
|
|
39
44
|
expoViews.forEach { view ->
|
|
40
45
|
view.onForeground(Unit)
|
|
46
|
+
view.cancelPauseIf()
|
|
47
|
+
view.isInBackground = false
|
|
41
48
|
}
|
|
42
49
|
}
|
|
43
50
|
|
|
@@ -45,6 +52,7 @@ object MediaPlayerManager {
|
|
|
45
52
|
expoViews.forEach { view ->
|
|
46
53
|
view.onBackground(Unit)
|
|
47
54
|
view.pauseIf()
|
|
55
|
+
view.isInBackground = true
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
}
|