/rxmusicplayer/src/main/java/com/orfium/rx/musicplayer/media/MediaService.kt

https://github.com/Orfium/RxMusicPlayer-android · Kotlin · 171 lines · 143 code · 26 blank · 2 comment · 9 complexity · 9016bf198577807315dbfb040b40ef58 MD5 · raw file

  1. package com.orfium.rx.musicplayer.media
  2. import android.app.Service
  3. import android.content.ComponentName
  4. import android.content.Intent
  5. import android.os.IBinder
  6. import android.os.SystemClock
  7. import android.support.v4.media.MediaMetadataCompat
  8. import android.support.v4.media.session.MediaSessionCompat
  9. import android.support.v4.media.session.PlaybackStateCompat
  10. import androidx.media.session.MediaButtonReceiver
  11. import com.orfium.rx.musicplayer.RxMusicPlayer
  12. import com.orfium.rx.musicplayer.common.Action
  13. import com.orfium.rx.musicplayer.common.PlaybackState
  14. import com.orfium.rx.musicplayer.factory.Factory
  15. import com.orfium.rx.musicplayer.notification.NotificationManager
  16. import com.orfium.rx.musicplayer.playback.Playback
  17. internal class MediaService: Service(), Playback.ServiceCallback {
  18. companion object {
  19. const val ACTION_PAUSE = "com.orfium.rx.musicplayer.pause"
  20. const val ACTION_PLAY = "com.orfium.rx.musicplayer.start"
  21. const val ACTION_PREV = "com.orfium.rx.musicplayer.previous"
  22. const val ACTION_NEXT = "com.orfium.rx.musicplayer.next"
  23. const val ACTION_STOP = "com.orfium.rx.musicplayer.stop"
  24. const val EXTRA_INTENT = "com.orfium.rx.musicplayer.intent"
  25. }
  26. private lateinit var mediaSession: MediaSessionCompat
  27. private lateinit var notificationManager: NotificationManager
  28. private lateinit var mediaManager: MediaManager
  29. override fun onBind(intent: Intent?): IBinder? {
  30. return null
  31. }
  32. override fun onCreate() {
  33. super.onCreate()
  34. val receiverComponentName = ComponentName(packageName, javaClass.name)
  35. mediaSession = MediaSessionCompat(applicationContext, javaClass.name, receiverComponentName, null).apply {
  36. setCallback(MediaSessionCallback())
  37. setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
  38. }
  39. notificationManager = Factory.createMediaNotification(this, mediaSession.sessionToken)
  40. mediaManager = Factory.createMediaManager(this).apply {
  41. subscribeQueue()
  42. }
  43. }
  44. override fun onStartCommand(startIntent: Intent?, flags: Int, startId: Int): Int {
  45. if (startIntent != null) {
  46. val extras = startIntent.extras
  47. val action = startIntent.action
  48. when {
  49. extras != null -> notificationManager.setIntent(extras.getParcelable(EXTRA_INTENT))
  50. action != null -> executeTask(action)
  51. }
  52. MediaButtonReceiver.handleIntent(mediaSession, startIntent)
  53. }
  54. return START_NOT_STICKY
  55. }
  56. override fun onDestroy() {
  57. mediaSession.release()
  58. mediaManager.unSubscribeQueue()
  59. stopForeground(true)
  60. super.onDestroy()
  61. }
  62. override fun onPlaybackStateChanged(state: PlaybackState, position: Long) {
  63. setSessionState(state, position)
  64. notificationManager.updateState(state)
  65. }
  66. override fun onPlaybackMediaChanged(media: Media?) {
  67. mediaSession.setMetadata(getMetadata(media))
  68. notificationManager.updateMedia(media)
  69. }
  70. private fun setSessionState(state: PlaybackState, position: Long) {
  71. val stateCompat = PlaybackStateCompat.Builder()
  72. .setActions(getActions(state))
  73. .setState(
  74. when (state) {
  75. is PlaybackState.Playing -> PlaybackStateCompat.STATE_PLAYING
  76. is PlaybackState.Buffering -> PlaybackStateCompat.STATE_BUFFERING
  77. is PlaybackState.Paused -> PlaybackStateCompat.STATE_PAUSED
  78. is PlaybackState.Completed -> PlaybackStateCompat.STATE_PAUSED
  79. is PlaybackState.Stopped -> PlaybackStateCompat.STATE_STOPPED
  80. else -> PlaybackStateCompat.STATE_NONE
  81. }, position, 1.0f, SystemClock.elapsedRealtime()
  82. )
  83. .build()
  84. mediaSession.isActive = state is PlaybackState.Playing || state is PlaybackState.Buffering
  85. mediaSession.setPlaybackState(stateCompat)
  86. }
  87. private fun getActions(state: PlaybackState): Long {
  88. var actions = PlaybackStateCompat.ACTION_PLAY_PAUSE or
  89. PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
  90. PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
  91. PlaybackStateCompat.ACTION_SET_REPEAT_MODE or
  92. PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
  93. if (state is PlaybackState.Playing || state is PlaybackState.Buffering) {
  94. actions = actions or PlaybackStateCompat.ACTION_PAUSE
  95. } else {
  96. actions = actions or PlaybackStateCompat.ACTION_PLAY
  97. }
  98. return actions
  99. }
  100. private fun getMetadata(media: Media?): MediaMetadataCompat {
  101. return MediaMetadataCompat.Builder()
  102. .putString(MediaMetadataCompat.METADATA_KEY_ART_URI, media?.image)
  103. .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, media?.title)
  104. .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, media?.artist)
  105. .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, media?.streamUrl)
  106. .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, media?.id?.toString())
  107. .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, media?.duration?.toLong() ?: 0)
  108. .build()
  109. }
  110. private fun executeTask(action: String) {
  111. when (action) {
  112. ACTION_PLAY -> RxMusicPlayer.action.onNext(Action.resume())
  113. ACTION_PREV -> RxMusicPlayer.action.onNext(Action.previous())
  114. ACTION_NEXT -> RxMusicPlayer.action.onNext(Action.next())
  115. ACTION_PAUSE -> RxMusicPlayer.action.onNext(Action.pause())
  116. ACTION_STOP -> RxMusicPlayer.action.onNext(Action.stop())
  117. }
  118. }
  119. private inner class MediaSessionCallback : MediaSessionCompat.Callback() {
  120. override fun onPlay() {
  121. RxMusicPlayer.action.onNext(Action.resume())
  122. }
  123. override fun onSkipToNext() {
  124. RxMusicPlayer.action.onNext(Action.next())
  125. }
  126. override fun onSkipToPrevious() {
  127. RxMusicPlayer.action.onNext(Action.previous())
  128. }
  129. override fun onPause() {
  130. RxMusicPlayer.action.onNext(Action.pause())
  131. }
  132. override fun onSetRepeatMode(repeatMode: Int) {
  133. // TODO
  134. }
  135. override fun onSetShuffleMode(@PlaybackStateCompat.ShuffleMode shuffleMode: Int) {
  136. // TODO
  137. }
  138. override fun onStop() {
  139. RxMusicPlayer.action.onNext(Action.stop())
  140. }
  141. override fun onSeekTo(pos: Long) {
  142. RxMusicPlayer.action.onNext(Action.seek(pos))
  143. }
  144. }
  145. }