Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
org.gradle.jvmargs=-Xmx2g -XX:+UseG1GC
kotlin.code.style=official
appVersion=1.7.0
appVersion=1.7.1
systemProp.sun.net.client.defaultReadTimeout=180000
systemProp.sun.net.client.defaultConnectTimeout=60000
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import dev.typetype.server.services.resolvePlaybackStartMs
import org.schabi.newpipe.extractor.services.youtube.sabr.SabrSegmentRequest
import org.schabi.newpipe.extractor.services.youtube.sabr.YoutubeSabrFormat

private const val MAX_SEGMENTS_PER_TRACK = 12

internal class SabrPlaybackWindowBuilder(private val sabrSessionStore: SabrSessionStore) {
suspend fun build(
holder: SabrSessionHolder,
Expand Down Expand Up @@ -140,6 +142,7 @@ internal class SabrPlaybackWindowBuilder(private val sabrSessionStore: SabrSessi
seq = progressive.nextSequence
coveredEndMs = progressive.coveredEndMs
if (coveredEndMs >= goalEndMs) break
if (progressive.hasReadableMedia) continue
blockedRequest = SabrSegmentRequest.media(format, seq)
blockedBy = "${format.trackName()}:${format.itag}:$seq pending"
break
Expand Down Expand Up @@ -214,7 +217,4 @@ internal class SabrPlaybackWindowBuilder(private val sabrSessionStore: SabrSessi
) {
fun covers(requiredEndMs: Long): Boolean = (track.segments.isNotEmpty() || atEnd) && coveredEndMs >= requiredEndMs
}
private companion object {
const val MAX_SEGMENTS_PER_TRACK = 12
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ import org.schabi.newpipe.extractor.services.youtube.sabr.YoutubeSabrFormat
internal data class SabrProgressiveWindowSegment(
val sequence: Int,
val response: SabrPlaybackWindowSegment,
val hasReadableMedia: Boolean,
)

internal data class SabrProgressiveWindowAppend(val nextSequence: Int, val coveredEndMs: Long)
internal data class SabrProgressiveWindowAppend(
val nextSequence: Int,
val coveredEndMs: Long,
val hasReadableMedia: Boolean,
)

internal fun MutableList<SabrPlaybackWindowSegment>.appendProgressiveWindowSegment(
holder: SabrSessionHolder,
Expand All @@ -27,6 +32,7 @@ internal fun MutableList<SabrPlaybackWindowSegment>.appendProgressiveWindowSegme
return SabrProgressiveWindowAppend(
segment.sequence + 1,
segment.response.startMs + segment.response.durationMs,
segment.hasReadableMedia,
)
}

Expand All @@ -52,6 +58,7 @@ internal fun SabrSessionHolder.progressiveWindowSegment(
startMs = startMs,
durationMs = durationMs,
),
actual != null,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,46 @@ class SabrProgressivePlaybackWindowTest {
assertEquals(9_985L, result.response.audio.segments.single().durationMs)
}

@Test
fun `vod window includes enough progressive segments to satisfy the buffer goal`() = runTest {
val audio = format(140, isAudio = true)
val video = format(299, isAudio = false)
val state = mockk<YoutubeSabrStreamState>(relaxed = true)
every { state.getSegmentNumberAtOrAfterTimeMs(any(), 5_731_077L) } returns 1
val session = mockk<YoutubeSabrSession>(relaxed = true)
every { session.streamState } returns state
every { session.getCachedSegment(any()) } returns null
every { session.getReadableSegment(any()) } answers {
val request = firstArg<SabrSegmentRequest>()
val durationMs = if (request.format.isAudio) 10_000L else 6_000L
readableSegment(
request.format,
sequence = request.sequenceNumber,
startMs = 5_731_000L + (request.sequenceNumber - 1L) * durationMs,
durationMs = durationMs,
)
}
val holder = holder(session, audio, video)
val store = mockk<SabrSessionStore>()
coEvery { store.cachedSegment(holder, any()) } returns null

val result = SabrPlaybackWindowBuilder(store).build(
holder,
SabrPlaybackWindowRequest(
generation = 0L,
playerTimeMs = 5_731_077L,
videoItag = video.itag,
audioItag = audio.itag,
bufferGoalMs = 30_000L,
),
)

assertTrue(result.isReady)
assertTrue(result.blockedRequests.isEmpty())
assertEquals(6, requireNotNull(result.response.video).segments.size)
assertEquals(4, result.response.audio.segments.size)
}

private fun readableSegment(
format: YoutubeSabrFormat,
sequence: Int = 1,
Expand Down