Skip to content
This repository has been archived by the owner on Aug 27, 2024. It is now read-only.

Commit

Permalink
Added a Cancel button to notification & re-enabled buffering indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
y20k committed Feb 20, 2021
1 parent 7ea3917 commit 375515e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class NotificationHelper(private val context: Context, sessionToken: MediaSessio
setSmallIcon(R.drawable.ic_notification_app_icon_white_24dp)
setUsePlayPauseActions(true)
setControlDispatcher(DefaultControlDispatcher(0L, 0L)) // hide fastforward and reweind
setUseStopAction(false) // set true to display the dismiss button
setUseStopAction(true) // set true to display the dismiss button
setUsePreviousAction(false)
setUsePreviousActionInCompactView(false)
setUseNextAction(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ object PreferencesHelper {


/* Loads uuid of last played station from shared preferences */
fun loadLastPlayedStation(context: Context): String {
fun loadLastPlayedStationUuid(context: Context): String {
val settings = PreferenceManager.getDefaultSharedPreferences(context)
return settings.getString(Keys.PREF_PLAYER_STATE_STATION_UUID, String()) ?: String()
}
Expand Down
122 changes: 64 additions & 58 deletions app/src/main/java/org/y20k/transistor/playback/PlayerService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import kotlin.math.min
/*
* PlayerService class
*/
class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
class PlayerService(): MediaBrowserServiceCompat() {


/* Define log tag */
Expand All @@ -78,13 +78,12 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
private var collectionProvider: CollectionProvider = CollectionProvider()
private var station: Station = Station()
private var isForegroundService: Boolean = false
private lateinit var player: SimpleExoPlayer
private lateinit var playerState: PlayerState
private lateinit var metadataHistory: MutableList<String>
private lateinit var backgroundJob: Job
private lateinit var packageValidator: PackageValidator
private lateinit var mediaSession: MediaSessionCompat
private lateinit var mediaSessionConnector: MediaSessionConnector
protected lateinit var mediaSession: MediaSessionCompat
protected lateinit var mediaSessionConnector: MediaSessionConnector
private lateinit var notificationHelper: NotificationHelper
private lateinit var userAgent: String
private lateinit var modificationDate: Date
Expand All @@ -93,6 +92,21 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
private var sleepTimerTimeRemaining: Long = 0L
private var playbackRestartCounter: Int = 0

private val attributes = AudioAttributes.Builder()
.setContentType(C.CONTENT_TYPE_MUSIC)
.setUsage(C.USAGE_MEDIA)
.build()

private val player: SimpleExoPlayer by lazy {
SimpleExoPlayer.Builder(this).build().apply {
setAudioAttributes(attributes, true)
setHandleAudioBecomingNoisy(true)
addListener(playerListener)
addMetadataOutput(metadataOutput)
addAnalyticsListener(analyticsListener)
}
}


/* Overrides onCreate from Service */
override fun onCreate() {
Expand All @@ -116,9 +130,6 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
// fetch the metadata history
metadataHistory = PreferencesHelper.loadMetadataHistory(this)

// create player
createPlayer()

// create a new MediaSession
createMediaSession()

Expand All @@ -133,12 +144,10 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
return CollectionHelper.buildStationMediaDescription(this@PlayerService, station)
}
override fun onSkipToPrevious(player: Player, controlDispatcher: ControlDispatcher) {
if (player.isPlaying) { player.pause() }
station = CollectionHelper.getPreviousStation(collection, station.uuid)
preparePlayer(true)
}
override fun onSkipToNext(player: Player, controlDispatcher: ControlDispatcher) {
if (player.isPlaying) { player.pause() }
station = CollectionHelper.getNextStation(collection, station.uuid)
preparePlayer(true)
}
Expand Down Expand Up @@ -205,32 +214,12 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
backgroundJob.cancel()
// release player
player.removeAnalyticsListener(analyticsListener)
player.removeMetadataOutput(this)
player.removeListener(playerListener)
player.removeMetadataOutput(metadataOutput)
player.release()
}


/* Overrides onMetadata from MetadataOutput */
override fun onMetadata(metadata: Metadata) {
for (i in 0 until metadata.length()) {
val entry = metadata[i]
// extract IceCast metadata
if (entry is IcyInfo) {
val icyInfo: IcyInfo = entry as IcyInfo
updateMetadata(icyInfo.title)
} else if (entry is IcyHeaders) {
val icyHeaders = entry as IcyHeaders
LogHelper.i(TAG, "icyHeaders:" + icyHeaders.name + " - " + icyHeaders.genre)
} else {
LogHelper.w(TAG, "Unsupported metadata received (type = ${entry.javaClass.simpleName})")
updateMetadata(null)
}
// TODO implement HLS metadata extraction (Id3Frame / PrivFrame)
// https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html
}
}


/* Updates metadata */
private fun updateMetadata(metadata: String?) {
// get metadata string
Expand Down Expand Up @@ -346,26 +335,6 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
}


/* Creates a simple exo player */
private fun createPlayer() {
if (!this::player.isInitialized) {
val audioAttributes: AudioAttributes = AudioAttributes.Builder()
.setContentType(C.CONTENT_TYPE_MUSIC)
.setUsage(C.USAGE_MEDIA)
.build()
player = SimpleExoPlayer.Builder(this)
.setWakeMode(C.WAKE_MODE_NETWORK)
.setAudioAttributes(audioAttributes, true)
.setHandleAudioBecomingNoisy(true)
// player.setMediaSourceFactory() does not make sense here, since Transistor selects MediaSourceFactory based on stream type
.build()
player.addListener(playerListener)
player.addMetadataOutput(this)
player.addAnalyticsListener(analyticsListener)
}
}


/* Prepares player with media source created from current station */
private fun preparePlayer(playWhenReady: Boolean) {
// sanity check
Expand All @@ -374,6 +343,9 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
return
}

// stop playback if necessary
if (player.isPlaying) { player.pause() }

// build media item.
val mediaItem: MediaItem = MediaItem.fromUri(station.getStreamUri())

Expand Down Expand Up @@ -569,8 +541,8 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
if (!playWhenReady) {
when (reason) {
Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM -> {
// playback reached end: stop / end playback
handlePlaybackChange(PlaybackStateCompat.STATE_STOPPED)
// playback reached end: try to resume
handlePlaybackEnded()
}
else -> {
// playback has been paused by user or OS: update media session and save state
Expand All @@ -581,6 +553,8 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
handlePlaybackChange(PlaybackStateCompat.STATE_STOPPED)
}
}
} else if (playWhenReady && player.playbackState == Player.STATE_BUFFERING) {
handlePlaybackChange(PlaybackStateCompat.STATE_BUFFERING)
}
}
}
Expand Down Expand Up @@ -615,6 +589,34 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
*/


/*
* MetadataOutput: handles metadata associated with current playback time
*/
private val metadataOutput = object : MetadataOutput {
override fun onMetadata(metadata: Metadata) {
for (i in 0 until metadata.length()) {
val entry = metadata[i]
// extract IceCast metadata
if (entry is IcyInfo) {
val icyInfo: IcyInfo = entry as IcyInfo
updateMetadata(icyInfo.title)
} else if (entry is IcyHeaders) {
val icyHeaders = entry as IcyHeaders
LogHelper.i(TAG, "icyHeaders:" + icyHeaders.name + " - " + icyHeaders.genre)
} else {
LogHelper.w(TAG, "Unsupported metadata received (type = ${entry.javaClass.simpleName})")
updateMetadata(null)
}
// TODO implement HLS metadata extraction (Id3Frame / PrivFrame)
// https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html
}
}
}
/*
* End of declaration
*/


// /*
// * MediaMetadataProvider: creates metadata for currently playing station
// */
Expand All @@ -639,12 +641,18 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH or
PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH

override fun onPrepare(playWhenReady: Boolean) = Unit
override fun onPrepareFromUri(uri: Uri, playWhenReady: Boolean, extras: Bundle?) = Unit

override fun onPrepare(playWhenReady: Boolean) {
if (station.isValid()) {
preparePlayer(playWhenReady)
} else {
val currentStationUuid: String = PreferencesHelper.loadLastPlayedStationUuid(this@PlayerService)
onPrepareFromMediaId(currentStationUuid, playWhenReady, null)
}
}

override fun onPrepareFromMediaId(mediaId: String, playWhenReady: Boolean, extras: Bundle?) {
// stop playback if necessary
if (player.isPlaying) { player.pause() }
// get station and start playback
station = CollectionHelper.getStation(collection, mediaId ?: String())
preparePlayer(playWhenReady)
Expand Down Expand Up @@ -726,8 +734,6 @@ class PlayerService(): MediaBrowserServiceCompat(), MetadataOutput {
return true
}
Keys.CMD_PLAY_STREAM -> {
// stop playback if necessary
if (player.isPlaying) { player.pause() }
// get station and start playback
val streamUri: String = extras?.getString(Keys.KEY_STREAM_URI) ?: String()
station = CollectionHelper.getStationWithStreamUri(collection, streamUri)
Expand Down

0 comments on commit 375515e

Please sign in to comment.