From 4afe91e4e8735c0f15d48a78ce2d01b0266b6f3a Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Thu, 2 Feb 2023 20:18:55 -0700 Subject: [PATCH] music: fix threading problems Fix issues with the current threading approach with the new parallel music loader. --- .../auxio/music/extractor/MediaStoreExtractor.kt | 2 ++ .../oxycblt/auxio/music/extractor/MetadataExtractor.kt | 10 +++++++++- .../java/org/oxycblt/auxio/music/system/Indexer.kt | 7 ++++--- .../org/oxycblt/auxio/music/system/IndexerService.kt | 4 ++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt index c3e3be70f..64d1abf9d 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreExtractor.kt @@ -28,6 +28,7 @@ import androidx.core.database.getIntOrNull import androidx.core.database.getStringOrNull import java.io.File import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.yield import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.library.RealSong import org.oxycblt.auxio.music.metadata.Date @@ -231,6 +232,7 @@ private abstract class RealMediaStoreExtractor(private val context: Context) : M populateMetadata(cursor, rawSong) incompleteSongs.send(rawSong) } + yield() } // Free the cursor and signal that no more incomplete songs will be produced by // this extractor. diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt index ae63b3024..216d86819 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataExtractor.kt @@ -22,6 +22,7 @@ import androidx.core.text.isDigitsOnly import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.MetadataRetriever import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.yield import org.oxycblt.auxio.music.library.RealSong import org.oxycblt.auxio.music.metadata.Date import org.oxycblt.auxio.music.metadata.TextTags @@ -53,7 +54,13 @@ class MetadataExtractor(private val context: Context) { for (i in taskPool.indices) { val task = taskPool[i] if (task != null) { - completeSongs.send(task.get() ?: continue) + val finishedRawSong = task.get() + if (finishedRawSong != null) { + completeSongs.send(finishedRawSong) + yield() + } else { + continue + } } val result = incompleteSongs.tryReceive() if (result.isClosed) { @@ -73,6 +80,7 @@ class MetadataExtractor(private val context: Context) { if (finishedRawSong != null) { completeSongs.send(finishedRawSong) taskPool[i] = null + yield() } else { ongoingTasks = true } diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt index 5f14733d7..cf8ce9c28 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt @@ -26,6 +26,7 @@ import java.util.LinkedList import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch @@ -99,8 +100,9 @@ interface Indexer { * @param withCache Whether to use the cache or not when loading. If false, the cache will still * be written, but no cache entries will be loaded into the new library. * @param scope The [CoroutineScope] to run the indexing job in. + * @return The [Job] stacking the indexing status. */ - fun index(context: Context, withCache: Boolean, scope: CoroutineScope) + fun index(context: Context, withCache: Boolean, scope: CoroutineScope): Job /** * Request that the music library should be reloaded. This should be used by components that do @@ -293,7 +295,7 @@ private class RealIndexer : Indexer { this.listener = null } - override fun index(context: Context, withCache: Boolean, scope: CoroutineScope) { + override fun index(context: Context, withCache: Boolean, scope: CoroutineScope) = scope.launch { val result = try { @@ -315,7 +317,6 @@ private class RealIndexer : Indexer { } emitCompletion(result) } - } @Synchronized override fun requestReindex(withCache: Boolean) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt index c368d8d35..6bae83f41 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt @@ -119,11 +119,11 @@ class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener { override fun onStartIndexing(withCache: Boolean) { if (indexer.isIndexing) { // Cancel the previous music loading job. - indexScope.cancel() + currentIndexJob?.cancel() indexer.reset() } // Start a new music loading job on a co-routine. - indexer.index(this@IndexerService, withCache, indexScope) + currentIndexJob = indexer.index(this@IndexerService, withCache, indexScope) } override fun onIndexerStateChanged(state: Indexer.State?) {