Try to fix the mess :)

This commit is contained in:
tzugen 2022-04-22 21:03:57 +02:00
parent 827654c0c1
commit 707339b88b
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
5 changed files with 64 additions and 35 deletions

View File

@ -77,7 +77,7 @@ class LegacyPlaylistManager : KoinComponent {
// Public facing playlist (immutable)
val playlist: List<DownloadFile>
get() = _playlist.toList()
get() = _playlist
@get:Synchronized
val playlistDuration: Long

View File

@ -150,18 +150,20 @@ class Downloader(
// Store the result in a flag to know if changes have occurred
var listChanged = cleanupActiveDownloads()
val playlist = legacyPlaylistManager.playlist
// Check if need to preload more from playlist
val preloadCount = Settings.preloadCount
// Start preloading at the current playing song
var start = mediaController.currentMediaItemIndex
if (start == -1) start = 0
if (start == -1 || start > playlist.size) start = 0
val end = (start + preloadCount).coerceAtMost(mediaController.mediaItemCount)
val end = (start + preloadCount).coerceAtMost(playlist.size)
for (i in start until end) {
val download = legacyPlaylistManager.playlist[i]
val download = playlist[i]
// Set correct priority (the lower the number, the higher the priority)
download.priority = i

View File

@ -18,6 +18,9 @@ import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import com.google.common.util.concurrent.MoreExecutors
import io.reactivex.rxjava3.disposables.CompositeDisposable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.moire.ultrasonic.app.UApp
@ -61,6 +64,8 @@ class MediaPlayerController(
private val rxBusSubscription: CompositeDisposable = CompositeDisposable()
private var mainScope = CoroutineScope(Dispatchers.Main)
private var sessionToken =
SessionToken(context, ComponentName(context, PlaybackService::class.java))
@ -94,10 +99,10 @@ class MediaPlayerController(
/*
* This will be called everytime the playlist has changed.
* We run the event through RxBus in order to throttle them
*/
override fun onTimelineChanged(timeline: Timeline, reason: Int) {
legacyPlaylistManager.rebuildPlaylist(controller!!)
serializeCurrentSession()
}
override fun onPlaybackStateChanged(playbackState: Int) {
@ -143,6 +148,20 @@ class MediaPlayerController(
isJukeboxEnabled = activeServerProvider.getActiveServer().jukeboxByDefault
}
rxBusSubscription += RxBus.throttledPlaylistObservable.subscribe {
// Even though Rx should launch on the main thread it doesn't always :(
mainScope.launch {
serializeCurrentSession()
}
}
rxBusSubscription += RxBus.throttledPlayerStateObservable.subscribe {
// Even though Rx should launch on the main thread it doesn't always :(
mainScope.launch {
serializeCurrentSession()
}
}
created = true
Timber.i("MediaPlayerController started")
}
@ -162,9 +181,6 @@ class MediaPlayerController(
}
}
// Save playback state
serializeCurrentSession()
// Update widget
if (currentPlaying != null) {
updateWidget(currentPlaying.track)
@ -367,8 +383,6 @@ class MediaPlayerController(
if (songs == null) return
val filteredSongs = songs.filterNotNull()
downloader.downloadBackground(filteredSongs, save)
serializeCurrentSession()
}
fun stopJukeboxService() {

View File

@ -9,8 +9,6 @@ package org.moire.ultrasonic.service
import android.content.Context
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@ -30,9 +28,6 @@ class PlaybackStateSerializer : KoinComponent {
private val context by inject<Context>()
private val lock: Lock = ReentrantLock()
private val setup = AtomicBoolean(false)
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
@ -41,25 +36,24 @@ class PlaybackStateSerializer : KoinComponent {
currentPlayingIndex: Int,
currentPlayingPosition: Int
) {
if (!setup.get()) return
if (isSerializing.get() || !isSetup.get()) return
if (lock.tryLock()) {
ioScope.launch {
try {
serializeNow(songs, currentPlayingIndex, currentPlayingPosition)
} finally {
lock.unlock()
}
}
isSerializing.set(true)
ioScope.launch {
serializeNow(songs, currentPlayingIndex, currentPlayingPosition)
}.invokeOnCompletion {
isSerializing.set(false)
}
}
fun serializeNow(
songs: Iterable<DownloadFile>,
referencedList: Iterable<DownloadFile>,
currentPlayingIndex: Int,
currentPlayingPosition: Int
) {
val state = State()
val songs = referencedList.toList()
for (downloadFile in songs) {
state.songs.add(downloadFile.track)
@ -78,16 +72,15 @@ class PlaybackStateSerializer : KoinComponent {
}
fun deserialize(afterDeserialized: (State?) -> Unit?) {
if (isDeserializing.get()) return
ioScope.launch {
try {
lock.lock()
deserializeNow(afterDeserialized)
setup.set(true)
isSetup.set(true)
} catch (all: Exception) {
Timber.e(all, "Had a problem deserializing:")
} finally {
lock.unlock()
isDeserializing.set(false)
}
}
}
@ -108,4 +101,10 @@ class PlaybackStateSerializer : KoinComponent {
afterDeserialized(state)
}
}
companion object {
private val isSetup = AtomicBoolean(false)
private val isSerializing = AtomicBoolean(false)
private val isDeserializing = AtomicBoolean(false)
}
}

View File

@ -1,5 +1,6 @@
package org.moire.ultrasonic.service
import android.os.Looper
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.CompositeDisposable
@ -8,42 +9,55 @@ import io.reactivex.rxjava3.subjects.PublishSubject
import java.util.concurrent.TimeUnit
class RxBus {
companion object {
private fun mainThread() = AndroidSchedulers.from(Looper.getMainLooper())
var activeServerChangePublisher: PublishSubject<Int> =
PublishSubject.create()
var activeServerChangeObservable: Observable<Int> =
activeServerChangePublisher.observeOn(AndroidSchedulers.mainThread())
activeServerChangePublisher.observeOn(mainThread())
val themeChangedEventPublisher: PublishSubject<Unit> =
PublishSubject.create()
val themeChangedEventObservable: Observable<Unit> =
themeChangedEventPublisher.observeOn(AndroidSchedulers.mainThread())
themeChangedEventPublisher.observeOn(mainThread())
val musicFolderChangedEventPublisher: PublishSubject<String> =
PublishSubject.create()
val musicFolderChangedEventObservable: Observable<String> =
musicFolderChangedEventPublisher.observeOn(AndroidSchedulers.mainThread())
musicFolderChangedEventPublisher.observeOn(mainThread())
val playerStatePublisher: PublishSubject<StateWithTrack> =
PublishSubject.create()
val playerStateObservable: Observable<StateWithTrack> =
playerStatePublisher.observeOn(AndroidSchedulers.mainThread())
playerStatePublisher.observeOn(mainThread())
.replay(1)
.autoConnect(0)
val throttledPlayerStateObservable: Observable<StateWithTrack> =
playerStatePublisher.observeOn(mainThread())
.replay(1)
.autoConnect(0)
.throttleLatest(300, TimeUnit.MILLISECONDS)
val playlistPublisher: PublishSubject<List<DownloadFile>> =
PublishSubject.create()
val playlistObservable: Observable<List<DownloadFile>> =
playlistPublisher.observeOn(AndroidSchedulers.mainThread())
playlistPublisher.observeOn(mainThread())
.replay(1)
.autoConnect(0)
val throttledPlaylistObservable: Observable<List<DownloadFile>> =
playlistPublisher.observeOn(mainThread())
.replay(1)
.autoConnect(0)
.throttleLatest(300, TimeUnit.MILLISECONDS)
// Commands
val dismissNowPlayingCommandPublisher: PublishSubject<Unit> =
PublishSubject.create()
val dismissNowPlayingCommandObservable: Observable<Unit> =
dismissNowPlayingCommandPublisher.observeOn(AndroidSchedulers.mainThread())
dismissNowPlayingCommandPublisher.observeOn(mainThread())
}
data class StateWithTrack(