diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt index 47843388..2b9c2ec5 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt @@ -109,7 +109,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable } rxSubscription = RxBus.playerStateObservable.subscribe { - Timber.i("NEW PLAY STATE") setPlayIcon(it.index == bindingAdapterPosition && it.track == downloadFile) } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt index 0f869aee..d5d31b6b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt @@ -3,6 +3,9 @@ package org.moire.ultrasonic.app import android.content.Context import android.os.StrictMode import androidx.multidex.MultiDexApplication +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import org.koin.core.logger.Level @@ -24,6 +27,8 @@ import timber.log.Timber.DebugTree class UApp : MultiDexApplication() { + private var ioScope = CoroutineScope(Dispatchers.IO) + init { instance = this if (BuildConfig.DEBUG) @@ -36,8 +41,12 @@ class UApp : MultiDexApplication() { if (BuildConfig.DEBUG) { Timber.plant(DebugTree()) } - if (Settings.debugLogToFile) { - FileLoggerTree.plantToTimberForest() + + // In general we should not access the settings from the main thread to avoid blocking... + ioScope.launch { + if (Settings.debugLogToFile) { + FileLoggerTree.plantToTimberForest() + } } startKoin { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt index 32e9d29c..1ed527ea 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt @@ -29,7 +29,6 @@ import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X1 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X2 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4 -import org.moire.ultrasonic.service.DownloadService.Companion.getInstance import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.Settings @@ -72,7 +71,7 @@ class MediaPlayerController( var controller: MediaController? = null - fun onCreate() { + fun onCreate(onCreated: () -> Unit) { if (created) return externalStorageMonitor.onCreate { reset() } isJukeboxEnabled = activeServerProvider.getActiveServer().jukeboxByDefault @@ -80,32 +79,25 @@ class MediaPlayerController( mediaControllerFuture.addListener({ controller = mediaControllerFuture.get() + Timber.i("MediaController Instance received") + controller?.addListener(object : Player.Listener { /* * Log all events */ -// override fun onEvents(player: Player, events: Player.Events) { -// //Timber.i("Media3 Event: %s", events) -// } + override fun onEvents(player: Player, events: Player.Events) { + for (i in 0 until events.size()) { + Timber.i("Media3 Event, event type: %s", events[i]) + } + } - // override fun onIsLoadingChanged(isLoading: Boolean) { -// super.onIsLoadingChanged(isLoading) -// } -// -// override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) { -// super.onPlayWhenReadyChanged(playWhenReady, reason) -// } -// -// override fun onPlaylistMetadataChanged(mediaMetadata: MediaMetadata) { -// super.onPlaylistMetadataChanged(mediaMetadata) -// } -// /* * This will be called everytime the playlist has changed. */ override fun onTimelineChanged(timeline: Timeline, reason: Int) { legacyPlaylistManager.rebuildPlaylist(controller!!) + serializeCurrentSession() } override fun onPlaybackStateChanged(playbackState: Int) { @@ -125,6 +117,10 @@ class MediaPlayerController( } }) + onCreated() + + Timber.i("MediaPlayerController creation complete") + // controller?.play() }, MoreExecutors.directExecutor()) @@ -134,7 +130,7 @@ class MediaPlayerController( } created = true - Timber.i("MediaPlayerController created") + Timber.i("MediaPlayerController started") } private fun playerStateChangedHandler() { @@ -145,10 +141,6 @@ class MediaPlayerController( Player.STATE_READY -> { if (isPlaying) { scrobbler.scrobble(currentPlaying, false) - } else { - playbackStateSerializer.serialize( - playList, currentMediaItemIndex, playerPosition - ) } } Player.STATE_ENDED -> { @@ -156,6 +148,11 @@ class MediaPlayerController( } } + // Save playback state + playbackStateSerializer.serialize( + playList, currentMediaItemIndex, playerPosition + ) + // Update widget if (currentPlaying != null) { updateWidget(currentPlaying.track) @@ -237,8 +234,9 @@ class MediaPlayerController( seekTo(currentPlayingIndex, currentPlayingPosition) } + prepare() + if (autoPlay) { - prepare() play() } @@ -246,11 +244,6 @@ class MediaPlayerController( } } - @Synchronized - fun preload() { - getInstance() - } - @Synchronized fun play(index: Int) { controller?.seekTo(index, 0L) @@ -356,12 +349,6 @@ class MediaPlayerController( } else { downloader.checkDownloads() } - - playbackStateSerializer.serialize( - legacyPlaylistManager.playlist, - currentMediaItemIndex, - playerPosition - ) } @Synchronized @@ -370,11 +357,7 @@ class MediaPlayerController( val filteredSongs = songs.filterNotNull() downloader.downloadBackground(filteredSongs, save) - playbackStateSerializer.serialize( - legacyPlaylistManager.playlist, - currentMediaItemIndex, - playerPosition - ) + serializeCurrentSession() } fun stopJukeboxService() { @@ -439,12 +422,6 @@ class MediaPlayerController( downloader.clearActiveDownloads() downloader.clearBackground() - playbackStateSerializer.serialize( - legacyPlaylistManager.playlist, - currentMediaItemIndex, - playerPosition - ) - jukeboxMediaPlayer.updatePlaylist() } @@ -453,13 +430,16 @@ class MediaPlayerController( controller?.removeMediaItem(position) + jukeboxMediaPlayer.updatePlaylist() + } + + @Synchronized + private fun serializeCurrentSession() { playbackStateSerializer.serialize( legacyPlaylistManager.playlist, currentMediaItemIndex, playerPosition ) - - jukeboxMediaPlayer.updatePlaylist() } @Synchronized @@ -625,7 +605,7 @@ class MediaPlayerController( } init { - Timber.i("MediaPlayerController constructed") + Timber.i("MediaPlayerController instance initiated") } enum class InsertionMode { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt index 70e9df92..dfdbeac3 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt @@ -29,32 +29,37 @@ class MediaPlayerLifecycleSupport : KoinComponent { onCreate(false, null) } - private fun onCreate(autoPlay: Boolean, afterCreated: Runnable?) { + private fun onCreate(autoPlay: Boolean, afterRestore: Runnable?) { if (created) { - afterCreated?.run() + afterRestore?.run() return } - mediaPlayerController.onCreate() - if (autoPlay) mediaPlayerController.preload() + mediaPlayerController.onCreate { + restoreLastSession(autoPlay, afterRestore) + } + CacheCleaner().clean() + created = true + Timber.i("LifecycleSupport created") + } + + private fun restoreLastSession(autoPlay: Boolean, afterRestore: Runnable?) { playbackStateSerializer.deserialize { + Timber.i("Restoring %s songs", it!!.songs.size) + mediaPlayerController.restore( - it!!.songs, + it.songs, it.currentPlayingIndex, it.currentPlayingPosition, autoPlay, false ) - afterCreated?.run() + afterRestore?.run() } - - CacheCleaner().clean() - created = true - Timber.i("LifecycleSupport created") } fun onDestroy() {