Fixed Crossfade
This commit is contained in:
parent
7e755611b0
commit
900ea92562
3 changed files with 24 additions and 76 deletions
|
@ -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)
|
|
@ -1573,4 +1573,4 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
return MusicService.this;
|
return MusicService.this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue