expo-video 1.2.5 → 1.2.7
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/CHANGELOG.md +29 -0
- package/android/build.gradle +4 -3
- package/android/src/main/java/expo/modules/video/PlayerEvent.kt +1 -1
- package/android/src/main/java/expo/modules/video/VideoManager.kt +1 -1
- package/android/src/main/java/expo/modules/video/VideoModule.kt +39 -6
- package/android/src/main/java/expo/modules/video/VideoPlayer.kt +7 -4
- package/android/src/main/java/expo/modules/video/VideoView.kt +4 -0
- package/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt +5 -2
- package/android/src/main/java/expo/modules/video/playbackService/PlaybackServiceConnection.kt +3 -3
- package/android/src/main/java/expo/modules/video/records/VideoSource.kt +35 -2
- package/android/src/main/java/expo/modules/video/utils/DataSourceUtils.kt +1 -1
- package/build/VideoPlayer.d.ts.map +1 -1
- package/build/VideoPlayer.js +19 -1
- package/build/VideoPlayer.js.map +1 -1
- package/build/VideoPlayer.types.d.ts +35 -2
- package/build/VideoPlayer.types.d.ts.map +1 -1
- package/build/VideoPlayer.types.js.map +1 -1
- package/build/VideoPlayer.web.d.ts +3 -0
- package/build/VideoPlayer.web.d.ts.map +1 -1
- package/build/VideoPlayer.web.js +11 -1
- package/build/VideoPlayer.web.js.map +1 -1
- package/build/VideoView.types.d.ts +8 -0
- package/build/VideoView.types.d.ts.map +1 -1
- package/build/VideoView.types.js.map +1 -1
- package/build/VideoView.web.d.ts.map +1 -1
- package/build/VideoView.web.js +21 -0
- package/build/VideoView.web.js.map +1 -1
- package/build/resolveAssetSource.d.ts +3 -0
- package/build/resolveAssetSource.d.ts.map +1 -0
- package/build/resolveAssetSource.js +3 -0
- package/build/resolveAssetSource.js.map +1 -0
- package/build/resolveAssetSource.web.d.ts +4 -0
- package/build/resolveAssetSource.web.d.ts.map +1 -0
- package/build/resolveAssetSource.web.js +16 -0
- package/build/resolveAssetSource.web.js.map +1 -0
- package/ios/NowPlayingManager.swift +1 -0
- package/ios/VideoModule.swift +37 -5
- package/ios/VideoView.swift +6 -0
- package/package.json +2 -2
- package/src/VideoPlayer.tsx +21 -1
- package/src/VideoPlayer.types.ts +42 -1
- package/src/VideoPlayer.web.tsx +12 -1
- package/src/VideoView.types.ts +10 -0
- package/src/VideoView.web.tsx +23 -0
- package/src/resolveAssetSource.ts +2 -0
- package/src/resolveAssetSource.web.ts +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,35 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 1.2.7 — 2024-09-26
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug fixes
|
|
16
|
+
|
|
17
|
+
- [Web] Fix invalid `resolveAssetSource` for web. ([#31664](https://github.com/expo/expo/pull/31664) by [@behenate](https://github.com/behenate))
|
|
18
|
+
|
|
19
|
+
## 1.2.6 — 2024-09-13
|
|
20
|
+
|
|
21
|
+
### 🛠 Breaking changes
|
|
22
|
+
|
|
23
|
+
- `showNowPlayingNotification` property of the player now defaults to `false`. ([#31261](https://github.com/expo/expo/pull/31261) by [@behenate](https://github.com/behenate))
|
|
24
|
+
|
|
25
|
+
### 🎉 New features
|
|
26
|
+
|
|
27
|
+
- [Android][iOS] Add properties for more advanced live stream configuration. ([#30648](https://github.com/expo/expo/pull/30648) by [@justjoostnl](https://github.com/justjoostnl))
|
|
28
|
+
- [iOS] Add live indicator in the now playing info. ([#30629](https://github.com/expo/expo/pull/30629) by [@justjoostnl](https://github.com/justjoostnl))
|
|
29
|
+
- Add fullscreen enter and exit events. ([#30922](https://github.com/expo/expo/pull/30922) by [@fobos531](https://github.com/fobos531))
|
|
30
|
+
- Add support for playback of local assets imported with the `require` function. ([#30837](https://github.com/expo/expo/pull/30837) by [@behenate](https://github.com/behenate))
|
|
31
|
+
|
|
32
|
+
### 🐛 Bug fixes
|
|
33
|
+
|
|
34
|
+
- [iOS] Fixed `player.currentTime` being `NaN` when source is not provided and `player.duration` being `NaN` inside the hook callback when the source is updated. ([#31011](https://github.com/expo/expo/pull/31011) by [@AlirezaHadjar](https://github.com/AlirezaHadjar))
|
|
35
|
+
- [Android] Fix wrong event being sent when the volume is changed. ([#30891](https://github.com/expo/expo/pull/30891) by [@behenate](https://github.com/behenate))
|
|
36
|
+
|
|
37
|
+
### 💡 Others
|
|
38
|
+
|
|
39
|
+
- Bump media3 version to 1.4.0. ([#31239](https://github.com/expo/expo/pull/31239) by [@behenate](https://github.com/behenate))
|
|
40
|
+
- [Android] The media will now be buffered even when the player is unmounted to match iOS behavior. ([#30626](https://github.com/expo/expo/pull/30626) by [@behenate](https://github.com/behenate))
|
|
41
|
+
|
|
13
42
|
## 1.2.5 — 2024-08-20
|
|
14
43
|
|
|
15
44
|
### 🐛 Bug fixes
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'host.exp.exponent'
|
|
4
|
-
version = '1.2.
|
|
4
|
+
version = '1.2.7'
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -14,14 +14,15 @@ android {
|
|
|
14
14
|
namespace "expo.modules.video"
|
|
15
15
|
defaultConfig {
|
|
16
16
|
versionCode 1
|
|
17
|
-
versionName '1.2.
|
|
17
|
+
versionName '1.2.7'
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
dependencies {
|
|
22
22
|
implementation 'com.facebook.react:react-android'
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// Remember to keep this in sync with the version in `expo-audio`
|
|
25
|
+
def androidxMedia3Version = "1.4.0"
|
|
25
26
|
implementation "androidx.media3:media3-session:${androidxMedia3Version}"
|
|
26
27
|
implementation "androidx.media3:media3-exoplayer:${androidxMedia3Version}"
|
|
27
28
|
implementation "androidx.media3:media3-exoplayer-dash:${androidxMedia3Version}"
|
|
@@ -23,7 +23,7 @@ sealed class PlayerEvent {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
data class VolumeChanged(val newValue: VolumeEvent, val oldValue: VolumeEvent?) : PlayerEvent() {
|
|
26
|
-
override val name = "
|
|
26
|
+
override val name = "volumeChange"
|
|
27
27
|
override val arguments = arrayOf(newValue, oldValue)
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -52,7 +52,7 @@ object VideoManager {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (videoPlayersToVideoViews[videoPlayer]?.size == 1) {
|
|
55
|
-
videoPlayer.serviceConnection.playbackServiceBinder?.service?.registerPlayer(videoPlayer
|
|
55
|
+
videoPlayer.serviceConnection.playbackServiceBinder?.service?.registerPlayer(videoPlayer)
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -4,9 +4,11 @@ package expo.modules.video
|
|
|
4
4
|
|
|
5
5
|
import android.app.Activity
|
|
6
6
|
import android.net.Uri
|
|
7
|
+
import androidx.media3.common.C
|
|
7
8
|
import androidx.media3.common.PlaybackParameters
|
|
8
9
|
import androidx.media3.common.Player.REPEAT_MODE_OFF
|
|
9
10
|
import androidx.media3.common.Player.REPEAT_MODE_ONE
|
|
11
|
+
import androidx.media3.common.Timeline
|
|
10
12
|
import com.facebook.react.uimanager.PixelUtil
|
|
11
13
|
import com.facebook.react.uimanager.Spacing
|
|
12
14
|
import com.facebook.react.uimanager.ViewProps
|
|
@@ -43,12 +45,13 @@ class VideoModule : Module() {
|
|
|
43
45
|
View(VideoView::class) {
|
|
44
46
|
Events(
|
|
45
47
|
"onPictureInPictureStart",
|
|
46
|
-
"onPictureInPictureStop"
|
|
48
|
+
"onPictureInPictureStop",
|
|
49
|
+
"onFullscreenEnter",
|
|
50
|
+
"onFullscreenExit"
|
|
47
51
|
)
|
|
48
52
|
|
|
49
53
|
Prop("player") { view: VideoView, player: VideoPlayer ->
|
|
50
54
|
view.videoPlayer = player
|
|
51
|
-
player.prepare()
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
Prop("nativeControls") { view: VideoView, useNativeControls: Boolean ->
|
|
@@ -149,7 +152,11 @@ class VideoModule : Module() {
|
|
|
149
152
|
|
|
150
153
|
Class(VideoPlayer::class) {
|
|
151
154
|
Constructor { source: VideoSource? ->
|
|
152
|
-
VideoPlayer(activity.applicationContext, appContext, source)
|
|
155
|
+
val player = VideoPlayer(activity.applicationContext, appContext, source)
|
|
156
|
+
appContext.mainQueue.launch {
|
|
157
|
+
player.prepare()
|
|
158
|
+
}
|
|
159
|
+
return@Constructor player
|
|
153
160
|
}
|
|
154
161
|
|
|
155
162
|
Property("playing")
|
|
@@ -193,6 +200,34 @@ class VideoModule : Module() {
|
|
|
193
200
|
}
|
|
194
201
|
}
|
|
195
202
|
|
|
203
|
+
Property("currentLiveTimestamp")
|
|
204
|
+
.get { ref: VideoPlayer ->
|
|
205
|
+
// TODO: same as `currentTime`
|
|
206
|
+
runBlocking(appContext.mainQueue.coroutineContext) {
|
|
207
|
+
val window = Timeline.Window()
|
|
208
|
+
if (!ref.player.currentTimeline.isEmpty) {
|
|
209
|
+
ref.player.currentTimeline.getWindow(ref.player.currentMediaItemIndex, window)
|
|
210
|
+
}
|
|
211
|
+
if (window.windowStartTimeMs == C.TIME_UNSET) {
|
|
212
|
+
null
|
|
213
|
+
} else {
|
|
214
|
+
window.windowStartTimeMs + ref.player.currentPosition
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
Property("currentOffsetFromLive")
|
|
220
|
+
.get { ref: VideoPlayer ->
|
|
221
|
+
// TODO: same as `currentTime`
|
|
222
|
+
runBlocking(appContext.mainQueue.coroutineContext) {
|
|
223
|
+
if (ref.player.currentLiveOffset == C.TIME_UNSET) {
|
|
224
|
+
null
|
|
225
|
+
} else {
|
|
226
|
+
ref.player.currentLiveOffset / 1000f
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
196
231
|
Property("duration")
|
|
197
232
|
.get { ref: VideoPlayer ->
|
|
198
233
|
ref.duration
|
|
@@ -284,9 +319,7 @@ class VideoModule : Module() {
|
|
|
284
319
|
|
|
285
320
|
appContext.mainQueue.launch {
|
|
286
321
|
ref.uncommittedSource = videoSource
|
|
287
|
-
|
|
288
|
-
ref.prepare()
|
|
289
|
-
}
|
|
322
|
+
ref.prepare()
|
|
290
323
|
}
|
|
291
324
|
}
|
|
292
325
|
|
|
@@ -36,7 +36,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
36
36
|
.setLooper(context.mainLooper)
|
|
37
37
|
.build()
|
|
38
38
|
|
|
39
|
-
val serviceConnection = PlaybackServiceConnection(WeakReference(
|
|
39
|
+
val serviceConnection = PlaybackServiceConnection(WeakReference(this))
|
|
40
40
|
|
|
41
41
|
var playing by IgnoreSameSet(false) { new, old ->
|
|
42
42
|
sendEvent(PlayerEvent.IsPlayingChanged(new, old))
|
|
@@ -57,7 +57,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
57
57
|
field = preservesPitch
|
|
58
58
|
playbackParameters = applyPitchCorrection(playbackParameters)
|
|
59
59
|
}
|
|
60
|
-
var showNowPlayingNotification =
|
|
60
|
+
var showNowPlayingNotification = false
|
|
61
61
|
set(value) {
|
|
62
62
|
field = value
|
|
63
63
|
serviceConnection.playbackServiceBinder?.service?.setShowNotification(value, this.player)
|
|
@@ -67,11 +67,12 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
67
67
|
|
|
68
68
|
var volume: Float by IgnoreSameSet(1f) { new: Float, old: Float ->
|
|
69
69
|
player.volume = if (muted) 0f else new
|
|
70
|
+
userVolume = volume
|
|
70
71
|
sendEvent(PlayerEvent.VolumeChanged(VolumeEvent(new, muted), VolumeEvent(old, muted)))
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
var muted: Boolean by IgnoreSameSet(false) { new: Boolean, old: Boolean ->
|
|
74
|
-
volume = if (new) 0f else userVolume
|
|
75
|
+
player.volume = if (new) 0f else userVolume
|
|
75
76
|
sendEvent(PlayerEvent.VolumeChanged(VolumeEvent(volume, new), VolumeEvent(volume, old)))
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -113,7 +114,9 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
override fun onVolumeChanged(volume: Float) {
|
|
116
|
-
|
|
117
|
+
if (!muted) {
|
|
118
|
+
this@VideoPlayer.volume = volume
|
|
119
|
+
}
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {
|
|
@@ -36,6 +36,8 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap
|
|
|
36
36
|
val playerView: PlayerView = PlayerView(context.applicationContext)
|
|
37
37
|
val onPictureInPictureStart by EventDispatcher<Unit>()
|
|
38
38
|
val onPictureInPictureStop by EventDispatcher<Unit>()
|
|
39
|
+
val onFullscreenEnter by EventDispatcher<Unit>()
|
|
40
|
+
val onFullscreenExit by EventDispatcher<Unit>()
|
|
39
41
|
|
|
40
42
|
var willEnterPiP: Boolean = false
|
|
41
43
|
var isInFullscreen: Boolean = false
|
|
@@ -154,6 +156,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap
|
|
|
154
156
|
@Suppress("DEPRECATION")
|
|
155
157
|
currentActivity.overridePendingTransition(0, 0)
|
|
156
158
|
}
|
|
159
|
+
onFullscreenEnter(Unit)
|
|
157
160
|
isInFullscreen = true
|
|
158
161
|
}
|
|
159
162
|
|
|
@@ -162,6 +165,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap
|
|
|
162
165
|
val fullScreenButton: ImageButton = playerView.findViewById(androidx.media3.ui.R.id.exo_fullscreen)
|
|
163
166
|
fullScreenButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter)
|
|
164
167
|
videoPlayer?.changePlayerView(playerView)
|
|
168
|
+
onFullscreenExit(Unit)
|
|
165
169
|
isInFullscreen = false
|
|
166
170
|
}
|
|
167
171
|
|
package/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt
CHANGED
|
@@ -20,6 +20,7 @@ import androidx.media3.session.SessionCommand
|
|
|
20
20
|
import com.google.common.collect.ImmutableList
|
|
21
21
|
import expo.modules.kotlin.AppContext
|
|
22
22
|
import expo.modules.video.R
|
|
23
|
+
import expo.modules.video.VideoPlayer
|
|
23
24
|
|
|
24
25
|
class PlaybackServiceBinder(val service: ExpoVideoPlaybackService) : Binder()
|
|
25
26
|
|
|
@@ -51,7 +52,8 @@ class ExpoVideoPlaybackService : MediaSessionService() {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
fun registerPlayer(
|
|
55
|
+
fun registerPlayer(videoPlayer: VideoPlayer) {
|
|
56
|
+
val player = videoPlayer.player
|
|
55
57
|
if (mediaSessions[player] != null) {
|
|
56
58
|
return
|
|
57
59
|
}
|
|
@@ -64,6 +66,7 @@ class ExpoVideoPlaybackService : MediaSessionService() {
|
|
|
64
66
|
|
|
65
67
|
mediaSessions[player] = mediaSession
|
|
66
68
|
addSession(mediaSession)
|
|
69
|
+
setShowNotification(videoPlayer.showNowPlayingNotification, player)
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
fun unregisterPlayer(player: ExoPlayer) {
|
|
@@ -82,7 +85,7 @@ class ExpoVideoPlaybackService : MediaSessionService() {
|
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) {
|
|
85
|
-
if (session.sessionExtras.getBoolean(SESSION_SHOW_NOTIFICATION,
|
|
88
|
+
if (session.sessionExtras.getBoolean(SESSION_SHOW_NOTIFICATION, false)) {
|
|
86
89
|
createNotification(session)
|
|
87
90
|
} else {
|
|
88
91
|
(session.player as? ExoPlayer)?.let {
|
package/android/src/main/java/expo/modules/video/playbackService/PlaybackServiceConnection.kt
CHANGED
|
@@ -4,14 +4,14 @@ import android.content.ComponentName
|
|
|
4
4
|
import android.content.ServiceConnection
|
|
5
5
|
import android.os.IBinder
|
|
6
6
|
import android.util.Log
|
|
7
|
-
import
|
|
7
|
+
import expo.modules.video.VideoPlayer
|
|
8
8
|
import java.lang.ref.WeakReference
|
|
9
9
|
|
|
10
|
-
class PlaybackServiceConnection(val player: WeakReference<
|
|
10
|
+
class PlaybackServiceConnection(val player: WeakReference<VideoPlayer>) : ServiceConnection {
|
|
11
11
|
var playbackServiceBinder: PlaybackServiceBinder? = null
|
|
12
12
|
|
|
13
13
|
override fun onServiceConnected(componentName: ComponentName, binder: IBinder) {
|
|
14
|
-
val player
|
|
14
|
+
val player = player.get() ?: return
|
|
15
15
|
playbackServiceBinder = binder as? PlaybackServiceBinder
|
|
16
16
|
playbackServiceBinder?.service?.registerPlayer(player) ?: run {
|
|
17
17
|
Log.w(
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
package expo.modules.video.records
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.ContentResolver
|
|
2
5
|
import android.content.Context
|
|
3
6
|
import android.net.Uri
|
|
7
|
+
import android.util.Log
|
|
4
8
|
import androidx.annotation.OptIn
|
|
5
9
|
import androidx.media3.common.MediaItem
|
|
6
10
|
import androidx.media3.common.MediaMetadata
|
|
7
11
|
import androidx.media3.common.util.UnstableApi
|
|
12
|
+
import androidx.media3.datasource.DataSpec
|
|
13
|
+
import androidx.media3.datasource.RawResourceDataSource
|
|
8
14
|
import androidx.media3.exoplayer.source.MediaSource
|
|
9
15
|
import expo.modules.kotlin.records.Field
|
|
10
16
|
import expo.modules.kotlin.records.Record
|
|
@@ -35,10 +41,10 @@ class VideoSource(
|
|
|
35
41
|
return buildMediaSourceWithHeaders(context, this)
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
fun toMediaItem() = MediaItem
|
|
44
|
+
fun toMediaItem(context: Context) = MediaItem
|
|
39
45
|
.Builder()
|
|
40
46
|
.apply {
|
|
41
|
-
setUri(uri)
|
|
47
|
+
setUri(parseLocalAssetId(uri, context))
|
|
42
48
|
setMediaId(toMediaId())
|
|
43
49
|
drm?.let {
|
|
44
50
|
if (it.type.isSupported()) {
|
|
@@ -57,4 +63,31 @@ class VideoSource(
|
|
|
57
63
|
)
|
|
58
64
|
}
|
|
59
65
|
.build()
|
|
66
|
+
|
|
67
|
+
// Using `resolveAssetSource` to generate a local asset URI returns a resource name for android release builds
|
|
68
|
+
// we have to get the raw resource URI to play the video
|
|
69
|
+
@SuppressLint("DiscouragedApi") // AFAIK, in this case, there's no other way to get the resource URI
|
|
70
|
+
private fun parseLocalAssetId(uri: Uri?, context: Context): Uri? {
|
|
71
|
+
if (uri == null || uri.scheme != null) {
|
|
72
|
+
return uri
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
val resourceId: Int = context.resources.getIdentifier(
|
|
76
|
+
uri.toString(),
|
|
77
|
+
"raw",
|
|
78
|
+
context.packageName
|
|
79
|
+
)
|
|
80
|
+
val parsedUri = Uri.Builder()
|
|
81
|
+
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
|
82
|
+
.appendPath(resourceId.toString())
|
|
83
|
+
.build()
|
|
84
|
+
val dataSpec = DataSpec(parsedUri)
|
|
85
|
+
val rawResourceDataSource = RawResourceDataSource(context)
|
|
86
|
+
rawResourceDataSource.open(dataSpec)
|
|
87
|
+
return rawResourceDataSource.uri
|
|
88
|
+
} catch (e: RawResourceDataSource.RawResourceDataSourceException) {
|
|
89
|
+
Log.e("ExpoVideo", "Error parsing local asset id, falling back to original uri", e)
|
|
90
|
+
return uri
|
|
91
|
+
}
|
|
92
|
+
}
|
|
60
93
|
}
|
|
@@ -44,7 +44,7 @@ fun buildMediaSourceFactory(context: Context, dataSourceFactory: DataSource.Fact
|
|
|
44
44
|
fun buildMediaSourceWithHeaders(context: Context, videoSource: VideoSource): MediaSource {
|
|
45
45
|
val dataSourceFactory = buildDataSourceFactory(context, videoSource)
|
|
46
46
|
val mediaSourceFactory = buildMediaSourceFactory(context, dataSourceFactory)
|
|
47
|
-
val mediaItem = videoSource.toMediaItem()
|
|
47
|
+
val mediaItem = videoSource.toMediaItem(context)
|
|
48
48
|
return mediaSourceFactory.createMediaSource(mediaItem)
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASpE;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GACpC,WAAW,CAQb;;AAeD,wBAA6C"}
|
package/build/VideoPlayer.js
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
import { useReleasingSharedObject } from 'expo-modules-core';
|
|
2
2
|
import NativeVideoModule from './NativeVideoModule';
|
|
3
|
+
import resolveAssetSource from './resolveAssetSource';
|
|
4
|
+
// TODO: Temporary solution until we develop a way of overriding prototypes that won't break the lazy loading of the module.
|
|
5
|
+
const replace = NativeVideoModule.VideoPlayer.prototype.replace;
|
|
6
|
+
NativeVideoModule.VideoPlayer.prototype.replace = function (source) {
|
|
7
|
+
return replace.call(this, parseSource(source));
|
|
8
|
+
};
|
|
3
9
|
/**
|
|
4
10
|
* Creates a `VideoPlayer`, which will be automatically cleaned up when the component is unmounted.
|
|
5
11
|
* @param source - A video source that is used to initialize the player.
|
|
6
12
|
* @param setup - A function that allows setting up the player. It will run after the player is created.
|
|
7
13
|
*/
|
|
8
14
|
export function useVideoPlayer(source, setup) {
|
|
9
|
-
const parsedSource =
|
|
15
|
+
const parsedSource = parseSource(source);
|
|
10
16
|
return useReleasingSharedObject(() => {
|
|
11
17
|
const player = new NativeVideoModule.VideoPlayer(parsedSource);
|
|
12
18
|
setup?.(player);
|
|
13
19
|
return player;
|
|
14
20
|
}, [JSON.stringify(parsedSource)]);
|
|
15
21
|
}
|
|
22
|
+
function parseSource(source) {
|
|
23
|
+
if (typeof source === 'number') {
|
|
24
|
+
return { uri: resolveAssetSource(source).uri };
|
|
25
|
+
}
|
|
26
|
+
else if (typeof source === 'string') {
|
|
27
|
+
return { uri: source };
|
|
28
|
+
}
|
|
29
|
+
if (typeof source?.assetId === 'number' && !source.uri) {
|
|
30
|
+
return { ...source, uri: resolveAssetSource(source.assetId).uri };
|
|
31
|
+
}
|
|
32
|
+
return source;
|
|
33
|
+
}
|
|
16
34
|
export default NativeVideoModule.VideoPlayer;
|
|
17
35
|
//# sourceMappingURL=VideoPlayer.js.map
|
package/build/VideoPlayer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlayer.js","sourceRoot":"","sources":["../src/VideoPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"VideoPlayer.js","sourceRoot":"","sources":["../src/VideoPlayer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAEpD,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAEtD,4HAA4H;AAC5H,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC;AAChE,iBAAiB,CAAC,WAAW,CAAC,SAAS,CAAC,OAAO,GAAG,UAAU,MAAmB;IAC7E,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAmB,EACnB,KAAqC;IAErC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAEzC,OAAO,wBAAwB,CAAC,GAAG,EAAE;QACnC,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QAC/D,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;QAChB,OAAO,MAAM,CAAC;IAChB,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,OAAO,EAAE,GAAG,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;KAChD;SAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACrC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;KACxB;IAED,IAAI,OAAO,MAAM,EAAE,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;QACtD,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC;KACnE;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,eAAe,iBAAiB,CAAC,WAAW,CAAC","sourcesContent":["import { useReleasingSharedObject } from 'expo-modules-core';\n\nimport NativeVideoModule from './NativeVideoModule';\nimport type { VideoPlayer, VideoSource } from './VideoPlayer.types';\nimport resolveAssetSource from './resolveAssetSource';\n\n// TODO: Temporary solution until we develop a way of overriding prototypes that won't break the lazy loading of the module.\nconst replace = NativeVideoModule.VideoPlayer.prototype.replace;\nNativeVideoModule.VideoPlayer.prototype.replace = function (source: VideoSource) {\n return replace.call(this, parseSource(source));\n};\n\n/**\n * Creates a `VideoPlayer`, which will be automatically cleaned up when the component is unmounted.\n * @param source - A video source that is used to initialize the player.\n * @param setup - A function that allows setting up the player. It will run after the player is created.\n */\nexport function useVideoPlayer(\n source: VideoSource,\n setup?: (player: VideoPlayer) => void\n): VideoPlayer {\n const parsedSource = parseSource(source);\n\n return useReleasingSharedObject(() => {\n const player = new NativeVideoModule.VideoPlayer(parsedSource);\n setup?.(player);\n return player;\n }, [JSON.stringify(parsedSource)]);\n}\n\nfunction parseSource(source: VideoSource): VideoSource {\n if (typeof source === 'number') {\n return { uri: resolveAssetSource(source).uri };\n } else if (typeof source === 'string') {\n return { uri: source };\n }\n\n if (typeof source?.assetId === 'number' && !source.uri) {\n return { ...source, uri: resolveAssetSource(source.assetId).uri };\n }\n return source;\n}\n\nexport default NativeVideoModule.VideoPlayer;\n"]}
|
|
@@ -28,6 +28,28 @@ export declare class VideoPlayer extends SharedObject<VideoPlayerEvents> {
|
|
|
28
28
|
* Setting `currentTime` to a new value seeks the player to the given time.
|
|
29
29
|
*/
|
|
30
30
|
currentTime: number;
|
|
31
|
+
/**
|
|
32
|
+
* The exact timestamp when the currently displayed video frame was sent from the server,
|
|
33
|
+
* based on the `EXT-X-PROGRAM-DATE-TIME` tag in the livestream metadata.
|
|
34
|
+
* If this metadata is missing, this property will return `null`.
|
|
35
|
+
* > This property is read-only.
|
|
36
|
+
* @platform android
|
|
37
|
+
* @platform ios
|
|
38
|
+
*/
|
|
39
|
+
readonly currentLiveTimestamp: number | null;
|
|
40
|
+
/**
|
|
41
|
+
* Float value indicating the latency of the live stream in seconds.
|
|
42
|
+
* If a livestream doesn't have the required metadata, this will return `null`.
|
|
43
|
+
* > This property is get-only
|
|
44
|
+
* @platform android
|
|
45
|
+
* @platform ios
|
|
46
|
+
*/
|
|
47
|
+
readonly currentOffsetFromLive: number | null;
|
|
48
|
+
/**
|
|
49
|
+
* Float value indicating the time offset from the live in seconds.
|
|
50
|
+
* @platform ios
|
|
51
|
+
*/
|
|
52
|
+
targetOffsetFromLive: number;
|
|
31
53
|
/**
|
|
32
54
|
* Float value indicating the duration of the current video in seconds.
|
|
33
55
|
* > This property is get-only
|
|
@@ -65,6 +87,10 @@ export declare class VideoPlayer extends SharedObject<VideoPlayerEvents> {
|
|
|
65
87
|
status: VideoPlayerStatus;
|
|
66
88
|
/**
|
|
67
89
|
* Boolean value determining whether the player should show the now playing notification.
|
|
90
|
+
*
|
|
91
|
+
* @default false
|
|
92
|
+
* @platrorm android
|
|
93
|
+
* @platform ios
|
|
68
94
|
*/
|
|
69
95
|
showNowPlayingNotification: boolean;
|
|
70
96
|
/**
|
|
@@ -137,11 +163,18 @@ export type VideoPlayerEvents = {
|
|
|
137
163
|
* - `error`: The player has encountered an error while loading or playing the video.
|
|
138
164
|
*/
|
|
139
165
|
export type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error';
|
|
140
|
-
export type VideoSource = string | {
|
|
166
|
+
export type VideoSource = string | number | {
|
|
141
167
|
/**
|
|
142
168
|
* The URI of the video.
|
|
169
|
+
*
|
|
170
|
+
* This property is exclusive with the `assetId` property. When both are present, the `assetId` will be ignored.
|
|
171
|
+
*/
|
|
172
|
+
uri?: string;
|
|
173
|
+
/**
|
|
174
|
+
* The asset ID of a local video asset, acquired with the `require` function.
|
|
175
|
+
* This property is exclusive with the `uri` property. When both are present, the `assetId` will be ignored.
|
|
143
176
|
*/
|
|
144
|
-
|
|
177
|
+
assetId?: number;
|
|
145
178
|
/**
|
|
146
179
|
* Specifies the DRM options which will be used by the player while loading the video.
|
|
147
180
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlayer.types.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,YAAY,CAAC,iBAAiB,CAAC;IACtE;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;;;OAIG;IACH,KAAK,EAAE,OAAO,CAAC;IAEf;;;;;;;OAOG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;OAMG;IACH,cAAc,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,MAAM,EAAE,iBAAiB,CAAC;IAE1B
|
|
1
|
+
{"version":3,"file":"VideoPlayer.types.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlayer.types.js","sourceRoot":"","sources":["../src/VideoPlayer.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { SharedObject } from 'expo-modules-core';\n\n/**\n * A class that represents an instance of the video player.\n */\nexport declare class VideoPlayer extends SharedObject<VideoPlayerEvents> {\n /**\n * Boolean value whether the player is currently playing.\n * > This property is get-only, use `play` and `pause` methods to control the playback.\n */\n playing: boolean;\n\n /**\n * Determines whether the player should automatically replay after reaching the end of the video.\n * @default false\n */\n loop: boolean;\n\n /**\n * Boolean value whether the player is currently muted.\n * Setting this property to `true`/`false` will mute/unmute the player.\n * @default false\n */\n muted: boolean;\n\n /**\n * Float value indicating the current playback time in seconds.\n *\n * If the player is not yet playing, this value indicates the time position\n * at which playback will begin once the `play()` method is called.\n *\n * Setting `currentTime` to a new value seeks the player to the given time.\n */\n currentTime: number;\n\n /**\n * Float value indicating the duration of the current video in seconds.\n * > This property is get-only\n */\n duration: number;\n\n /**\n * Float value between 0 and 1 representing the current volume.\n * Muting the player doesn't affect the volume. In other words, when the player is muted, the volume is the same as\n * when unmuted. Similarly, setting the volume doesn't unmute the player.\n * @default 1.0\n */\n volume: number;\n\n /**\n * Boolean value indicating if the player should correct audio pitch when the playback speed changes.\n * > On web, changing this property is not supported, the player will always correct the pitch.\n * @default true\n * @platform android\n * @platform ios\n */\n preservesPitch: boolean;\n\n /**\n * Float value between 0 and 16 indicating the current playback speed of the player.\n * @default 1.0\n */\n playbackRate: number;\n\n /**\n * Boolean value indicating whether the player is currently playing a live stream.\n * > This property is get-only\n */\n isLive: boolean;\n\n /**\n * Indicates the current status of the player.\n * > This property is get-only\n */\n status: VideoPlayerStatus;\n\n /**\n * Boolean value determining whether the player should show the now playing notification.\n */\n showNowPlayingNotification: boolean;\n\n /**\n * Determines whether the player should continue playing after the app enters the background.\n * @default false\n * @platform ios\n * @platform android\n */\n staysActiveInBackground: boolean;\n\n /**\n * Initializes a new video player instance with the given source.\n * @hidden\n */\n constructor(source: VideoSource);\n\n /**\n * Resumes the player.\n */\n play(): void;\n\n /**\n * Pauses the player.\n */\n pause(): void;\n\n /**\n * Replaces the current source with a new one.\n */\n replace(source: VideoSource): void;\n\n /**\n * Seeks the playback by the given number of seconds.\n */\n seekBy(seconds: number): void;\n\n /**\n * Seeks the playback to the beginning.\n */\n replay(): void;\n}\n\n/**\n * Handlers for events which can be emitted by the player.\n */\nexport type VideoPlayerEvents = {\n /**\n * Handler for an event emitted when the status of the player changes.\n */\n statusChange(\n newStatus: VideoPlayerStatus,\n oldStatus: VideoPlayerStatus,\n error?: PlayerError\n ): void;\n /**\n * Handler for an event emitted when the player starts or stops playback.\n */\n playingChange(newIsPlaying: boolean, oldIsPlaying: boolean): void;\n /**\n * Handler for an event emitted when the `playbackRate` property of the player changes.\n */\n playbackRateChange(newPlaybackRate: number, oldPlaybackRate: number): void;\n /**\n * Handler for an event emitted when the `volume` property of the player changes.\n */\n volumeChange(newVolume: VolumeEvent, oldVolume: VolumeEvent): void;\n /**\n * Handler for an event emitted when the player plays to the end of the current source.\n */\n playToEnd(): void;\n /**\n * Handler for an event emitted when the current media source of the player changes.\n */\n sourceChange(newSource: VideoSource, previousSource: VideoSource): void;\n};\n\n/**\n * Describes the current status of the player.\n * - `idle`: The player is not playing or loading any videos.\n * - `loading`: The player is loading video data from the provided source\n * - `readyToPlay`: The player has loaded enough data to start playing or to continue playback.\n * - `error`: The player has encountered an error while loading or playing the video.\n */\nexport type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error';\n\nexport type VideoSource =\n | string\n | {\n /**\n * The URI of the video.\n */\n uri
|
|
1
|
+
{"version":3,"file":"VideoPlayer.types.js","sourceRoot":"","sources":["../src/VideoPlayer.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { SharedObject } from 'expo-modules-core';\n\n/**\n * A class that represents an instance of the video player.\n */\nexport declare class VideoPlayer extends SharedObject<VideoPlayerEvents> {\n /**\n * Boolean value whether the player is currently playing.\n * > This property is get-only, use `play` and `pause` methods to control the playback.\n */\n playing: boolean;\n\n /**\n * Determines whether the player should automatically replay after reaching the end of the video.\n * @default false\n */\n loop: boolean;\n\n /**\n * Boolean value whether the player is currently muted.\n * Setting this property to `true`/`false` will mute/unmute the player.\n * @default false\n */\n muted: boolean;\n\n /**\n * Float value indicating the current playback time in seconds.\n *\n * If the player is not yet playing, this value indicates the time position\n * at which playback will begin once the `play()` method is called.\n *\n * Setting `currentTime` to a new value seeks the player to the given time.\n */\n currentTime: number;\n\n /**\n * The exact timestamp when the currently displayed video frame was sent from the server,\n * based on the `EXT-X-PROGRAM-DATE-TIME` tag in the livestream metadata.\n * If this metadata is missing, this property will return `null`.\n * > This property is read-only.\n * @platform android\n * @platform ios\n */\n readonly currentLiveTimestamp: number | null;\n\n /**\n * Float value indicating the latency of the live stream in seconds.\n * If a livestream doesn't have the required metadata, this will return `null`.\n * > This property is get-only\n * @platform android\n * @platform ios\n */\n readonly currentOffsetFromLive: number | null;\n\n /**\n * Float value indicating the time offset from the live in seconds.\n * @platform ios\n */\n targetOffsetFromLive: number;\n\n /**\n * Float value indicating the duration of the current video in seconds.\n * > This property is get-only\n */\n duration: number;\n\n /**\n * Float value between 0 and 1 representing the current volume.\n * Muting the player doesn't affect the volume. In other words, when the player is muted, the volume is the same as\n * when unmuted. Similarly, setting the volume doesn't unmute the player.\n * @default 1.0\n */\n volume: number;\n\n /**\n * Boolean value indicating if the player should correct audio pitch when the playback speed changes.\n * > On web, changing this property is not supported, the player will always correct the pitch.\n * @default true\n * @platform android\n * @platform ios\n */\n preservesPitch: boolean;\n\n /**\n * Float value between 0 and 16 indicating the current playback speed of the player.\n * @default 1.0\n */\n playbackRate: number;\n\n /**\n * Boolean value indicating whether the player is currently playing a live stream.\n * > This property is get-only\n */\n isLive: boolean;\n\n /**\n * Indicates the current status of the player.\n * > This property is get-only\n */\n status: VideoPlayerStatus;\n\n /**\n * Boolean value determining whether the player should show the now playing notification.\n *\n * @default false\n * @platrorm android\n * @platform ios\n */\n showNowPlayingNotification: boolean;\n\n /**\n * Determines whether the player should continue playing after the app enters the background.\n * @default false\n * @platform ios\n * @platform android\n */\n staysActiveInBackground: boolean;\n\n /**\n * Initializes a new video player instance with the given source.\n * @hidden\n */\n constructor(source: VideoSource);\n\n /**\n * Resumes the player.\n */\n play(): void;\n\n /**\n * Pauses the player.\n */\n pause(): void;\n\n /**\n * Replaces the current source with a new one.\n */\n replace(source: VideoSource): void;\n\n /**\n * Seeks the playback by the given number of seconds.\n */\n seekBy(seconds: number): void;\n\n /**\n * Seeks the playback to the beginning.\n */\n replay(): void;\n}\n\n/**\n * Handlers for events which can be emitted by the player.\n */\nexport type VideoPlayerEvents = {\n /**\n * Handler for an event emitted when the status of the player changes.\n */\n statusChange(\n newStatus: VideoPlayerStatus,\n oldStatus: VideoPlayerStatus,\n error?: PlayerError\n ): void;\n /**\n * Handler for an event emitted when the player starts or stops playback.\n */\n playingChange(newIsPlaying: boolean, oldIsPlaying: boolean): void;\n /**\n * Handler for an event emitted when the `playbackRate` property of the player changes.\n */\n playbackRateChange(newPlaybackRate: number, oldPlaybackRate: number): void;\n /**\n * Handler for an event emitted when the `volume` property of the player changes.\n */\n volumeChange(newVolume: VolumeEvent, oldVolume: VolumeEvent): void;\n /**\n * Handler for an event emitted when the player plays to the end of the current source.\n */\n playToEnd(): void;\n /**\n * Handler for an event emitted when the current media source of the player changes.\n */\n sourceChange(newSource: VideoSource, previousSource: VideoSource): void;\n};\n\n/**\n * Describes the current status of the player.\n * - `idle`: The player is not playing or loading any videos.\n * - `loading`: The player is loading video data from the provided source\n * - `readyToPlay`: The player has loaded enough data to start playing or to continue playback.\n * - `error`: The player has encountered an error while loading or playing the video.\n */\nexport type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error';\n\nexport type VideoSource =\n | string\n | number\n | {\n /**\n * The URI of the video.\n *\n * This property is exclusive with the `assetId` property. When both are present, the `assetId` will be ignored.\n */\n uri?: string;\n\n /**\n * The asset ID of a local video asset, acquired with the `require` function.\n * This property is exclusive with the `uri` property. When both are present, the `assetId` will be ignored.\n */\n assetId?: number;\n\n /**\n * Specifies the DRM options which will be used by the player while loading the video.\n */\n drm?: DRMOptions;\n\n /**\n * Specifies information which will be displayed in the now playing notification.\n * When undefined the player will display information contained in the video metadata.\n */\n metadata?: VideoMetadata;\n\n /**\n * Specifies headers sent with the video request.\n * > For DRM license headers use the `headers` field of [`DRMOptions`](#drmoptions).\n * @platform android\n * @platform ios\n */\n headers?: Record<string, string>;\n }\n | null;\n\n/**\n * Contains information about any errors that the player encountered during the playback\n */\nexport type PlayerError = {\n message: string;\n};\n\n/**\n * Contains information about the current volume and whether the player is muted.\n */\nexport type VolumeEvent = {\n volume: number;\n isMuted: boolean;\n};\n\n/**\n * Contains information that will be displayed in the now playing notification when the video is playing.\n */\nexport type VideoMetadata = {\n /**\n * The title of the video.\n */\n title?: string;\n /**\n * Secondary text that will be displayed under the title.\n */\n artist?: string;\n};\n\n/**\n * Specifies which type of DRM to use. Android supports Widevine, PlayReady and ClearKey, iOS supports FairPlay.\n */\nexport type DRMType = 'clearkey' | 'fairplay' | 'playready' | 'widevine';\n\n/**\n * Specifies DRM options which will be used by the player while loading the video.\n */\nexport type DRMOptions = {\n /**\n * Determines which type of DRM to use.\n */\n type: DRMType;\n\n /**\n * Determines the license server URL.\n */\n licenseServer: string;\n\n /**\n * Determines headers sent to the license server on license requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * Specifies whether the DRM is a multi-key DRM.\n * @platform android\n */\n multiKey?: boolean;\n\n /**\n * Specifies the content ID of the stream.\n * @platform ios\n */\n contentId?: string;\n\n /**\n * Specifies the certificate URL for the FairPlay DRM.\n * @platform ios\n */\n certificateUrl?: string;\n\n /**\n * Specifies the base64 encoded certificate data for the FairPlay DRM.\n * When this property is set, the `certificateUrl` property is ignored.\n * @platform ios\n */\n base64CertificateData?: string;\n};\n"]}
|
|
@@ -17,6 +17,9 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject<VideoPl
|
|
|
17
17
|
_error: PlayerError | null;
|
|
18
18
|
staysActiveInBackground: boolean;
|
|
19
19
|
showNowPlayingNotification: boolean;
|
|
20
|
+
currentLiveTimestamp: number | null;
|
|
21
|
+
currentOffsetFromLive: number | null;
|
|
22
|
+
targetOffsetFromLive: number;
|
|
20
23
|
set muted(value: boolean);
|
|
21
24
|
get muted(): boolean;
|
|
22
25
|
set playbackRate(value: number);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlayer.web.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.web.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACZ,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"VideoPlayer.web.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.web.tsx"],"names":[],"mappings":"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"}
|
package/build/VideoPlayer.web.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
+
import resolveAssetSource from './resolveAssetSource';
|
|
2
3
|
export function useVideoPlayer(source, setup) {
|
|
3
4
|
const parsedSource = typeof source === 'string' ? { uri: source } : source;
|
|
4
5
|
return useMemo(() => {
|
|
@@ -8,9 +9,15 @@ export function useVideoPlayer(source, setup) {
|
|
|
8
9
|
}, [JSON.stringify(source)]);
|
|
9
10
|
}
|
|
10
11
|
export function getSourceUri(source) {
|
|
11
|
-
if (typeof source
|
|
12
|
+
if (typeof source === 'string') {
|
|
12
13
|
return source;
|
|
13
14
|
}
|
|
15
|
+
if (typeof source === 'number') {
|
|
16
|
+
return resolveAssetSource(source)?.uri ?? null;
|
|
17
|
+
}
|
|
18
|
+
if (typeof source?.assetId === 'number' && !source?.uri) {
|
|
19
|
+
return resolveAssetSource(source.assetId)?.uri ?? null;
|
|
20
|
+
}
|
|
14
21
|
return source?.uri ?? null;
|
|
15
22
|
}
|
|
16
23
|
export default class VideoPlayerWeb extends globalThis.expo.SharedObject {
|
|
@@ -32,6 +39,9 @@ export default class VideoPlayerWeb extends globalThis.expo.SharedObject {
|
|
|
32
39
|
_error = null;
|
|
33
40
|
staysActiveInBackground = false; // Not supported on web. Dummy to match the interface.
|
|
34
41
|
showNowPlayingNotification = false; // Not supported on web. Dummy to match the interface.
|
|
42
|
+
currentLiveTimestamp = null; // Not supported on web. Dummy to match the interface.
|
|
43
|
+
currentOffsetFromLive = null; // Not supported on web. Dummy to match the interface.
|
|
44
|
+
targetOffsetFromLive = 0; // Not supported on web. Dummy to match the interface.
|
|
35
45
|
set muted(value) {
|
|
36
46
|
this._mountedVideos.forEach((video) => {
|
|
37
47
|
video.muted = value;
|