mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Video] Say No to Audio (Disable `expo-video` `AudioSession` management) (#5101)

authored by hailey.at and committed by

GitHub 05e61346 0e1de199

+121 -28
+118 -28
patches/expo-video+1.2.4.patch
··· 5 5 @@ -41,6 +41,11 @@ sealed class PlayerEvent { 6 6 override val name = "playToEnd" 7 7 } 8 - 8 + 9 9 + data class PlayerTimeRemainingChanged(val timeRemaining: Double): PlayerEvent() { 10 10 + override val name = "timeRemainingChange" 11 11 + override val arguments = arrayOf(timeRemaining) ··· 32 32 setTimeBarInteractive(requireLinearPlayback) 33 33 + setShowSubtitleButton(true) 34 34 } 35 - 35 + 36 36 @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) 37 37 @@ -27,7 +28,8 @@ internal fun PlayerView.setTimeBarInteractive(interactive: Boolean) { 38 - 38 + 39 39 @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) 40 40 internal fun PlayerView.setFullscreenButtonVisibility(visible: Boolean) { 41 41 - val fullscreenButton = findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_fullscreen) ··· 93 93 + "onEnterFullscreen", 94 94 + "onExitFullscreen" 95 95 ) 96 - 96 + 97 97 Prop("player") { view: VideoView, player: VideoPlayer -> 98 98 diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt 99 99 index 58f00af..5ad8237 100644 ··· 101 101 +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt 102 102 @@ -1,5 +1,6 @@ 103 103 package expo.modules.video 104 - 104 + 105 105 +import ProgressTracker 106 106 import android.content.Context 107 107 import android.view.SurfaceView ··· 111 111 .setLooper(context.mainLooper) 112 112 .build() 113 113 + var progressTracker: ProgressTracker? = null 114 - 114 + 115 115 val serviceConnection = PlaybackServiceConnection(WeakReference(player)) 116 - 116 + 117 117 var playing by IgnoreSameSet(false) { new, old -> 118 118 sendEvent(PlayerEvent.IsPlayingChanged(new, old)) 119 119 + addOrRemoveProgressTracker() 120 120 } 121 - 121 + 122 122 var uncommittedSource: VideoSource? = source 123 123 @@ -141,6 +144,9 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou 124 124 } 125 - 125 + 126 126 override fun close() { 127 127 + this.progressTracker?.remove() 128 128 + this.progressTracker = null ··· 133 133 @@ -228,7 +234,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou 134 134 listeners.removeAll { it.get() == videoPlayerListener } 135 135 } 136 - 136 + 137 137 - private fun sendEvent(event: PlayerEvent) { 138 138 + fun sendEvent(event: PlayerEvent) { 139 139 // Emits to the native listeners ··· 173 173 val onPictureInPictureStop by EventDispatcher<Unit>() 174 174 + val onEnterFullscreen by EventDispatcher() 175 175 + val onExitFullscreen by EventDispatcher() 176 - 176 + 177 177 var willEnterPiP: Boolean = false 178 178 var isInFullscreen: Boolean = false 179 179 @@ -154,6 +156,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap ··· 183 183 + onEnterFullscreen(mapOf()) 184 184 isInFullscreen = true 185 185 } 186 - 186 + 187 187 @@ -162,6 +165,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap 188 188 val fullScreenButton: ImageButton = playerView.findViewById(androidx.media3.ui.R.id.exo_fullscreen) 189 189 fullScreenButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter) ··· 191 191 + this.onExitFullscreen(mapOf()) 192 192 isInFullscreen = false 193 193 } 194 - 194 + 195 195 diff --git a/node_modules/expo-video/build/VideoPlayer.types.d.ts b/node_modules/expo-video/build/VideoPlayer.types.d.ts 196 - index a09fcfe..65fe29a 100644 196 + index a09fcfe..5eac9e5 100644 197 197 --- a/node_modules/expo-video/build/VideoPlayer.types.d.ts 198 198 +++ b/node_modules/expo-video/build/VideoPlayer.types.d.ts 199 199 @@ -128,6 +128,8 @@ export type VideoPlayerEvents = { ··· 219 219 } 220 220 //# sourceMappingURL=VideoView.types.d.ts.map 221 221 \ No newline at end of file 222 + diff --git a/node_modules/expo-video/ios/VideoManager.swift b/node_modules/expo-video/ios/VideoManager.swift 223 + index 094a8b0..412fd0c 100644 224 + --- a/node_modules/expo-video/ios/VideoManager.swift 225 + +++ b/node_modules/expo-video/ios/VideoManager.swift 226 + @@ -51,45 +51,45 @@ class VideoManager { 227 + // MARK: - Audio Session Management 228 + 229 + internal func setAppropriateAudioSessionOrWarn() { 230 + - let audioSession = AVAudioSession.sharedInstance() 231 + - var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = [] 232 + - 233 + - let isAnyPlayerPlaying = videoPlayers.allObjects.contains { player in 234 + - player.isPlaying 235 + - } 236 + - let areAllPlayersMuted = videoPlayers.allObjects.allSatisfy { player in 237 + - player.isMuted 238 + - } 239 + - let needsPiPSupport = videoViews.allObjects.contains { view in 240 + - view.allowPictureInPicture 241 + - } 242 + - let anyPlayerShowsNotification = videoPlayers.allObjects.contains { player in 243 + - player.showNowPlayingNotification 244 + - } 245 + - // The notification won't be shown if we allow the audio to mix with others 246 + - let shouldAllowMixing = (!isAnyPlayerPlaying || areAllPlayersMuted) && !anyPlayerShowsNotification 247 + - let isOutputtingAudio = !areAllPlayersMuted && isAnyPlayerPlaying 248 + - let shouldUpdateToAllowMixing = !audioSession.categoryOptions.contains(.mixWithOthers) && shouldAllowMixing 249 + - 250 + - if shouldAllowMixing { 251 + - audioSessionCategoryOptions.insert(.mixWithOthers) 252 + - } 253 + - 254 + - if isOutputtingAudio || needsPiPSupport || shouldUpdateToAllowMixing || anyPlayerShowsNotification { 255 + - do { 256 + - try audioSession.setCategory(.playback, mode: .moviePlayback) 257 + - } catch { 258 + - log.warn("Failed to set audio session category. This might cause issues with audio playback and Picture in Picture. \(error.localizedDescription)") 259 + - } 260 + - } 261 + - 262 + - // Make sure audio session is active if any video is playing 263 + - if isAnyPlayerPlaying { 264 + - do { 265 + - try audioSession.setActive(true) 266 + - } catch { 267 + - log.warn("Failed to activate the audio session. This might cause issues with audio playback. \(error.localizedDescription)") 268 + - } 269 + - } 270 + +// let audioSession = AVAudioSession.sharedInstance() 271 + +// var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = [] 272 + +// 273 + +// let isAnyPlayerPlaying = videoPlayers.allObjects.contains { player in 274 + +// player.isPlaying 275 + +// } 276 + +// let areAllPlayersMuted = videoPlayers.allObjects.allSatisfy { player in 277 + +// player.isMuted 278 + +// } 279 + +// let needsPiPSupport = videoViews.allObjects.contains { view in 280 + +// view.allowPictureInPicture 281 + +// } 282 + +// let anyPlayerShowsNotification = videoPlayers.allObjects.contains { player in 283 + +// player.showNowPlayingNotification 284 + +// } 285 + +// // The notification won't be shown if we allow the audio to mix with others 286 + +// let shouldAllowMixing = (!isAnyPlayerPlaying || areAllPlayersMuted) && !anyPlayerShowsNotification 287 + +// let isOutputtingAudio = !areAllPlayersMuted && isAnyPlayerPlaying 288 + +// let shouldUpdateToAllowMixing = !audioSession.categoryOptions.contains(.mixWithOthers) && shouldAllowMixing 289 + +// 290 + +// if shouldAllowMixing { 291 + +// audioSessionCategoryOptions.insert(.mixWithOthers) 292 + +// } 293 + +// 294 + +// if isOutputtingAudio || needsPiPSupport || shouldUpdateToAllowMixing || anyPlayerShowsNotification { 295 + +// do { 296 + +// try audioSession.setCategory(.playback, mode: .moviePlayback) 297 + +// } catch { 298 + +// log.warn("Failed to set audio session category. This might cause issues with audio playback and Picture in Picture. \(error.localizedDescription)") 299 + +// } 300 + +// } 301 + +// 302 + +// // Make sure audio session is active if any video is playing 303 + +// if isAnyPlayerPlaying { 304 + +// do { 305 + +// try audioSession.setActive(true) 306 + +// } catch { 307 + +// log.warn("Failed to activate the audio session. This might cause issues with audio playback. \(error.localizedDescription)") 308 + +// } 309 + +// } 310 + } 311 + } 222 312 diff --git a/node_modules/expo-video/ios/VideoModule.swift b/node_modules/expo-video/ios/VideoModule.swift 223 313 index c537a12..e4a918f 100644 224 314 --- a/node_modules/expo-video/ios/VideoModule.swift ··· 232 322 + "onEnterFullscreen", 233 323 + "onExitFullscreen" 234 324 ) 235 - 325 + 236 326 Prop("player") { (view, player: VideoPlayer?) in 237 327 diff --git a/node_modules/expo-video/ios/VideoPlayer.swift b/node_modules/expo-video/ios/VideoPlayer.swift 238 - index 3315b88..f482390 100644 328 + index 3315b88..733ab1f 100644 239 329 --- a/node_modules/expo-video/ios/VideoPlayer.swift 240 330 +++ b/node_modules/expo-video/ios/VideoPlayer.swift 241 331 @@ -185,6 +185,10 @@ internal final class VideoPlayer: SharedRef<AVPlayer>, Hashable, VideoPlayerObse 242 332 safeEmit(event: "sourceChange", arguments: newVideoPlayerItem?.videoSource, oldVideoPlayerItem?.videoSource) 243 333 } 244 - 334 + 245 335 + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) { 246 336 + safeEmit(event: "timeRemainingChange", arguments: timeRemaining) 247 337 + } ··· 250 340 if self.appContext != nil { 251 341 self.emit(event: event, arguments: repeat each arguments) 252 342 diff --git a/node_modules/expo-video/ios/VideoPlayerObserver.swift b/node_modules/expo-video/ios/VideoPlayerObserver.swift 253 - index d289e26..de9a26f 100644 343 + index d289e26..ea4d96f 100644 254 344 --- a/node_modules/expo-video/ios/VideoPlayerObserver.swift 255 345 +++ b/node_modules/expo-video/ios/VideoPlayerObserver.swift 256 346 @@ -21,6 +21,7 @@ protocol VideoPlayerObserverDelegate: AnyObject { ··· 259 349 func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) 260 350 + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) 261 351 } 262 - 352 + 263 353 // Default implementations for the delegate 264 354 @@ -33,6 +34,7 @@ extension VideoPlayerObserverDelegate { 265 355 func onItemChanged(player: AVPlayer, oldVideoPlayerItem: VideoPlayerItem?, newVideoPlayerItem: VideoPlayerItem?) {} ··· 267 357 func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) {} 268 358 + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) {} 269 359 } 270 - 360 + 271 361 // Wrapper used to store WeakReferences to the observer delegate 272 362 @@ -91,6 +93,7 @@ class VideoPlayerObserver { 273 363 private var playerVolumeObserver: NSKeyValueObservation? 274 364 private var playerCurrentItemObserver: NSKeyValueObservation? 275 365 private var playerIsMutedObserver: NSKeyValueObservation? 276 366 + private var playerPeriodicTimeObserver: Any? 277 - 367 + 278 368 // Current player item observers 279 369 private var playbackBufferEmptyObserver: NSKeyValueObservation? 280 370 @@ -152,6 +155,9 @@ class VideoPlayerObserver { ··· 285 375 + player?.removeTimeObserver(playerPeriodicTimeObserver) 286 376 + } 287 377 } 288 - 378 + 289 379 private func initializeCurrentPlayerItemObservers(player: AVPlayer, playerItem: AVPlayerItem) { 290 380 @@ -270,6 +276,7 @@ class VideoPlayerObserver { 291 - 381 + 292 382 if isPlaying != (player.timeControlStatus == .playing) { 293 383 isPlaying = player.timeControlStatus == .playing 294 384 + addPeriodicTimeObserverIfNeeded() 295 385 } 296 386 } 297 - 387 + 298 388 @@ -310,4 +317,28 @@ class VideoPlayerObserver { 299 389 } 300 390 } ··· 329 419 --- a/node_modules/expo-video/ios/VideoView.swift 330 420 +++ b/node_modules/expo-video/ios/VideoView.swift 331 421 @@ -41,6 +41,8 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { 332 - 422 + 333 423 let onPictureInPictureStart = EventDispatcher() 334 424 let onPictureInPictureStop = EventDispatcher() 335 425 + let onEnterFullscreen = EventDispatcher() 336 426 + let onExitFullscreen = EventDispatcher() 337 - 427 + 338 428 public override var bounds: CGRect { 339 429 didSet { 340 430 @@ -163,6 +165,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { ··· 344 434 + onEnterFullscreen() 345 435 isFullscreen = true 346 436 } 347 - 437 + 348 438 @@ -179,6 +182,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { 349 439 if wasPlaying { 350 440 self.player?.pointer.play() ··· 364 454 + 365 455 + timeRemainingChange(timeRemaining: number): void; 366 456 }; 367 - 457 + 368 458 /** 369 459 diff --git a/node_modules/expo-video/src/VideoView.types.ts b/node_modules/expo-video/src/VideoView.types.ts 370 460 index 29fe5db..e1fbf59 100644
+3
patches/expo-video+1.2.4.patch.md
··· 4 4 5 5 This patch adds two props to `VideoView`: `onEnterFullscreen` and `onExitFullscreen` which do exactly what they say on 6 6 the tin. 7 + 8 + This patch also removes the audio session management that Expo does on its own, as we handle audio session management 9 + ourselves.