UNPKG

timeline-state-resolver

Version:
797 lines • 39.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VizMSEDevice = void 0; const _ = require("underscore"); const device_1 = require("./../../devices/device"); const timeline_state_resolver_types_1 = require("timeline-state-resolver-types"); const v_connection_1 = require("@tv2media/v-connection"); const doOnTime_1 = require("../../devices/doOnTime"); const lib_1 = require("../../lib"); const msehttp_1 = require("@tv2media/v-connection/dist/msehttp"); const vizMSEManager_1 = require("./vizMSEManager"); const types_1 = require("./types"); /** The ideal time to prepare elements before going on air */ const IDEAL_PREPARE_TIME = 1000; /** Minimum time to wait after preparing elements */ const PREPARE_TIME_WAIT = 50; /** * This class is used to interface with a vizRT Media Sequence Editor, through the v-connection library. * It features playing both "internal" graphics element and vizPilot elements. */ class VizMSEDevice extends device_1.DeviceWithState { constructor(deviceId, deviceOptions, getCurrentTime) { super(deviceId, deviceOptions, getCurrentTime); this._commandReceiver = this._defaultCommandReceiver.bind(this); this._vizMSEConnected = false; if (deviceOptions.options) { if (deviceOptions.commandReceiver) this._commandReceiver = deviceOptions.commandReceiver; } this._doOnTime = new doOnTime_1.DoOnTime(() => { return this.getCurrentTime(); }, doOnTime_1.SendMode.IN_ORDER, this._deviceOptions); this.handleDoOnTime(this._doOnTime, 'VizMSE'); this._doOnTimeBurst = new doOnTime_1.DoOnTime(() => { return this.getCurrentTime(); }, doOnTime_1.SendMode.BURST, this._deviceOptions); this.handleDoOnTime(this._doOnTimeBurst, 'VizMSE.burst'); } async init(initOptions, activeRundownPlaylistId) { this._initOptions = initOptions; if (!this._initOptions.host) throw new Error('VizMSE bad option: host'); if (!this._initOptions.profile) throw new Error('VizMSE bad option: profile'); this._vizMSE = (0, v_connection_1.createMSE)(this._initOptions.host, this._initOptions.restPort, this._initOptions.wsPort); this._vizmseManager = new vizMSEManager_1.VizMSEManager(this, this._vizMSE, this._initOptions.preloadAllElements ?? false, this._initOptions.onlyPreloadActivePlaylist ?? false, this._initOptions.purgeUnknownElements ?? false, this._initOptions.autoLoadInternalElements ?? false, this._initOptions.engineRestPort, this._initOptions.showDirectoryPath ?? '', initOptions.profile, initOptions.playlistID); this._vizmseManager.on('connectionChanged', (connected) => this.connectionChanged(connected)); this._vizmseManager.on('updateMediaObject', (docId, doc) => this.emit('updateMediaObject', this.deviceId, docId, doc)); this._vizmseManager.on('clearMediaObjects', () => this.emit('clearMediaObjects', this.deviceId)); this._vizmseManager.on('info', (str) => this.emit('info', 'VizMSE: ' + str)); this._vizmseManager.on('warning', (str) => this.emit('warning', 'VizMSE: ' + str)); this._vizmseManager.on('error', (e) => this.emit('error', 'VizMSE', typeof e === 'string' ? new Error(e) : e)); this._vizmseManager.on('debug', (...args) => this.emitDebug(...args)); this._vizmseManager .initializeRundown(activeRundownPlaylistId) .then(() => { // reset any states we had to re-enforce them this.clearStates(); this.emit('resyncStates'); }) .catch((e) => this.emit('error', 'Failed to initialise Viz Rundown', e)); return true; } /** * Terminates the device safely such that things can be garbage collected. */ async terminate() { if (this._vizmseManager) { await this._vizmseManager.terminate(); this._vizmseManager.removeAllListeners(); delete this._vizmseManager; } this._doOnTime.dispose(); } /** Called by the Conductor a bit before a .handleState is called */ prepareForHandleState(newStateTime) { // clear any queued commands later than this time: this._doOnTime.clearQueueNowAndAfter(newStateTime); this.cleanUpStates(0, newStateTime); } /** * Generates an array of VizMSE commands by comparing the newState against the oldState, or the current device state. */ handleState(newState, newMappings) { super.onHandleState(newState, newMappings); // check if initialized: if (!this._vizmseManager || !this._vizmseManager.initialized) { this.emit('warning', 'VizMSE.v-connection not initialized yet'); return; } const previousStateTime = Math.max(this.getCurrentTime(), newState.time); const oldVizMSEState = (this.getStateBefore(previousStateTime) || { state: { time: 0, layer: {} } }) .state; const convertTrace = (0, lib_1.startTrace)(`device:convertState`, { deviceId: this.deviceId }); const newVizMSEState = this.convertStateToVizMSE(newState, newMappings); this.emit('timeTrace', (0, lib_1.endTrace)(convertTrace)); const diffTrace = (0, lib_1.startTrace)(`device:diffState`, { deviceId: this.deviceId }); const commandsToAchieveState = this._diffStates(oldVizMSEState, newVizMSEState, newState.time); this.emit('timeTrace', (0, lib_1.endTrace)(diffTrace)); // clear any queued commands later than this time: this._doOnTime.clearQueueNowAndAfter(previousStateTime); // add the new commands to the queue this._addToQueue(commandsToAchieveState); // store the new state, for later use: this.setState(newVizMSEState, newState.time); } /** * Clear any scheduled commands after this time * @param clearAfterTime */ clearFuture(clearAfterTime) { this._doOnTime.clearQueueAfter(clearAfterTime); } get canConnect() { return true; } get connected() { return this._vizMSEConnected; } async activate(payload) { if (!payload || !payload.activeRundownPlaylistId) { return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Error, response: (0, lib_1.t)('Invalid payload'), }; } if (!this._vizmseManager) { return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Error, response: (0, lib_1.t)('Unable to activate vizMSE, not initialized yet'), }; } const activeRundownPlaylistId = payload.activeRundownPlaylist; const previousPlaylistId = this._vizmseManager?.activeRundownPlaylistId; await this._vizmseManager.activate(activeRundownPlaylistId); if (!payload.clearAll) { return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Ok, }; } this.clearStates(); if (this._initOptions && activeRundownPlaylistId !== previousPlaylistId) { if (this._initOptions.clearAllCommands && this._initOptions.clearAllCommands.length) { await this._vizmseManager.clearEngines({ type: types_1.VizMSECommandType.CLEAR_ALL_ENGINES, time: this.getCurrentTime(), timelineObjId: 'makeReady', channels: 'all', commands: this._initOptions.clearAllCommands, }); } } return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Ok, }; } async purgeRundown(clearAll) { await this._vizmseManager?.purgeRundown(clearAll); } async clearEngines() { await this._vizmseManager?.clearEngines({ type: types_1.VizMSECommandType.CLEAR_ALL_ENGINES, time: this.getCurrentTime(), timelineObjId: 'clearAllEnginesAction', channels: 'all', commands: this._initOptions?.clearAllCommands || [], }); } async resetViz(payload) { await this.purgeRundown(true); // note - this might not be 100% necessary await this.clearEngines(); await this._vizmseManager?.activate(payload?.activeRundownPlaylistId); // lastly make sure we reset so timeline state is sent again this.clearStates(); this.emit('resetResolver'); } async executeAction(actionId, payload) { switch (actionId) { case timeline_state_resolver_types_1.VizMSEActions.PurgeRundown: await this.purgeRundown(true); return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Ok }; case timeline_state_resolver_types_1.VizMSEActions.Activate: return this.activate(payload); case timeline_state_resolver_types_1.VizMSEActions.StandDown: return this.executeStandDown(); case timeline_state_resolver_types_1.VizMSEActions.ClearAllEngines: await this.clearEngines(); return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Ok }; case timeline_state_resolver_types_1.VizMSEActions.VizReset: await this.resetViz(payload ?? {}); return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Ok }; default: return (0, lib_1.actionNotFoundMessage)(actionId); } } get deviceType() { return timeline_state_resolver_types_1.DeviceType.VIZMSE; } get deviceName() { return `VizMSE ${this._vizMSE ? this._vizMSE.hostname : 'Uninitialized'}`; } get queue() { return this._doOnTime.getQueue(); } get supportsExpectedPlayoutItems() { return true; } handleExpectedPlayoutItems(expectedPlayoutItems) { this.emitDebug('VIZDEBUG: handleExpectedPlayoutItems called'); if (this._vizmseManager) { this.emitDebug('VIZDEBUG: manager exists'); this._vizmseManager.setExpectedPlayoutItems(expectedPlayoutItems); } } getCurrentState() { return (this.getState() || { state: undefined }).state; } connectionChanged(connected) { if (connected === true || connected === false) this._vizMSEConnected = connected; if (connected === false) { this.emit('clearMediaObjects', this.deviceId); } this.emit('connectionChanged', this.getStatus()); } /** * Takes a timeline state and returns a VizMSE State that will work with the state lib. * @param timelineState The timeline state to generate from. */ convertStateToVizMSE(timelineState, mappings) { const state = { time: timelineState.time, layer: {}, }; _.each(timelineState.layers, (layer, layerName) => { const layerExt = layer; let foundMapping = mappings[layerName]; let isLookahead = false; if (!foundMapping && layerExt.isLookahead && layerExt.lookaheadForLayer) { foundMapping = mappings[layerExt.lookaheadForLayer]; isLookahead = true; } if (foundMapping && foundMapping.device === timeline_state_resolver_types_1.DeviceType.VIZMSE && foundMapping.deviceId === this.deviceId) { if (layer.content) { const content = layer.content; switch (content.type) { case timeline_state_resolver_types_1.TimelineContentTypeVizMSE.LOAD_ALL_ELEMENTS: state.layer[layerName] = (0, lib_1.literal)({ timelineObjId: layer.id, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.LOAD_ALL_ELEMENTS, }); break; case timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CLEAR_ALL_ELEMENTS: { // Special case: clear all graphics: const showId = this._vizmseManager?.resolveShowNameToId(content.showName); if (!showId) { this.emit('warning', `convertStateToVizMSE: Unable to find Show Id for Clear-All template and Show Name "${content.showName}"`); break; } state.isClearAll = { timelineObjId: layer.id, showId, channelsToSendCommands: content.channelsToSendCommands, }; break; } case timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONTINUE: state.layer[layerName] = (0, lib_1.literal)({ timelineObjId: layer.id, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONTINUE, direction: content.direction, reference: content.reference, }); break; case timeline_state_resolver_types_1.TimelineContentTypeVizMSE.INITIALIZE_SHOWS: state.layer[layerName] = (0, lib_1.literal)({ timelineObjId: layer.id, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.INITIALIZE_SHOWS, showIds: _.compact(content.showNames.map((showName) => this._vizmseManager?.resolveShowNameToId(showName))), }); break; case timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CLEANUP_SHOWS: state.layer[layerName] = (0, lib_1.literal)({ timelineObjId: layer.id, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CLEANUP_SHOWS, showIds: _.compact(content.showNames.map((showName) => this._vizmseManager?.resolveShowNameToId(showName))), }); break; case timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONCEPT: state.layer[layerName] = (0, lib_1.literal)({ timelineObjId: layer.id, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONCEPT, concept: content.concept, }); break; default: { const stateLayer = this._contentToStateLayer(layer.id, content); if (stateLayer) { if (isLookahead) stateLayer.lookahead = true; state.layer[layerName] = stateLayer; } break; } } } } }); if (state.isClearAll) { // clear rest of state: state.layer = {}; } // Fix references: _.each(state.layer, (layer) => { if (layer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONTINUE) { const otherLayer = state.layer[layer.reference]; if (otherLayer) { if (otherLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL || otherLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT) { layer.referenceContent = otherLayer; } else { // it's not possible to reference that kind of object this.emit('warning', `object "${layer.timelineObjId}" of contentType="${layer.contentType}", cannot reference object "${otherLayer.timelineObjId}" on layer "${layer.reference}" of contentType="${otherLayer.contentType}" `); } } } }); return state; } _contentToStateLayer(timelineObjId, content) { if (content.type === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL) { const showId = this._vizmseManager?.resolveShowNameToId(content.showName); if (!showId) { this.emit('warning', `_contentToStateLayer: Unable to find Show Id for template "${content.templateName}" and Show Name "${content.showName}"`); return undefined; } const o = { timelineObjId: timelineObjId, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, continueStep: content.continueStep, cue: content.cue, outTransition: content.outTransition, templateName: content.templateName, templateData: content.templateData, channelName: content.channelName, delayTakeAfterOutTransition: content.delayTakeAfterOutTransition, showId, }; return o; } else if (content.type === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT) { const o = { timelineObjId: timelineObjId, contentType: timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT, continueStep: content.continueStep, cue: content.cue, outTransition: content.outTransition, templateVcpId: content.templateVcpId, channelName: content.channelName, delayTakeAfterOutTransition: content.delayTakeAfterOutTransition, }; return o; } return undefined; } /** * Prepares the physical device for playout. * @param okToDestroyStuff Whether it is OK to do things that affects playout visibly */ async makeReady(okToDestroyStuff, activeRundownPlaylistId) { const previousPlaylistId = this._vizmseManager?.activeRundownPlaylistId; if (this._vizmseManager) { await this._vizmseManager.cleanupAllShows(); await this._vizmseManager.activate(activeRundownPlaylistId); } else throw new Error(`Unable to activate vizMSE, not initialized yet!`); if (okToDestroyStuff) { // reset our own state(s): this.clearStates(); if (this._vizmseManager) { if (this._initOptions && activeRundownPlaylistId !== previousPlaylistId) { if (this._initOptions.clearAllOnMakeReady && this._initOptions.clearAllCommands && this._initOptions.clearAllCommands.length) { await this._vizmseManager.clearEngines({ type: types_1.VizMSECommandType.CLEAR_ALL_ENGINES, time: this.getCurrentTime(), timelineObjId: 'makeReady', channels: 'all', commands: this._initOptions.clearAllCommands, }); } } } else throw new Error(`Unable to activate vizMSE, not initialized yet!`); } } async executeStandDown() { if (this._vizmseManager) { if (!this._initOptions || !this._initOptions.dontDeactivateOnStandDown) { await this._vizmseManager.deactivate(); } else { this._vizmseManager.standDownActiveRundown(); // because we still want to stop monitoring expectedPlayoutItems } } return { result: timeline_state_resolver_types_1.ActionExecutionResultCode.Ok, }; } /** * The standDown event could be triggered at a time after broadcast * @param okToDestroyStuff If true, the device may do things that might affect the visible output */ async standDown(okToDestroyStuff) { if (okToDestroyStuff) { return this.executeStandDown().then(() => undefined); } } getStatus() { let statusCode = device_1.StatusCode.GOOD; const messages = []; if (!this._vizMSEConnected) { statusCode = device_1.StatusCode.BAD; messages.push('Not connected'); } else if (this._vizmseManager) { if (this._vizmseManager.notLoadedCount > 0 || this._vizmseManager.loadingCount > 0) { statusCode = device_1.StatusCode.WARNING_MINOR; messages.push(`Got ${this._vizmseManager.notLoadedCount} elements not yet loaded to the Viz Engine (${this._vizmseManager.loadingCount} are currently loading)`); } if (this._vizmseManager.enginesDisconnected.length) { statusCode = device_1.StatusCode.BAD; this._vizmseManager.enginesDisconnected.forEach((engine) => { messages.push(`Viz Engine ${engine} disconnected`); }); } } return { statusCode: statusCode, messages: messages, active: this.isActive, }; } /** * Compares the new timeline-state with the old one, and generates commands to account for the difference */ _diffStates(oldState, newState, time) { const highPrioCommands = []; const lowPrioCommands = []; const addCommand = (command, lowPriority) => { ; (lowPriority ? lowPrioCommands : highPrioCommands).push(command); }; /** The time of when to run "preparation" commands */ let prepareTime = Math.min(time, Math.max(time - IDEAL_PREPARE_TIME, oldState.time + PREPARE_TIME_WAIT // earliset possible prepareTime )); if (prepareTime < this.getCurrentTime()) { // Only to not emit an unnessesary slowCommand event prepareTime = this.getCurrentTime(); } if (time < prepareTime) { prepareTime = time - 10; } _.each(newState.layer, (newLayer, layerId) => { const oldLayer = oldState.layer[layerId]; if (newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.LOAD_ALL_ELEMENTS) { if (!oldLayer || !_.isEqual(newLayer, oldLayer)) { addCommand((0, lib_1.literal)({ timelineObjId: newLayer.timelineObjId, fromLookahead: newLayer.lookahead, layerId: layerId, type: types_1.VizMSECommandType.LOAD_ALL_ELEMENTS, time: time, }), newLayer.lookahead); } } else if (newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONTINUE) { if ((!oldLayer || !_.isEqual(newLayer, oldLayer)) && newLayer.referenceContent) { const props = { timelineObjId: newLayer.timelineObjId, fromLookahead: newLayer.lookahead, layerId: layerId, content: vizMSEManager_1.VizMSEManager.getPlayoutItemContentFromLayer(newLayer.referenceContent), }; if ((newLayer.direction || 1) === 1) { addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.CONTINUE_ELEMENT, time: time, }), newLayer.lookahead); } else { addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.CONTINUE_ELEMENT_REVERSE, time: time, }), newLayer.lookahead); } } } else if (newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.INITIALIZE_SHOWS) { if (!oldLayer || !_.isEqual(newLayer, oldLayer)) { addCommand((0, lib_1.literal)({ type: types_1.VizMSECommandType.INITIALIZE_SHOWS, timelineObjId: newLayer.timelineObjId, showIds: newLayer.showIds, time: time, }), newLayer.lookahead); } } else if (newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CLEANUP_SHOWS) { if (!oldLayer || !_.isEqual(newLayer, oldLayer)) { const command = (0, lib_1.literal)({ type: types_1.VizMSECommandType.CLEANUP_SHOWS, timelineObjId: newLayer.timelineObjId, showIds: newLayer.showIds, time: time, }); addCommand(command, newLayer.lookahead); } } else if (newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.CONCEPT) { if (!oldLayer || !_.isEqual(newLayer, oldLayer)) { addCommand((0, lib_1.literal)({ concept: newLayer.concept, type: types_1.VizMSECommandType.SET_CONCEPT, time: time, timelineObjId: newLayer.timelineObjId, })); } } else { const props = { timelineObjId: newLayer.timelineObjId, fromLookahead: newLayer.lookahead, layerId: layerId, content: vizMSEManager_1.VizMSEManager.getPlayoutItemContentFromLayer(newLayer), }; if (!oldLayer || !_.isEqual(_.omit(newLayer, ['continueStep', 'timelineObjId', 'outTransition']), _.omit(oldLayer, ['continueStep', 'timelineObjId', 'outTransition']))) { if (newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL || newLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT) { // Maybe prepare the element first: addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.PREPARE_ELEMENT, time: prepareTime, }), newLayer.lookahead); if (newLayer.cue) { // Cue the element addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.CUE_ELEMENT, time: time, }), newLayer.lookahead); } else { // Start playing element addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.TAKE_ELEMENT, time: time, }), newLayer.lookahead); } } } else if ((oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL || oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT) && (newLayer.continueStep || 0) > (oldLayer.continueStep || 0)) { // An increase in continueStep should result in triggering a continue: addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.CONTINUE_ELEMENT, time: time, }), newLayer.lookahead); } else if ((oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL || oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT) && (newLayer.continueStep || 0) < (oldLayer.continueStep || 0)) { // A decrease in continueStep should result in triggering a continue: addCommand((0, lib_1.literal)({ ...props, type: types_1.VizMSECommandType.CONTINUE_ELEMENT_REVERSE, time: time, }), newLayer.lookahead); } } }); _.each(oldState.layer, (oldLayer, layerId) => { const newLayer = newState.layer[layerId]; if (!newLayer) { if (oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL || oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_PILOT) { // Stopped playing addCommand((0, lib_1.literal)({ type: types_1.VizMSECommandType.TAKEOUT_ELEMENT, time: time, timelineObjId: oldLayer.timelineObjId, fromLookahead: oldLayer.lookahead, layerId: layerId, transition: oldLayer && oldLayer.outTransition, content: vizMSEManager_1.VizMSEManager.getPlayoutItemContentFromLayer(oldLayer), }), oldLayer.lookahead); } else if (oldLayer.contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.INITIALIZE_SHOWS) { addCommand((0, lib_1.literal)({ type: types_1.VizMSECommandType.INITIALIZE_SHOWS, timelineObjId: oldLayer.timelineObjId, showIds: [], time: time, }), oldLayer.lookahead); } } }); if (newState.isClearAll && !oldState.isClearAll) { // Special: clear all graphics const clearingCommands = []; const templateName = this._initOptions && this._initOptions.clearAllTemplateName; if (!templateName) { this.emit('warning', `vizMSE: initOptions.clearAllTemplateName is not set!`); } else { // Start playing special element: clearingCommands.push((0, lib_1.literal)({ timelineObjId: newState.isClearAll.timelineObjId, time: time, type: types_1.VizMSECommandType.CLEAR_ALL_ELEMENTS, templateName: templateName, showId: newState.isClearAll.showId, })); } if (newState.isClearAll.channelsToSendCommands && this._initOptions && this._initOptions.clearAllCommands && this._initOptions.clearAllCommands.length) { // Send special commands to the engines: clearingCommands.push((0, lib_1.literal)({ timelineObjId: newState.isClearAll.timelineObjId, time: time, type: types_1.VizMSECommandType.CLEAR_ALL_ENGINES, channels: newState.isClearAll.channelsToSendCommands, commands: this._initOptions.clearAllCommands, })); } return clearingCommands; } const sortCommands = (commands) => { // Sort the commands so that take out:s are run first return commands.sort((a, b) => { if (a.type === types_1.VizMSECommandType.TAKEOUT_ELEMENT && b.type !== types_1.VizMSECommandType.TAKEOUT_ELEMENT) return -1; if (a.type !== types_1.VizMSECommandType.TAKEOUT_ELEMENT && b.type === types_1.VizMSECommandType.TAKEOUT_ELEMENT) return 1; return 0; }); }; sortCommands(highPrioCommands); sortCommands(lowPrioCommands); const concatCommands = sortCommands(highPrioCommands.concat(lowPrioCommands)); let highestDelay = 0; concatCommands.forEach((command) => { if (command.type === types_1.VizMSECommandType.TAKEOUT_ELEMENT) { if (command.transition && command.transition.delay) { if (command.transition.delay > highestDelay) { highestDelay = command.transition.delay; } } } }); if (highestDelay > 0) { concatCommands.forEach((command, index) => { if (command.type === types_1.VizMSECommandType.TAKE_ELEMENT && command.layerId && (newState.layer[command.layerId].contentType === timeline_state_resolver_types_1.TimelineContentTypeVizMSE.ELEMENT_INTERNAL || !!newState.layer[command.layerId].delayTakeAfterOutTransition)) { ; concatCommands[index].transition = { type: timeline_state_resolver_types_1.VIZMSETransitionType.DELAY, delay: highestDelay + 20, }; } }); } if (concatCommands.length) { this.emitDebug(`VIZMSE: COMMANDS: ${JSON.stringify(sortCommands(concatCommands))}`); } return sortCommands(concatCommands); } async _doCommand(command, context, timlineObjId) { const time = this.getCurrentTime(); return this._commandReceiver(time, command, context, timlineObjId); } /** * Add commands to queue, to be executed at the right time */ _addToQueue(commandsToAchieveState) { _.each(commandsToAchieveState, (cmd) => { this._doOnTime.queue(cmd.time, cmd.layerId, async (c) => { return this._doCommand(c.cmd, c.cmd.type + '_' + c.cmd.timelineObjId, c.cmd.timelineObjId); }, { cmd: cmd }); this._doOnTimeBurst.queue(cmd.time, undefined, async (c) => { if (c.cmd.type === types_1.VizMSECommandType.TAKE_ELEMENT && !c.cmd.fromLookahead) { if (this._vizmseManager && c.cmd.layerId) { this._vizmseManager.clearAllWaitWithLayer(c.cmd.layerId); } } return Promise.resolve(); }, { cmd: cmd }); }); } /** * Sends commands to the VizMSE server * @param time deprecated * @param cmd Command to execute */ async _defaultCommandReceiver(_time, cmd, context, timelineObjId) { const cwc = { context: context, timelineObjId: timelineObjId, command: cmd, }; this.emitDebug(cwc); try { if (!this._vizmseManager) { throw new Error(`Not initialized yet`); } switch (cmd.type) { case types_1.VizMSECommandType.PREPARE_ELEMENT: await this._vizmseManager.prepareElement(cmd); break; case types_1.VizMSECommandType.CUE_ELEMENT: await this._vizmseManager.cueElement(cmd); break; case types_1.VizMSECommandType.TAKE_ELEMENT: await this._vizmseManager.takeElement(cmd); break; case types_1.VizMSECommandType.TAKEOUT_ELEMENT: await this._vizmseManager.takeoutElement(cmd); break; case types_1.VizMSECommandType.CONTINUE_ELEMENT: await this._vizmseManager.continueElement(cmd); break; case types_1.VizMSECommandType.CONTINUE_ELEMENT_REVERSE: await this._vizmseManager.continueElementReverse(cmd); break; case types_1.VizMSECommandType.LOAD_ALL_ELEMENTS: await this._vizmseManager.loadAllElements(cmd); break; case types_1.VizMSECommandType.CLEAR_ALL_ELEMENTS: await this._vizmseManager.clearAll(cmd); break; case types_1.VizMSECommandType.CLEAR_ALL_ENGINES: await this._vizmseManager.clearEngines(cmd); break; case types_1.VizMSECommandType.SET_CONCEPT: await this._vizmseManager.setConcept(cmd); break; case types_1.VizMSECommandType.INITIALIZE_SHOWS: await this._vizmseManager.initializeShows(cmd); break; case types_1.VizMSECommandType.CLEANUP_SHOWS: await this._vizmseManager.cleanupShows(cmd); break; default: // @ts-ignore never throw new Error(`Unsupported command type "${cmd.type}"`); } } catch (e) { const error = e; let errorString = error && error.message ? error.message : error.toString(); if (error?.stack) { errorString += '\n' + error.stack; } if (e instanceof msehttp_1.HTTPClientError || e instanceof msehttp_1.HTTPServerError) { errorString += `\n\nPath: ${e.path}` + '\n\n' + (e.body ?? '[No request body present]') + `\n\nStatus: ${e.status}` + `\nResponse:\n ${e.response}`; } this.emit('commandError', new Error(errorString), cwc); } } ignoreWaitsInTests() { if (!this._vizmseManager) throw new Error('_vizmseManager not set'); this._vizmseManager.ignoreAllWaits = true; } } exports.VizMSEDevice = VizMSEDevice; //# sourceMappingURL=index.js.map