From 0fd8ab0adedbb55bc5bea9200485d51f64999e0c Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Sat, 14 May 2022 12:13:55 +0530 Subject: [PATCH] Fix Playback speed and pitch for PlaybackManager --- .../monkey/retromusic/service/CastPlayer.kt | 6 +++ .../retromusic/service/CrossFadePlayer.kt | 32 ++++++------ .../monkey/retromusic/service/MultiPlayer.kt | 49 +++---------------- .../monkey/retromusic/service/MusicService.kt | 8 +-- .../retromusic/service/PlaybackHandler.kt | 1 - .../retromusic/service/PlaybackManager.kt | 26 ++++++++-- 6 files changed, 54 insertions(+), 68 deletions(-) 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 ad9891a1f..baec003e3 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 @@ -3,6 +3,7 @@ package code.name.monkey.retromusic.service import code.name.monkey.retromusic.cast.CastHelper.toMediaInfo import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.service.playback.Playback +import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed import com.google.android.gms.cast.MediaLoadOptions import com.google.android.gms.cast.MediaSeekOptions import com.google.android.gms.cast.MediaStatus @@ -18,6 +19,7 @@ class CastPlayer(castSession: CastSession) : Playback, init { remoteMediaClient?.registerCallback(this) + remoteMediaClient?.setPlaybackRate(playbackSpeed.toDouble().coerceIn(0.5, 2.0)) } private var isActuallyPlaying = false @@ -93,6 +95,10 @@ class CastPlayer(castSession: CastSession) : Playback, override fun setCrossFadeDuration(duration: Int) {} + override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) { + remoteMediaClient?.setPlaybackRate(speed.toDouble().coerceIn(0.5, 2.0)) + } + override fun onStatusUpdated() { when (remoteMediaClient?.playerState) { MediaStatus.PLAYER_STATE_IDLE -> { 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 4a54231f7..451f545b8 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 @@ -2,12 +2,10 @@ package code.name.monkey.retromusic.service import android.animation.Animator import android.content.Context -import android.content.Intent import android.media.AudioAttributes import android.media.AudioManager import android.media.MediaPlayer import android.media.PlaybackParams -import android.media.audiofx.AudioEffect import android.os.PowerManager import android.util.Log import androidx.core.net.toUri @@ -20,7 +18,6 @@ import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.service.AudioFader.Companion.createFadeAnimator import code.name.monkey.retromusic.service.playback.Playback import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks -import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil.playbackPitch import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed @@ -144,6 +141,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion } hasDataSource = true } else { + completion(true) mIsInitialized = true } } @@ -170,7 +168,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion player.setAudioAttributes( AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC).build() ) - player.setPlaybackSpeedPitch(PreferenceUtil.playbackSpeed, PreferenceUtil.playbackPitch) + player.setPlaybackSpeedPitch(playbackSpeed, playbackPitch) player.setOnPreparedListener { player.setOnPreparedListener(null) completion(true) @@ -329,8 +327,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion getNextPlayer()?.let { player -> val nextSong = MusicPlayerRemote.nextSong if (nextSong != null) { - setDataSourceImpl(player, - MusicUtil.getSongFileUri(nextSong.id).toString()) { success -> + setDataSourceImpl(player, nextSong.uri.toString()) { success -> // Switch to other player (Crossfade) only if next song exists if (success) switchPlayer() } @@ -358,16 +355,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) { getCurrentPlayer()?.setPlaybackSpeedPitch(speed, pitch) - } - - private fun MediaPlayer.setPlaybackSpeedPitch(speed: Float, pitch: Float) { - if (hasMarshmallow()) { - val wasPlaying: Boolean = isPlaying - playbackParams = PlaybackParams().setSpeed(speed).setPitch(pitch) - if (!wasPlaying) { - if (isPlaying) pause() - } - } + getNextPlayer()?.setPlaybackSpeedPitch(speed, pitch) } companion object { @@ -375,4 +363,14 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion } } -internal fun crossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main) \ No newline at end of file +internal fun crossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main) + +fun MediaPlayer.setPlaybackSpeedPitch(speed: Float, pitch: Float) { + if (hasMarshmallow()) { + val wasPlaying: Boolean = isPlaying + playbackParams = PlaybackParams().setSpeed(speed).setPitch(pitch) + if (!wasPlaying) { + if (isPlaying) pause() + } + } +} \ No newline at end of file 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 602f2a8f2..76b26edd1 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 @@ -14,19 +14,12 @@ package code.name.monkey.retromusic.service import android.content.Context -import android.content.SharedPreferences -import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.media.AudioAttributes import android.media.MediaPlayer import android.media.MediaPlayer.OnCompletionListener -import android.media.PlaybackParams import android.net.Uri import android.os.PowerManager import android.util.Log -import androidx.preference.PreferenceManager -import code.name.monkey.appthemehelper.util.VersionUtils.hasMarshmallow -import code.name.monkey.retromusic.PLAYBACK_PITCH -import code.name.monkey.retromusic.PLAYBACK_SPEED import code.name.monkey.retromusic.R import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.extensions.uri @@ -41,7 +34,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed * @author Andrew Neal, Karim Abou Zeid (kabouzeid) */ class MultiPlayer internal constructor(private val context: Context) : Playback, - MediaPlayer.OnErrorListener, OnCompletionListener, OnSharedPreferenceChangeListener { + MediaPlayer.OnErrorListener, OnCompletionListener { private var mCurrentMediaPlayer = MediaPlayer() private var mNextMediaPlayer: MediaPlayer? = null private var callbacks: PlaybackCallbacks? = null @@ -52,6 +45,10 @@ class MultiPlayer internal constructor(private val context: Context) : Playback, override var isInitialized = false private set + init { + mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) + } + /** * @param song The song object you want to play * @return True if the `player` has been prepared and is ready to play, false otherwise @@ -89,12 +86,12 @@ class MultiPlayer internal constructor(private val context: Context) : Playback, } else { player.setDataSource(path) } - setPlaybackSpeedPitch(player) player.setAudioAttributes(AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build() ) + player.setPlaybackSpeedPitch(playbackSpeed, playbackPitch) player.setOnPreparedListener { player.setOnPreparedListener(null) completion(true) @@ -198,8 +195,6 @@ class MultiPlayer internal constructor(private val context: Context) : Playback, if (mNextMediaPlayer != null) { mNextMediaPlayer?.release() } - PreferenceManager.getDefaultSharedPreferences(context) - .unregisterOnSharedPreferenceChangeListener(this) } /** @@ -298,9 +293,6 @@ class MultiPlayer internal constructor(private val context: Context) : Playback, override val audioSessionId: Int get() = mCurrentMediaPlayer.audioSessionId - /** - * {@inheritDoc} - */ override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean { isInitialized = false mCurrentMediaPlayer.release() @@ -311,9 +303,6 @@ class MultiPlayer internal constructor(private val context: Context) : Playback, return false } - /** - * {@inheritDoc} - */ override fun onCompletion(mp: MediaPlayer) { if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { isInitialized = false @@ -328,34 +317,12 @@ class MultiPlayer internal constructor(private val context: Context) : Playback, } override fun setCrossFadeDuration(duration: Int) {} - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - if (key == PLAYBACK_SPEED || key == PLAYBACK_PITCH) { - setPlaybackSpeedPitch(mCurrentMediaPlayer) - } - } - private fun setPlaybackSpeedPitch(mp: MediaPlayer) { - if (hasMarshmallow()) { - val wasPlaying = mp.isPlaying - mp.playbackParams = PlaybackParams() - .setSpeed(playbackSpeed) - .setPitch(playbackPitch) - if (!wasPlaying) { - if (mp.isPlaying) mp.pause() - } - } + override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) { + mCurrentMediaPlayer.setPlaybackSpeedPitch(speed, pitch) } companion object { val TAG: String = MultiPlayer::class.java.simpleName } - - /** - * Constructor of `MultiPlayer` - */ - init { - mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) - PreferenceManager.getDefaultSharedPreferences(context) - .registerOnSharedPreferenceChangeListener(this) - } } \ No newline at end of file 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 a0672d5ec..c6a825790 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 @@ -692,15 +692,15 @@ class MusicService : MediaBrowserServiceCompat(), ) { when (key) { PLAYBACK_SPEED, PLAYBACK_PITCH -> { - playback?.setPlaybackSpeedPitch(playbackSpeed, playbackPitch) + playbackManager.setPlaybackSpeedPitch(playbackSpeed, playbackPitch) } CROSS_FADE_DURATION -> { val progress = songProgressMillis val wasPlaying = isPlaying - playbackManager.maybeSwitchToCrossFade(crossFadeDuration) - restorePlaybackState(wasPlaying, progress) - + if (playbackManager.maybeSwitchToCrossFade(crossFadeDuration)) { + restorePlaybackState(wasPlaying, progress) + } } ALBUM_ART_ON_LOCK_SCREEN, BLURRED_ALBUM_ART -> updateMediaSessionMetaData() COLORED_NOTIFICATION -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/PlaybackHandler.kt b/app/src/main/java/code/name/monkey/retromusic/service/PlaybackHandler.kt index 86fbb04ac..1fa3c2ba3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/PlaybackHandler.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/PlaybackHandler.kt @@ -97,7 +97,6 @@ internal class PlaybackHandler(service: MusicService, looper: Looper) : Handler( } AudioManager.AUDIOFOCUS_LOSS -> { // Lost focus for an unbounded amount of time: stop playback and release media playback - val isAudioFocusEnabled = isAudioFocusEnabled if (!isAudioFocusEnabled) { service.pause(true) } 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 b1e5dd081..1ee3f727a 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 @@ -92,8 +92,12 @@ class PlaybackManager(val context: Context) { playback?.setCrossFadeDuration(duration) } - fun maybeSwitchToCrossFade(crossFadeDuration: Int) { - /* Switch to MultiPlayer if Crossfade duration is 0 and + /** + * @param crossFadeDuration CrossFade duration + * @return Whether switched playback + */ + fun maybeSwitchToCrossFade(crossFadeDuration: Int): Boolean { + /* Switch to MultiPlayer if CrossFade duration is 0 and Playback is not an instance of MultiPlayer */ if (playback !is MultiPlayer && crossFadeDuration == 0) { if (playback != null) { @@ -101,13 +105,16 @@ class PlaybackManager(val context: Context) { } playback = null playback = MultiPlayer(context) + return true } else if (playback !is CrossFadePlayer && crossFadeDuration > 0) { if (playback != null) { playback?.release() } playback = null playback = CrossFadePlayer(context) + return true } + return false } fun release() { @@ -126,7 +133,7 @@ class PlaybackManager(val context: Context) { context.sendBroadcast(intent) } - fun closeAudioEffectSession() { + private fun closeAudioEffectSession() { val audioEffectsIntent = Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION) if (playback != null) { audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, @@ -141,12 +148,18 @@ class PlaybackManager(val context: Context) { switchToPlayback(createLocalPlayback(), onChange) } - fun switchToRemotePlayback(castSession: CastSession, onChange: (wasPlaying: Boolean, progress: Int) -> Unit) { + fun switchToRemotePlayback( + castSession: CastSession, + onChange: (wasPlaying: Boolean, progress: Int) -> Unit, + ) { playbackLocation = PlaybackLocation.REMOTE switchToPlayback(CastPlayer(castSession), onChange) } - private fun switchToPlayback(playback: Playback, onChange: (wasPlaying: Boolean, progress: Int) -> Unit) { + private fun switchToPlayback( + playback: Playback, + onChange: (wasPlaying: Boolean, progress: Int) -> Unit, + ) { val oldPlayback = playback val wasPlaying: Boolean = oldPlayback.isPlaying val progress: Int = oldPlayback.position() @@ -167,6 +180,9 @@ class PlaybackManager(val context: Context) { } } + fun setPlaybackSpeedPitch(playbackSpeed: Float, playbackPitch: Float) { + playback?.setPlaybackSpeedPitch(playbackSpeed, playbackPitch) + } } enum class PlaybackLocation {