address playback review findings

- treat flac/wav/alac as lossless and ignore the bitrate for them, so the declared length never drops below the real encoded size and truncates a lossless transcode
- read the effective stream quality once per media item and use it for both the URL and the clip, closing the window where they disagreed
- honour a bounded DataSpec length in KnownLengthDataSource and reject non-positive length fragments
- drop MetadataDurationPlayer: clipping already gives the timeline the real duration, and the forwarder could publish a wrong metadata duration for direct play
- drop the dead PlaybackState.error/lastError now that errors are toast-only, and tighten the floor test to assert the exact value
This commit is contained in:
austinried
2026-10-04 00:30:00 +00:00
parent ebaa486126
commit a0647deaae
9 changed files with 27 additions and 50 deletions
@@ -27,9 +27,16 @@ class StreamLengthTest {
@Test
fun aTinyBitrateStillClearsTheEncodersFloor() {
val length = declaredStreamLength(180_000, StreamQuality(24, "mp3"))!!
assertEquals(2_062_144L, declaredStreamLength(180_000, StreamQuality(24, "mp3")))
}
assertTrue(length >= 180 * 32_000 / 8)
@Test
fun losslessFormatsIgnoreTheBitrateAndAllowForTheLargestStream() {
val cdQuality = declaredStreamLength(320_000, StreamQuality(64, "flac"))!!
val highBitrate = declaredStreamLength(320_000, StreamQuality(320, "flac"))!!
assertEquals(cdQuality, highBitrate)
assertTrue(cdQuality >= 320 * 1_411_200 / 8)
}
@Test
@@ -280,28 +280,6 @@ class PlaybackControllerTest {
await { !controller.state.value.isBuffering }
}
@Test
fun playbackFailuresAreSurfacedUntilTheNextTrack() {
seedAlbum(3, sourceId = 1)
controller.playAlbum(1, "al1", 0)
await {
controller.state.value.item
?.id == "s1"
}
handle.fail("ERROR_CODE_IO_UNSPECIFIED")
await { controller.state.value.error == "ERROR_CODE_IO_UNSPECIFIED" }
handle.advanceTo(handle.currentIndex + 1)
await {
controller.state.value.item
?.id == "s2"
}
assertEquals(null, controller.state.value.error)
}
@Test
fun playbackErrorsAreShownAsAToast() {
seedAlbum(3, sourceId = 1)