diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt index 2a67051d6..e3404f24a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt @@ -33,19 +33,15 @@ class CastPlayer(castSession: CastSession) : Playback, override var callbacks: Playback.PlaybackCallbacks? = null - override fun setDataSource( - song: Song, - force: Boolean, - completion: (success: Boolean) -> Unit, - ) { - try { + override fun setDataSource(song: Song, force: Boolean): Boolean { + return try { val mediaLoadOptions = MediaLoadOptions.Builder().setPlayPosition(0).setAutoplay(true).build() remoteMediaClient?.load(song.toMediaInfo()!!, mediaLoadOptions) - completion(true) + true } catch (e: Exception) { e.printStackTrace() - completion(false) + false } } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt index da27e6b36..af9661feb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt @@ -120,25 +120,17 @@ class CrossFadePlayer(context: Context) : LocalPlayback(context) { override val isPlaying: Boolean get() = mIsInitialized && getCurrentPlayer()?.isPlaying == true - override fun setDataSource( - song: Song, - force: Boolean, - completion: (success: Boolean) -> Unit, - ) { + override fun setDataSource(song: Song, force: Boolean): Boolean { if (force) hasDataSource = false mIsInitialized = false /* We've already set DataSource if initialized is true in setNextDataSource */ - if (!hasDataSource) { - getCurrentPlayer()?.let { - setDataSourceImpl(it, song.uri.toString()) { success -> - mIsInitialized = success - completion(success) - } - } + return if (!hasDataSource) { + mIsInitialized = setDataSourceImpl(getCurrentPlayer()!!, song.uri.toString()) hasDataSource = true + mIsInitialized } else { - completion(true) mIsInitialized = true + true } } @@ -293,8 +285,8 @@ class CrossFadePlayer(context: Context) : LocalPlayback(context) { val nextSong = MusicPlayerRemote.nextSong // Switch to other player (Crossfade) only if next song exists if (nextSong != null) { - setDataSourceImpl(player, nextSong.uri.toString()) { success -> - if (success) switchPlayer() + if (setDataSourceImpl(player, nextSong.uri.toString())) { + switchPlayer() } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt b/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt index fafbae0ec..ee039f42c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt @@ -109,13 +109,10 @@ abstract class LocalPlayback(val context: Context) : Playback, MediaPlayer.OnErr * @param path The path of the file, or the http/rtsp URL of the stream you want to play * @return True if the player has been prepared and is ready to play, false otherwise */ - fun setDataSourceImpl( - player: MediaPlayer, - path: String, - completion: (success: Boolean) -> Unit, - ) { - player.reset() + fun setDataSourceImpl(player: MediaPlayer, path: String): Boolean { try { + player.reset() + player.setOnPreparedListener(null) if (path.startsWith("content://")) { player.setDataSource(context, path.toUri()) } else { @@ -126,17 +123,14 @@ abstract class LocalPlayback(val context: Context) : Playback, MediaPlayer.OnErr .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build() ) - player.setOnPreparedListener { - player.setOnPreparedListener(null) - completion(true) - } - player.prepareAsync() + player.prepare() } catch (e: Exception) { - completion(false) e.printStackTrace() + return false } player.setOnCompletionListener(this) player.setOnErrorListener(this) + return true } private fun unregisterBecomingNoisyReceiver() { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt index 8421b60f1..d0e766b3f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt @@ -46,19 +46,13 @@ class MultiPlayer(context: Context) : LocalPlayback(context) { * @param song The song object you want to play * @return True if the `player` has been prepared and is ready to play, false otherwise */ - override fun setDataSource( - song: Song, - force: Boolean, - completion: (success: Boolean) -> Unit, - ) { + override fun setDataSource(song: Song, force: Boolean): Boolean { isInitialized = false - setDataSourceImpl(mCurrentMediaPlayer, song.uri.toString()) { success -> - isInitialized = success - if (isInitialized) { - setNextDataSource(null) - } - completion(isInitialized) + isInitialized = setDataSourceImpl(mCurrentMediaPlayer, song.uri.toString()) + if (isInitialized) { + setNextDataSource(null) } + return isInitialized } /** @@ -86,28 +80,26 @@ class MultiPlayer(context: Context) : LocalPlayback(context) { mNextMediaPlayer = MediaPlayer() mNextMediaPlayer?.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) mNextMediaPlayer?.audioSessionId = audioSessionId - setDataSourceImpl(mNextMediaPlayer!!, path) { success -> - if (success) { - try { - mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer) - } catch (e: IllegalArgumentException) { - Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) - if (mNextMediaPlayer != null) { - mNextMediaPlayer?.release() - mNextMediaPlayer = null - } - } catch (e: IllegalStateException) { - Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) - if (mNextMediaPlayer != null) { - mNextMediaPlayer?.release() - mNextMediaPlayer = null - } - } - } else { + if (setDataSourceImpl(mNextMediaPlayer!!, path)) { + try { + mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer) + } catch (e: IllegalArgumentException) { + Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) if (mNextMediaPlayer != null) { mNextMediaPlayer?.release() mNextMediaPlayer = null } + } catch (e: IllegalStateException) { + Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) + if (mNextMediaPlayer != null) { + mNextMediaPlayer?.release() + mNextMediaPlayer = null + } + } + } else { + if (mNextMediaPlayer != null) { + mNextMediaPlayer?.release() + mNextMediaPlayer = null } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index 512cd3839..cee0a47ed 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -117,6 +117,11 @@ class MusicService : MediaBrowserServiceCompat(), private var trackEndedByCrossfade = false private val serviceScope = CoroutineScope(Job() + Main) + // Every chromecast method needs to run on main thread or you are greeted with IllegalStateException + // So it will use Main dispatcher + // And by using Default dispatcher for local playback we are reducing the burden from main thread + private val playerDispatcher get() = if (playbackManager.isLocalPlayback) Default else Main + @JvmField var position = -1 private val appWidgetBig = AppWidgetBig.instance @@ -436,11 +441,8 @@ class MusicService : MediaBrowserServiceCompat(), } private fun setPosition(position: Int) { - openTrackAndPrepareNextAt(position) { success -> - if (success) { - notifyChange(PLAY_STATE_CHANGED) - } - } + openTrackAndPrepareNextAt(position) + notifyChange(PLAY_STATE_CHANGED) } private fun getPreviousPosition(force: Boolean): Int { @@ -755,16 +757,15 @@ class MusicService : MediaBrowserServiceCompat(), } @Synchronized - fun openTrackAndPrepareNextAt(position: Int, completion: (success: Boolean) -> Unit) { + fun openTrackAndPrepareNextAt(position: Int): Boolean { this.position = position - openCurrent { success -> - completion(success) - notifyChange(META_CHANGED) - notHandledMetaChangedForCurrentTrack = false - if (success) { - prepareNextImpl() - } + val prepared = openCurrent() + if (prepared) { + prepareNextImpl() } + notifyChange(META_CHANGED) + notHandledMetaChangedForCurrentTrack = false + return prepared } fun pause(force: Boolean = false) { @@ -793,16 +794,11 @@ class MusicService : MediaBrowserServiceCompat(), } fun playSongAt(position: Int) { - // Every chromecast method needs to run on main thread or you are greeted with IllegalStateException - // So it will use Main dispatcher - // And by using Default dispatcher for local playback we are reduce the burden of main thread - serviceScope.launch(if(playbackManager.isLocalPlayback) Default else Main) { - openTrackAndPrepareNextAt(position) { success -> - if (success) { - play() - } else { - showToast(resources.getString(R.string.unplayable_file)) - } + serviceScope.launch(playerDispatcher) { + if (openTrackAndPrepareNextAt(position)) { + play() + } else { + showToast(R.string.unplayable_file) } } } @@ -917,15 +913,14 @@ class MusicService : MediaBrowserServiceCompat(), originalPlayingQueue = ArrayList(restoredOriginalQueue) playingQueue = ArrayList(restoredQueue) position = restoredPosition - withContext(Main) { - openCurrent { - prepareNext() - if (restoredPositionInTrack > 0) { - seek(restoredPositionInTrack) - } - notHandledMetaChangedForCurrentTrack = true - sendChangeInternal(META_CHANGED) + withContext(playerDispatcher) { + openCurrent() + prepareNext() + if (restoredPositionInTrack > 0) { + seek(restoredPositionInTrack) } + notHandledMetaChangedForCurrentTrack = true + sendChangeInternal(META_CHANGED) if (receivedHeadsetConnected) { play() receivedHeadsetConnected = false @@ -1169,15 +1164,18 @@ class MusicService : MediaBrowserServiceCompat(), } @Synchronized - private fun openCurrent(completion: (success: Boolean) -> Unit) { + private fun openCurrent(): Boolean { val force = if (!trackEndedByCrossfade) { true } else { trackEndedByCrossfade = false false } - playbackManager.setDataSource(currentSong, force) { success -> - completion(success) + return try { + playbackManager.setDataSource(currentSong, force) + } catch (e: Exception) { + e.printStackTrace() + false } } @@ -1191,12 +1189,10 @@ class MusicService : MediaBrowserServiceCompat(), private fun restorePlaybackState(wasPlaying: Boolean, progress: Int) { playbackManager.setCallbacks(this) - openTrackAndPrepareNextAt(position) { success -> - if (success) { - seek(progress) - if (wasPlaying) { - play() - } + if (openTrackAndPrepareNextAt(position)) { + seek(progress) + if (wasPlaying) { + play() } } playbackManager.setCrossFadeDuration(crossFadeDuration) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt b/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt index 9186bd534..f64b7d600 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/PlaybackManager.kt @@ -16,7 +16,7 @@ class PlaybackManager(val context: Context) { var playback: Playback? = null private var playbackLocation = PlaybackLocation.LOCAL - val isLocalPlayback get() = playbackLocation== PlaybackLocation.LOCAL + val isLocalPlayback get() = playbackLocation == PlaybackLocation.LOCAL val audioSessionId: Int get() = if (playback != null) { @@ -86,12 +86,8 @@ class PlaybackManager(val context: Context) { fun seek(millis: Int): Int = playback!!.seek(millis) - fun setDataSource( - song: Song, - force: Boolean, - completion: (success: Boolean) -> Unit, - ) { - playback?.setDataSource(song, force, completion) + fun setDataSource(song: Song, force: Boolean): Boolean { + return playback?.setDataSource(song, force) == true } fun setNextDataSource(trackUri: String) { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt index 3795e7634..f3521ab96 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt @@ -25,9 +25,7 @@ interface Playback { val audioSessionId: Int - fun setDataSource( - song: Song, force: Boolean, completion: (success: Boolean) -> Unit, - ) + fun setDataSource(song: Song, force: Boolean):Boolean fun setNextDataSource(path: String?)