expo-video 3.0.8 → 3.0.10

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/AndroidManifest.xml +0 -8
  4. package/android/src/main/java/expo/modules/video/VideoExceptions.kt +8 -0
  5. package/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt +125 -46
  6. package/android/src/main/java/expo/modules/video/playbackService/PlaybackServiceConnection.kt +35 -12
  7. package/android/src/main/java/expo/modules/video/player/VideoPlayer.kt +36 -4
  8. package/build/VideoPlayer.types.d.ts +5 -0
  9. package/build/VideoPlayer.types.d.ts.map +1 -1
  10. package/build/VideoPlayer.types.js.map +1 -1
  11. package/build/VideoView.web.d.ts.map +1 -1
  12. package/build/VideoView.web.js +43 -9
  13. package/build/VideoView.web.js.map +1 -1
  14. package/expo-module.config.json +1 -1
  15. package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.0.8/expo.modules.video-3.0.8-sources.jar → 3.0.10/expo.modules.video-3.0.10-sources.jar} +0 -0
  16. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10-sources.jar.md5 +1 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10-sources.jar.sha1 +1 -0
  18. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10-sources.jar.sha256 +1 -0
  19. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10-sources.jar.sha512 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.aar +0 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.aar.md5 +1 -0
  22. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.aar.sha1 +1 -0
  23. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.aar.sha256 +1 -0
  24. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.aar.sha512 +1 -0
  25. package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.0.8/expo.modules.video-3.0.8.module → 3.0.10/expo.modules.video-3.0.10.module} +22 -22
  26. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.module.md5 +1 -0
  27. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.module.sha1 +1 -0
  28. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.module.sha256 +1 -0
  29. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.module.sha512 +1 -0
  30. package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.0.8/expo.modules.video-3.0.8.pom → 3.0.10/expo.modules.video-3.0.10.pom} +1 -1
  31. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.pom.md5 +1 -0
  32. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.pom.sha1 +1 -0
  33. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.pom.sha256 +1 -0
  34. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.10/expo.modules.video-3.0.10.pom.sha512 +1 -0
  35. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml +4 -4
  36. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.md5 +1 -1
  37. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha1 +1 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha256 +1 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha512 +1 -1
  40. package/package.json +2 -2
  41. package/plugin/build/withExpoVideo.js +44 -8
  42. package/plugin/src/withExpoVideo.ts +51 -7
  43. package/src/VideoPlayer.types.ts +5 -0
  44. package/src/VideoView.web.tsx +57 -9
  45. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8-sources.jar.md5 +0 -1
  46. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8-sources.jar.sha1 +0 -1
  47. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8-sources.jar.sha256 +0 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8-sources.jar.sha512 +0 -1
  49. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.aar +0 -0
  50. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.aar.md5 +0 -1
  51. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.aar.sha1 +0 -1
  52. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.aar.sha256 +0 -1
  53. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.aar.sha512 +0 -1
  54. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.module.md5 +0 -1
  55. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.module.sha1 +0 -1
  56. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.module.sha256 +0 -1
  57. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.module.sha512 +0 -1
  58. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.pom.md5 +0 -1
  59. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.pom.sha1 +0 -1
  60. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.pom.sha256 +0 -1
  61. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.0.8/expo.modules.video-3.0.8.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,22 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 3.0.10 — 2025-09-04
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - [Web] Fix fullscreen enter/exit methods and listeners not working in Safari on iOS. ([#39320](https://github.com/expo/expo/pull/39320) by [@behenate](https://github.com/behenate))
18
+
19
+ ## 3.0.9 — 2025-09-03
20
+
21
+ ### 🛠 Breaking changes
22
+
23
+ - [Android] In order to show the now playing notification, the `supportsBackgroundPlayground` property of the config plugin has to be `true`. ([#38980](https://github.com/expo/expo/pull/38980) by [@kerwanp](https://github.com/kerwanp))
24
+
25
+ ### 🐛 Bug fixes
26
+
27
+ - [Android] Fix video player stopping playback a few minutes after locking the device. ([#38980](https://github.com/expo/expo/pull/38980) by [@kerwanp](https://github.com/kerwanp))
28
+
13
29
  ## 3.0.8 — 2025-09-02
14
30
 
15
31
  _This version does not introduce any user-facing changes._
@@ -4,13 +4,13 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '3.0.8'
7
+ version = '3.0.10'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.video"
11
11
  defaultConfig {
12
12
  versionCode 1
13
- versionName '3.0.8'
13
+ versionName '3.0.10'
14
14
  }
15
15
  }
16
16
 
@@ -8,13 +8,5 @@
8
8
  android:supportsPictureInPicture="true"
9
9
  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|navigation"
10
10
  android:theme="@style/Fullscreen" />
11
- <service
12
- android:name=".playbackService.ExpoVideoPlaybackService"
13
- android:exported="false"
14
- android:foregroundServiceType="mediaPlayback">
15
- <intent-filter>
16
- <action android:name="androidx.media3.session.MediaSessionService" />
17
- </intent-filter>
18
- </service>
19
11
  </application>
20
12
  </manifest>
@@ -3,6 +3,8 @@ package expo.modules.video
3
3
  import expo.modules.kotlin.exception.CodedException
4
4
  import expo.modules.video.enums.DRMType
5
5
 
6
+ private const val defaultServiceBindingTip = "Make sure that the expo-video config plugin is properly configured to avoid issues with displaying the now playing notification and sustaining background playback."
7
+
6
8
  internal class FullScreenVideoViewNotFoundException :
7
9
  CodedException("VideoView id wasn't passed to the activity")
8
10
 
@@ -35,3 +37,9 @@ internal class FailedToGetAudioFocusManagerException :
35
37
 
36
38
  internal class VideoCacheException(message: String?, cause: Throwable? = null) :
37
39
  CodedException(message ?: "Unexpected expo-video cache error", cause)
40
+
41
+ internal class NowPlayingException(message: String?, cause: Throwable? = null) :
42
+ CodedException(message ?: "Unexpected expo-video now playing exception", cause)
43
+
44
+ internal fun getPlaybackServiceErrorMessage(message: String?, tip: String = defaultServiceBindingTip) =
45
+ (message ?: "Expo-video playback service binder error") + ". $tip"
@@ -2,12 +2,14 @@ package expo.modules.video.playbackService
2
2
 
3
3
  import android.app.NotificationChannel
4
4
  import android.app.NotificationManager
5
+ import android.app.Service
5
6
  import android.content.Context
6
7
  import android.content.Intent
7
8
  import android.os.Binder
8
9
  import android.os.Build
9
10
  import android.os.Bundle
10
11
  import android.os.IBinder
12
+ import androidx.annotation.MainThread
11
13
  import androidx.annotation.OptIn
12
14
  import androidx.core.app.NotificationCompat
13
15
  import androidx.media3.common.util.UnstableApi
@@ -19,15 +21,27 @@ import androidx.media3.session.MediaStyleNotificationHelper
19
21
  import androidx.media3.session.SessionCommand
20
22
  import com.google.common.collect.ImmutableList
21
23
  import expo.modules.kotlin.AppContext
24
+ import expo.modules.kotlin.exception.Exceptions
22
25
  import expo.modules.video.R
26
+ import expo.modules.video.getPlaybackServiceErrorMessage
23
27
  import expo.modules.video.player.VideoPlayer
28
+ import kotlinx.coroutines.launch
29
+ import java.lang.ref.WeakReference
24
30
 
25
31
  class PlaybackServiceBinder(val service: ExpoVideoPlaybackService) : Binder()
26
32
 
27
33
  @OptIn(UnstableApi::class)
28
34
  class ExpoVideoPlaybackService : MediaSessionService() {
35
+ private lateinit var weakContext: WeakReference<AppContext>
36
+ var appContext: AppContext
37
+ get() = weakContext.get() ?: throw Exceptions.AppContextLost()
38
+ set(value) {
39
+ weakContext = WeakReference(value)
40
+ }
29
41
  private val mediaSessions = mutableMapOf<ExoPlayer, MediaSession>()
30
42
  private val binder = PlaybackServiceBinder(this)
43
+ private var mostRecentInteractionSession: MediaSession? = null
44
+ private var isForeground: Boolean = false
31
45
 
32
46
  private val commandSeekForward = SessionCommand(SEEK_FORWARD_COMMAND, Bundle.EMPTY)
33
47
  private val commandSeekBackward = SessionCommand(SEEK_BACKWARD_COMMAND, Bundle.EMPTY)
@@ -44,42 +58,50 @@ class ExpoVideoPlaybackService : MediaSessionService() {
44
58
  .build()
45
59
 
46
60
  fun setShowNotification(showNotification: Boolean, player: ExoPlayer) {
47
- val sessionExtras = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
48
- mediaSessions[player]?.sessionExtras?.deepCopy() ?: Bundle()
49
- } else {
50
- Bundle()
51
- }
52
- sessionExtras.putBoolean(SESSION_SHOW_NOTIFICATION, showNotification)
53
- mediaSessions[player]?.let {
54
- it.sessionExtras = sessionExtras
55
- onUpdateNotification(it, showNotification)
61
+ appContext.mainQueue.launch {
62
+ val sessionExtras = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
63
+ mediaSessions[player]?.sessionExtras?.deepCopy() ?: Bundle()
64
+ } else {
65
+ Bundle()
66
+ }
67
+ sessionExtras.putBoolean(SESSION_SHOW_NOTIFICATION, showNotification)
68
+ mediaSessions[player]?.let {
69
+ it.sessionExtras = sessionExtras
70
+ onUpdateNotification(it, showNotification && player.playWhenReady)
71
+ }
56
72
  }
57
73
  }
58
74
 
59
75
  fun registerPlayer(videoPlayer: VideoPlayer) {
60
- val player = videoPlayer.player
61
- if (mediaSessions[player] != null) {
62
- return
63
- }
76
+ appContext.mainQueue.launch {
77
+ val player = videoPlayer.player
78
+ if (mediaSessions[player] != null) {
79
+ return@launch
80
+ }
64
81
 
65
- val mediaSession = MediaSession.Builder(this, player)
66
- .setId("ExpoVideoPlaybackService_${player.hashCode()}")
67
- .setCallback(VideoMediaSessionCallback())
68
- .setCustomLayout(ImmutableList.of(seekBackwardButton, seekForwardButton))
69
- .build()
82
+ val mediaSession = MediaSession.Builder(this@ExpoVideoPlaybackService, player)
83
+ .setId("ExpoVideoPlaybackService_${player.hashCode()}")
84
+ .setCallback(VideoMediaSessionCallback())
85
+ .setCustomLayout(ImmutableList.of(seekBackwardButton, seekForwardButton))
86
+ .build()
70
87
 
71
- mediaSessions[player] = mediaSession
72
- addSession(mediaSession)
73
- setShowNotification(videoPlayer.showNowPlayingNotification, player)
88
+ mediaSessions[player] = mediaSession
89
+ addSession(mediaSession)
90
+ setShowNotification(videoPlayer.showNowPlayingNotification, player)
91
+ }
74
92
  }
75
93
 
76
94
  fun unregisterPlayer(player: ExoPlayer) {
77
- hidePlayerNotification(player)
78
- val session = mediaSessions.remove(player)
79
- session?.release()
80
- if (mediaSessions.isEmpty()) {
81
- cleanup()
82
- stopSelf()
95
+ appContext.mainQueue.launch {
96
+ hidePlayerNotification(player)
97
+ val session = mediaSessions.remove(player)
98
+ session?.release()
99
+ if (mediaSessions.isEmpty()) {
100
+ cleanup()
101
+ stopSelf()
102
+ } else {
103
+ setMostRecentInteractionSession(findMostRecentInteractionSession())
104
+ }
83
105
  }
84
106
  }
85
107
 
@@ -89,15 +111,48 @@ class ExpoVideoPlaybackService : MediaSessionService() {
89
111
  }
90
112
 
91
113
  override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) {
92
- if (session.sessionExtras.getBoolean(SESSION_SHOW_NOTIFICATION, false)) {
93
- createNotification(session)
94
- } else {
95
- (session.player as? ExoPlayer)?.let {
96
- hidePlayerNotification(it)
114
+ appContext.mainQueue.launch {
115
+ if (startInForegroundRequired && session.wantsToShowNotification()) {
116
+ setMostRecentInteractionSession(session)
117
+ } else {
118
+ setMostRecentInteractionSession(findMostRecentInteractionSession())
97
119
  }
98
120
  }
99
121
  }
100
122
 
123
+ @MainThread
124
+ private fun setMostRecentInteractionSession(session: MediaSession?) {
125
+ if (session?.player?.playWhenReady == false) {
126
+ stopForeground(STOP_FOREGROUND_DETACH)
127
+ isForeground = false
128
+ }
129
+
130
+ if (mostRecentInteractionSession != session) {
131
+ hideAllNotifications()
132
+ }
133
+
134
+ mostRecentInteractionSession = session
135
+ session?.let {
136
+ createNotification(it, it.player.playWhenReady)
137
+ } ?: run {
138
+ stopForeground(STOP_FOREGROUND_REMOVE)
139
+ isForeground = false
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Finds a session that is playing media. And wants to show a notification
145
+ * If none exists, returns a session that wants to show a notification.
146
+ * The current mostRecentInteractionSession always has priority to reduce the number of unnecessary notification changes.
147
+ */
148
+ @MainThread
149
+ private fun findMostRecentInteractionSession(): MediaSession? {
150
+ val prioritizedSessions = (listOfNotNull(mostRecentInteractionSession) + mediaSessions.values.toList()).distinct()
151
+
152
+ return prioritizedSessions.firstOrNull { it.wantsToShowNotification() && it.player.playWhenReady }
153
+ ?: prioritizedSessions.firstOrNull { it.wantsToShowNotification() }
154
+ }
155
+
101
156
  override fun onTaskRemoved(rootIntent: Intent?) {
102
157
  cleanup()
103
158
  stopSelf()
@@ -112,7 +167,8 @@ class ExpoVideoPlaybackService : MediaSessionService() {
112
167
  super.onDestroy()
113
168
  }
114
169
 
115
- private fun createNotification(session: MediaSession) {
170
+ @MainThread
171
+ private fun createNotification(session: MediaSession, startInForegroundRequired: Boolean = false) {
116
172
  if (session.player.currentMediaItem == null) {
117
173
  return
118
174
  }
@@ -130,33 +186,55 @@ class ExpoVideoPlaybackService : MediaSessionService() {
130
186
  .setStyle(MediaStyleNotificationHelper.MediaStyle(session))
131
187
  .build()
132
188
 
133
- // Each of the players has it's own notification when playing.
134
- notificationManager.notify(session.player.hashCode(), notificationCompat)
189
+ val notificationId = session.player.hashCode()
190
+
191
+ if (startInForegroundRequired) {
192
+ try {
193
+ startForeground(notificationId, notificationCompat)
194
+ isForeground = true
195
+ } catch (e: Exception) {
196
+ appContext.jsLogger?.error(getPlaybackServiceErrorMessage("Failed to start the expo-video foreground service"), e)
197
+ }
198
+ } else {
199
+ notificationManager.notify(notificationId, notificationCompat)
200
+ }
135
201
  }
136
202
 
137
203
  private fun cleanup() {
138
- hideAllNotifications()
204
+ appContext.mainQueue.launch {
205
+ stopForeground(Service.STOP_FOREGROUND_REMOVE)
206
+ isForeground = false
207
+
208
+ hideAllNotifications()
209
+
210
+ val sessionsToRelease = mediaSessions.values.toList()
211
+ mediaSessions.clear()
212
+ for (session in sessionsToRelease) {
213
+ session.release()
214
+ }
139
215
 
140
- val sessionsToRelease = mediaSessions.values.toList()
141
- mediaSessions.clear()
142
- for (session in sessionsToRelease) {
143
- session.release()
216
+ val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
217
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
218
+ notificationManager.deleteNotificationChannel(CHANNEL_ID)
219
+ }
144
220
  }
145
221
  }
146
222
 
223
+ @MainThread
147
224
  private fun hidePlayerNotification(player: ExoPlayer) {
148
225
  val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
149
226
  notificationManager.cancel(player.hashCode())
150
227
  }
151
228
 
229
+ @MainThread
152
230
  private fun hideAllNotifications() {
153
231
  val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
154
232
  notificationManager.cancelAll()
155
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
156
- notificationManager.deleteNotificationChannel(CHANNEL_ID)
157
- }
158
233
  }
159
234
 
235
+ private fun MediaSession.wantsToShowNotification(): Boolean =
236
+ this.sessionExtras.getBoolean(SESSION_SHOW_NOTIFICATION, false)
237
+
160
238
  companion object {
161
239
  const val SEEK_FORWARD_COMMAND = "SEEK_FORWARD"
162
240
  const val SEEK_BACKWARD_COMMAND = "SEEK_REWIND"
@@ -164,7 +242,7 @@ class ExpoVideoPlaybackService : MediaSessionService() {
164
242
  const val SESSION_SHOW_NOTIFICATION = "showNotification"
165
243
  const val SEEK_INTERVAL_MS = 10000L
166
244
 
167
- fun startService(appContext: AppContext, context: Context, serviceConnection: PlaybackServiceConnection) {
245
+ fun startService(appContext: AppContext, context: Context, serviceConnection: PlaybackServiceConnection): Boolean {
168
246
  appContext.reactContext?.apply {
169
247
  val intent = Intent(context, ExpoVideoPlaybackService::class.java)
170
248
  intent.action = SERVICE_INTERFACE
@@ -172,13 +250,14 @@ class ExpoVideoPlaybackService : MediaSessionService() {
172
250
  startService(intent)
173
251
 
174
252
  val flags = if (Build.VERSION.SDK_INT >= 29) {
175
- BIND_AUTO_CREATE or Context.BIND_INCLUDE_CAPABILITIES
253
+ BIND_AUTO_CREATE or BIND_INCLUDE_CAPABILITIES
176
254
  } else {
177
255
  BIND_AUTO_CREATE
178
256
  }
179
257
 
180
- bindService(intent, serviceConnection, flags)
258
+ return bindService(intent, serviceConnection, flags)
181
259
  }
260
+ return false
182
261
  }
183
262
  }
184
263
  }
@@ -3,37 +3,60 @@ package expo.modules.video.playbackService
3
3
  import android.content.ComponentName
4
4
  import android.content.ServiceConnection
5
5
  import android.os.IBinder
6
- import android.util.Log
7
6
  import androidx.annotation.OptIn
8
7
  import androidx.media3.common.util.UnstableApi
8
+ import expo.modules.kotlin.AppContext
9
+ import expo.modules.kotlin.exception.Exceptions
10
+ import expo.modules.video.getPlaybackServiceErrorMessage
9
11
  import expo.modules.video.player.VideoPlayer
10
12
  import java.lang.ref.WeakReference
11
13
 
12
14
  @OptIn(UnstableApi::class)
13
- class PlaybackServiceConnection(val player: WeakReference<VideoPlayer>) : ServiceConnection {
15
+ class PlaybackServiceConnection(val player: WeakReference<VideoPlayer>, appContext: AppContext) : ServiceConnection {
14
16
  var playbackServiceBinder: PlaybackServiceBinder? = null
17
+ private set
18
+ var isConnected = false
19
+ private set
20
+ private val _appContext = WeakReference(appContext)
21
+ private val appContext: AppContext
22
+ get() = _appContext.get() ?: throw Exceptions.AppContextLost()
15
23
 
16
24
  override fun onServiceConnected(componentName: ComponentName, binder: IBinder) {
17
25
  val player = player.get() ?: return
18
- playbackServiceBinder = binder as? PlaybackServiceBinder
19
- playbackServiceBinder?.service?.registerPlayer(player) ?: run {
20
- Log.w(
21
- "ExpoVideo",
22
- "Expo Video could not bind to the playback service. " +
23
- "This will cause issues with playback notifications and sustaining background playback."
26
+ val serviceBinder: PlaybackServiceBinder = binder as? PlaybackServiceBinder ?: run {
27
+ appContext.jsLogger?.error(
28
+ getPlaybackServiceErrorMessage("Expo-video could not bind to the playback service")
24
29
  )
30
+ return
25
31
  }
32
+
33
+ isConnected = true
34
+ playbackServiceBinder = serviceBinder
35
+ serviceBinder.service.appContext = appContext
36
+ serviceBinder.service.registerPlayer(player)
26
37
  }
27
38
 
28
39
  override fun onServiceDisconnected(componentName: ComponentName) {
29
40
  playbackServiceBinder = null
41
+ isConnected = false
42
+ }
43
+
44
+ override fun onBindingDied(name: ComponentName?) {
45
+ isConnected = false
46
+ appContext.jsLogger?.error(
47
+ getPlaybackServiceErrorMessage(
48
+ "Expo-video has lost connection to the playback service binder",
49
+ "This will cause issues with now playing notification and sustaining background playback."
50
+ )
51
+ )
52
+ super.onBindingDied(name)
30
53
  }
31
54
 
32
55
  override fun onNullBinding(componentName: ComponentName) {
33
- Log.w(
34
- "ExpoVideo",
35
- "Expo Video could not bind to the playback service. " +
36
- "This will cause issues with playback notifications and sustaining background playback."
56
+ isConnected = false
57
+ appContext.jsLogger?.error(
58
+ getPlaybackServiceErrorMessage("Expo Video could not bind to the playback service")
37
59
  )
60
+ super.onNullBinding(componentName)
38
61
  }
39
62
  }
@@ -23,6 +23,7 @@ import androidx.media3.exoplayer.analytics.AnalyticsListener
23
23
  import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
24
24
  import androidx.media3.ui.PlayerView
25
25
  import expo.modules.kotlin.AppContext
26
+ import expo.modules.kotlin.exception.Exceptions
26
27
  import expo.modules.kotlin.sharedobjects.SharedObject
27
28
  import expo.modules.video.IntervalUpdateClock
28
29
  import expo.modules.video.IntervalUpdateEmitter
@@ -31,6 +32,7 @@ import expo.modules.video.delegates.IgnoreSameSet
31
32
  import expo.modules.video.enums.AudioMixingMode
32
33
  import expo.modules.video.enums.PlayerStatus
33
34
  import expo.modules.video.enums.PlayerStatus.*
35
+ import expo.modules.video.getPlaybackServiceErrorMessage
34
36
  import expo.modules.video.playbackService.ExpoVideoPlaybackService
35
37
  import expo.modules.video.playbackService.PlaybackServiceConnection
36
38
  import expo.modules.video.records.BufferOptions
@@ -64,7 +66,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
64
66
  .build()
65
67
 
66
68
  private val firstFrameEventGenerator = createFirstFrameEventGenerator()
67
- val serviceConnection = PlaybackServiceConnection(WeakReference(this))
69
+ val serviceConnection = PlaybackServiceConnection(WeakReference(this), appContext)
68
70
  val intervalUpdateClock = IntervalUpdateClock(this)
69
71
 
70
72
  var playing by IgnoreSameSet(false) { new, old ->
@@ -81,6 +83,12 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
81
83
  var status: PlayerStatus = IDLE
82
84
  var requiresLinearPlayback = false
83
85
  var staysActiveInBackground = false
86
+ set(value) {
87
+ field = value
88
+ if (value) {
89
+ startPlaybackService()
90
+ }
91
+ }
84
92
  var preservesPitch = false
85
93
  set(preservesPitch) {
86
94
  field = preservesPitch
@@ -89,7 +97,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
89
97
  var showNowPlayingNotification = false
90
98
  set(value) {
91
99
  field = value
92
- serviceConnection.playbackServiceBinder?.service?.setShowNotification(value, this.player)
100
+ serviceSetShowNotification(value)
93
101
  }
94
102
  var duration = 0f
95
103
  var isLive = false
@@ -291,7 +299,6 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
291
299
  }
292
300
 
293
301
  init {
294
- ExpoVideoPlaybackService.startService(appContext, context, serviceConnection)
295
302
  player.addListener(playerListener)
296
303
  player.addAnalyticsListener(analyticsListener)
297
304
  VideoManager.registerVideoPlayer(this)
@@ -303,7 +310,9 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
303
310
  }
304
311
 
305
312
  override fun close() {
306
- appContext?.reactContext?.unbindService(serviceConnection)
313
+ if (serviceConnection.isConnected) {
314
+ appContext?.reactContext?.unbindService(serviceConnection)
315
+ }
307
316
  serviceConnection.playbackServiceBinder?.service?.unregisterPlayer(player)
308
317
  VideoManager.unregisterVideoPlayer(this@VideoPlayer)
309
318
 
@@ -398,6 +407,29 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
398
407
  isLive = false
399
408
  }
400
409
 
410
+ private fun startPlaybackService(): Boolean {
411
+ if (serviceConnection.playbackServiceBinder?.service != null) {
412
+ // PlaybackService already running.
413
+ return true
414
+ }
415
+ val appContext = appContext ?: throw Exceptions.AppContextLost()
416
+ val serviceStarted = ExpoVideoPlaybackService.startService(appContext, context, serviceConnection)
417
+
418
+ if (!serviceStarted) {
419
+ appContext.jsLogger?.error(
420
+ getPlaybackServiceErrorMessage("Expo-video has failed to bind with the playback service binder")
421
+ )
422
+ }
423
+ return serviceStarted
424
+ }
425
+
426
+ private fun serviceSetShowNotification(showNotification: Boolean) {
427
+ if (showNotification) {
428
+ startPlaybackService()
429
+ }
430
+ serviceConnection.playbackServiceBinder?.service?.setShowNotification(showNotification, this.player)
431
+ }
432
+
401
433
  fun addListener(videoPlayerListener: VideoPlayerListener) {
402
434
  if (listeners.all { it.get() != videoPlayerListener }) {
403
435
  listeners.add(WeakReference(videoPlayerListener))
@@ -115,6 +115,8 @@ export declare class VideoPlayer extends SharedObject<VideoPlayerEvents> {
115
115
  /**
116
116
  * Boolean value determining whether the player should show the now playing notification.
117
117
  *
118
+ * > **Note**: On Android, `supportsBackgroundPlayback` property of the [config plugin](#configuration-in-app-config)
119
+ * > has to be `true` for the now playing notification to work.
118
120
  * @default false
119
121
  * @platform android
120
122
  * @platform ios
@@ -122,6 +124,9 @@ export declare class VideoPlayer extends SharedObject<VideoPlayerEvents> {
122
124
  showNowPlayingNotification: boolean;
123
125
  /**
124
126
  * Determines whether the player should continue playing after the app enters the background.
127
+ *
128
+ * > **Note**: The `supportsBackgroundPlayback` property of the [config plugin](#configuration-in-app-config)
129
+ * > has to be `true` for the background playback to work.
125
130
  * @default false
126
131
  * @platform ios
127
132
  * @platform android
@@ -1 +1 @@
1
- {"version":3,"file":"VideoPlayer.types.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"VideoPlayer.types.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.types.ts"],"names":[],"mappings":"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"}