Handle sending progress update

This commit is contained in:
Naveen 2023-08-07 03:53:12 +05:30
parent f32e6a370e
commit 464a6dc8ca
No known key found for this signature in database
GPG key ID: 0E155DAD31671DA3
3 changed files with 105 additions and 52 deletions

View file

@ -6,8 +6,8 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.session.*
import com.simplemobiletools.musicplayer.extensions.config
import com.simplemobiletools.musicplayer.services.playback.library.MediaItemProvider
import com.simplemobiletools.musicplayer.services.playback.player.PlayerListener
import com.simplemobiletools.musicplayer.services.playback.player.SimplePlayer
import com.simplemobiletools.musicplayer.services.playback.player.getPlayerListener
import com.simplemobiletools.musicplayer.services.playback.player.initializeSessionAndPlayer
@OptIn(UnstableApi::class)
@ -18,6 +18,8 @@ class PlaybackService : MediaLibraryService() {
internal lateinit var mediaItemProvider: MediaItemProvider
internal var listener: PlayerListener? = null
internal var currentRoot = ""
override fun onCreate() {
@ -30,7 +32,7 @@ class PlaybackService : MediaLibraryService() {
private fun releaseMediaSession() {
mediaSession.release()
player.removeListener(getPlayerListener())
player.removeListener(listener!!)
player.release()
}
@ -42,6 +44,7 @@ class PlaybackService : MediaLibraryService() {
}
fun stopService() {
player.pause()
player.stop()
releaseMediaSession()
stopSelf()

View file

@ -5,58 +5,32 @@ package com.simplemobiletools.musicplayer.services.playback.player
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.media3.common.AudioAttributes
import androidx.media3.common.C
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaLibraryService
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.musicplayer.R
import com.simplemobiletools.musicplayer.activities.MainActivity
import com.simplemobiletools.musicplayer.services.playback.PlaybackService
import com.simplemobiletools.musicplayer.services.playback.getCustomLayout
import com.simplemobiletools.musicplayer.services.playback.getMediaSessionCallback
private const val SEEK_INCREMENT_MS = 10000L
private var playerListener: Player.Listener? = null
internal fun PlaybackService.getPlayerListener(): Player.Listener {
if (playerListener == null) {
playerListener = object : Player.Listener {
override fun onEvents(player: Player, events: Player.Events) {
if (events.containsAny(
Player.EVENT_POSITION_DISCONTINUITY,
Player.EVENT_MEDIA_ITEM_TRANSITION,
Player.EVENT_PLAY_WHEN_READY_CHANGED,
Player.EVENT_TRACKS_CHANGED,
Player.EVENT_TIMELINE_CHANGED,
Player.EVENT_IS_PLAYING_CHANGED
)
) {
val currentMediaId = player.currentMediaItem?.mediaId
if (currentMediaId != null && currentRoot.isNotEmpty()) {
mediaItemProvider.saveRecentItemsWithStartPosition(
mediaId = currentMediaId,
startPosition = player.currentPosition,
rootId = currentRoot
)
}
}
}
override fun onPlayerError(error: PlaybackException) = toast(R.string.unknown_error_occurred, Toast.LENGTH_LONG)
}
}
return playerListener!!
}
private const val SEEK_INTERVAL_MS = 10000L
internal fun PlaybackService.initializeSessionAndPlayer(handleAudioFocus: Boolean, handleAudioBecomingNoisy: Boolean, skipSilence: Boolean) {
player = SimplePlayer(
player = initializePlayer(handleAudioFocus, handleAudioBecomingNoisy, skipSilence)
listener = PlayerListener(context = this)
player.addListener(listener!!)
mediaSession = MediaLibraryService.MediaLibrarySession.Builder(this, player, getMediaSessionCallback())
.setSessionActivity(getSessionActivityIntent())
.build()
mediaSession.setCustomLayout(getCustomLayout())
}
private fun Context.initializePlayer(handleAudioFocus: Boolean, handleAudioBecomingNoisy: Boolean, skipSilence: Boolean): SimplePlayer {
return SimplePlayer(
ExoPlayer.Builder(this)
.setWakeMode(C.WAKE_MODE_LOCAL)
.setHandleAudioBecomingNoisy(handleAudioBecomingNoisy)
@ -68,18 +42,10 @@ internal fun PlaybackService.initializeSessionAndPlayer(handleAudioFocus: Boolea
handleAudioFocus
)
.setSkipSilenceEnabled(skipSilence)
.setSeekBackIncrementMs(SEEK_INCREMENT_MS)
.setSeekForwardIncrementMs(SEEK_INCREMENT_MS)
.setSeekBackIncrementMs(SEEK_INTERVAL_MS)
.setSeekForwardIncrementMs(SEEK_INTERVAL_MS)
.build()
)
player.addListener(getPlayerListener())
mediaSession = MediaLibraryService.MediaLibrarySession.Builder(this, player, getMediaSessionCallback())
.setSessionActivity(getSessionActivityIntent())
.build()
mediaSession.setCustomLayout(getCustomLayout())
}
private fun Context.getSessionActivityIntent(): PendingIntent {

View file

@ -0,0 +1,84 @@
package com.simplemobiletools.musicplayer.services.playback.player
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import androidx.core.os.postDelayed
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.musicplayer.R
import com.simplemobiletools.musicplayer.models.Events
import com.simplemobiletools.musicplayer.services.playback.PlaybackService
import org.greenrobot.eventbus.EventBus
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
@UnstableApi
class PlayerListener(private val context: PlaybackService) : Player.Listener {
private val handler = Handler(Looper.getMainLooper())
private val updateIntervalMillis = 800L
override fun onPlayerError(error: PlaybackException) = context.toast(R.string.unknown_error_occurred, Toast.LENGTH_LONG)
override fun onEvents(player: Player, events: Player.Events) {
if (
events.containsAny(
Player.EVENT_POSITION_DISCONTINUITY,
Player.EVENT_MEDIA_ITEM_TRANSITION,
Player.EVENT_PLAY_WHEN_READY_CHANGED,
Player.EVENT_TRACKS_CHANGED,
Player.EVENT_TIMELINE_CHANGED,
Player.EVENT_IS_PLAYING_CHANGED,
Player.EVENT_PLAYBACK_STATE_CHANGED,
Player.EVENT_MEDIA_METADATA_CHANGED
)
) {
val currentMediaId = player.currentMediaItem?.mediaId
if (currentMediaId != null && context.currentRoot.isNotEmpty()) {
context.mediaItemProvider.saveRecentItemsWithStartPosition(
mediaId = currentMediaId,
startPosition = player.currentPosition,
rootId = context.currentRoot
)
}
}
}
override fun onIsPlayingChanged(isPlaying: Boolean) {
if (isPlaying) {
schedulePositionUpdate()
} else {
cancelPositionUpdate()
}
}
override fun onPositionDiscontinuity(oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, reason: Int) {
if (context.player.isPlaying) {
schedulePositionUpdate()
} else {
cancelPositionUpdate()
}
}
private fun schedulePositionUpdate() {
handler.removeCallbacksAndMessages(null)
handler.postDelayed(updateIntervalMillis) {
updatePosition()
}
}
private fun cancelPositionUpdate() {
handler.removeCallbacksAndMessages(null)
}
private fun updatePosition() {
val currentPosition = context.player.currentPosition
if (currentPosition >= 0) {
val progress = currentPosition.seconds.toInt(DurationUnit.SECONDS)
EventBus.getDefault().post(Events.ProgressUpdated(progress))
schedulePositionUpdate()
}
}
}