From cf79af527312fc04db53f6106a948d271de266c0 Mon Sep 17 00:00:00 2001 From: nk Date: Mon, 1 Jun 2026 12:21:22 +0300 Subject: [PATCH] feat(service): add ExoPlayer controller and MediaSessionService --- .../com/radiola/service/PlayerController.kt | 63 +++++++++++++++++++ .../java/com/radiola/service/PlayerService.kt | 51 +++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 app/src/main/java/com/radiola/service/PlayerController.kt create mode 100644 app/src/main/java/com/radiola/service/PlayerService.kt diff --git a/app/src/main/java/com/radiola/service/PlayerController.kt b/app/src/main/java/com/radiola/service/PlayerController.kt new file mode 100644 index 0000000..fb2f1bc --- /dev/null +++ b/app/src/main/java/com/radiola/service/PlayerController.kt @@ -0,0 +1,63 @@ +package com.radiola.service + +import android.content.Context +import androidx.media3.common.AudioAttributes +import androidx.media3.common.C +import androidx.media3.common.MediaItem +import androidx.media3.common.Player +import androidx.media3.exoplayer.ExoPlayer +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PlayerController @Inject constructor( + @ApplicationContext context: Context +) { + private val _isPlaying = MutableStateFlow(false) + val isPlaying: StateFlow = _isPlaying + + private val _currentStationPrefix = MutableStateFlow(null) + val currentStationPrefix: StateFlow = _currentStationPrefix + + val exoPlayer: ExoPlayer = ExoPlayer.Builder(context) + .setAudioAttributes( + AudioAttributes.Builder() + .setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC) + .build(), + true + ) + .setHandleAudioBecomingNoisy(true) + .build() + .apply { + addListener(object : Player.Listener { + override fun onIsPlayingChanged(playing: Boolean) { + _isPlaying.value = playing + } + }) + } + + fun play(url: String, stationPrefix: String) { + val mediaItem = MediaItem.fromUri(url) + exoPlayer.setMediaItem(mediaItem) + exoPlayer.prepare() + exoPlayer.play() + _currentStationPrefix.value = stationPrefix + } + + fun pause() { + exoPlayer.pause() + } + + fun stop() { + exoPlayer.stop() + _currentStationPrefix.value = null + } + + fun release() { + exoPlayer.release() + } +} diff --git a/app/src/main/java/com/radiola/service/PlayerService.kt b/app/src/main/java/com/radiola/service/PlayerService.kt new file mode 100644 index 0000000..c2ebc65 --- /dev/null +++ b/app/src/main/java/com/radiola/service/PlayerService.kt @@ -0,0 +1,51 @@ +package com.radiola.service + +import android.app.PendingIntent +import android.content.Intent +import androidx.media3.common.util.UnstableApi +import androidx.media3.session.MediaSession +import androidx.media3.session.MediaSessionService +import com.radiola.MainActivity +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +@UnstableApi +class PlayerService : MediaSessionService() { + + @Inject + lateinit var playerController: PlayerController + + private var mediaSession: MediaSession? = null + + override fun onCreate() { + super.onCreate() + mediaSession = MediaSession.Builder(this, playerController.exoPlayer) + .setSessionActivity( + PendingIntent.getActivity( + this, + 0, + Intent(this, MainActivity::class.java), + PendingIntent.FLAG_IMMUTABLE + ) + ) + .build() + } + + override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession + + override fun onTaskRemoved(rootIntent: Intent?) { + if (!playerController.isPlaying.value) { + stopSelf() + } + } + + override fun onDestroy() { + mediaSession?.run { + player.release() + release() + } + mediaSession = null + super.onDestroy() + } +}