Fix Playback speed and pitch for PlaybackManager

This commit is contained in:
Prathamesh More 2022-05-14 12:13:55 +05:30
parent 1033711357
commit 0fd8ab0ade
6 changed files with 54 additions and 68 deletions

View file

@ -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 -> {

View file

@ -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)
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()
}
}
}

View file

@ -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)
}
}

View file

@ -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 -> {

View file

@ -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)
}

View file

@ -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 {