@@ -18,7 +18,6 @@ import dev.typetype.server.services.StreamService
1818import dev.typetype.server.services.markServed
1919import io.ktor.http.HttpStatusCode
2020import io.ktor.server.application.ApplicationCall
21- import io.ktor.server.request.receive
2221import io.ktor.server.response.respond
2322import dev.typetype.server.sabr.YoutubeSabrFormat
2423
@@ -34,12 +33,23 @@ internal class SabrPlaybackHandler(
3433 private val playbackService = SabrPlaybackSessionService (sabrSessionStore)
3534 private val infoResolver = SabrPlaybackInfoResolver (sabrSessionStore, authenticatedSabrInfoService)
3635 private val accessValidator = SabrPlaybackAccessValidator (streamService, youtubeSessionStreamInfo)
36+ private val prewarmHandoffs = SabrPlaybackPrewarmHandoffs ()
3737
3838 suspend fun create (call : ApplicationCall , videoId : String ) {
3939 val access = call.accessProfileOrRespond(authService, accessControlService, adminSettingsService) ? : return
4040 if (! validateAccess(call, videoId, access)) return
4141 val request = call.playbackRequest()
4242 val startTimeMs = request.effectiveStartTimeMs()
43+ val isPrewarm = call.request.queryParameters[" prewarm" ]?.toBooleanStrictOrNull() == true
44+ val handoffKey = prewarmHandoffs.key(access.userId, videoId, request, startTimeMs)
45+ if (! isPrewarm) {
46+ val handoff = handoffKey?.let (prewarmHandoffs::take)
47+ val existing = handoff?.let { playbackService.lookup(it.sessionToken) }
48+ if (existing != null && existing.terminalFailure() == null ) {
49+ PlaybackTraceLog .record(" sabr_prewarm_handoff" , " result=hit videoItag=${existing.videoFormat.itag} audioItag=${existing.audioFormat.itag} audioTrackId=${existing.audioFormat.audioTrackId} startTimeMs=${handoff.startTimeMs} ready=${handoff.ready} " )
50+ return respondPrepared(call, existing, videoId, handoff.startTimeMs, handoff.ready)
51+ }
52+ }
4353 val infoStartedAt = System .nanoTime()
4454 val prepared = infoResolver.initial(access.userId, videoId, startTimeMs)
4555 PlaybackTraceLog .record(" sabr_info" , " durationMs=${(System .nanoTime() - infoStartedAt) / 1_000_000 } result=${if (prepared == null ) " miss" else " ready" } startTimeMs=$startTimeMs " )
@@ -59,6 +69,10 @@ internal class SabrPlaybackHandler(
5969 )
6070 PlaybackTraceLog .record(" sabr_session_prepare" , " durationMs=${(System .nanoTime() - prepareStartedAt) / 1_000_000 } ready=${preparation.ready} videoItag=${video.itag} audioItag=${audio.itag} audioTrackId=${audio.audioTrackId} audioOnly=${request.audioOnly} isLive=${request.isLive} startTimeMs=${preparation.startTimeMs} " )
6171 preparation.holder.setActiveTracks(videoActive = ! request.audioOnly, audioActive = true )
72+ if (isPrewarm && handoffKey != null && preparation.holder.terminalFailure() == null ) {
73+ prewarmHandoffs.remember(handoffKey, SabrPlaybackPrewarmSession (preparation.holder.sessionToken, preparation.startTimeMs, preparation.ready))
74+ PlaybackTraceLog .record(" sabr_prewarm_handoff" , " result=stored videoItag=${video.itag} audioItag=${audio.itag} audioTrackId=${audio.audioTrackId} startTimeMs=$startTimeMs " )
75+ }
6276 respondPrepared(call, preparation.holder, videoId, preparation.startTimeMs, preparation.ready)
6377 }
6478
@@ -160,26 +174,6 @@ internal class SabrPlaybackHandler(
160174 }
161175 }
162176
163- private suspend fun ApplicationCall.playbackRequest (): SabrPlaybackRequest {
164- val body = runCatching { receive<SabrPlaybackRequest >() }.getOrNull()
165- return SabrPlaybackRequest (
166- videoItag = body?.videoItag ? : request.queryParameters[" videoItag" ]?.toIntOrNull(),
167- audioItag = body?.audioItag ? : request.queryParameters[" audioItag" ]?.toIntOrNull(),
168- audioTrackId = body?.audioTrackId ? : request.queryParameters[" audioTrackId" ],
169- startTimeMs = body?.startTimeMs ? : request.queryParameters[" startTimeMs" ]?.toLongOrNull(),
170- playerTimeMs = body?.playerTimeMs ? : request.queryParameters[" playerTimeMs" ]?.toLongOrNull(),
171- audioOnly = body?.audioOnly ? : request.queryParameters[" audioOnly" ]?.toBooleanStrictOrNull() ? : false ,
172- isLive = body?.isLive ? : request.queryParameters[" isLive" ]?.toBooleanStrictOrNull() ? : false ,
173- )
174- }
175-
176- private fun SabrPlaybackRequest.effectiveStartTimeMs (): Long =
177- (playerTimeMs ? : startTimeMs ? : 0L ).coerceAtLeast(0L )
178-
179- private fun SabrPlaybackRequest.keepsCurrentFormats (holder : SabrSessionHolder ): Boolean =
180- (videoItag == null || videoItag == holder.videoFormat.itag) &&
181- (audioItag == null || audioItag == holder.audioFormat.itag) &&
182- (audioTrackId.isNullOrBlank() || audioTrackId == holder.audioFormat.audioTrackId)
183177
184178 private suspend fun selectAudio (
185179 call : ApplicationCall ,
0 commit comments