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:
parent
0a3382cafd
commit
9087ad5e45
5 changed files with 16 additions and 102 deletions
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue