Skip to content

Commit 2ff395b

Browse files
committed
wip
1 parent 2fa2c15 commit 2ff395b

File tree

12 files changed

+95
-43
lines changed

12 files changed

+95
-43
lines changed

packages/corelib/src/dataModel/PieceInstance.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export interface PieceInstance {
5151

5252
piece: PieceInstancePiece
5353

54+
// owner: 'part' | 'rundown'
55+
5456
/** A flag to signal a given Piece has been deactivated manually */
5557
disabled?: boolean
5658

packages/corelib/src/playout/__tests__/processAndPrune.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { PieceInstance, PieceInstancePiece, ResolvedPieceInstance } from '../../
55
import { literal } from '../../lib'
66
import { protectString } from '../../protectedString'
77
import {
8+
createPartCurrentTimes,
89
PieceInstanceWithTimings,
910
processAndPrunePieceInstanceTimings,
1011
resolvePrunedPieceInstance,
@@ -61,7 +62,7 @@ describe('processAndPrunePieceInstanceTimings', () => {
6162
},
6263
},
6364
pieceInstances,
64-
nowInPart,
65+
createPartCurrentTimes(nowInPart, 0), // nocommit - this is a hack to avoid changing tests
6566
undefined,
6667
includeVirtual
6768
)

packages/corelib/src/playout/processAndPrune.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,26 @@ export interface PieceInstanceWithTimings extends ReadonlyDeep<PieceInstance> {
6767
priority: number
6868
}
6969

70+
export interface PartCurrentTimes {
71+
/** The current time when this was sampled */
72+
readonly currentTime: number
73+
/** The time the part started playback, if it has begun */
74+
readonly partStartTime: number | null
75+
/** An approximate current time within the part */
76+
readonly nowInPart: number
77+
}
78+
79+
export function createPartCurrentTimes(
80+
currentTime: number,
81+
partStartTime: number | undefined | null
82+
): PartCurrentTimes {
83+
return {
84+
currentTime,
85+
partStartTime: partStartTime ?? null,
86+
nowInPart: typeof partStartTime === 'number' ? currentTime - partStartTime : 0,
87+
}
88+
}
89+
7090
/**
7191
* Process the infinite pieces to determine the start time and a maximum end time for each.
7292
* Any pieces which have no chance of being shown (duplicate start times) are pruned
@@ -76,7 +96,7 @@ export interface PieceInstanceWithTimings extends ReadonlyDeep<PieceInstance> {
7696
export function processAndPrunePieceInstanceTimings(
7797
sourceLayers: SourceLayers,
7898
pieces: ReadonlyDeep<PieceInstance[]>,
79-
nowInPart: number,
99+
partTimes: PartCurrentTimes,
80100
keepDisabledPieces?: boolean,
81101
includeVirtual?: boolean
82102
): PieceInstanceWithTimings[] {
@@ -90,22 +110,28 @@ export function processAndPrunePieceInstanceTimings(
90110
}
91111
}
92112

93-
const groupedPieces = groupByToMapFunc(
94-
keepDisabledPieces ? pieces : pieces.filter((p) => !p.disabled),
113+
// If the part has a start times, we have concrete times for everything so we know how to interleave any absolute timed pieces.
114+
115+
// nocommit For now we can ignore absolute timed pieces,
116+
const relativePieces = pieces.filter((p) => !p.piece.enable.isAbsolute)
117+
118+
const piecesGroupedByExclusiveGroupOrLayer = groupByToMapFunc(
119+
keepDisabledPieces ? relativePieces : relativePieces.filter((p) => !p.disabled),
95120
// At this stage, if a Piece is disabled, the `keepDisabledPieces` must be turned on. If that's the case
96121
// we split out the disabled Pieces onto the sourceLayerId they actually exist on, instead of putting them
97122
// onto the shared "exclusivityGroup" layer. This may cause it to not display "exactly" accurately
98123
// while in the disabled state, but it should keep it from affecting any not-disabled Pieces.
99124
(p) =>
100125
p.disabled ? p.piece.sourceLayerId : exclusiveGroupMap.get(p.piece.sourceLayerId) || p.piece.sourceLayerId
101126
)
102-
for (const pieces of groupedPieces.values()) {
127+
for (const piecesInExclusiveGroupOrLayer of piecesGroupedByExclusiveGroupOrLayer.values()) {
103128
// Group and sort the pieces so that we can step through each point in time
129+
const piecesByStartMap = groupByToMapFunc(piecesInExclusiveGroupOrLayer, (p) => getPieceStartTimeWithinPart(p))
104130
const piecesByStart: Array<[number | 'now', ReadonlyDeep<PieceInstance[]>]> = _.sortBy(
105-
Array.from(groupByToMapFunc(pieces, (p) => getPieceStartTimeWithinPart(p)).entries()).map(([k, v]) =>
131+
Array.from(piecesByStartMap.entries()).map(([k, v]) =>
106132
literal<[number | 'now', ReadonlyDeep<PieceInstance[]>]>([k === 'now' ? 'now' : Number(k), v])
107133
),
108-
([k]) => (k === 'now' ? nowInPart : k)
134+
([k]) => (k === 'now' ? partTimes.nowInPart : k)
109135
)
110136

111137
// Step through time

packages/job-worker/src/playout/infinites.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import {
99
buildPiecesStartingInThisPartQuery,
1010
buildPastInfinitePiecesForThisPartQuery,
1111
} from '@sofie-automation/corelib/dist/playout/infinites'
12-
import { processAndPrunePieceInstanceTimings } from '@sofie-automation/corelib/dist/playout/processAndPrune'
12+
import {
13+
createPartCurrentTimes,
14+
processAndPrunePieceInstanceTimings,
15+
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
1316
import { JobContext } from '../jobs'
1417
import { ReadonlyDeep } from 'type-fest'
1518
import { PlayoutModel } from './model/PlayoutModel'
@@ -253,11 +256,14 @@ export async function syncPlayheadInfinitesForNextPartInstance(
253256
toPartInstance.partInstance.part
254257
)
255258

256-
const nowInPart = getCurrentTime() - (fromPartInstance.partInstance.timings?.plannedStartedPlayback ?? 0)
259+
const partTimes = createPartCurrentTimes(
260+
getCurrentTime(),
261+
fromPartInstance.partInstance.timings?.plannedStartedPlayback
262+
)
257263
const prunedPieceInstances = processAndPrunePieceInstanceTimings(
258264
showStyleBase.sourceLayers,
259265
fromPartInstance.pieceInstances.map((p) => p.pieceInstance),
260-
nowInPart,
266+
partTimes,
261267
undefined,
262268
true
263269
)

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { SourceLayers } from '@sofie-automation/corelib/dist/dataModel/ShowStyle
44
import { JobContext } from '../jobs'
55
import { getCurrentTime } from '../lib'
66
import {
7+
createPartCurrentTimes,
78
processAndPrunePieceInstanceTimings,
89
resolvePrunedPieceInstance,
910
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
@@ -26,15 +27,14 @@ export function getResolvedPiecesForCurrentPartInstance(
2627
): ResolvedPieceInstance[] {
2728
if (now === undefined) now = getCurrentTime()
2829

29-
const partStarted = partInstance.partInstance.timings?.plannedStartedPlayback
30-
const nowInPart = partStarted ? now - partStarted : 0
30+
const partTimes = createPartCurrentTimes(now, partInstance.partInstance.timings?.plannedStartedPlayback)
3131

3232
const preprocessedPieces = processAndPrunePieceInstanceTimings(
3333
sourceLayers,
3434
partInstance.pieceInstances.map((p) => p.pieceInstance),
35-
nowInPart
35+
partTimes
3636
)
37-
return preprocessedPieces.map((instance) => resolvePrunedPieceInstance(nowInPart, instance))
37+
return preprocessedPieces.map((instance) => resolvePrunedPieceInstance(partTimes.nowInPart, instance))
3838
}
3939

4040
export function getResolvedPiecesForPartInstancesOnTimeline(

packages/job-worker/src/playout/take.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import { WrappedShowStyleBlueprint } from '../blueprints/cache'
2222
import { innerStopPieces } from './adlibUtils'
2323
import { reportPartInstanceHasStarted, reportPartInstanceHasStopped } from './timings/partPlayback'
2424
import { convertPartInstanceToBlueprints, convertResolvedPieceInstanceToBlueprints } from '../blueprints/context/lib'
25-
import { processAndPrunePieceInstanceTimings } from '@sofie-automation/corelib/dist/playout/processAndPrune'
25+
import {
26+
createPartCurrentTimes,
27+
processAndPrunePieceInstanceTimings,
28+
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
2629
import { TakeNextPartProps } from '@sofie-automation/corelib/dist/worker/studio'
2730
import { runJobWithPlayoutModel } from './lock'
2831
import _ = require('underscore')
@@ -527,10 +530,11 @@ export function updatePartInstanceOnTake(
527530
}
528531

529532
// calculate and cache playout timing properties, so that we don't depend on the previousPartInstance:
533+
const partTimes = createPartCurrentTimes(getCurrentTime(), null)
530534
const tmpTakePieces = processAndPrunePieceInstanceTimings(
531535
showStyle.sourceLayers,
532536
takePartInstance.pieceInstances.map((p) => p.pieceInstance),
533-
0
537+
partTimes
534538
)
535539
const partPlayoutTimings = playoutModel.calculatePartTimings(currentPartInstance, takePartInstance, tmpTakePieces)
536540

packages/job-worker/src/playout/timeline/generate.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { getResolvedPiecesForPartInstancesOnTimeline } from '../resolvedPieces'
2727
import {
2828
processAndPrunePieceInstanceTimings,
2929
PieceInstanceWithTimings,
30+
createPartCurrentTimes,
3031
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
3132
import { StudioPlayoutModel, StudioPlayoutModelBase } from '../../studio/model/StudioPlayoutModel'
3233
import { getLookeaheadObjects } from '../lookahead'
@@ -244,7 +245,7 @@ export interface SelectedPartInstancesTimelineInfo {
244245
}
245246
export interface SelectedPartInstanceTimelineInfo {
246247
nowInPart: number
247-
partStarted: number | undefined
248+
partStarted: number | null
248249
partInstance: ReadonlyDeep<DBPartInstance>
249250
pieceInstances: PieceInstanceWithTimings[]
250251
calculatedTimings: PartCalculatedTimings
@@ -257,20 +258,19 @@ function getPartInstanceTimelineInfo(
257258
): SelectedPartInstanceTimelineInfo | undefined {
258259
if (!partInstance) return undefined
259260

260-
const partStarted = partInstance.partInstance.timings?.plannedStartedPlayback
261-
const nowInPart = partStarted === undefined ? 0 : currentTime - partStarted
261+
const partTimes = createPartCurrentTimes(currentTime, partInstance.partInstance.timings?.plannedStartedPlayback)
262262
const pieceInstances = processAndPrunePieceInstanceTimings(
263263
sourceLayers,
264264
partInstance.pieceInstances.map((p) => p.pieceInstance),
265-
nowInPart
265+
partTimes
266266
)
267267

268268
const partInstanceWithOverrides = partInstance.getPartInstanceWithQuickLoopOverrides()
269269
return {
270270
partInstance: partInstanceWithOverrides,
271271
pieceInstances,
272-
nowInPart,
273-
partStarted,
272+
nowInPart: partTimes.nowInPart,
273+
partStarted: partTimes.partStartTime,
274274
// Approximate `calculatedTimings`, for the partInstances which already have it cached
275275
calculatedTimings: getPartTimingsOrDefaults(partInstanceWithOverrides, pieceInstances),
276276
}

packages/live-status-gateway/src/collections/pieceInstancesHandler.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import _ = require('underscore')
1111
import { CorelibPubSub } from '@sofie-automation/corelib/dist/pubsub'
1212
import { PartInstanceId, PieceInstanceId } from '@sofie-automation/corelib/dist/dataModel/Ids'
1313
import {
14+
createPartCurrentTimes,
1415
processAndPrunePieceInstanceTimings,
1516
resolvePrunedPieceInstance,
1617
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
@@ -78,25 +79,24 @@ export class PieceInstancesHandler
7879
filterActive: boolean
7980
): ReadonlyDeep<PieceInstance>[] {
8081
// Approximate when 'now' is in the PartInstance, so that any adlibbed Pieces will be timed roughly correctly
81-
const partStarted = partInstance?.timings?.plannedStartedPlayback
82-
const nowInPart = partStarted === undefined ? 0 : Date.now() - partStarted
82+
const partTimes = createPartCurrentTimes(Date.now(), partInstance?.timings?.plannedStartedPlayback)
8383

8484
const prunedPieceInstances = processAndPrunePieceInstanceTimings(
8585
this._sourceLayers,
8686
pieceInstances,
87-
nowInPart,
88-
false,
87+
partTimes,
8988
false
9089
)
9190
if (!filterActive) return prunedPieceInstances
9291

9392
return prunedPieceInstances.filter((pieceInstance) => {
94-
const resolvedPieceInstance = resolvePrunedPieceInstance(nowInPart, pieceInstance)
93+
const resolvedPieceInstance = resolvePrunedPieceInstance(partTimes.nowInPart, pieceInstance)
9594

9695
return (
97-
resolvedPieceInstance.resolvedStart <= nowInPart &&
96+
resolvedPieceInstance.resolvedStart <= partTimes.nowInPart &&
9897
(resolvedPieceInstance.resolvedDuration == null ||
99-
resolvedPieceInstance.resolvedStart + resolvedPieceInstance.resolvedDuration > nowInPart) &&
98+
resolvedPieceInstance.resolvedStart + resolvedPieceInstance.resolvedDuration >
99+
partTimes.nowInPart) &&
100100
pieceInstance.piece.virtual !== true &&
101101
pieceInstance.disabled !== true
102102
)

packages/webui/src/client/lib/rundown.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/Rund
2626
import { literal, protectString, groupByToMap } from './tempLib'
2727
import { getCurrentTime } from './systemTime'
2828
import {
29+
createPartCurrentTimes,
2930
processAndPrunePieceInstanceTimings,
3031
resolvePrunedPieceInstance,
3132
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
@@ -499,19 +500,20 @@ export namespace RundownUtils {
499500
pieceInstanceSimulation
500501
)
501502

502-
const partStarted = partE.instance.timings?.plannedStartedPlayback
503-
const nowInPart = partStarted ? getCurrentTime() - partStarted : 0
504-
503+
const partTimes = createPartCurrentTimes(
504+
getCurrentTime(),
505+
partE.instance.timings?.plannedStartedPlayback
506+
)
505507
const preprocessedPieces = processAndPrunePieceInstanceTimings(
506508
showStyleBase.sourceLayers,
507509
rawPieceInstances,
508-
nowInPart,
510+
partTimes,
509511
includeDisabledPieces
510512
)
511513

512514
// insert items into the timeline for resolution
513515
partE.pieces = preprocessedPieces.map((piece) => {
514-
const resolvedPiece = resolvePrunedPieceInstance(nowInPart, piece)
516+
const resolvedPiece = resolvePrunedPieceInstance(partTimes.nowInPart, piece)
515517
const resPiece: PieceExtended = {
516518
instance: piece,
517519
renderedDuration: resolvedPiece.resolvedDuration ?? null,

packages/webui/src/client/lib/rundownLayouts.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import {
44
RundownPlaylistActivationId,
55
StudioId,
66
} from '@sofie-automation/corelib/dist/dataModel/Ids'
7-
import { processAndPrunePieceInstanceTimings } from '@sofie-automation/corelib/dist/playout/processAndPrune'
7+
import {
8+
createPartCurrentTimes,
9+
processAndPrunePieceInstanceTimings,
10+
} from '@sofie-automation/corelib/dist/playout/processAndPrune'
811
import { UIShowStyleBase } from '@sofie-automation/meteor-lib/dist/api/showStyles'
912
import { PieceInstance } from '@sofie-automation/corelib/dist/dataModel/PieceInstance'
1013
import {
@@ -138,13 +141,11 @@ export function getUnfinishedPieceInstancesReactive(
138141
playlistActivationId: playlistActivationId,
139142
}).fetch()
140143

141-
const nowInPart = partInstance.timings?.plannedStartedPlayback
142-
? now - partInstance.timings.plannedStartedPlayback
143-
: 0
144+
const partTimes = createPartCurrentTimes(now, partInstance.timings?.plannedStartedPlayback)
144145
prospectivePieces = processAndPrunePieceInstanceTimings(
145146
showStyleBase.sourceLayers,
146147
prospectivePieces,
147-
nowInPart
148+
partTimes
148149
)
149150

150151
let nearestEnd = Number.POSITIVE_INFINITY

0 commit comments

Comments
 (0)