Skip to content

Commit ad450c3

Browse files
committed
feat: add object to timeline to trigger a regeneration at point in time
1 parent e52379b commit ad450c3

File tree

17 files changed

+196
-28
lines changed

17 files changed

+196
-28
lines changed

meteor/server/api/__tests__/cleanup.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ async function setDefaultDatatoDB(env: DefaultEnvironment, now: number) {
410410
generationVersions: {} as any,
411411
timelineBlob: '' as any,
412412
timelineHash: '' as any,
413+
regenerateTimelineToken: undefined,
413414
})
414415
await TimelineDatastore.mutableCollection.insertAsync({
415416
_id: getRandomId(),

meteor/server/lib/__tests__/lib.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ describe('server/lib', () => {
4242
generated: 1234,
4343
timelineBlob: serializeTimelineBlob(mystudioObjs),
4444
generationVersions: {} as any,
45+
regenerateTimelineToken: undefined,
4546
})
4647

4748
const mystudio2Objs: Array<TimelineObjGeneric> = [
@@ -62,6 +63,7 @@ describe('server/lib', () => {
6263
generated: 1234,
6364
timelineBlob: serializeTimelineBlob(mystudio2Objs),
6465
generationVersions: {} as any,
66+
regenerateTimelineToken: undefined,
6567
})
6668

6769
const options: SaveIntoDbHooks<any> = {

packages/corelib/src/dataModel/Timeline.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
PartPlaybackCallbackData,
1919
PiecePlaybackCallbackData,
2020
PlayoutChangedType,
21+
TriggerRegenerationCallbackData,
2122
} from '@sofie-automation/shared-lib/dist/peripheralDevice/peripheralDeviceAPI'
2223
export { PartPlaybackCallbackData, PiecePlaybackCallbackData }
2324

@@ -74,6 +75,16 @@ export interface TimelineObjPieceAbstract extends Omit<TimelineObjRundown, 'enab
7475
}
7576
}
7677

78+
export interface TimelineObjRegenerateTrigger extends TimelineObjRundown {
79+
// used for sending callbacks
80+
content: {
81+
deviceType: TSR.DeviceType.ABSTRACT
82+
type: 'callback'
83+
callBack: PlayoutChangedType.TRIGGER_REGENERATION
84+
callBackData: TriggerRegenerationCallbackData
85+
}
86+
}
87+
7788
export function updateLookaheadLayer(obj: TimelineObjRundown): void {
7889
// Set lookaheadForLayer to reference the original layer:
7990
obj.lookaheadForLayer = obj.layer
@@ -102,4 +113,10 @@ export interface TimelineComplete {
102113
timelineBlob: TimelineBlob
103114
/** Version numbers of sofie at the time the timeline was generated */
104115
generationVersions: TimelineCompleteGenerationVersions
116+
117+
/**
118+
* A special regenerate object can be on the timeline to trigger a regeneration at a certain point
119+
* It uses this token to verify that the regeneration request is valid
120+
*/
121+
regenerateTimelineToken: string | undefined
105122
}

packages/job-worker/src/playout/__tests__/playout.test.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ import { DBPartInstance } from '@sofie-automation/corelib/dist/dataModel/PartIns
4343
import { ReadonlyDeep } from 'type-fest'
4444
import { adjustFakeTime, getCurrentTime, useFakeCurrentTime } from '../../__mocks__/time'
4545
import { PieceLifespan } from '@sofie-automation/blueprints-integration'
46-
import { PlayoutChangedType } from '@sofie-automation/shared-lib/dist/peripheralDevice/peripheralDeviceAPI'
46+
import {
47+
PlayoutChangedResult,
48+
PlayoutChangedType,
49+
} from '@sofie-automation/shared-lib/dist/peripheralDevice/peripheralDeviceAPI'
4750
import { ProcessedShowStyleCompound } from '../../jobs'
4851
import { handleOnPlayoutPlaybackChanged } from '../timings'
4952
import { sleep } from '@sofie-automation/shared-lib/dist/lib/lib'
@@ -592,7 +595,7 @@ describe('Playout API', () => {
592595
time: now,
593596
},
594597
},
595-
...pieceInstances.map((pieceInstance) => {
598+
...pieceInstances.map((pieceInstance): PlayoutChangedResult => {
596599
return {
597600
type: PlayoutChangedType.PIECE_PLAYBACK_STARTED,
598601
objId: 'objectId',
@@ -685,7 +688,7 @@ describe('Playout API', () => {
685688
time: now,
686689
},
687690
},
688-
...pieceInstances.map((pieceInstance) => {
691+
...pieceInstances.map((pieceInstance): PlayoutChangedResult => {
689692
return {
690693
type: PlayoutChangedType.PIECE_PLAYBACK_STOPPED,
691694
objId: 'objectId',

packages/job-worker/src/playout/__tests__/resolvedPieces.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ describe('Resolved Pieces', () => {
412412
partStarted,
413413
// Approximate `calculatedTimings`, for the partInstances which already have it cached
414414
calculatedTimings: getPartTimingsOrDefaults(partInstance, pieceInstances),
415+
regenerateTimelineAt: undefined,
415416
}
416417
}
417418

packages/job-worker/src/playout/__tests__/timeline.test.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -355,18 +355,19 @@ async function doOnPlayoutPlaybackChanged(
355355
}
356356
: undefined,
357357
// The piece controlObjects start offset into the part, so need a manual offset
358-
...Object.entries<number | null>(timings.pieceOffsets).map(([pieceInstanceId, offset]) =>
359-
offset !== null
360-
? {
361-
type: PlayoutChangedType.PIECE_PLAYBACK_STARTED,
362-
data: {
363-
partInstanceId: timings.partId,
364-
pieceInstanceId: protectString(pieceInstanceId),
365-
time: timings.baseTime + offset,
366-
},
367-
objId: getPieceControlObjectId(protectString(pieceInstanceId)),
368-
}
369-
: undefined
358+
...Object.entries<number | null>(timings.pieceOffsets).map(
359+
([pieceInstanceId, offset]): PlayoutChangedResult | undefined =>
360+
offset !== null
361+
? {
362+
type: PlayoutChangedType.PIECE_PLAYBACK_STARTED,
363+
data: {
364+
partInstanceId: timings.partId,
365+
pieceInstanceId: protectString(pieceInstanceId),
366+
time: timings.baseTime + offset,
367+
},
368+
objId: getPieceControlObjectId(protectString(pieceInstanceId)),
369+
}
370+
: undefined
370371
),
371372
]),
372373
})

packages/job-worker/src/playout/lookahead/__tests__/lookahead.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ describe('Lookahead', () => {
276276
partStarted: getCurrentTime() + 546,
277277
pieceInstances: ['1', '2'] as any,
278278
calculatedTimings: { inTransitionStart: null } as any,
279+
regenerateTimelineAt: undefined,
279280
}
280281

281282
const expectedPrevious = {
@@ -299,6 +300,7 @@ describe('Lookahead', () => {
299300
partStarted: getCurrentTime() + 865,
300301
pieceInstances: ['3', '4'] as any,
301302
calculatedTimings: { inTransitionStart: null } as any,
303+
regenerateTimelineAt: undefined,
302304
}
303305
const expectedCurrent = {
304306
part: partInstancesInfo.current.partInstance,
@@ -319,6 +321,7 @@ describe('Lookahead', () => {
319321
partStarted: getCurrentTime() + 142,
320322
pieceInstances: ['5'] as any,
321323
calculatedTimings: { inTransitionStart: null } as any,
324+
regenerateTimelineAt: undefined,
322325
}
323326
const expectedNext = {
324327
part: partInstancesInfo.next.partInstance,

packages/job-worker/src/playout/model/implementation/PlayoutModelImpl.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,14 +812,16 @@ export class PlayoutModelImpl extends PlayoutModelReadonlyImpl implements Playou
812812

813813
setTimeline(
814814
timelineObjs: TimelineObjGeneric[],
815-
generationVersions: TimelineCompleteGenerationVersions
815+
generationVersions: TimelineCompleteGenerationVersions,
816+
regenerateTimelineToken: string | undefined
816817
): ReadonlyDeep<TimelineComplete> {
817818
this.timelineImpl = {
818819
_id: this.context.studioId,
819820
timelineHash: getRandomId(), // randomized on every timeline change
820821
generated: getCurrentTime(),
821822
timelineBlob: serializeTimelineBlob(timelineObjs),
822823
generationVersions: generationVersions,
824+
regenerateTimelineToken: regenerateTimelineToken,
823825
}
824826
this.#timelineHasChanged = true
825827

packages/job-worker/src/playout/timeline/__tests__/rundown.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ describe('buildTimelineObjsForRundown', () => {
201201
partInstance: createMockPartInstance('part0'),
202202
pieceInstances: [],
203203
calculatedTimings: DEFAULT_PART_TIMINGS,
204+
regenerateTimelineAt: undefined,
204205
},
205206
}
206207

@@ -221,6 +222,7 @@ describe('buildTimelineObjsForRundown', () => {
221222
partInstance: createMockPartInstance('part0'),
222223
pieceInstances: [createMockPieceInstance('piece0')],
223224
calculatedTimings: DEFAULT_PART_TIMINGS,
225+
regenerateTimelineAt: undefined,
224226
},
225227
}
226228

@@ -254,6 +256,7 @@ describe('buildTimelineObjsForRundown', () => {
254256
),
255257
pieceInstances: [createMockPieceInstance('piece0')],
256258
calculatedTimings: DEFAULT_PART_TIMINGS,
259+
regenerateTimelineAt: undefined,
257260
},
258261
}
259262

@@ -279,13 +282,15 @@ describe('buildTimelineObjsForRundown', () => {
279282
partInstance: createMockPartInstance('part0'),
280283
pieceInstances: [createMockPieceInstance('piece0')],
281284
calculatedTimings: DEFAULT_PART_TIMINGS,
285+
regenerateTimelineAt: undefined,
282286
},
283287
next: {
284288
nowInPart: 0,
285289
partStarted: undefined,
286290
partInstance: createMockPartInstance('part1'),
287291
pieceInstances: [createMockPieceInstance('piece1')],
288292
calculatedTimings: DEFAULT_PART_TIMINGS,
293+
regenerateTimelineAt: undefined,
289294
},
290295
}
291296

@@ -312,13 +317,15 @@ describe('buildTimelineObjsForRundown', () => {
312317
partInstance: createMockPartInstance('part0', { autoNext: true, expectedDuration: 5000 }),
313318
pieceInstances: [createMockPieceInstance('piece0')],
314319
calculatedTimings: DEFAULT_PART_TIMINGS,
320+
regenerateTimelineAt: undefined,
315321
},
316322
next: {
317323
nowInPart: 0,
318324
partStarted: undefined,
319325
partInstance: createMockPartInstance('part1'),
320326
pieceInstances: [createMockPieceInstance('piece1')],
321327
calculatedTimings: DEFAULT_PART_TIMINGS,
328+
regenerateTimelineAt: undefined,
322329
},
323330
}
324331

@@ -353,13 +360,15 @@ describe('buildTimelineObjsForRundown', () => {
353360
),
354361
pieceInstances: [createMockPieceInstance('piece9')],
355362
calculatedTimings: DEFAULT_PART_TIMINGS,
363+
regenerateTimelineAt: undefined,
356364
},
357365
current: {
358366
nowInPart: 1234,
359367
partStarted: 5678,
360368
partInstance: createMockPartInstance('part0'),
361369
pieceInstances: [createMockPieceInstance('piece0')],
362370
calculatedTimings: DEFAULT_PART_TIMINGS,
371+
regenerateTimelineAt: undefined,
363372
},
364373
}
365374

@@ -395,6 +404,7 @@ describe('buildTimelineObjsForRundown', () => {
395404
),
396405
pieceInstances: [createMockPieceInstance('piece9'), createMockPieceInstance('piece8')],
397406
calculatedTimings: DEFAULT_PART_TIMINGS,
407+
regenerateTimelineAt: undefined,
398408
},
399409
current: {
400410
nowInPart: 1234,
@@ -409,6 +419,7 @@ describe('buildTimelineObjsForRundown', () => {
409419
fromPartPostroll: 400,
410420
fromPartKeepalive: 100,
411421
},
422+
regenerateTimelineAt: undefined,
412423
},
413424
}
414425

@@ -448,6 +459,7 @@ describe('buildTimelineObjsForRundown', () => {
448459
}),
449460
],
450461
calculatedTimings: DEFAULT_PART_TIMINGS,
462+
regenerateTimelineAt: undefined,
451463
},
452464
current: {
453465
nowInPart: 1234,
@@ -462,6 +474,7 @@ describe('buildTimelineObjsForRundown', () => {
462474
fromPartPostroll: 400,
463475
fromPartKeepalive: 100,
464476
},
477+
regenerateTimelineAt: undefined,
465478
},
466479
}
467480

@@ -488,6 +501,7 @@ describe('buildTimelineObjsForRundown', () => {
488501
partInstance: createMockPartInstance('part0', { autoNext: true, expectedDuration: 5000 }),
489502
pieceInstances: [createMockPieceInstance('piece0')],
490503
calculatedTimings: DEFAULT_PART_TIMINGS,
504+
regenerateTimelineAt: undefined,
491505
},
492506
next: {
493507
nowInPart: 0,
@@ -502,6 +516,7 @@ describe('buildTimelineObjsForRundown', () => {
502516
fromPartPostroll: 400,
503517
fromPartKeepalive: 100,
504518
},
519+
regenerateTimelineAt: undefined,
505520
},
506521
}
507522

@@ -543,6 +558,7 @@ describe('buildTimelineObjsForRundown', () => {
543558
}),
544559
],
545560
calculatedTimings: DEFAULT_PART_TIMINGS,
561+
regenerateTimelineAt: undefined,
546562
},
547563
next: {
548564
nowInPart: 0,
@@ -565,6 +581,7 @@ describe('buildTimelineObjsForRundown', () => {
565581
fromPartPostroll: 400,
566582
fromPartKeepalive: 100,
567583
},
584+
regenerateTimelineAt: undefined,
568585
},
569586
}
570587

@@ -597,6 +614,7 @@ describe('buildTimelineObjsForRundown', () => {
597614
),
598615
pieceInstances: [createMockPieceInstance('piece9')],
599616
calculatedTimings: DEFAULT_PART_TIMINGS,
617+
regenerateTimelineAt: undefined,
600618
}
601619

602620
it('infinite starting in current', () => {
@@ -613,6 +631,7 @@ describe('buildTimelineObjsForRundown', () => {
613631
createMockInfinitePieceInstance('piece1', {}, { plannedStartedPlayback: undefined }),
614632
],
615633
calculatedTimings: DEFAULT_PART_TIMINGS,
634+
regenerateTimelineAt: undefined,
616635
},
617636
}
618637

@@ -641,6 +660,7 @@ describe('buildTimelineObjsForRundown', () => {
641660
partInstance: createMockPartInstance('part0'),
642661
pieceInstances: [createMockPieceInstance('piece0')],
643662
calculatedTimings: DEFAULT_PART_TIMINGS,
663+
regenerateTimelineAt: undefined,
644664
},
645665
}
646666

@@ -669,6 +689,7 @@ describe('buildTimelineObjsForRundown', () => {
669689
partInstance: createMockPartInstance('part0'),
670690
pieceInstances: [createMockPieceInstance('piece0')],
671691
calculatedTimings: DEFAULT_PART_TIMINGS,
692+
regenerateTimelineAt: undefined,
672693
},
673694
}
674695

@@ -696,6 +717,7 @@ describe('buildTimelineObjsForRundown', () => {
696717
partInstance: createMockPartInstance('part0'),
697718
pieceInstances: [createMockPieceInstance('piece0'), continueInfinitePiece(infinitePiece)],
698719
calculatedTimings: DEFAULT_PART_TIMINGS,
720+
regenerateTimelineAt: undefined,
699721
},
700722
}
701723

@@ -727,6 +749,7 @@ describe('buildTimelineObjsForRundown', () => {
727749
),
728750
pieceInstances: [createMockPieceInstance('piece0'), infinitePiece],
729751
calculatedTimings: DEFAULT_PART_TIMINGS,
752+
regenerateTimelineAt: undefined,
730753
},
731754
next: {
732755
nowInPart: 0,
@@ -742,6 +765,7 @@ describe('buildTimelineObjsForRundown', () => {
742765
),
743766
pieceInstances: [createMockPieceInstance('piece1'), continueInfinitePiece(infinitePiece)],
744767
calculatedTimings: DEFAULT_PART_TIMINGS,
768+
regenerateTimelineAt: undefined,
745769
},
746770
}
747771

@@ -771,6 +795,7 @@ describe('buildTimelineObjsForRundown', () => {
771795
),
772796
pieceInstances: [createMockPieceInstance('piece0'), createMockInfinitePieceInstance('piece6')],
773797
calculatedTimings: DEFAULT_PART_TIMINGS,
798+
regenerateTimelineAt: undefined,
774799
},
775800
next: {
776801
nowInPart: 0,
@@ -789,6 +814,7 @@ describe('buildTimelineObjsForRundown', () => {
789814
...DEFAULT_PART_TIMINGS,
790815
fromPartKeepalive: 100,
791816
},
817+
regenerateTimelineAt: undefined,
792818
},
793819
}
794820

@@ -821,6 +847,7 @@ describe('buildTimelineObjsForRundown', () => {
821847
createMockInfinitePieceInstance('piece6', { excludeDuringPartKeepalive: true }),
822848
],
823849
calculatedTimings: DEFAULT_PART_TIMINGS,
850+
regenerateTimelineAt: undefined,
824851
},
825852
next: {
826853
nowInPart: 0,
@@ -839,6 +866,7 @@ describe('buildTimelineObjsForRundown', () => {
839866
...DEFAULT_PART_TIMINGS,
840867
fromPartKeepalive: 100,
841868
},
869+
regenerateTimelineAt: undefined,
842870
},
843871
}
844872

0 commit comments

Comments
 (0)