Milan Jurkulak před 3 roky
rodič
revize
8c00d69e3b

+ 1 - 0
app/src/main/AndroidManifest.xml

@@ -27,6 +27,7 @@
         android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
         tools:ignore="ScopedStorage" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 
     <uses-permission

+ 21 - 3
tvlib/src/main/AndroidManifest.xml

@@ -5,8 +5,8 @@
   ~  e: mj@mjdev.org
   ~  w: https://mjdev.org
   -->
-<manifest xmlns:tools="http://schemas.android.com/tools"
-    xmlns:android="http://schemas.android.com/apk/res/android">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
 
     <!--    <permission-->
     <!--        android:name="android.permission.QUERY_ALL_PACKAGES"-->
@@ -19,10 +19,28 @@
     </queries>
 
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
+    <uses-permission
+        android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
         tools:ignore="ScopedStorage" />
 
+    <application>
+
+        <service
+            android:name=".service.PlaybackService"
+            android:exported="true"
+            android:foregroundServiceType="mediaPlayback"
+            tools:ignore="ExportedService">
+
+            <intent-filter>
+                <action android:name="androidx.media3.session.MediaSessionService" />
+            </intent-filter>
+
+        </service>
+
+    </application>
+
 </manifest>

+ 48 - 0
tvlib/src/main/kotlin/org/mjdev/tvlib/service/PlaybackService.kt

@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) Milan Jurkulák 2023.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package org.mjdev.tvlib.service
+
+import androidx.media3.common.AudioAttributes
+import androidx.media3.common.C
+import androidx.media3.exoplayer.ExoPlayer
+import androidx.media3.session.MediaSession
+import androidx.media3.session.MediaSessionService
+
+class PlaybackService : MediaSessionService() {
+
+    private var mediaSession: MediaSession? = null
+
+    val player by lazy {
+        ExoPlayer.Builder(applicationContext)
+            .setAudioAttributes(
+                AudioAttributes.Builder()
+                    .setUsage(C.USAGE_MEDIA)
+                    .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE)
+                    .build(), true
+            ).build()
+    }
+
+    override fun onGetSession(
+        controllerInfo: MediaSession.ControllerInfo
+    ): MediaSession? = mediaSession
+
+    override fun onCreate() {
+        super.onCreate()
+        mediaSession = MediaSession.Builder(this, player).build()
+    }
+
+    override fun onDestroy() {
+        mediaSession?.run {
+            player.release()
+            release()
+            mediaSession = null
+        }
+        super.onDestroy()
+    }
+}

+ 29 - 4
tvlib/src/main/kotlin/org/mjdev/tvlib/ui/components/media/ExoPlayerImpl.kt

@@ -37,6 +37,7 @@ import androidx.core.content.getSystemService
 import androidx.lifecycle.Lifecycle.Event.ON_PAUSE
 import androidx.lifecycle.Lifecycle.Event.ON_RESUME
 import androidx.media3.common.AudioAttributes
+import androidx.media3.common.C
 import androidx.media3.common.DeviceInfo
 import androidx.media3.common.MediaItem
 import androidx.media3.common.MediaMetadata
@@ -67,9 +68,19 @@ import org.mjdev.tvlib.ui.components.audiopreview.AudioPreview
 @UnstableApi
 class ExoPlayerImpl(
     override val context: Context,
-    private val exoPlayer: ExoPlayer = ExoPlayer.Builder(context).build()
 ) : IMediaPlayer, PlayerNotificationManager.MediaDescriptionAdapter {
 
+//    private val sessionToken by lazy {
+//        MediaSessionCompat.Token.fromToken(
+//            SessionToken(
+//                context, ComponentName(
+//                    context,
+//                    PlaybackService::class.java
+//                )
+//            )
+//        )
+//    }
+
     private val playerNotificationManager by lazy {
         val notifyChannelName = this::class.java.`package`?.name ?: "MediaPlayer"
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -88,9 +99,23 @@ class ExoPlayerImpl(
             notificationId,
             notifyChannelName,
             this
-        ).apply {
-            // todo details ?
-        }.build()
+        )
+            .setMediaDescriptionAdapter(this@ExoPlayerImpl)
+            .build()
+            .apply {
+//                setMediaSessionToken(sessionToken)
+            }
+    }
+
+    // todo from session
+    private val exoPlayer: ExoPlayer by lazy {
+        ExoPlayer.Builder(context)
+            .setAudioAttributes(
+                AudioAttributes.Builder()
+                    .setUsage(C.USAGE_MEDIA)
+                    .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE)
+                    .build(), true
+            ).build()
     }
 
     override fun getCurrentContentTitle(player: Player): String =