Fixed Crossfade

main
Prathamesh More 2021-09-20 16:11:33 +05:30
parent 7e755611b0
commit 900ea92562
3 changed files with 24 additions and 76 deletions

View File

@ -1,7 +1,6 @@
package code.name.monkey.retromusic.service package code.name.monkey.retromusic.service
import android.animation.Animator import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.media.AudioAttributes import android.media.AudioAttributes
@ -9,17 +8,16 @@ import android.media.AudioManager
import android.media.MediaPlayer import android.media.MediaPlayer
import android.media.audiofx.AudioEffect import android.media.audiofx.AudioEffect
import android.net.Uri import android.net.Uri
import android.os.Handler
import android.os.Message
import android.os.PowerManager import android.os.PowerManager
import android.widget.Toast import android.widget.Toast
import androidx.core.animation.doOnEnd
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
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
import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import kotlinx.coroutines.*
/** @author Prathamesh M */ /** @author Prathamesh M */
@ -37,7 +35,6 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
private var player1 = MediaPlayer() private var player1 = MediaPlayer()
private var player2 = MediaPlayer() private var player2 = MediaPlayer()
private var durationListener = DurationListener() private var durationListener = DurationListener()
private var trackEndHandledByCrossFade = false
private var mIsInitialized = false private var mIsInitialized = false
private var hasDataSource: Boolean = false /* Whether first player has DataSource */ private var hasDataSource: Boolean = false /* Whether first player has DataSource */
private var fadeInAnimator: Animator? = null private var fadeInAnimator: Animator? = null
@ -231,17 +228,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
} }
override fun onCompletion(mp: MediaPlayer?) { override fun onCompletion(mp: MediaPlayer?) {
if (mp == getNextPlayer()) { if (mp == getCurrentPlayer()) {
if (trackEndHandledByCrossFade) {
trackEndHandledByCrossFade = false
} else {
notifyTrackEnded()
}
}
}
private fun notifyTrackEnded(){
if (callbacks != null) {
callbacks?.onTrackEnded() callbacks?.onTrackEnded()
} }
} }
@ -276,53 +263,23 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
private fun fadeIn(mediaPlayer: MediaPlayer) { private fun fadeIn(mediaPlayer: MediaPlayer) {
fadeInAnimator = createFadeAnimator(true, mediaPlayer) { fadeInAnimator = createFadeAnimator(true, mediaPlayer) {
println("Fade In Completed")
fadeInAnimator = null fadeInAnimator = null
durationListener.start()
} }
fadeInAnimator?.start() fadeInAnimator?.start()
} }
private fun fadeOut(mediaPlayer: MediaPlayer) { private fun fadeOut(mediaPlayer: MediaPlayer) {
fadeOutAnimator = createFadeAnimator(false, mediaPlayer) { fadeOutAnimator = createFadeAnimator(false, mediaPlayer) {
println("Fade Out Completed")
fadeOutAnimator = null fadeOutAnimator = null
mediaPlayer.stop()
} }
fadeOutAnimator?.start() fadeOutAnimator?.start()
} }
private fun cancelFade() { private fun cancelFade() {
fadeInAnimator?.cancel()
fadeOutAnimator?.cancel()
fadeInAnimator = null fadeInAnimator = null
fadeOutAnimator = null fadeOutAnimator = null
getCurrentPlayer()?.setVolume(1f, 1f)
getNextPlayer()?.setVolume(0f, 0f)
}
private fun createFadeAnimator(
fadeIn: Boolean /* fadeIn -> true fadeOut -> false*/,
mediaPlayer: MediaPlayer,
callback: Runnable /* Code to run when Animator Ends*/
): Animator? {
val duration = PreferenceUtil.crossFadeDuration * 1000
if (duration == 0) {
return null
}
val startValue = if (fadeIn) 0f else 1.0f
val endValue = if (fadeIn) 1.0f else 0f
val animator = ValueAnimator.ofFloat(startValue, endValue)
animator.duration = duration.toLong()
animator.addUpdateListener { animation: ValueAnimator ->
mediaPlayer.setVolume(
animation.animatedValue as Float, animation.animatedValue as Float
)
}
animator.doOnEnd {
callback.run()
// Set end values
mediaPlayer.setVolume(endValue, endValue)
}
return animator
} }
override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
@ -347,28 +304,22 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
NOT_SET NOT_SET
} }
inner class DurationListener : Handler() { inner class DurationListener : CoroutineScope by CrossFadeScope() {
private var job: Job? = null
fun start() { fun start() {
nextRefresh() job?.cancel()
} job = launch {
while (true) {
fun stop() { delay(250)
removeMessages(DURATION_CHANGED) onDurationUpdated(position(), duration())
} }
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == DURATION_CHANGED) {
nextRefresh()
onDurationUpdated(position(), duration())
} }
} }
private fun nextRefresh() { fun stop() {
val message = obtainMessage(DURATION_CHANGED) job?.cancel()
removeMessages(DURATION_CHANGED)
sendMessageDelayed(message, 100)
} }
} }
@ -376,6 +327,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
fun onDurationUpdated(progress: Int, total: Int) { fun onDurationUpdated(progress: Int, total: Int) {
if (total > 0 && (total - progress).div(1000) == PreferenceUtil.crossFadeDuration) { if (total > 0 && (total - progress).div(1000) == PreferenceUtil.crossFadeDuration) {
getNextPlayer()?.let { player -> getNextPlayer()?.let { player ->
durationListener.stop()
val nextSong = MusicPlayerRemote.nextSong val nextSong = MusicPlayerRemote.nextSong
if (nextSong != null) { if (nextSong != null) {
setDataSourceImpl(player, MusicUtil.getSongFileUri(nextSong.id).toString()) setDataSourceImpl(player, MusicUtil.getSongFileUri(nextSong.id).toString())
@ -396,11 +348,8 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
} else { } else {
CurrentPlayer.PLAYER_ONE CurrentPlayer.PLAYER_ONE
} }
notifyTrackEnded() callbacks?.onTrackEndedWithCrossfade()
trackEndHandledByCrossFade = true
}
companion object {
private const val DURATION_CHANGED = 1
} }
} }
internal fun CrossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)

View File

@ -1573,4 +1573,4 @@ public class MusicService extends MediaBrowserServiceCompat
return MusicService.this; return MusicService.this;
} }
} }
} }

View File

@ -80,7 +80,7 @@ class PlaybackHandler extends Handler {
case TRACK_WENT_TO_NEXT: case TRACK_WENT_TO_NEXT:
if (service.pendingQuit if (service.pendingQuit
|| service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) { || service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
service.pause(); service.pause();
service.seek(0); service.seek(0);
if (service.pendingQuit) { if (service.pendingQuit) {
@ -96,10 +96,9 @@ class PlaybackHandler extends Handler {
break; break;
case TRACK_ENDED: case TRACK_ENDED:
service.trackEndedByCrossfade = true;
// if there is a timer finished, don't continue // if there is a timer finished, don't continue
if (service.pendingQuit if (service.pendingQuit
|| service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) { || service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
service.notifyChange(PLAY_STATE_CHANGED); service.notifyChange(PLAY_STATE_CHANGED);
service.seek(0); service.seek(0);
if (service.pendingQuit) { if (service.pendingQuit) {
@ -169,4 +168,4 @@ class PlaybackHandler extends Handler {
break; break;
} }
} }
} }