@@ -50,6 +50,9 @@ import { applyAbPlaybackForTimeline } from '../abPlayback'
5050import { stringifyError } from '@sofie-automation/shared-lib/dist/lib/stringifyError'
5151import { PlayoutPartInstanceModel } from '../model/PlayoutPartInstanceModel'
5252import { PlayoutChangedType } from '@sofie-automation/shared-lib/dist/peripheralDevice/peripheralDeviceAPI'
53+ import { PieceInstance } from '@sofie-automation/corelib/dist/dataModel/PieceInstance'
54+
55+ const DEFAULT_ABSOLUTE_PIECE_PREPARE_TIME = 30000
5356
5457function isModelForStudio ( model : StudioPlayoutModelBase ) : model is StudioPlayoutModel {
5558 const tmp = model as StudioPlayoutModel
@@ -257,29 +260,48 @@ export interface SelectedPartInstanceTimelineInfo {
257260 partInstance : ReadonlyDeep < DBPartInstance >
258261 pieceInstances : PieceInstanceWithTimings [ ]
259262 calculatedTimings : PartCalculatedTimings
263+ regenerateTimelineAt : number | undefined
260264}
261265
262266function getPartInstanceTimelineInfo (
267+ absolutePiecePrepareTime : number ,
263268 currentTime : Time ,
264269 sourceLayers : SourceLayers ,
265270 partInstance : PlayoutPartInstanceModel | null
266271) : SelectedPartInstanceTimelineInfo | undefined {
267272 if ( ! partInstance ) return undefined
268273
269274 const partTimes = createPartCurrentTimes ( currentTime , partInstance . partInstance . timings ?. plannedStartedPlayback )
270- const pieceInstances = processAndPrunePieceInstanceTimings (
271- sourceLayers ,
272- partInstance . pieceInstances . map ( ( p ) => p . pieceInstance ) ,
273- partTimes
274- )
275+
276+ let regenerateTimelineAt : Time | undefined = undefined
277+
278+ const rawPieceInstances : ReadonlyDeep < PieceInstance > [ ] = [ ]
279+ for ( const { pieceInstance } of partInstance . pieceInstances ) {
280+ if (
281+ pieceInstance . piece . enable . isAbsolute &&
282+ typeof pieceInstance . piece . enable . start === 'number' &&
283+ pieceInstance . piece . enable . start > currentTime + absolutePiecePrepareTime
284+ ) {
285+ // This absolute timed piece is starting too far in the future, ignore it
286+ regenerateTimelineAt = Math . min (
287+ regenerateTimelineAt ?? Number . POSITIVE_INFINITY ,
288+ pieceInstance . piece . enable . start - absolutePiecePrepareTime
289+ )
290+
291+ continue
292+ }
293+
294+ rawPieceInstances . push ( pieceInstance )
295+ }
275296
276297 const partInstanceWithOverrides = partInstance . getPartInstanceWithQuickLoopOverrides ( )
277298 return {
278299 partInstance : partInstanceWithOverrides ,
279- pieceInstances,
300+ pieceInstances : processAndPrunePieceInstanceTimings ( sourceLayers , rawPieceInstances , partTimes ) ,
280301 partTimes,
281302 // Approximate `calculatedTimings`, for the partInstances which already have it cached
282- calculatedTimings : getPartTimingsOrDefaults ( partInstanceWithOverrides , pieceInstances ) ,
303+ calculatedTimings : getPartTimingsOrDefaults ( partInstanceWithOverrides , rawPieceInstances ) ,
304+ regenerateTimelineAt,
283305 }
284306}
285307
@@ -320,10 +342,27 @@ async function getTimelineRundown(
320342 }
321343
322344 const currentTime = getCurrentTime ( )
345+ const absolutePiecePrepareTime =
346+ context . studio . settings . rundownGlobalPiecesPrepareTime || DEFAULT_ABSOLUTE_PIECE_PREPARE_TIME
323347 const partInstancesInfo : SelectedPartInstancesTimelineInfo = {
324- current : getPartInstanceTimelineInfo ( currentTime , showStyle . sourceLayers , currentPartInstance ) ,
325- next : getPartInstanceTimelineInfo ( currentTime , showStyle . sourceLayers , nextPartInstance ) ,
326- previous : getPartInstanceTimelineInfo ( currentTime , showStyle . sourceLayers , previousPartInstance ) ,
348+ current : getPartInstanceTimelineInfo (
349+ absolutePiecePrepareTime ,
350+ currentTime ,
351+ showStyle . sourceLayers ,
352+ currentPartInstance
353+ ) ,
354+ next : getPartInstanceTimelineInfo (
355+ absolutePiecePrepareTime ,
356+ currentTime ,
357+ showStyle . sourceLayers ,
358+ nextPartInstance
359+ ) ,
360+ previous : getPartInstanceTimelineInfo (
361+ absolutePiecePrepareTime ,
362+ currentTime ,
363+ showStyle . sourceLayers ,
364+ previousPartInstance
365+ ) ,
327366 }
328367
329368 if ( partInstancesInfo . next && nextPartInstance ) {
@@ -350,14 +389,18 @@ async function getTimelineRundown(
350389 timelineObjs = timelineObjs . concat ( await pLookaheadObjs )
351390
352391 let regenerateTimelineToken : string | undefined
353- if ( rundownTimelineResult . timingContext ?. regenerateTimelineAt ) {
392+ const regenerateTimelineAt = Math . min (
393+ partInstancesInfo . current ?. regenerateTimelineAt ?? Number . POSITIVE_INFINITY ,
394+ partInstancesInfo . next ?. regenerateTimelineAt ?? Number . POSITIVE_INFINITY
395+ )
396+ if ( regenerateTimelineAt < Number . POSITIVE_INFINITY ) {
354397 // The timeline has requested a regeneration at a specific time
355398 regenerateTimelineToken = getHash ( `regenerate-${ playoutModel . playlistId } -${ getCurrentTime ( ) } ` )
356399 timelineObjs . push (
357400 literal < TimelineObjRegenerateTrigger & OnGenerateTimelineObjExt > ( {
358401 id : `regenerate_${ regenerateTimelineToken } ` ,
359402 enable : {
360- start : rundownTimelineResult . timingContext . regenerateTimelineAt ,
403+ start : regenerateTimelineAt ,
361404 } ,
362405 layer : '__timeline_regeneration_trigger__' , // Some unique name, as callbacks need to be on a layer
363406 priority : 1 ,
0 commit comments