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

zio/stable
Hailey 2024-09-03 08:33:21 -07:00 committed by GitHub
parent 0e1de19903
commit 05e61346b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 121 additions and 28 deletions

View File

@ -5,7 +5,7 @@ index 473f964..f37aff9 100644
@@ -41,6 +41,11 @@ sealed class PlayerEvent { @@ -41,6 +41,11 @@ sealed class PlayerEvent {
override val name = "playToEnd" override val name = "playToEnd"
} }
+ data class PlayerTimeRemainingChanged(val timeRemaining: Double): PlayerEvent() { + data class PlayerTimeRemainingChanged(val timeRemaining: Double): PlayerEvent() {
+ override val name = "timeRemainingChange" + override val name = "timeRemainingChange"
+ override val arguments = arrayOf(timeRemaining) + override val arguments = arrayOf(timeRemaining)
@ -32,10 +32,10 @@ index 9905e13..47342ff 100644
setTimeBarInteractive(requireLinearPlayback) setTimeBarInteractive(requireLinearPlayback)
+ setShowSubtitleButton(true) + setShowSubtitleButton(true)
} }
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
@@ -27,7 +28,8 @@ internal fun PlayerView.setTimeBarInteractive(interactive: Boolean) { @@ -27,7 +28,8 @@ internal fun PlayerView.setTimeBarInteractive(interactive: Boolean) {
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
internal fun PlayerView.setFullscreenButtonVisibility(visible: Boolean) { internal fun PlayerView.setFullscreenButtonVisibility(visible: Boolean) {
- val fullscreenButton = findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_fullscreen) - val fullscreenButton = findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_fullscreen)
@ -93,7 +93,7 @@ index ec3da2a..5a1397a 100644
+ "onEnterFullscreen", + "onEnterFullscreen",
+ "onExitFullscreen" + "onExitFullscreen"
) )
Prop("player") { view: VideoView, player: VideoPlayer -> Prop("player") { view: VideoView, player: VideoPlayer ->
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 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
index 58f00af..5ad8237 100644 index 58f00af..5ad8237 100644
@ -101,7 +101,7 @@ index 58f00af..5ad8237 100644
+++ b/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
@@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
package expo.modules.video package expo.modules.video
+import ProgressTracker +import ProgressTracker
import android.content.Context import android.content.Context
import android.view.SurfaceView import android.view.SurfaceView
@ -111,18 +111,18 @@ index 58f00af..5ad8237 100644
.setLooper(context.mainLooper) .setLooper(context.mainLooper)
.build() .build()
+ var progressTracker: ProgressTracker? = null + var progressTracker: ProgressTracker? = null
val serviceConnection = PlaybackServiceConnection(WeakReference(player)) val serviceConnection = PlaybackServiceConnection(WeakReference(player))
var playing by IgnoreSameSet(false) { new, old -> var playing by IgnoreSameSet(false) { new, old ->
sendEvent(PlayerEvent.IsPlayingChanged(new, old)) sendEvent(PlayerEvent.IsPlayingChanged(new, old))
+ addOrRemoveProgressTracker() + addOrRemoveProgressTracker()
} }
var uncommittedSource: VideoSource? = source var uncommittedSource: VideoSource? = source
@@ -141,6 +144,9 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou @@ -141,6 +144,9 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
} }
override fun close() { override fun close() {
+ this.progressTracker?.remove() + this.progressTracker?.remove()
+ this.progressTracker = null + this.progressTracker = null
@ -133,7 +133,7 @@ index 58f00af..5ad8237 100644
@@ -228,7 +234,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou @@ -228,7 +234,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
listeners.removeAll { it.get() == videoPlayerListener } listeners.removeAll { it.get() == videoPlayerListener }
} }
- private fun sendEvent(event: PlayerEvent) { - private fun sendEvent(event: PlayerEvent) {
+ fun sendEvent(event: PlayerEvent) { + fun sendEvent(event: PlayerEvent) {
// Emits to the native listeners // Emits to the native listeners
@ -173,7 +173,7 @@ index a951d80..3932535 100644
val onPictureInPictureStop by EventDispatcher<Unit>() val onPictureInPictureStop by EventDispatcher<Unit>()
+ val onEnterFullscreen by EventDispatcher() + val onEnterFullscreen by EventDispatcher()
+ val onExitFullscreen by EventDispatcher() + val onExitFullscreen by EventDispatcher()
var willEnterPiP: Boolean = false var willEnterPiP: Boolean = false
var isInFullscreen: Boolean = false var isInFullscreen: Boolean = false
@@ -154,6 +156,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap @@ -154,6 +156,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap
@ -183,7 +183,7 @@ index a951d80..3932535 100644
+ onEnterFullscreen(mapOf()) + onEnterFullscreen(mapOf())
isInFullscreen = true isInFullscreen = true
} }
@@ -162,6 +165,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap @@ -162,6 +165,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap
val fullScreenButton: ImageButton = playerView.findViewById(androidx.media3.ui.R.id.exo_fullscreen) val fullScreenButton: ImageButton = playerView.findViewById(androidx.media3.ui.R.id.exo_fullscreen)
fullScreenButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter) fullScreenButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter)
@ -191,9 +191,9 @@ index a951d80..3932535 100644
+ this.onExitFullscreen(mapOf()) + this.onExitFullscreen(mapOf())
isInFullscreen = false isInFullscreen = false
} }
diff --git a/node_modules/expo-video/build/VideoPlayer.types.d.ts b/node_modules/expo-video/build/VideoPlayer.types.d.ts diff --git a/node_modules/expo-video/build/VideoPlayer.types.d.ts b/node_modules/expo-video/build/VideoPlayer.types.d.ts
index a09fcfe..65fe29a 100644 index a09fcfe..5eac9e5 100644
--- a/node_modules/expo-video/build/VideoPlayer.types.d.ts --- a/node_modules/expo-video/build/VideoPlayer.types.d.ts
+++ b/node_modules/expo-video/build/VideoPlayer.types.d.ts +++ b/node_modules/expo-video/build/VideoPlayer.types.d.ts
@@ -128,6 +128,8 @@ export type VideoPlayerEvents = { @@ -128,6 +128,8 @@ export type VideoPlayerEvents = {
@ -219,6 +219,96 @@ index cb9ca6d..ed8bb7e 100644
} }
//# sourceMappingURL=VideoView.types.d.ts.map //# sourceMappingURL=VideoView.types.d.ts.map
\ No newline at end of file \ No newline at end of file
diff --git a/node_modules/expo-video/ios/VideoManager.swift b/node_modules/expo-video/ios/VideoManager.swift
index 094a8b0..412fd0c 100644
--- a/node_modules/expo-video/ios/VideoManager.swift
+++ b/node_modules/expo-video/ios/VideoManager.swift
@@ -51,45 +51,45 @@ class VideoManager {
// MARK: - Audio Session Management
internal func setAppropriateAudioSessionOrWarn() {
- let audioSession = AVAudioSession.sharedInstance()
- var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = []
-
- let isAnyPlayerPlaying = videoPlayers.allObjects.contains { player in
- player.isPlaying
- }
- let areAllPlayersMuted = videoPlayers.allObjects.allSatisfy { player in
- player.isMuted
- }
- let needsPiPSupport = videoViews.allObjects.contains { view in
- view.allowPictureInPicture
- }
- let anyPlayerShowsNotification = videoPlayers.allObjects.contains { player in
- player.showNowPlayingNotification
- }
- // The notification won't be shown if we allow the audio to mix with others
- let shouldAllowMixing = (!isAnyPlayerPlaying || areAllPlayersMuted) && !anyPlayerShowsNotification
- let isOutputtingAudio = !areAllPlayersMuted && isAnyPlayerPlaying
- let shouldUpdateToAllowMixing = !audioSession.categoryOptions.contains(.mixWithOthers) && shouldAllowMixing
-
- if shouldAllowMixing {
- audioSessionCategoryOptions.insert(.mixWithOthers)
- }
-
- if isOutputtingAudio || needsPiPSupport || shouldUpdateToAllowMixing || anyPlayerShowsNotification {
- do {
- try audioSession.setCategory(.playback, mode: .moviePlayback)
- } catch {
- log.warn("Failed to set audio session category. This might cause issues with audio playback and Picture in Picture. \(error.localizedDescription)")
- }
- }
-
- // Make sure audio session is active if any video is playing
- if isAnyPlayerPlaying {
- do {
- try audioSession.setActive(true)
- } catch {
- log.warn("Failed to activate the audio session. This might cause issues with audio playback. \(error.localizedDescription)")
- }
- }
+// let audioSession = AVAudioSession.sharedInstance()
+// var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = []
+//
+// let isAnyPlayerPlaying = videoPlayers.allObjects.contains { player in
+// player.isPlaying
+// }
+// let areAllPlayersMuted = videoPlayers.allObjects.allSatisfy { player in
+// player.isMuted
+// }
+// let needsPiPSupport = videoViews.allObjects.contains { view in
+// view.allowPictureInPicture
+// }
+// let anyPlayerShowsNotification = videoPlayers.allObjects.contains { player in
+// player.showNowPlayingNotification
+// }
+// // The notification won't be shown if we allow the audio to mix with others
+// let shouldAllowMixing = (!isAnyPlayerPlaying || areAllPlayersMuted) && !anyPlayerShowsNotification
+// let isOutputtingAudio = !areAllPlayersMuted && isAnyPlayerPlaying
+// let shouldUpdateToAllowMixing = !audioSession.categoryOptions.contains(.mixWithOthers) && shouldAllowMixing
+//
+// if shouldAllowMixing {
+// audioSessionCategoryOptions.insert(.mixWithOthers)
+// }
+//
+// if isOutputtingAudio || needsPiPSupport || shouldUpdateToAllowMixing || anyPlayerShowsNotification {
+// do {
+// try audioSession.setCategory(.playback, mode: .moviePlayback)
+// } catch {
+// log.warn("Failed to set audio session category. This might cause issues with audio playback and Picture in Picture. \(error.localizedDescription)")
+// }
+// }
+//
+// // Make sure audio session is active if any video is playing
+// if isAnyPlayerPlaying {
+// do {
+// try audioSession.setActive(true)
+// } catch {
+// log.warn("Failed to activate the audio session. This might cause issues with audio playback. \(error.localizedDescription)")
+// }
+// }
}
}
diff --git a/node_modules/expo-video/ios/VideoModule.swift b/node_modules/expo-video/ios/VideoModule.swift diff --git a/node_modules/expo-video/ios/VideoModule.swift b/node_modules/expo-video/ios/VideoModule.swift
index c537a12..e4a918f 100644 index c537a12..e4a918f 100644
--- a/node_modules/expo-video/ios/VideoModule.swift --- a/node_modules/expo-video/ios/VideoModule.swift
@ -232,16 +322,16 @@ index c537a12..e4a918f 100644
+ "onEnterFullscreen", + "onEnterFullscreen",
+ "onExitFullscreen" + "onExitFullscreen"
) )
Prop("player") { (view, player: VideoPlayer?) in Prop("player") { (view, player: VideoPlayer?) in
diff --git a/node_modules/expo-video/ios/VideoPlayer.swift b/node_modules/expo-video/ios/VideoPlayer.swift diff --git a/node_modules/expo-video/ios/VideoPlayer.swift b/node_modules/expo-video/ios/VideoPlayer.swift
index 3315b88..f482390 100644 index 3315b88..733ab1f 100644
--- a/node_modules/expo-video/ios/VideoPlayer.swift --- a/node_modules/expo-video/ios/VideoPlayer.swift
+++ b/node_modules/expo-video/ios/VideoPlayer.swift +++ b/node_modules/expo-video/ios/VideoPlayer.swift
@@ -185,6 +185,10 @@ internal final class VideoPlayer: SharedRef<AVPlayer>, Hashable, VideoPlayerObse @@ -185,6 +185,10 @@ internal final class VideoPlayer: SharedRef<AVPlayer>, Hashable, VideoPlayerObse
safeEmit(event: "sourceChange", arguments: newVideoPlayerItem?.videoSource, oldVideoPlayerItem?.videoSource) safeEmit(event: "sourceChange", arguments: newVideoPlayerItem?.videoSource, oldVideoPlayerItem?.videoSource)
} }
+ func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) { + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) {
+ safeEmit(event: "timeRemainingChange", arguments: timeRemaining) + safeEmit(event: "timeRemainingChange", arguments: timeRemaining)
+ } + }
@ -250,7 +340,7 @@ index 3315b88..f482390 100644
if self.appContext != nil { if self.appContext != nil {
self.emit(event: event, arguments: repeat each arguments) self.emit(event: event, arguments: repeat each arguments)
diff --git a/node_modules/expo-video/ios/VideoPlayerObserver.swift b/node_modules/expo-video/ios/VideoPlayerObserver.swift diff --git a/node_modules/expo-video/ios/VideoPlayerObserver.swift b/node_modules/expo-video/ios/VideoPlayerObserver.swift
index d289e26..de9a26f 100644 index d289e26..ea4d96f 100644
--- a/node_modules/expo-video/ios/VideoPlayerObserver.swift --- a/node_modules/expo-video/ios/VideoPlayerObserver.swift
+++ b/node_modules/expo-video/ios/VideoPlayerObserver.swift +++ b/node_modules/expo-video/ios/VideoPlayerObserver.swift
@@ -21,6 +21,7 @@ protocol VideoPlayerObserverDelegate: AnyObject { @@ -21,6 +21,7 @@ protocol VideoPlayerObserverDelegate: AnyObject {
@ -259,7 +349,7 @@ index d289e26..de9a26f 100644
func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status)
+ func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double)
} }
// Default implementations for the delegate // Default implementations for the delegate
@@ -33,6 +34,7 @@ extension VideoPlayerObserverDelegate { @@ -33,6 +34,7 @@ extension VideoPlayerObserverDelegate {
func onItemChanged(player: AVPlayer, oldVideoPlayerItem: VideoPlayerItem?, newVideoPlayerItem: VideoPlayerItem?) {} func onItemChanged(player: AVPlayer, oldVideoPlayerItem: VideoPlayerItem?, newVideoPlayerItem: VideoPlayerItem?) {}
@ -267,14 +357,14 @@ index d289e26..de9a26f 100644
func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) {} func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) {}
+ func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) {} + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) {}
} }
// Wrapper used to store WeakReferences to the observer delegate // Wrapper used to store WeakReferences to the observer delegate
@@ -91,6 +93,7 @@ class VideoPlayerObserver { @@ -91,6 +93,7 @@ class VideoPlayerObserver {
private var playerVolumeObserver: NSKeyValueObservation? private var playerVolumeObserver: NSKeyValueObservation?
private var playerCurrentItemObserver: NSKeyValueObservation? private var playerCurrentItemObserver: NSKeyValueObservation?
private var playerIsMutedObserver: NSKeyValueObservation? private var playerIsMutedObserver: NSKeyValueObservation?
+ private var playerPeriodicTimeObserver: Any? + private var playerPeriodicTimeObserver: Any?
// Current player item observers // Current player item observers
private var playbackBufferEmptyObserver: NSKeyValueObservation? private var playbackBufferEmptyObserver: NSKeyValueObservation?
@@ -152,6 +155,9 @@ class VideoPlayerObserver { @@ -152,6 +155,9 @@ class VideoPlayerObserver {
@ -285,16 +375,16 @@ index d289e26..de9a26f 100644
+ player?.removeTimeObserver(playerPeriodicTimeObserver) + player?.removeTimeObserver(playerPeriodicTimeObserver)
+ } + }
} }
private func initializeCurrentPlayerItemObservers(player: AVPlayer, playerItem: AVPlayerItem) { private func initializeCurrentPlayerItemObservers(player: AVPlayer, playerItem: AVPlayerItem) {
@@ -270,6 +276,7 @@ class VideoPlayerObserver { @@ -270,6 +276,7 @@ class VideoPlayerObserver {
if isPlaying != (player.timeControlStatus == .playing) { if isPlaying != (player.timeControlStatus == .playing) {
isPlaying = player.timeControlStatus == .playing isPlaying = player.timeControlStatus == .playing
+ addPeriodicTimeObserverIfNeeded() + addPeriodicTimeObserverIfNeeded()
} }
} }
@@ -310,4 +317,28 @@ class VideoPlayerObserver { @@ -310,4 +317,28 @@ class VideoPlayerObserver {
} }
} }
@ -329,12 +419,12 @@ index f4579e4..10c5908 100644
--- a/node_modules/expo-video/ios/VideoView.swift --- a/node_modules/expo-video/ios/VideoView.swift
+++ b/node_modules/expo-video/ios/VideoView.swift +++ b/node_modules/expo-video/ios/VideoView.swift
@@ -41,6 +41,8 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { @@ -41,6 +41,8 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
let onPictureInPictureStart = EventDispatcher() let onPictureInPictureStart = EventDispatcher()
let onPictureInPictureStop = EventDispatcher() let onPictureInPictureStop = EventDispatcher()
+ let onEnterFullscreen = EventDispatcher() + let onEnterFullscreen = EventDispatcher()
+ let onExitFullscreen = EventDispatcher() + let onExitFullscreen = EventDispatcher()
public override var bounds: CGRect { public override var bounds: CGRect {
didSet { didSet {
@@ -163,6 +165,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { @@ -163,6 +165,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
@ -344,7 +434,7 @@ index f4579e4..10c5908 100644
+ onEnterFullscreen() + onEnterFullscreen()
isFullscreen = true isFullscreen = true
} }
@@ -179,6 +182,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { @@ -179,6 +182,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
if wasPlaying { if wasPlaying {
self.player?.pointer.play() self.player?.pointer.play()
@ -364,7 +454,7 @@ index aaf4b63..f438196 100644
+ +
+ timeRemainingChange(timeRemaining: number): void; + timeRemainingChange(timeRemaining: number): void;
}; };
/** /**
diff --git a/node_modules/expo-video/src/VideoView.types.ts b/node_modules/expo-video/src/VideoView.types.ts diff --git a/node_modules/expo-video/src/VideoView.types.ts b/node_modules/expo-video/src/VideoView.types.ts
index 29fe5db..e1fbf59 100644 index 29fe5db..e1fbf59 100644

View File

@ -4,3 +4,6 @@
This patch adds two props to `VideoView`: `onEnterFullscreen` and `onExitFullscreen` which do exactly what they say on This patch adds two props to `VideoView`: `onEnterFullscreen` and `onExitFullscreen` which do exactly what they say on
the tin. the tin.
This patch also removes the audio session management that Expo does on its own, as we handle audio session management
ourselves.