-
Notifications
You must be signed in to change notification settings - Fork 1
/
PillarboxMediaLibrarySession.kt
229 lines (211 loc) · 9.44 KB
/
PillarboxMediaLibrarySession.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.player.session
import android.app.PendingIntent
import androidx.annotation.IntRange
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.session.LibraryResult
import androidx.media3.session.MediaLibraryService
import androidx.media3.session.MediaLibraryService.MediaLibrarySession
import androidx.media3.session.MediaSession
import androidx.media3.session.SessionError
import ch.srgssr.pillarbox.player.PillarboxPlayer
import ch.srgssr.pillarbox.player.utils.PendingIntentUtils
import com.google.common.collect.ImmutableList
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
/**
* An extended [PillarboxMediaSession] for the [PillarboxMediaLibraryService].
* Build an instance with [Builder] and return it from [PillarboxMediaLibraryService.onGetSession] with [PillarboxMediaLibrarySession.mediaSession].
*
* @see MediaLibrarySession
* @see PillarboxMediaLibraryService
* @see PillarboxMediaBrowser
*/
open class PillarboxMediaLibrarySession internal constructor() : PillarboxMediaSession() {
/**
* An extended [PillarboxMediaSession.Callback] for the [PillarboxMediaLibrarySession].
*
* When you return [LibraryResult] with [MediaItem] media items, each item must
* have valid [mediaId][MediaItem.mediaId] and specify [isBrowsable][MediaMetadata.isBrowsable] and [isPlayable][MediaMetadata.isPlayable] in its
* [mediaMetadata][MediaItem.mediaMetadata].
* @see MediaLibrarySession.Callback
*/
interface Callback : PillarboxMediaSession.Callback {
/**
* Called when a [PillarboxMediaBrowser] requests the root [MediaItem].
* @see MediaLibrarySession.Callback.onGetLibraryRoot
*/
fun onGetLibraryRoot(
session: PillarboxMediaLibrarySession,
browser: MediaSession.ControllerInfo,
params: MediaLibraryService.LibraryParams?,
): ListenableFuture<LibraryResult<MediaItem>> {
return Futures.immediateFuture(LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED))
}
/**
* Called when a [PillarboxMediaBrowser] requests the child media items of the given parent id.
* @see MediaLibrarySession.Callback.onGetChildren
*/
fun onGetChildren(
session: PillarboxMediaLibrarySession,
browser: MediaSession.ControllerInfo,
parentId: String,
@IntRange(from = 0) page: Int,
@IntRange(from = 1) pageSize: Int,
params: MediaLibraryService.LibraryParams?,
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return Futures.immediateFuture(LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED))
}
/**
* Called when a [PillarboxMediaBrowser] requests a [MediaItem] from [mediaId].
* @see MediaLibrarySession.Callback.onGetItem
*/
fun onGetItem(
session: PillarboxMediaLibrarySession,
browser: MediaSession.ControllerInfo,
mediaId: String
): ListenableFuture<LibraryResult<MediaItem>> {
return Futures.immediateFuture(LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED))
}
/**
* Called when a [MediaBrowser][androidx.media3.session.MediaBrowser] requests a search.
* @see MediaLibrarySession.Callback.onSearch
*/
fun onSearch(
session: PillarboxMediaLibrarySession,
browser: MediaSession.ControllerInfo,
query: String,
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<Void>> {
return Futures.immediateFuture(LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED))
}
/**
* Called when a [PillarboxMediaBrowser] requests the child media items of the given parent id.
* @see MediaLibrarySession.Callback.onGetSearchResult
*/
fun onGetSearchResult(
session: PillarboxMediaLibrarySession,
browser: MediaSession.ControllerInfo,
query: String,
page: Int,
pageSize: Int,
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return Futures.immediateFuture(LibraryResult.ofError(SessionError.ERROR_NOT_SUPPORTED))
}
}
/**
* A builder for [PillarboxMediaLibrarySession].
*
* Any incoming requests from the [PillarboxMediaBrowser] will be handled on the application
* thread of the underlying [PillarboxPlayer].
*
* @param service The [MediaLibraryService] that instantiates the [PillarboxMediaLibrarySession].
* @param player The underlying player to perform playback and handle transport controls.
* @param callback The [Callback] to handle requests from [PillarboxMediaBrowser].
*/
class Builder(
private val service: MediaLibraryService,
private val player: PillarboxPlayer,
private val callback: Callback,
) {
private var pendingIntent: PendingIntent? = PendingIntentUtils.getDefaultPendingIntent(service)
private var id: String? = null
/**
* Set session activity
* @param pendingIntent The [PendingIntent].
* @return the builder for convenience.
* @see MediaLibrarySession.Builder.setSessionActivity
*/
fun setSessionActivity(pendingIntent: PendingIntent): Builder {
this.pendingIntent = pendingIntent
return this
}
/**
* Set id
* @param id The ID. Must be unique among all sessions per package.
* @return the builder for convenience.
* @see MediaLibrarySession.Builder.setId
*/
fun setId(id: String): Builder {
this.id = id
return this
}
/**
* Build
*
* @return a new [PillarboxMediaLibrarySession]
*/
fun build(): PillarboxMediaLibrarySession {
val pillarboxMediaSession = PillarboxMediaLibrarySession()
val media3Callback = MediaLibraryCallbackImpl(callback, pillarboxMediaSession)
val mediaSessionBuilder = MediaLibrarySession.Builder(service, player, media3Callback)
val mediaSession = mediaSessionBuilder.apply {
id?.let { setId(it) }
pendingIntent?.let { setSessionActivity(it) }
}.build()
pillarboxMediaSession.setMediaSession(mediaSession)
return pillarboxMediaSession
}
}
override val mediaSession: MediaLibrarySession
get() = super.mediaSession as MediaLibrarySession
internal class MediaLibraryCallbackImpl(
callback: Callback,
mediaSession: PillarboxMediaLibrarySession
) : MediaSessionCallbackImpl(callback, mediaSession), MediaLibrarySession.Callback {
override fun onGetLibraryRoot(
session: MediaLibrarySession,
browser: MediaSession.ControllerInfo,
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<MediaItem>> {
return (callback as Callback).onGetLibraryRoot(this.mediaSession as PillarboxMediaLibrarySession, browser, params)
}
override fun onGetChildren(
session: MediaLibrarySession,
browser: MediaSession.ControllerInfo,
parentId: String,
page: Int,
pageSize: Int,
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return (callback as Callback).onGetChildren(this.mediaSession as PillarboxMediaLibrarySession, browser, parentId, page, pageSize, params)
}
override fun onGetItem(
session: MediaLibrarySession,
browser: MediaSession.ControllerInfo,
mediaId: String
): ListenableFuture<LibraryResult<MediaItem>> {
return (callback as Callback).onGetItem(this.mediaSession as PillarboxMediaLibrarySession, browser, mediaId)
}
override fun onSearch(
session: MediaLibrarySession,
browser: MediaSession.ControllerInfo,
query: String,
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<Void>> {
return (callback as Callback).onSearch(this.mediaSession as PillarboxMediaLibrarySession, browser, query, params)
}
override fun onGetSearchResult(
session: MediaLibrarySession,
browser: MediaSession.ControllerInfo,
query: String,
page: Int,
pageSize: Int,
params: MediaLibraryService.LibraryParams?
): ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> {
return (callback as Callback).onGetSearchResult(this.mediaSession as PillarboxMediaLibrarySession, browser, query, page, pageSize, params)
}
override fun onAddMediaItems(
mediaSession: MediaSession,
controller: MediaSession.ControllerInfo,
mediaItems: MutableList<MediaItem>
): ListenableFuture<MutableList<MediaItem>> {
return (callback as Callback).onAddMediaItems(this.mediaSession as PillarboxMediaLibrarySession, controller, mediaItems)
}
}
}