-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMediaMetadataState.kt
More file actions
325 lines (281 loc) · 12.6 KB
/
Copy pathMediaMetadataState.kt
File metadata and controls
325 lines (281 loc) · 12.6 KB
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
package io.oliverapps.radio.player.state
import android.net.Uri
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.*
import androidx.media3.common.Player
import androidx.media3.common.Rating
import androidx.media3.common.listen
import androidx.media3.common.util.UnstableApi
import com.google.common.collect.ImmutableList
//use the new androidx.media3.ui.compose.state.rememberCurrentMediaItemState instead
//see https://github.com/at-oliverapps/media3-compose-utils/blob/main/Media3ComposeSample/mobile/src/main/java/io/oliverapps/sample/media3/compose/MIniPlayer.kt for usecases
/*
@UnstableApi
@Composable
fun rememberMediaMetadata(player: Player): MediaMetadataState {
// Remember a new MetadataState instance whenever the player instance changes.
val metadataState = remember(player) { MediaMetadataState(player) }
// Launch a coroutine to observe media metadata changes whenever the player instance changes.
LaunchedEffect(player) {
metadataState.observe()
}
return metadataState
}
@UnstableApi
class MediaMetadataState(private val player: Player) {
// --- Individual MediaMetadata Fields ---
/** Optional title. */
var title: CharSequence? by mutableStateOf(null)
private set
/** Optional artist. */
var artist: CharSequence? by mutableStateOf(null)
private set
/** Optional album title. */
var albumTitle: CharSequence? by mutableStateOf(null)
private set
/** Optional album artist. */
var albumArtist: CharSequence? by mutableStateOf(null)
private set
/** Optional display title. */
var displayTitle: CharSequence? by mutableStateOf(null)
private set
/**
* Optional subtitle.
*
* This is the secondary title of the media, unrelated to closed captions.
*/
var subtitle: CharSequence? by mutableStateOf(null)
private set
/** Optional description. */
var description: CharSequence? by mutableStateOf(null)
private set
/**
* Optional duration, non-negative and in milliseconds.
*
* This field is populated by the app when building the metadata object and is for
* informational purpose only. For retrieving the duration of the media item currently being
* played, use [Player.getDuration] instead.
*/
var durationMs: Long? by mutableStateOf(null)
private set
/** Optional user [Rating]. */
var userRating: Rating? by mutableStateOf(null)
private set
/** Optional overall [Rating]. */
var overallRating: Rating? by mutableStateOf(null)
private set
/** Optional artwork data as a compressed byte array. */
var artworkData: ByteArray? by mutableStateOf(null)
private set
/** Optional [PictureType] of the artwork data. */
var artworkDataType: Int? by mutableStateOf(null) // Integer in Java becomes Int in Kotlin
private set
/** Optional artwork [Uri]. */
var artworkUri: Uri? by mutableStateOf(null)
private set
/** Optional track number. */
var trackNumber: Int? by mutableStateOf(null)
private set
/** Optional total number of tracks. */
var totalTrackCount: Int? by mutableStateOf(null)
/**
* Optional [FolderType].
*
* @deprecated Use [isBrowsable] to indicate if an item is a browsable folder and use
* [mediaType] to indicate the type of the folder.
*/
@Deprecated(
"Use isBrowsable to indicate if an item is a browsable folder and use mediaType to indicate the type of the folder."
)
@Suppress("deprecation") // Defining field of deprecated type.
var folderType: Int? by mutableStateOf(null)
private set
/** Optional boolean to indicate that the media is a browsable folder. */
var isBrowsable: Boolean? by mutableStateOf(null)
private set
/** Optional boolean to indicate that the media is playable. */
var isPlayable: Boolean? by mutableStateOf(null)
private set
/**
* @deprecated Use [recordingYear] instead.
*/
@Deprecated("Use recordingYear instead.")
var year: Int? by mutableStateOf(null)
private set
/** Optional year of the recording date. */
var recordingYear: Int? by mutableStateOf(null)
private set
/**
* Optional month of the recording date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
var recordingMonth: Int? by mutableStateOf(null)
private set
/**
* Optional day of the recording date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
var recordingDay: Int? by mutableStateOf(null)
private set
/** Optional year of the release date. */
var releaseYear: Int? by mutableStateOf(null)
private set
/**
* Optional month of the release date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
var releaseMonth: Int? by mutableStateOf(null)
private set
/**
* Optional day of the release date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
var releaseDay: Int? by mutableStateOf(null)
private set
/** Optional writer. */
var writer: CharSequence? by mutableStateOf(null)
private set
/** Optional composer. */
var composer: CharSequence? by mutableStateOf(null)
private set
/** Optional conductor. */
var conductor: CharSequence? by mutableStateOf(null)
private set
/** Optional disc number. */
var discNumber: Int? by mutableStateOf(null)
private set
/** Optional total number of discs. */
var totalDiscCount: Int? by mutableStateOf(null)
private set
/** Optional genre. */
var genre: CharSequence? by mutableStateOf(null)
private set
/** Optional compilation. */
var compilation: CharSequence? by mutableStateOf(null)
private set
/** Optional name of the station streaming the media. */
var station: CharSequence? by mutableStateOf(null)
private set
/** Optional [MediaType]. */
var mediaType: Int? by mutableStateOf(null)
private set
/**
* Optional extras [Bundle].
*
* Given the complexities of checking the equality of two [Bundle] instances, the
* contents of these extras are not considered in the [equals] and [hashCode] implementation.
*/
var extras: Bundle? by mutableStateOf(null)
private set
/**
* The IDs of the supported commands of this media item (see for instance `CommandButton.sessionCommand.customAction`
* of the Media3 session module).
*/
var supportedCommands: ImmutableList<String> by mutableStateOf(ImmutableList.of())
private set
/**
* Subscribes to updates from [Player.Events] and listens to
* [Player.EVENT_MEDIA_METADATA_CHANGED] in order to update the [metadata] state.
* This function should be called within a CoroutineScope, typically from a [LaunchedEffect].
*/
suspend fun observe(): Nothing {
// Immediately update the state with the current media metadata when observation starts.
// This handles cases where media metadata might be available before the first event.
title = player.mediaMetadata.title
artist = player.mediaMetadata.artist
albumTitle = player.mediaMetadata.albumTitle
albumArtist = player.mediaMetadata.albumArtist
displayTitle = player.mediaMetadata.displayTitle
subtitle = player.mediaMetadata.subtitle
description = player.mediaMetadata.description
durationMs = player.mediaMetadata.durationMs
userRating = player.mediaMetadata.userRating
overallRating = player.mediaMetadata.overallRating
artworkData = player.mediaMetadata.artworkData
artworkDataType = player.mediaMetadata.artworkDataType
artworkUri = player.mediaMetadata.artworkUri
trackNumber = player.mediaMetadata.trackNumber
totalTrackCount = player.mediaMetadata.totalTrackCount
@Suppress("deprecation") // Assigning deprecated field
folderType = player.mediaMetadata.folderType
isBrowsable = player.mediaMetadata.isBrowsable
isPlayable = player.mediaMetadata.isPlayable
@Suppress("deprecation") // Assigning deprecated field
year = player.mediaMetadata.year
recordingYear = player.mediaMetadata.recordingYear
recordingMonth = player.mediaMetadata.recordingMonth
recordingDay = player.mediaMetadata.recordingDay
releaseYear = player.mediaMetadata.releaseYear
releaseMonth = player.mediaMetadata.releaseMonth
releaseDay = player.mediaMetadata.releaseDay
writer = player.mediaMetadata.writer
composer = player.mediaMetadata.composer
conductor = player.mediaMetadata.conductor
discNumber = player.mediaMetadata.discNumber
totalDiscCount = player.mediaMetadata.totalDiscCount
genre = player.mediaMetadata.genre
compilation = player.mediaMetadata.compilation
station = player.mediaMetadata.station
mediaType = player.mediaMetadata.mediaType
extras = player.mediaMetadata.extras
supportedCommands = player.mediaMetadata.supportedCommands
// Listen for player events. The 'listen' function is assumed to be provided by your Player API.
// It takes a lambda that receives the set of events that occurred.
player.listen { events ->
// Check if the media metadata changed event is present in the received events.
if (events.contains(Player.EVENT_MEDIA_METADATA_CHANGED)) { // Changed to EVENT_MEDIA_METADATA_CHANGED
// If media metadata changed, update the 'metadata' state with the player's new media metadata.
title = player.mediaMetadata.title
artist = player.mediaMetadata.artist
albumTitle = player.mediaMetadata.albumTitle
albumArtist = player.mediaMetadata.albumArtist
displayTitle = player.mediaMetadata.displayTitle
subtitle = player.mediaMetadata.subtitle
description = player.mediaMetadata.description
durationMs = player.mediaMetadata.durationMs
userRating = player.mediaMetadata.userRating
overallRating = player.mediaMetadata.overallRating
artworkData = player.mediaMetadata.artworkData
artworkDataType = player.mediaMetadata.artworkDataType
artworkUri = player.mediaMetadata.artworkUri
trackNumber = player.mediaMetadata.trackNumber
totalTrackCount = player.mediaMetadata.totalTrackCount
@Suppress("deprecation") // Assigning deprecated field
folderType = player.mediaMetadata.folderType
isBrowsable = player.mediaMetadata.isBrowsable
isPlayable = player.mediaMetadata.isPlayable
@Suppress("deprecation") // Assigning deprecated field
year = player.mediaMetadata.year
recordingYear = player.mediaMetadata.recordingYear
recordingMonth = player.mediaMetadata.recordingMonth
recordingDay = player.mediaMetadata.recordingDay
releaseYear = player.mediaMetadata.releaseYear
releaseMonth = player.mediaMetadata.releaseMonth
releaseDay = player.mediaMetadata.releaseDay
writer = player.mediaMetadata.writer
composer = player.mediaMetadata.composer
conductor = player.mediaMetadata.conductor
discNumber = player.mediaMetadata.discNumber
totalDiscCount = player.mediaMetadata.totalDiscCount
genre = player.mediaMetadata.genre
compilation = player.mediaMetadata.compilation
station = player.mediaMetadata.station
mediaType = player.mediaMetadata.mediaType
extras = player.mediaMetadata.extras
supportedCommands = player.mediaMetadata.supportedCommands
}
}
// The 'observe' function is designed to run indefinitely, similar to a stream listener.
// It will keep the coroutine active as long as the player is being observed.
// If the player.listen function doesn't complete (e.g., it's a suspending listen),
// then Nothing means this function will not return normally.
}
}
*/