playback: make sanitization runtime
Do not save the playback state when sanitizing. After some thought, there is no situation where re-saving the playback state is desirable. A previously saved state will be consistent with a sanitized state, and there is no need to save when the service is active. Thus, save on speed and reduce insane race conditions by just sanitizing the current runtime state and not saving at all.
This commit is contained in:
parent
83d6c529e2
commit
e0a05ef486
5 changed files with 41 additions and 30 deletions
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
|
|
@ -32,7 +32,7 @@ If you have the knowledge, you can also implement the feature yourself and creat
|
|||
Its also recommended that you read about [Auxio's Architecture](../info/ARCHITECTURE.md) as well to make changes better and more efficient.
|
||||
|
||||
## Translations
|
||||
I don't really see the use in weblate, so currently you should see the [Translations Megathread]](https://github.com/OxygenCobalt/Auxio/issues/3) to see how to propose translations.
|
||||
Go to Auxio's weblate project [here](https://hosted.weblate.org/engage/auxio/).
|
||||
|
||||
## Code Contributions
|
||||
If you have knowledge of Android/Kotlin, feel free to to contribute to the project.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.oxycblt.auxio.util.getSystemServiceSafe
|
|||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.newMainPendingIntent
|
||||
|
||||
/** The notification responsible for showing the indexer state. */
|
||||
class IndexerNotification(private val context: Context) :
|
||||
NotificationCompat.Builder(context, CHANNEL_ID) {
|
||||
private val notificationManager = context.getSystemServiceSafe(NotificationManager::class)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.launch
|
||||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateDatabase
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
|
@ -118,16 +117,10 @@ class IndexerService : Service(), Indexer.Controller, Settings.Callback {
|
|||
// Wipe possibly-invalidated album covers
|
||||
imageLoader.memoryCache?.clear()
|
||||
|
||||
// PlaybackStateManager needs to be updated. We would do this in the
|
||||
// playback module, but this service could be the only component capable
|
||||
// of doing this at a particular point. Note that while it's certain
|
||||
// that PlaybackStateManager is initialized by now, it's best to be safe
|
||||
// and check first.
|
||||
if (playbackManager.isInitialized) {
|
||||
playbackManager.sanitize(
|
||||
PlaybackStateDatabase.getInstance(this@IndexerService),
|
||||
newLibrary)
|
||||
}
|
||||
// Clear invalid models from PlaybackStateManager. Shared objects
|
||||
// shouldn't be plugged into the callback system of other shared
|
||||
// objects, so we must update it here.
|
||||
playbackManager.sanitize(newLibrary)
|
||||
}
|
||||
|
||||
musicStore.updateLibrary(newLibrary)
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ class MusicStore private constructor() {
|
|||
}
|
||||
|
||||
fun sanitize(song: Song) = songs.find { it.id == song.id }
|
||||
fun sanitize(songs: List<Song>) = songs.mapNotNull { sanitize(it) }
|
||||
fun sanitize(album: Album) = albums.find { it.id == album.id }
|
||||
fun sanitize(artist: Artist) = artists.find { it.id == artist.id }
|
||||
fun sanitize(genre: Genre) = genres.find { it.id == genre.id }
|
||||
|
|
|
|||
|
|
@ -384,24 +384,40 @@ class PlaybackStateManager private constructor() {
|
|||
withContext(Dispatchers.IO) { database.write(state) }
|
||||
}
|
||||
|
||||
suspend fun sanitize(database: PlaybackStateDatabase, newLibrary: MusicStore.Library) {
|
||||
// Since we need to sanitize the state and re-save it for consistency, take the
|
||||
// easy way out and just write a new state and restore from it. Don't really care.
|
||||
// TODO: Do we even need to save here? Doesn't seem like it's required for
|
||||
@Synchronized
|
||||
fun sanitize(newLibrary: MusicStore.Library) {
|
||||
if (!isInitialized) {
|
||||
logD("Not initialized, no need to sanitize")
|
||||
return
|
||||
}
|
||||
|
||||
logD("Sanitizing state")
|
||||
val state = synchronized(this) { makeStateImpl() }
|
||||
|
||||
val sanitizedState =
|
||||
withContext(Dispatchers.IO) {
|
||||
database.write(state)
|
||||
database.read(newLibrary)
|
||||
val oldSongId = song?.id
|
||||
val oldPosition = positionMs
|
||||
|
||||
parent =
|
||||
parent?.let {
|
||||
when (it) {
|
||||
is Album -> newLibrary.sanitize(it)
|
||||
is Artist -> newLibrary.sanitize(it)
|
||||
is Genre -> newLibrary.sanitize(it)
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if (sanitizedState != null) {
|
||||
applyStateImpl(sanitizedState)
|
||||
}
|
||||
_queue = newLibrary.sanitize(_queue).toMutableList()
|
||||
|
||||
while (song?.id != oldSongId && index > -1) {
|
||||
index--
|
||||
}
|
||||
|
||||
// Continuing playback while also possibly doing drastic state updates is
|
||||
// a bad idea, so pause.
|
||||
isPlaying = false
|
||||
notifyNewPlayback()
|
||||
|
||||
// Controller may have reloaded the media item, re-seek to the previous position
|
||||
seekTo(oldPosition)
|
||||
}
|
||||
|
||||
private fun makeStateImpl() =
|
||||
|
|
|
|||
Loading…
Reference in a new issue