music: fix threading problems

Fix issues with the current threading approach with the new parallel
music loader.
This commit is contained in:
Alexander Capehart 2023-02-02 20:18:55 -07:00
parent 1df1d40408
commit 4afe91e4e8
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 17 additions and 6 deletions

View file

@ -28,6 +28,7 @@ import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull import androidx.core.database.getStringOrNull
import java.io.File import java.io.File
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.library.RealSong import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.metadata.Date import org.oxycblt.auxio.music.metadata.Date
@ -231,6 +232,7 @@ private abstract class RealMediaStoreExtractor(private val context: Context) : M
populateMetadata(cursor, rawSong) populateMetadata(cursor, rawSong)
incompleteSongs.send(rawSong) incompleteSongs.send(rawSong)
} }
yield()
} }
// Free the cursor and signal that no more incomplete songs will be produced by // Free the cursor and signal that no more incomplete songs will be produced by
// this extractor. // this extractor.

View file

@ -22,6 +22,7 @@ import androidx.core.text.isDigitsOnly
import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.MetadataRetriever import com.google.android.exoplayer2.MetadataRetriever
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.library.RealSong import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.metadata.Date import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.TextTags import org.oxycblt.auxio.music.metadata.TextTags
@ -53,7 +54,13 @@ class MetadataExtractor(private val context: Context) {
for (i in taskPool.indices) { for (i in taskPool.indices) {
val task = taskPool[i] val task = taskPool[i]
if (task != null) { 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() val result = incompleteSongs.tryReceive()
if (result.isClosed) { if (result.isClosed) {
@ -73,6 +80,7 @@ class MetadataExtractor(private val context: Context) {
if (finishedRawSong != null) { if (finishedRawSong != null) {
completeSongs.send(finishedRawSong) completeSongs.send(finishedRawSong)
taskPool[i] = null taskPool[i] = null
yield()
} else { } else {
ongoingTasks = true ongoingTasks = true
} }

View file

@ -26,6 +26,7 @@ import java.util.LinkedList
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch 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 * @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. * be written, but no cache entries will be loaded into the new library.
* @param scope The [CoroutineScope] to run the indexing job in. * @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 * 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 this.listener = null
} }
override fun index(context: Context, withCache: Boolean, scope: CoroutineScope) { override fun index(context: Context, withCache: Boolean, scope: CoroutineScope) =
scope.launch { scope.launch {
val result = val result =
try { try {
@ -315,7 +317,6 @@ private class RealIndexer : Indexer {
} }
emitCompletion(result) emitCompletion(result)
} }
}
@Synchronized @Synchronized
override fun requestReindex(withCache: Boolean) { override fun requestReindex(withCache: Boolean) {

View file

@ -119,11 +119,11 @@ class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener {
override fun onStartIndexing(withCache: Boolean) { override fun onStartIndexing(withCache: Boolean) {
if (indexer.isIndexing) { if (indexer.isIndexing) {
// Cancel the previous music loading job. // Cancel the previous music loading job.
indexScope.cancel() currentIndexJob?.cancel()
indexer.reset() indexer.reset()
} }
// Start a new music loading job on a co-routine. // 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?) { override fun onIndexerStateChanged(state: Indexer.State?) {