feat: add RadioPlayerAdapter — thin Player facade for Media3
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,160 @@
|
|||||||
|
package xyz.cottongin.radio247.service
|
||||||
|
|
||||||
|
import android.os.Looper
|
||||||
|
import androidx.media3.common.BasePlayer
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.MediaMetadata
|
||||||
|
import androidx.media3.common.PlaybackParameters
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.Timeline
|
||||||
|
import xyz.cottongin.radio247.audio.IcyMetadata
|
||||||
|
import xyz.cottongin.radio247.data.model.Station
|
||||||
|
|
||||||
|
class RadioPlayerAdapter(
|
||||||
|
private val onPlay: () -> Unit,
|
||||||
|
private val onStop: () -> Unit,
|
||||||
|
) : BasePlayer() {
|
||||||
|
|
||||||
|
private val listeners = mutableListOf<Player.Listener>()
|
||||||
|
private var _playbackState: Int = Player.STATE_IDLE
|
||||||
|
private var _playWhenReady: Boolean = false
|
||||||
|
private var _mediaMetadata: MediaMetadata = MediaMetadata.EMPTY
|
||||||
|
private var _currentMediaItem: MediaItem? = null
|
||||||
|
|
||||||
|
override fun getApplicationLooper(): Looper = Looper.getMainLooper()
|
||||||
|
|
||||||
|
override fun addListener(listener: Player.Listener) {
|
||||||
|
listeners.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeListener(listener: Player.Listener) {
|
||||||
|
listeners.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAvailableCommands(): Player.Commands =
|
||||||
|
Player.Commands.Builder()
|
||||||
|
.add(Player.COMMAND_PLAY_PAUSE)
|
||||||
|
.add(Player.COMMAND_STOP)
|
||||||
|
.add(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)
|
||||||
|
.add(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override fun getPlaybackState(): Int = _playbackState
|
||||||
|
override fun getPlayWhenReady(): Boolean = _playWhenReady
|
||||||
|
override fun isPlaying(): Boolean = _playbackState == Player.STATE_READY && _playWhenReady
|
||||||
|
override fun getMediaMetadata(): MediaMetadata = _mediaMetadata
|
||||||
|
override fun getCurrentMediaItem(): MediaItem? = _currentMediaItem
|
||||||
|
|
||||||
|
override fun play() {
|
||||||
|
_playWhenReady = true
|
||||||
|
onPlay()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pause() {
|
||||||
|
_playWhenReady = false
|
||||||
|
onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop() {
|
||||||
|
_playWhenReady = false
|
||||||
|
onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun prepare() {}
|
||||||
|
|
||||||
|
override fun setPlayWhenReady(playWhenReady: Boolean) {
|
||||||
|
if (playWhenReady) play() else pause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun release() {
|
||||||
|
listeners.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPlaybackParameters(): PlaybackParameters = PlaybackParameters.DEFAULT
|
||||||
|
override fun setPlaybackParameters(playbackParameters: PlaybackParameters) {}
|
||||||
|
|
||||||
|
override fun getRepeatMode(): Int = Player.REPEAT_MODE_OFF
|
||||||
|
override fun setRepeatMode(repeatMode: Int) {}
|
||||||
|
|
||||||
|
override fun getShuffleModeEnabled(): Boolean = false
|
||||||
|
override fun setShuffleModeEnabled(shuffleModeEnabled: Boolean) {}
|
||||||
|
|
||||||
|
override fun seekToDefaultPosition() {}
|
||||||
|
override fun seekToDefaultPosition(mediaItemIndex: Int) {}
|
||||||
|
override fun seekTo(positionMs: Long) {}
|
||||||
|
override fun seekTo(mediaItemIndex: Int, positionMs: Long) {}
|
||||||
|
|
||||||
|
override fun getCurrentTimeline(): Timeline = Timeline.EMPTY
|
||||||
|
override fun getCurrentMediaItemIndex(): Int = 0
|
||||||
|
override fun getContentPosition(): Long = 0
|
||||||
|
override fun getContentDuration(): Long = C.TIME_UNSET
|
||||||
|
override fun getCurrentPosition(): Long = 0
|
||||||
|
override fun getDuration(): Long = C.TIME_UNSET
|
||||||
|
override fun getBufferedPosition(): Long = 0
|
||||||
|
override fun getTotalBufferedDuration(): Long = 0
|
||||||
|
override fun isCurrentMediaItemLive(): Boolean = true
|
||||||
|
|
||||||
|
fun updatePlaybackState(state: PlaybackState) {
|
||||||
|
val (newPlayerState, newPlayWhenReady) = when (state) {
|
||||||
|
is PlaybackState.Idle -> Player.STATE_IDLE to false
|
||||||
|
is PlaybackState.Connecting -> Player.STATE_BUFFERING to true
|
||||||
|
is PlaybackState.Playing -> Player.STATE_READY to true
|
||||||
|
is PlaybackState.Paused -> Player.STATE_READY to false
|
||||||
|
is PlaybackState.Reconnecting -> Player.STATE_BUFFERING to true
|
||||||
|
}
|
||||||
|
|
||||||
|
val stateChanged = newPlayerState != _playbackState
|
||||||
|
val playWhenReadyChanged = newPlayWhenReady != _playWhenReady
|
||||||
|
_playbackState = newPlayerState
|
||||||
|
_playWhenReady = newPlayWhenReady
|
||||||
|
|
||||||
|
if (stateChanged || playWhenReadyChanged) {
|
||||||
|
listeners.forEach { listener ->
|
||||||
|
if (playWhenReadyChanged) {
|
||||||
|
listener.onPlayWhenReadyChanged(
|
||||||
|
newPlayWhenReady,
|
||||||
|
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (stateChanged) {
|
||||||
|
listener.onPlaybackStateChanged(newPlayerState)
|
||||||
|
}
|
||||||
|
listener.onIsPlayingChanged(isPlaying)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateStation(station: Station) {
|
||||||
|
_currentMediaItem = MediaItem.Builder()
|
||||||
|
.setMediaId("station:${station.id}")
|
||||||
|
.setMediaMetadata(
|
||||||
|
MediaMetadata.Builder()
|
||||||
|
.setTitle(station.name)
|
||||||
|
.setIsPlayable(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
listeners.forEach {
|
||||||
|
it.onMediaItemTransition(
|
||||||
|
_currentMediaItem,
|
||||||
|
Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateMetadata(
|
||||||
|
station: Station,
|
||||||
|
metadata: IcyMetadata?,
|
||||||
|
artworkUri: android.net.Uri? = null
|
||||||
|
) {
|
||||||
|
_mediaMetadata = MediaMetadata.Builder()
|
||||||
|
.setStation(station.name)
|
||||||
|
.setTitle(metadata?.title ?: station.name)
|
||||||
|
.setArtist(metadata?.artist)
|
||||||
|
.setArtworkUri(artworkUri)
|
||||||
|
.setIsPlayable(true)
|
||||||
|
.build()
|
||||||
|
listeners.forEach { it.onMediaMetadataChanged(_mediaMetadata) }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user