address review: offload artwork decode, drop the redundant metadata override, cancel the loader

This commit is contained in:
austinried
2026-10-04 00:29:58 +00:00
parent 4095d038a9
commit 97ca4230da
3 changed files with 35 additions and 24 deletions
@@ -5,9 +5,9 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.annotation.OptIn
import androidx.media3.common.MediaMetadata
import androidx.media3.common.util.BitmapLoader
import androidx.media3.common.util.UnstableApi
import androidx.media3.common.util.Util
import coil3.ImageLoader
import coil3.request.ImageRequest
import coil3.request.SuccessResult
@@ -20,6 +20,7 @@ import com.subtracks.data.repo.SourceRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
private const val ARTWORK_SIZE = 512
@@ -46,7 +47,11 @@ class CoverArtBitmapLoader(
) : BitmapLoader {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun supportsMimeType(mimeType: String): Boolean = mimeType.startsWith("image/")
override fun supportsMimeType(mimeType: String): Boolean = Util.isBitmapFactorySupportedMimeType(mimeType)
fun shutdown() {
scope.cancel()
}
override fun loadBitmap(uri: Uri): ListenableFuture<Bitmap> {
val coverArtId =
@@ -80,19 +85,20 @@ class CoverArtBitmapLoader(
return future
}
override fun loadBitmapFromMetadata(metadata: MediaMetadata): ListenableFuture<Bitmap> {
metadata.artworkData?.let { return decodeBitmap(it) }
metadata.artworkUri?.let { return loadBitmap(it) }
return Futures.immediateFailedFuture(IllegalArgumentException("Artwork has no data or URI"))
}
override fun decodeBitmap(data: ByteArray): ListenableFuture<Bitmap> =
try {
BitmapFactory
.decodeByteArray(data, 0, data.size)
?.let { Futures.immediateFuture(it) }
?: Futures.immediateFailedFuture(IllegalArgumentException("Could not decode artwork"))
} catch (e: Exception) {
Futures.immediateFailedFuture(e)
override fun decodeBitmap(data: ByteArray): ListenableFuture<Bitmap> {
val future = SettableFuture.create<Bitmap>()
scope.launch {
try {
val bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)
if (bitmap == null) {
future.setException(IllegalArgumentException("Could not decode artwork"))
} else {
future.set(bitmap)
}
} catch (e: Exception) {
future.setException(e)
}
}
return future
}
}
@@ -132,7 +132,7 @@ class Media3PlayerHandle(
.setTitle(item.title)
.setArtist(item.artist)
.setAlbumTitle(item.album)
.setArtworkUri(item.coverArtId?.let(CoverArtArtwork::uri))
.setArtworkUri(item.coverArtId?.takeIf { it.isNotEmpty() }?.let(CoverArtArtwork::uri))
.setIsBrowsable(false)
.setIsPlayable(true)
.setExtras(
@@ -21,6 +21,7 @@ import org.koin.core.context.GlobalContext
class PlaybackService : MediaSessionService() {
private var session: MediaSession? = null
private var artworkLoader: CoverArtBitmapLoader? = null
@OptIn(UnstableApi::class)
override fun onCreate() {
@@ -39,6 +40,13 @@ class PlaybackService : MediaSessionService() {
.setMediaSourceFactory(
DefaultMediaSourceFactory(this).setDataSourceFactory(OkHttpDataSource.Factory(streamingClient())),
).build()
val loader =
CoverArtBitmapLoader(
applicationContext,
GlobalContext.get().get<SourceRepository>(),
SingletonImageLoader.get(this),
)
artworkLoader = loader
session =
MediaSession
.Builder(this, player)
@@ -49,13 +57,8 @@ class PlaybackService : MediaSessionService() {
Intent(this, MainActivity::class.java),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
),
).setBitmapLoader(
CoverArtBitmapLoader(
this,
GlobalContext.get().get<SourceRepository>(),
SingletonImageLoader.get(this),
),
).build()
).setBitmapLoader(loader)
.build()
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = session
@@ -85,6 +88,8 @@ class PlaybackService : MediaSessionService() {
}
override fun onDestroy() {
artworkLoader?.shutdown()
artworkLoader = null
session?.run {
player.release()
release()