Try to fix the mess :)
This commit is contained in:
parent
827654c0c1
commit
707339b88b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue