playback: remove custom bitmap loading

Media3 simply will not tolerate me doing this. I am basically stuck
at the mercy of the Android OS now, until I can have my own unified
source of truth with cover loading.
This commit is contained in:
Alexander Capehart 2024-05-17 13:38:12 -06:00
parent 0a3382cafd
commit 9087ad5e45
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 16 additions and 102 deletions

View file

@ -1,90 +0,0 @@
/*
* Copyright (c) 2024 Auxio Project
* MediaSessionBitmapLoader.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image.service
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import androidx.media3.common.MediaMetadata
import androidx.media3.common.util.BitmapLoader
import coil.ImageLoader
import coil.memory.MemoryCache
import coil.request.Options
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.image.extractor.CoverKeyer
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.service.MediaSessionUID
class MediaSessionBitmapLoader
@Inject
constructor(
@ApplicationContext private val context: Context,
private val musicRepository: MusicRepository,
private val bitmapProvider: BitmapProvider,
private val keyer: CoverKeyer,
private val imageLoader: ImageLoader,
) : BitmapLoader {
override fun decodeBitmap(data: ByteArray): ListenableFuture<Bitmap> {
throw NotImplementedError()
}
override fun loadBitmap(uri: Uri): ListenableFuture<Bitmap> {
throw NotImplementedError()
}
override fun supportsMimeType(mimeType: String): Boolean {
return true
}
override fun loadBitmapFromMetadata(metadata: MediaMetadata): ListenableFuture<Bitmap>? {
val deviceLibrary = musicRepository.deviceLibrary ?: return null
val future = SettableFuture.create<Bitmap>()
val song =
when (val uid =
metadata.extras?.getString("uid")?.let { MediaSessionUID.fromString(it) }) {
is MediaSessionUID.Single -> deviceLibrary.findSong(uid.uid)
is MediaSessionUID.Joined -> deviceLibrary.findSong(uid.childUid)
else -> return null
}
?: return null
// Even launching a coroutine to obtained cached covers is enough to make the notification
// go without covers.
val key = keyer.key(listOf(song.cover), Options(context))
if (imageLoader.memoryCache?.get(MemoryCache.Key(key)) != null) {
future.set(imageLoader.memoryCache?.get(MemoryCache.Key(key))?.bitmap)
return future
}
bitmapProvider.load(
song,
object : BitmapProvider.Target {
override fun onCompleted(bitmap: Bitmap?) {
if (bitmap == null) {
future.setException(IllegalStateException("Bitmap is null"))
} else {
future.set(bitmap)
}
}
})
return future
}
}

View file

@ -74,7 +74,7 @@ fun Song.toMediaItem(context: Context, parent: MusicParent?): MediaItem {
.setMediaType(MediaMetadata.MEDIA_TYPE_MUSIC)
.setIsPlayable(true)
.setIsBrowsable(false)
.setArtworkUri(album.cover.single.mediaStoreCoverUri)
.setArtworkUri(cover.mediaStoreCoverUri)
.setExtras(
Bundle().apply {
putString("uid", mediaSessionUID.toString())

View file

@ -21,6 +21,7 @@ package org.oxycblt.auxio.playback.service
import android.content.Context
import android.content.Intent
import android.media.audiofx.AudioEffect
import android.os.Bundle
import androidx.media3.common.AudioAttributes
import androidx.media3.common.C
import androidx.media3.common.MediaItem
@ -42,6 +43,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.oxycblt.auxio.image.ImageSettings
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Song
@ -69,13 +71,15 @@ class ExoPlaybackStateHolder(
private val persistenceRepository: PersistenceRepository,
private val playbackSettings: PlaybackSettings,
private val commandFactory: PlaybackCommand.Factory,
private val replayGainProcessor: ReplayGainAudioProcessor,
private val musicRepository: MusicRepository,
private val replayGainProcessor: ReplayGainAudioProcessor
private val imageSettings: ImageSettings
) :
PlaybackStateHolder,
Player.Listener,
MusicRepository.UpdateListener,
PlaybackSettings.Listener {
PlaybackSettings.Listener,
ImageSettings.Listener {
private val saveJob = Job()
private val saveScope = CoroutineScope(Dispatchers.IO + saveJob)
private val restoreScope = CoroutineScope(Dispatchers.IO + saveJob)
@ -86,6 +90,7 @@ class ExoPlaybackStateHolder(
private set
fun attach() {
imageSettings.registerListener(this)
player.addListener(this)
replayGainProcessor.attach()
playbackManager.registerStateHolder(this)
@ -99,6 +104,7 @@ class ExoPlaybackStateHolder(
playbackManager.unregisterStateHolder(this)
musicRepository.removeUpdateListener(this)
replayGainProcessor.release()
imageSettings.unregisterListener(this)
player.release()
}
@ -516,9 +522,10 @@ class ExoPlaybackStateHolder(
private val persistenceRepository: PersistenceRepository,
private val playbackSettings: PlaybackSettings,
private val commandFactory: PlaybackCommand.Factory,
private val musicRepository: MusicRepository,
private val mediaSourceFactory: MediaSource.Factory,
private val replayGainProcessor: ReplayGainAudioProcessor
private val replayGainProcessor: ReplayGainAudioProcessor,
private val musicRepository: MusicRepository,
private val imageSettings: ImageSettings,
) {
fun create(): ExoPlaybackStateHolder {
// Since Auxio is a music player, only specify an audio renderer to save
@ -556,8 +563,9 @@ class ExoPlaybackStateHolder(
persistenceRepository,
playbackSettings,
commandFactory,
replayGainProcessor,
musicRepository,
replayGainProcessor)
imageSettings)
}
}

View file

@ -48,7 +48,6 @@ import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.ForegroundListener
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.service.MediaSessionBitmapLoader
import org.oxycblt.auxio.music.service.MediaItemBrowser
import org.oxycblt.auxio.playback.state.DeferredPlayback
import org.oxycblt.auxio.playback.state.PlaybackStateManager
@ -61,7 +60,6 @@ constructor(
private val playbackManager: PlaybackStateManager,
private val actionHandler: PlaybackActionHandler,
private val mediaItemBrowser: MediaItemBrowser,
private val bitmapLoader: MediaSessionBitmapLoader,
exoHolderFactory: ExoPlaybackStateHolder.Factory
) :
MediaLibrarySession.Callback,
@ -143,9 +141,7 @@ constructor(
}
private fun createSession(service: MediaLibraryService) =
MediaLibrarySession.Builder(service, exoHolder.mediaSessionPlayer, this)
.setBitmapLoader(bitmapLoader)
.build()
MediaLibrarySession.Builder(service, exoHolder.mediaSessionPlayer, this).build()
override fun onConnect(
session: MediaSession,

View file

@ -12,7 +12,7 @@ buildscript {
}
plugins {
id "com.android.application" version '8.3.2' apply false
id "com.android.application" version '8.4.0' apply false
id "androidx.navigation.safeargs.kotlin" version "$navigation_version" apply false
id "org.jetbrains.kotlin.android" version "$kotlin_version" apply false
id "com.google.devtools.ksp" version '1.9.23-1.0.20' apply false