mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-15 00:42:54 +01:00
playback: retain durable reset identity through Media3
This commit is contained in:
@@ -266,6 +266,7 @@ internal fun MediaItem.resetItem(): QueueResetItem? {
|
||||
upNext = extras.getBoolean(EXTRA_RESET_UP_NEXT),
|
||||
entryOccurrence = extras.getInt(EXTRA_RESET_ENTRY_OCCURRENCE),
|
||||
occurrence = extras.getLong(EXTRA_RESET_OCCURRENCE),
|
||||
originEntryId = extras.takeIf { it.containsKey(EXTRA_RESET_ORIGIN_ENTRY_ID) }?.getLong(EXTRA_RESET_ORIGIN_ENTRY_ID),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -291,6 +292,7 @@ private const val EXTRA_RESET_POSITION = "resetPosition"
|
||||
private const val EXTRA_RESET_UP_NEXT = "resetUpNext"
|
||||
private const val EXTRA_RESET_ENTRY_OCCURRENCE = "resetEntryOccurrence"
|
||||
private const val EXTRA_RESET_OCCURRENCE = "resetOccurrence"
|
||||
private const val EXTRA_RESET_ORIGIN_ENTRY_ID = "resetOriginEntryId"
|
||||
|
||||
internal fun MediaItem?.replayGain(): ReplayGain {
|
||||
val extras = this?.mediaMetadata?.extras ?: return ReplayGain()
|
||||
@@ -348,6 +350,7 @@ internal fun queueMediaItem(
|
||||
putBoolean(EXTRA_RESET_UP_NEXT, reset.upNext)
|
||||
putInt(EXTRA_RESET_ENTRY_OCCURRENCE, reset.entryOccurrence)
|
||||
putLong(EXTRA_RESET_OCCURRENCE, reset.occurrence)
|
||||
reset.originEntryId?.let { putLong(EXTRA_RESET_ORIGIN_ENTRY_ID, it) }
|
||||
}
|
||||
},
|
||||
).build()
|
||||
|
||||
@@ -48,6 +48,15 @@ class FakePlayerHandle : PlayerHandle {
|
||||
@Volatile
|
||||
var beforeRemoveFirst: (() -> Unit)? = null
|
||||
|
||||
@Volatile
|
||||
var roundTripItemsThroughMedia3 = false
|
||||
|
||||
private fun storedItem(item: QueueItem): QueueItem {
|
||||
if (!roundTripItemsThroughMedia3) return item
|
||||
val mediaItem = queueMediaItem(item, local = null, stream = "http://stream/${item.id}", transcode = false)
|
||||
return queueItemFromMediaItem(mediaItem)
|
||||
}
|
||||
|
||||
private fun checkThread() {
|
||||
val expected = expectedThread ?: return
|
||||
check(Thread.currentThread() == expected) { "Expected $expected, was ${Thread.currentThread()}" }
|
||||
@@ -92,7 +101,7 @@ class FakePlayerHandle : PlayerHandle {
|
||||
item: QueueItem,
|
||||
) {
|
||||
operations += "replaceItem($index, ${item.id})"
|
||||
if (index in items.indices) items[index] = item
|
||||
if (index in items.indices) items[index] = storedItem(item)
|
||||
}
|
||||
|
||||
override fun setWindow(
|
||||
@@ -102,7 +111,7 @@ class FakePlayerHandle : PlayerHandle {
|
||||
) {
|
||||
operations += "setWindow(size=${items.size}, start=$startIndex, position=$startPositionMs)"
|
||||
this.items.clear()
|
||||
this.items += items
|
||||
this.items += items.map(::storedItem)
|
||||
index = startIndex
|
||||
positionMs = startPositionMs
|
||||
idle = true
|
||||
@@ -115,13 +124,13 @@ class FakePlayerHandle : PlayerHandle {
|
||||
|
||||
override fun addFirst(item: QueueItem) {
|
||||
operations += "addFirst(${item.id})"
|
||||
items.add(0, item)
|
||||
items.add(0, storedItem(item))
|
||||
index++
|
||||
}
|
||||
|
||||
override fun addLast(item: QueueItem) {
|
||||
operations += "addLast(${item.id})"
|
||||
items += item
|
||||
items += storedItem(item)
|
||||
}
|
||||
|
||||
override fun insertAt(
|
||||
@@ -129,7 +138,7 @@ class FakePlayerHandle : PlayerHandle {
|
||||
item: QueueItem,
|
||||
) {
|
||||
operations += "insertAt($index, ${item.id})"
|
||||
items.add(index, item)
|
||||
items.add(index, storedItem(item))
|
||||
if (index <= this.index) this.index++
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,15 @@ class MediaItemTest {
|
||||
@Test
|
||||
fun theItemKeepsItsResetIdentity() {
|
||||
val resetItem =
|
||||
QueueResetItem(QueueOrigin(QueueKind.Playlist, 1, "p1"), "s1", 2, upNext = false, entryOccurrence = 1, occurrence = 1)
|
||||
QueueResetItem(
|
||||
QueueOrigin(QueueKind.Playlist, 1, "p1"),
|
||||
"s1",
|
||||
2,
|
||||
upNext = false,
|
||||
entryOccurrence = 1,
|
||||
occurrence = 1,
|
||||
originEntryId = 7,
|
||||
)
|
||||
|
||||
val item = queueMediaItem(song.copy(resetItem = resetItem), local = null, stream = "http://server/stream?s=s1", transcode = false)
|
||||
|
||||
|
||||
@@ -3611,6 +3611,24 @@ class PlaybackControllerTest {
|
||||
assertEquals(3L, controller.state.value.position)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aResetKeepsAMovedSecondDuplicateContextEntryByDurableIdentity() {
|
||||
handle.roundTripItemsThroughMedia3 = true
|
||||
seedPlaylist(2)
|
||||
runBlocking { queues.replace(listOf(queues.playlistEntry(1, "p1"), queues.playlistEntry(1, "p1"))) }
|
||||
controller.connect()
|
||||
await { controller.state.value.item != null }
|
||||
controller.playAt(3)
|
||||
await { handle.currentItem?.id == "s2" && controller.state.value.position == 3L }
|
||||
runBlocking { controller.move(2, 0) }
|
||||
val point = runBlocking { queues.captureResetPoint() }
|
||||
|
||||
runBlocking { queues.resetChangedOrigins(setOf(QueueOrigin(QueueKind.Playlist, 1, "p1")), point) }
|
||||
|
||||
assertEquals(1L, controller.state.value.position)
|
||||
assertEquals("s2", handle.currentItem?.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun repeatedResetsKeepTheSecondDuplicateUpNextEntry() {
|
||||
seedAlbum(3, sourceId = 1)
|
||||
|
||||
Reference in New Issue
Block a user