music: simplify tag extraction spin

Simplify the tag extraction loop to not depend on the co-routine
primitives.

This actually makes the music loading process a bit faster since the
loop isn't as tight.
This commit is contained in:
Alexander Capehart 2023-02-13 09:19:50 -07:00
parent 213409924b
commit d0b2fb8517
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 20 additions and 16 deletions

View file

@ -47,6 +47,7 @@ class Auxio : Application() {
// Adding static shortcuts in a dynamic manner is better than declaring them
// manually, as it will properly handle the difference between debug and release
// Auxio instances.
// TODO: Switch to static shortcuts
ShortcutManagerCompat.addDynamicShortcuts(
this,
listOf(

View file

@ -57,8 +57,8 @@ class TagExtractorImpl @Inject constructor(@ApplicationContext private val conte
// producing similar throughput's to other kinds of manual metadata extraction.
val taskPool: Array<Task?> = arrayOfNulls(TASK_CAPACITY)
for (song in incompleteSongs) {
spin@ while (true) {
// Spin until there is an open slot we can insert a task in.
for (i in taskPool.indices) {
val task = taskPool[i]
if (task != null) {
@ -70,12 +70,9 @@ class TagExtractorImpl @Inject constructor(@ApplicationContext private val conte
continue
}
}
val result = incompleteSongs.tryReceive()
if (result.isClosed) {
taskPool[i] = null
taskPool[i] = Task(context, song)
break@spin
}
taskPool[i] = result.getOrNull()?.let { Task(context, it) }
}
}

View file

@ -328,6 +328,7 @@ constructor(
): Library {
if (ContextCompat.checkSelfPermission(context, Indexer.PERMISSION_READ_AUDIO) ==
PackageManager.PERMISSION_DENIED) {
logE("Permission check failed")
// No permissions, signal that we can't do anything.
throw Indexer.NoPermissionException()
}
@ -337,6 +338,7 @@ constructor(
emitIndexing(Indexer.Indexing.Indeterminate)
// Do the initial query of the cache and media databases in parallel.
logD("Starting queries")
val mediaStoreQueryJob = scope.async { mediaStoreExtractor.query() }
val cache =
if (withCache) {
@ -349,6 +351,7 @@ constructor(
// Now start processing the queried song information in parallel. Songs that can't be
// received from the cache are consisted incomplete and pushed to a separate channel
// that will eventually be processed into completed raw songs.
logD("Starting song discovery")
val completeSongs = Channel<RawSong>(Channel.UNLIMITED)
val incompleteSongs = Channel<RawSong>(Channel.UNLIMITED)
val mediaStoreJob =
@ -363,15 +366,18 @@ constructor(
rawSongs.add(rawSong)
emitIndexing(Indexer.Indexing.Songs(rawSongs.size, query.projectedTotal))
}
// These should be no-ops
mediaStoreJob.await()
metadataJob.await()
if (rawSongs.isEmpty()) {
logE("Music library was empty")
throw Indexer.NoMusicException()
}
// Successfully loaded the library, now save the cache and create the library in
// parallel.
logD("Discovered ${rawSongs.size} songs, starting finalization")
emitIndexing(Indexer.Indexing.Indeterminate)
val libraryJob = scope.async(Dispatchers.Main) { Library.from(rawSongs, musicSettings) }
if (cache == null || cache.invalidated) {