Fix Playback speed and pitch for PlaybackManager
This commit is contained in:
parent
1033711357
commit
0fd8ab0ade
6 changed files with 54 additions and 68 deletions
|
@ -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 -> {
|
||||
|
|
|
@ -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 {
|
||||
|
@ -376,3 +364,13 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
|
|||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
if (playbackManager.maybeSwitchToCrossFade(crossFadeDuration)) {
|
||||
restorePlaybackState(wasPlaying, progress)
|
||||
|
||||
}
|
||||
}
|
||||
ALBUM_ART_ON_LOCK_SCREEN, BLURRED_ALBUM_ART -> updateMediaSessionMetaData()
|
||||
COLORED_NOTIFICATION -> {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue