diff --git a/packages/timeline-state-resolver/src/integrations/vmix/__tests__/vMixTimelineStateConverter.spec.ts b/packages/timeline-state-resolver/src/integrations/vmix/__tests__/vMixTimelineStateConverter.spec.ts index 66a25af2a..3d88cef0b 100644 --- a/packages/timeline-state-resolver/src/integrations/vmix/__tests__/vMixTimelineStateConverter.spec.ts +++ b/packages/timeline-state-resolver/src/integrations/vmix/__tests__/vMixTimelineStateConverter.spec.ts @@ -8,6 +8,7 @@ import { TimelineContentTypeVMix, TimelineContentVMixAny, VMixInputType, + VMixTransitionType, } from 'timeline-state-resolver-types' import { VMixTimelineStateConverter } from '../vMixTimelineStateConverter' import { VMixOutput, VMixStateDiffer } from '../vMixStateDiffer' @@ -136,6 +137,74 @@ describe('VMixTimelineStateConverter', () => { expect(result.reportedState.inputsAddedByUsAudio[prefixAddedInput(filePath)]).toBeUndefined() }) + it('allows overriding transitions in usual layer order', () => { + const converter = createTestee() + const result = converter.getVMixStateFromTimelineState( + wrapInTimelineState({ + pgm0: wrapInTimelineObject('pgm0', { + deviceType: DeviceType.VMIX, + type: TimelineContentTypeVMix.PROGRAM, + input: 2, + }), + pgm1: wrapInTimelineObject('pgm1', { + deviceType: DeviceType.VMIX, + type: TimelineContentTypeVMix.PROGRAM, + transition: { + duration: 500, + effect: VMixTransitionType.Fade, + }, + }), + }), + { + pgm0: wrapInMapping({ + mappingType: MappingVmixType.Program, + }), + pgm1: wrapInMapping({ + mappingType: MappingVmixType.Program, + }), + } + ) + expect(result.reportedState.mixes[0]?.transition).toEqual({ + duration: 500, + effect: VMixTransitionType.Fade, + }) + expect(result.reportedState.mixes[0]?.program).toEqual(2) + }) + + it('does not allow overriding transitions in reverse layer order', () => { + const converter = createTestee() + const result = converter.getVMixStateFromTimelineState( + wrapInTimelineState({ + pgm0: wrapInTimelineObject('pgm0', { + deviceType: DeviceType.VMIX, + type: TimelineContentTypeVMix.PROGRAM, + transition: { + duration: 500, + effect: VMixTransitionType.Fade, + }, + }), + pgm1: wrapInTimelineObject('pgm1', { + deviceType: DeviceType.VMIX, + type: TimelineContentTypeVMix.PROGRAM, + input: 2, + }), + }), + { + pgm0: wrapInMapping({ + mappingType: MappingVmixType.Program, + }), + pgm1: wrapInMapping({ + mappingType: MappingVmixType.Program, + }), + } + ) + expect(result.reportedState.mixes[0]?.transition).toEqual({ + duration: 0, + effect: VMixTransitionType.Cut, + }) + expect(result.reportedState.mixes[0]?.program).toEqual(2) + }) + // TODO: maybe we can't trust the defaults when adding an input? Make this test pass eventually // it('tracks audio state for mapped inputs added by us', () => { // const converter = createTestee() diff --git a/packages/timeline-state-resolver/src/integrations/vmix/vMixTimelineStateConverter.ts b/packages/timeline-state-resolver/src/integrations/vmix/vMixTimelineStateConverter.ts index baf9b787d..45fb7d9d8 100644 --- a/packages/timeline-state-resolver/src/integrations/vmix/vMixTimelineStateConverter.ts +++ b/packages/timeline-state-resolver/src/integrations/vmix/vMixTimelineStateConverter.ts @@ -71,6 +71,11 @@ export class VMixTimelineStateConverter { this._switchToInput(content.input, deviceState, mixProgram, content.transition) } else if (content.inputLayer) { this._switchToInput(content.inputLayer, deviceState, mixProgram, content.transition, true) + } else if (content.transition) { + const mixState = deviceState.reportedState.mixes[mixProgram] + if (mixState) { + mixState.transition = content.transition + } } } break @@ -238,7 +243,7 @@ export class VMixTimelineStateConverter { mixState.preview = mixState.program mixState.program = input - mixState.transition = transition || { effect: VMixTransitionType.Cut, duration: 0 } + mixState.transition = transition ?? { effect: VMixTransitionType.Cut, duration: 0 } mixState.layerToProgram = layerToProgram } }