fix(mobile): expo-video bez ConcurrentModificationException przy liscie sluchaczy
close() odtwarzacza (watek JS albo sprzatajacy obiekty) wypisywal AudioFocusManager z listy sluchaczy, a glowny watek w tym samym czasie rozsylal zdarzenie po prepare() i iterowal ta liste (0.4.2, GOON-7A, Edge przy przewijaniu). Listy sluchaczy odtwarzacza i odtwarzaczy w AudioFocusManager to teraz CopyOnWriteArrayList, dopisywanie pod synchronized, usuwanie przez atomowe removeIf. Natywne, czeka na APK. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2a2c0d7e9d
commit
30dd83557d
1 changed files with 74 additions and 0 deletions
|
|
@ -1,3 +1,40 @@
|
|||
diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/AudioFocusManager.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/AudioFocusManager.kt
|
||||
index aa911b1..671bf05 100644
|
||||
--- a/node_modules/expo-video/android/src/main/java/expo/modules/video/AudioFocusManager.kt
|
||||
+++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/AudioFocusManager.kt
|
||||
@@ -21,7 +21,9 @@ class AudioFocusManager(private val appContext: AppContext) : AudioManager.OnAud
|
||||
}
|
||||
}
|
||||
|
||||
- private var players: MutableList<WeakReference<VideoPlayer>> = mutableListOf()
|
||||
+ // CopyOnWriteArrayList z tego samego powodu co listeners w VideoPlayer: register/unregister
|
||||
+ // przychodza z watku JS i sprzatajacego, a forEach po liscie idzie na glownym (Goon, GOON-7A).
|
||||
+ private val players = java.util.concurrent.CopyOnWriteArrayList<WeakReference<VideoPlayer>>()
|
||||
private var currentFocusRequest: AudioFocusRequest? = null
|
||||
private var currentMixingMode: AudioMixingMode = AudioMixingMode.MIX_WITH_OTHERS
|
||||
private val anyPlayerRequiresFocus: Boolean
|
||||
@@ -89,8 +91,10 @@ class AudioFocusManager(private val appContext: AppContext) : AudioManager.OnAud
|
||||
}
|
||||
|
||||
fun registerPlayer(player: VideoPlayer) {
|
||||
- players.find { it.get() == player } ?: run {
|
||||
- players.add(WeakReference(player))
|
||||
+ synchronized(players) {
|
||||
+ players.find { it.get() == player } ?: run {
|
||||
+ players.add(WeakReference(player))
|
||||
+ }
|
||||
}
|
||||
player.addListener(this)
|
||||
updateAudioFocus()
|
||||
@@ -98,7 +102,7 @@ class AudioFocusManager(private val appContext: AppContext) : AudioManager.OnAud
|
||||
|
||||
fun unregisterPlayer(player: VideoPlayer) {
|
||||
player.removeListener(this)
|
||||
- players.removeAll { it.get() == player }
|
||||
+ players.removeIf { it.get() == player }
|
||||
updateAudioFocus()
|
||||
}
|
||||
|
||||
diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt
|
||||
index cd798cf..8cb6dfb 100644
|
||||
--- a/node_modules/expo-video/android/src/main/java/expo/modules/video/playbackService/ExpoVideoPlaybackService.kt
|
||||
|
|
@ -34,3 +71,40 @@ index cd798cf..8cb6dfb 100644
|
|||
}
|
||||
|
||||
private fun hidePlayerNotification(player: ExoPlayer) {
|
||||
diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/player/VideoPlayer.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/player/VideoPlayer.kt
|
||||
index ec7accf..dd365e3 100644
|
||||
--- a/node_modules/expo-video/android/src/main/java/expo/modules/video/player/VideoPlayer.kt
|
||||
+++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/player/VideoPlayer.kt
|
||||
@@ -44,7 +44,11 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
||||
private var renderersFactory = DefaultRenderersFactory(context)
|
||||
.forceEnableMediaCodecAsynchronousQueueing()
|
||||
.setEnableDecoderFallback(true)
|
||||
- private var listeners: MutableList<WeakReference<VideoPlayerListener>> = mutableListOf()
|
||||
+ // CopyOnWriteArrayList, nie ArrayList: close() (watek JS albo sprzatajacy obiekty) wypisuje
|
||||
+ // stad AudioFocusManager, a glowny watek w tym samym czasie rozsyla zdarzenie po prepare()
|
||||
+ // i iteruje liste -> ConcurrentModificationException (Goon 0.4.2, Sentry GOON-7A, Edge
|
||||
+ // tworzy i zwalnia odtwarzacze przy kazdym przewinieciu). Iteracja idzie po migawce.
|
||||
+ private val listeners = java.util.concurrent.CopyOnWriteArrayList<WeakReference<VideoPlayerListener>>()
|
||||
val loadControl: VideoPlayerLoadControl = VideoPlayerLoadControl.Builder().build()
|
||||
val subtitles: VideoPlayerSubtitles = VideoPlayerSubtitles(this)
|
||||
val trackSelector = DefaultTrackSelector(context)
|
||||
@@ -320,13 +324,16 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
||||
}
|
||||
|
||||
fun addListener(videoPlayerListener: VideoPlayerListener) {
|
||||
- if (listeners.all { it.get() != videoPlayerListener }) {
|
||||
- listeners.add(WeakReference(videoPlayerListener))
|
||||
+ synchronized(listeners) {
|
||||
+ if (listeners.all { it.get() != videoPlayerListener }) {
|
||||
+ listeners.add(WeakReference(videoPlayerListener))
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
fun removeListener(videoPlayerListener: VideoPlayerListener) {
|
||||
- listeners.removeAll { it.get() == videoPlayerListener }
|
||||
+ // removeIf listy (atomowe), nie kotlinowe removeAll { }, ktore usuwa po indeksach.
|
||||
+ listeners.removeIf { it.get() == videoPlayerListener }
|
||||
}
|
||||
|
||||
private fun sendEvent(event: PlayerEvent) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue