@@ -11,7 +11,6 @@ import android.content.ComponentName
1111import android.content.Context
1212import android.view.SurfaceView
1313import androidx.annotation.OptIn
14- import androidx.media3.common.Player
1514import androidx.media3.common.util.UnstableApi
1615import androidx.media3.session.MediaController
1716import androidx.media3.session.MediaSession
@@ -35,6 +34,7 @@ import com.nextcloud.client.player.util.PlayerUtil.updateMediaItems
3534import com.owncloud.android.datamodel.OCFile
3635import kotlinx.coroutines.CoroutineScope
3736import kotlinx.coroutines.Dispatchers
37+ import kotlinx.coroutines.Job
3838import kotlinx.coroutines.SupervisorJob
3939import kotlinx.coroutines.cancel
4040import kotlinx.coroutines.flow.Flow
@@ -82,16 +82,20 @@ class PlaybackModel @Inject constructor(
8282 private val controllerListener = object : MediaController .Listener {
8383 override fun onDisconnected (controller : MediaController ) {
8484 controller.removeListener(playerListener)
85+ if (this @PlaybackModel.controller == = controller) {
86+ this @PlaybackModel.controller = null
87+ }
8588 videoSurfaceView = null
8689 invalidateCurrentFiles()
87- controllerScope?.cancel ()
90+ stopFilesFlow ()
8891 checkProgressPeriodicAction.stop()
8992 notifyPlaybackUpdate()
9093 }
9194 }
9295
9396 private var controllerScope: CoroutineScope ? = null
94- private var controller: Player ? = null
97+ private var controller: MediaController ? = null
98+ private var filesFlowJob: Job ? = null
9599
96100 private var mediaSession: MediaSession ? = null
97101
@@ -126,6 +130,12 @@ class PlaybackModel @Inject constructor(
126130 }
127131
128132 suspend fun start () {
133+ if (controller?.isConnected == true ) {
134+ return
135+ }
136+
137+ releaseController()
138+
129139 videoSurfaceView = null
130140 val sessionToken = SessionToken (context, ComponentName (context, PlaybackService ::class .java))
131141 controller = MediaController .Builder (context, sessionToken)
@@ -136,8 +146,26 @@ class PlaybackModel @Inject constructor(
136146 addListener(playerListener)
137147 setRepeatMode(playbackSettings.repeatMode)
138148 shuffleModeEnabled = playbackSettings.isShuffle
139- controllerScope = CoroutineScope (SupervisorJob () + Dispatchers .Main .immediate)
140149 }
150+ controllerScope = CoroutineScope (SupervisorJob () + Dispatchers .Main .immediate)
151+ }
152+
153+ private fun releaseController () {
154+ stopFilesFlow()
155+ checkProgressPeriodicAction.stop()
156+ invalidateCurrentFiles()
157+
158+ val current = controller ? : return
159+ controller = null
160+ current.removeListener(playerListener)
161+ current.release()
162+ }
163+
164+ private fun stopFilesFlow () {
165+ filesFlowJob?.cancel()
166+ filesFlowJob = null
167+ controllerScope?.cancel()
168+ controllerScope = null
141169 }
142170
143171 @Suppress(" TooGenericExceptionCaught" )
@@ -161,7 +189,8 @@ class PlaybackModel @Inject constructor(
161189 }
162190
163191 fun setFilesFlow (filesFlow : Flow <PlaybackFiles >) {
164- controllerScope?.launch {
192+ filesFlowJob?.cancel()
193+ filesFlowJob = controllerScope?.launch {
165194 filesFlow
166195 .catch {
167196 notifyPlaybackError(it)
@@ -177,21 +206,22 @@ class PlaybackModel @Inject constructor(
177206 return
178207 }
179208
180- controller?.let { controller ->
181- val currentFile = controller.currentMediaItem?.mediaMetadata?.playbackFile
182- val mediaItems = files.list.map { it.toMediaItem() }
183-
184- if (currentFile == null ) {
185- controller.setMediaItems(mediaItems)
186- } else if (files.list.any { it.id == currentFile.id }) {
187- controller.updateMediaItems(mediaItems)
188- } else {
189- val nextFileIndex = getNextFileIndex(files, currentFile)
190- controller.setMediaItems(mediaItems, nextFileIndex, 0 )
191- }
209+ val controller = controller ? : return
210+ val mediaItems = files.list.map { it.toMediaItem() }
211+
212+ if (controller.readMediaIds() == mediaItems.map { it.mediaId }) {
213+ return
214+ }
192215
193- controller.prepare()
216+ val currentFile = controller.currentMediaItem?.mediaMetadata?.playbackFile
217+
218+ when {
219+ currentFile == null -> controller.setMediaItems(mediaItems)
220+ files.list.any { it.id == currentFile.id } -> controller.updateMediaItems(mediaItems)
221+ else -> controller.setMediaItems(mediaItems, getNextFileIndex(files, currentFile), 0 )
194222 }
223+
224+ controller.prepare()
195225 }
196226
197227 private fun getNextFileIndex (files : PlaybackFiles , currentFile : PlaybackFile ): Int = (files.list + currentFile)
@@ -201,7 +231,7 @@ class PlaybackModel @Inject constructor(
201231
202232 fun release () {
203233 videoSurfaceView = null
204- controller?.release ()
234+ releaseController ()
205235 mediaSession?.player?.release()
206236 mediaSession?.release()
207237 mediaSession = null
0 commit comments