Upgrade to media3-beta01
This commit is contained in:
parent
5deb7d4d58
commit
9961213f09
|
@ -10,7 +10,7 @@ ktlintGradle = "10.2.0"
|
||||||
detekt = "1.19.0"
|
detekt = "1.19.0"
|
||||||
preferences = "1.1.1"
|
preferences = "1.1.1"
|
||||||
media = "1.3.1"
|
media = "1.3.1"
|
||||||
media3 = "1.0.0-alpha03"
|
media3 = "1.0.0-beta01"
|
||||||
|
|
||||||
androidSupport = "28.0.0"
|
androidSupport = "28.0.0"
|
||||||
androidLegacySupport = "1.0.0"
|
androidLegacySupport = "1.0.0"
|
||||||
|
@ -101,4 +101,3 @@ kluentAndroid = { module = "org.amshove.kluent:kluent-android", versio
|
||||||
mockWebServer = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
|
mockWebServer = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
|
||||||
apacheCodecs = { module = "commons-codec:commons-codec", version.ref = "apacheCodecs" }
|
apacheCodecs = { module = "commons-codec:commons-codec", version.ref = "apacheCodecs" }
|
||||||
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
|
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
<!-- Needs to be exported: https://android.googlesource.com/platform/developers/build/+/4de32d4/prebuilts/gradle/MediaBrowserService/README.md -->
|
<!-- Needs to be exported: https://android.googlesource.com/platform/developers/build/+/4de32d4/prebuilts/gradle/MediaBrowserService/README.md -->
|
||||||
<service android:name=".playback.PlaybackService"
|
<service android:name=".playback.PlaybackService"
|
||||||
android:label="@string/common.appname"
|
android:label="@string/common.appname"
|
||||||
|
android:foregroundServiceType="mediaPlayback"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
|
@ -21,7 +21,6 @@ import androidx.media3.common.Player
|
||||||
import androidx.media3.session.LibraryResult
|
import androidx.media3.session.LibraryResult
|
||||||
import androidx.media3.session.MediaLibraryService
|
import androidx.media3.session.MediaLibraryService
|
||||||
import androidx.media3.session.MediaSession
|
import androidx.media3.session.MediaSession
|
||||||
import androidx.media3.session.SessionResult
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
@ -89,7 +88,7 @@ private const val SEARCH_QUERY_PREFIX = "androidx://media3-session/setMediaUri"
|
||||||
*/
|
*/
|
||||||
@Suppress("TooManyFunctions", "LargeClass", "UnusedPrivateMember")
|
@Suppress("TooManyFunctions", "LargeClass", "UnusedPrivateMember")
|
||||||
class AutoMediaBrowserCallback(var player: Player) :
|
class AutoMediaBrowserCallback(var player: Player) :
|
||||||
MediaLibraryService.MediaLibrarySession.MediaLibrarySessionCallback, KoinComponent {
|
MediaLibraryService.MediaLibrarySession.Callback, KoinComponent {
|
||||||
|
|
||||||
private val mediaPlayerController by inject<MediaPlayerController>()
|
private val mediaPlayerController by inject<MediaPlayerController>()
|
||||||
private val activeServerProvider: ActiveServerProvider by inject()
|
private val activeServerProvider: ActiveServerProvider by inject()
|
||||||
|
@ -181,39 +180,19 @@ class AutoMediaBrowserCallback(var player: Player) :
|
||||||
return onLoadChildren(parentId)
|
return onLoadChildren(parentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setMediaItemFromSearchQuery(query: String) {
|
// https://stackoverflow.com/questions/70096715/adding-mediaitem-when-using-the-media3-library-caused-an-error
|
||||||
// Only accept query with pattern "play [Title]" or "[Title]"
|
override fun onAddMediaItems(
|
||||||
// Where [Title]: must be exactly matched
|
mediaSession: MediaSession,
|
||||||
// If no media with exact name found, play a random media instead
|
|
||||||
val mediaTitle =
|
|
||||||
if (query.startsWith("play ", ignoreCase = true)) {
|
|
||||||
query.drop(5)
|
|
||||||
} else {
|
|
||||||
query
|
|
||||||
}
|
|
||||||
|
|
||||||
playFromMediaId(mediaTitle)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSetMediaUri(
|
|
||||||
session: MediaSession,
|
|
||||||
controller: MediaSession.ControllerInfo,
|
controller: MediaSession.ControllerInfo,
|
||||||
uri: Uri,
|
mediaItems: MutableList<MediaItem>
|
||||||
extras: Bundle
|
): ListenableFuture<MutableList<MediaItem>> {
|
||||||
): Int {
|
|
||||||
|
|
||||||
if (uri.toString().startsWith(SEARCH_QUERY_PREFIX) ||
|
val updatedMediaItems = mediaItems.map { mediaItem ->
|
||||||
uri.toString().startsWith(SEARCH_QUERY_PREFIX_COMPAT)
|
mediaItem.buildUpon()
|
||||||
) {
|
.setUri(mediaItem.requestMetadata.mediaUri)
|
||||||
val searchQuery =
|
.build()
|
||||||
uri.getQueryParameter("query")
|
|
||||||
?: return SessionResult.RESULT_ERROR_NOT_SUPPORTED
|
|
||||||
setMediaItemFromSearchQuery(searchQuery)
|
|
||||||
|
|
||||||
return SessionResult.RESULT_SUCCESS
|
|
||||||
} else {
|
|
||||||
return SessionResult.RESULT_ERROR_NOT_SUPPORTED
|
|
||||||
}
|
}
|
||||||
|
return Futures.immediateFuture(updatedMediaItems.toMutableList())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ReturnCount", "ComplexMethod")
|
@Suppress("ReturnCount", "ComplexMethod")
|
||||||
|
|
|
@ -50,7 +50,7 @@ class LegacyPlaylistManager : KoinComponent {
|
||||||
|
|
||||||
for (i in 0 until n) {
|
for (i in 0 until n) {
|
||||||
val item = controller.getMediaItemAt(i)
|
val item = controller.getMediaItemAt(i)
|
||||||
val file = mediaItemCache[item.mediaMetadata.mediaUri.toString()]
|
val file = mediaItemCache[item.requestMetadata.toString()]
|
||||||
if (file != null)
|
if (file != null)
|
||||||
_playlist.add(file)
|
_playlist.add(file)
|
||||||
}
|
}
|
||||||
|
@ -59,11 +59,11 @@ class LegacyPlaylistManager : KoinComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addToCache(item: MediaItem, file: DownloadFile) {
|
fun addToCache(item: MediaItem, file: DownloadFile) {
|
||||||
mediaItemCache.put(item.mediaMetadata.mediaUri.toString(), file)
|
mediaItemCache.put(item.requestMetadata.toString(), file)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateCurrentPlaying(item: MediaItem?) {
|
fun updateCurrentPlaying(item: MediaItem?) {
|
||||||
currentPlaying = mediaItemCache[item?.mediaMetadata?.mediaUri.toString()]
|
currentPlaying = mediaItemCache[item?.requestMetadata.toString()]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
package org.moire.ultrasonic.playback
|
package org.moire.ultrasonic.playback
|
||||||
|
|
||||||
|
/*
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
@ -24,14 +25,17 @@ import androidx.media3.session.MediaController
|
||||||
import androidx.media3.session.MediaNotification
|
import androidx.media3.session.MediaNotification
|
||||||
import androidx.media3.session.MediaNotification.ActionFactory
|
import androidx.media3.session.MediaNotification.ActionFactory
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a copy of DefaultMediaNotificationProvider.java with some small changes
|
* This is a copy of DefaultMediaNotificationProvider.java with some small changes
|
||||||
* I have opened a bug https://github.com/androidx/media/issues/65 to make it easier to customize
|
* I have opened a bug https://github.com/androidx/media/issues/65 to make it easier to customize
|
||||||
* the icons and actions without creating our own copy of this class..
|
* the icons and actions without creating our own copy of this class..
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
//@UnstableApi
|
||||||
/* package */
|
/* package */
|
||||||
|
// Disabled while getting updated
|
||||||
|
/*
|
||||||
internal class MediaNotificationProvider(context: Context) :
|
internal class MediaNotificationProvider(context: Context) :
|
||||||
MediaNotification.Provider {
|
MediaNotification.Provider {
|
||||||
private val context: Context = context.applicationContext
|
private val context: Context = context.applicationContext
|
||||||
|
@ -148,3 +152,4 @@ internal class MediaNotificationProvider(context: Context) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -13,11 +13,11 @@ import androidx.media3.common.AudioAttributes
|
||||||
import androidx.media3.common.C
|
import androidx.media3.common.C
|
||||||
import androidx.media3.common.C.CONTENT_TYPE_MUSIC
|
import androidx.media3.common.C.CONTENT_TYPE_MUSIC
|
||||||
import androidx.media3.common.C.USAGE_MEDIA
|
import androidx.media3.common.C.USAGE_MEDIA
|
||||||
import androidx.media3.common.MediaItem
|
|
||||||
import androidx.media3.datasource.DataSource
|
import androidx.media3.datasource.DataSource
|
||||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||||
import androidx.media3.exoplayer.ExoPlayer
|
import androidx.media3.exoplayer.ExoPlayer
|
||||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||||
|
import androidx.media3.session.DefaultMediaNotificationProvider
|
||||||
import androidx.media3.session.MediaLibraryService
|
import androidx.media3.session.MediaLibraryService
|
||||||
import androidx.media3.session.MediaSession
|
import androidx.media3.session.MediaSession
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
@ -38,7 +38,7 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
|
||||||
private lateinit var mediaLibrarySession: MediaLibrarySession
|
private lateinit var mediaLibrarySession: MediaLibrarySession
|
||||||
private lateinit var apiDataSource: APIDataSource.Factory
|
private lateinit var apiDataSource: APIDataSource.Factory
|
||||||
|
|
||||||
private lateinit var librarySessionCallback: MediaLibrarySession.MediaLibrarySessionCallback
|
private lateinit var librarySessionCallback: MediaLibrarySession.Callback
|
||||||
|
|
||||||
private var rxBusSubscription = CompositeDisposable()
|
private var rxBusSubscription = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -48,18 +48,6 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
|
||||||
* For some reason the LocalConfiguration of MediaItem are stripped somewhere in ExoPlayer,
|
* For some reason the LocalConfiguration of MediaItem are stripped somewhere in ExoPlayer,
|
||||||
* and thereby customarily it is required to rebuild it..
|
* and thereby customarily it is required to rebuild it..
|
||||||
*/
|
*/
|
||||||
private class CustomMediaItemFiller : MediaSession.MediaItemFiller {
|
|
||||||
override fun fillInLocalConfiguration(
|
|
||||||
session: MediaSession,
|
|
||||||
controller: MediaSession.ControllerInfo,
|
|
||||||
mediaItem: MediaItem
|
|
||||||
): MediaItem {
|
|
||||||
// Again, set the Uri, so that it will get a LocalConfiguration
|
|
||||||
return mediaItem.buildUpon()
|
|
||||||
.setUri(mediaItem.mediaMetadata.mediaUri)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
Timber.i("onCreate called")
|
Timber.i("onCreate called")
|
||||||
|
@ -102,7 +90,7 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
|
||||||
private fun initializeSessionAndPlayer() {
|
private fun initializeSessionAndPlayer() {
|
||||||
if (isStarted) return
|
if (isStarted) return
|
||||||
|
|
||||||
setMediaNotificationProvider(MediaNotificationProvider(UApp.applicationContext()))
|
setMediaNotificationProvider(DefaultMediaNotificationProvider(UApp.applicationContext()))
|
||||||
|
|
||||||
val subsonicAPIClient: SubsonicAPIClient by inject()
|
val subsonicAPIClient: SubsonicAPIClient by inject()
|
||||||
|
|
||||||
|
@ -134,7 +122,6 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
|
||||||
|
|
||||||
// This will need to use the AutoCalls
|
// This will need to use the AutoCalls
|
||||||
mediaLibrarySession = MediaLibrarySession.Builder(this, player, librarySessionCallback)
|
mediaLibrarySession = MediaLibrarySession.Builder(this, player, librarySessionCallback)
|
||||||
.setMediaItemFiller(CustomMediaItemFiller())
|
|
||||||
.setSessionActivity(getPendingIntentForContent())
|
.setSessionActivity(getPendingIntentForContent())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
|
|
@ -659,16 +659,22 @@ fun Track.toMediaItem(): MediaItem {
|
||||||
val bitrate = Settings.maxBitRate
|
val bitrate = Settings.maxBitRate
|
||||||
val uri = "$id|$bitrate|$filePath"
|
val uri = "$id|$bitrate|$filePath"
|
||||||
|
|
||||||
|
|
||||||
|
val rmd = MediaItem.RequestMetadata.Builder()
|
||||||
|
.setMediaUri(uri.toUri())
|
||||||
|
.build()
|
||||||
|
|
||||||
val metadata = MediaMetadata.Builder()
|
val metadata = MediaMetadata.Builder()
|
||||||
metadata.setTitle(title)
|
metadata.setTitle(title)
|
||||||
.setArtist(artist)
|
.setArtist(artist)
|
||||||
.setAlbumTitle(album)
|
.setAlbumTitle(album)
|
||||||
.setMediaUri(uri.toUri())
|
|
||||||
.setAlbumArtist(artist)
|
.setAlbumArtist(artist)
|
||||||
|
.build()
|
||||||
|
|
||||||
val mediaItem = MediaItem.Builder()
|
val mediaItem = MediaItem.Builder()
|
||||||
.setUri(uri)
|
.setUri(uri)
|
||||||
.setMediaId(id)
|
.setMediaId(id)
|
||||||
|
.setRequestMetadata(rmd)
|
||||||
.setMediaMetadata(metadata.build())
|
.setMediaMetadata(metadata.build())
|
||||||
|
|
||||||
return mediaItem.build()
|
return mediaItem.build()
|
||||||
|
|
Loading…
Reference in New Issue