-
Notifications
You must be signed in to change notification settings - Fork 1
/
PillarboxMediaSessionService.kt
122 lines (113 loc) · 3.89 KB
/
PillarboxMediaSessionService.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.player.service
import android.app.PendingIntent
import android.content.Intent
import androidx.media3.common.C
import androidx.media3.common.Player
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
import ch.srgssr.pillarbox.player.PillarboxPlayer
import ch.srgssr.pillarbox.player.utils.PendingIntentUtils
/**
* `PillarboxMediaSessionService` implementation of [MediaSessionService].
* It is the recommended way to make background playback for Android.
*
* It handles only one [MediaSession] with one [PillarboxPlayer].
*
* Usage:
* Add these permissions inside your manifest:
*
* ```xml
* <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
* <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
* ```
*
* And add your `PlaybackService` to the application manifest as follow:
*
* ```xml
* <service
* android:name=".service.DemoMediaSessionService"
* android:exported="true"
* android:foregroundServiceType="mediaPlayback">
* <intent-filter>
* <action android:name="androidx.media3.session.MediaSessionService" />
* </intent-filter>
* </service>
* ```
*
* Use [MediaControllerConnection] to connect this Service to a `MediaController`.
* ```kotlin
* val connection = MediaControllerConnection(context, ComponentName(application, DemoMediaSessionService::class.java))
* connection.mediaController.collectLatest { useController(it) }
* ...
* connection.release() // when controller no more needed.
* ```
*/
@Suppress("MemberVisibilityCanBePrivate")
abstract class PillarboxMediaSessionService : MediaSessionService() {
private var player: Player? = null
private var mediaSession: MediaSession? = null
/**
* Release on task removed
*/
var releaseOnTaskRemoved = true
/**
* Set player to use with this Service.
* @param player PillarboxPlayer to link to this service.
* @param mediaSessionCallback The MediaSession.Callback to use [MediaSession.Builder.setCallback].
*/
fun setPlayer(
player: PillarboxPlayer,
mediaSessionCallback: MediaSession.Callback = object : DefaultMediaSessionCallback {}
) {
if (this.player == null) {
this.player = player
player.setWakeMode(C.WAKE_MODE_NETWORK)
player.setHandleAudioFocus(true)
val builder = MediaSession.Builder(this, player)
.setCallback(mediaSessionCallback)
.setId(packageName)
sessionActivity()?.let {
builder.setSessionActivity(it)
}
mediaSession = builder.build()
}
}
/**
* Session activity use with [mediaSession] called when [setPlayer]
*/
open fun sessionActivity(): PendingIntent? = PendingIntentUtils.getDefaultPendingIntent(this)
override fun onDestroy() {
release()
super.onDestroy()
}
/**
* Release the player and the MediaSession.
* The [mediaSession] is set to null after this call
*
* called automatically in [onDestroy] and [onTaskRemoved] is [releaseOnTaskRemoved] = true
*/
open fun release() {
mediaSession?.run {
player.release()
release()
mediaSession = null
}
}
// Return a MediaSession to link with the MediaController that is making
// this request.
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession
/**
* We choose to stop playback when user remove application from the tasks
*/
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
if (releaseOnTaskRemoved) {
release()
stopSelf()
}
}
}