import { create as XMLBuilder } from 'xmlbuilder' ; import { Options as OptionsNS } from './AMCPConnectionOptions' ; import CasparCGVersion = OptionsNS . CasparCGVersion ; /***/ export namespace Config { /***/ export namespace v2xx { /***/ export class CasparCGConfigVO { public channelGrid : boolean = false ; public flash : v2xx . Flash = new v2xx . Flash ( ) ; public templateHosts : Array < v2xx . TemplateHost > = [ ] ; } /***/ export class Channel { public _type : string = 'channel' ; public videoMode : string = 'PAL' ; public consumers : Array < Consumer > = [ ] ; public straightAlphaOutput : boolean = false ; public channelLayout : string = 'stereo' ; } /***/ export class Consumer { public _type : string ; } /***/ export class DecklinkConsumer extends Consumer { _type = 'decklink' ; public device : number = 1 ; public keyDevice : Number | null = null ; public embeddedAudio : boolean = false ; public channelLayout : string = 'stereo' ; public latency : string = 'normal' ; public keyer : string = 'external' ; public keyOnly : boolean = false ; public bufferDepth : number = 3 ; } /***/ export class BluefishConsumer extends Consumer { _type = 'bluefish' ; public device : number = 1 ; public embeddedAudio : boolean = false ; public channelLayout : string = 'stereo' ; public keyOnly : boolean = false ; } /***/ export class SystemAudioConsumer extends Consumer { _type = 'system-audio' ; } /***/ export class ScreenConsumer extends Consumer { _type = 'screen' ; public device : number = 1 ; public aspectRatio : string = 'default' ; public stretch : string = 'fill' ; public windowed : boolean = true ; public keyOnly : boolean = false ; public autoDeinterlace : boolean = true ; public vsync : boolean = false ; public borderless : boolean = false ; } /***/ export class NewtekIvgaConsumer extends Consumer { _type = 'newtek-ivga' ; } /***/ export class Controller { public _type : string = 'tcp' ; public port : number | null = null ; public protocol : string = '' ; } /***/ export class Mixer { public blendModes : boolean = false ; public straightAlpha : boolean = false ; public mipmappingDefaultOn : boolean = false ; } /***/ export class OscClient { public _type : string = 'predefined-client' ; public address : string = '' ; public port : number | null = null ; } /***/ export class Thumbnails { public generateThumbnails : boolean = true ; public width : number = 256 ; public height : number = 144 ; public videoGrid : number = 2 ; public scanIntervalMillis : number = 5000 ; public generateDelayMillis : number = 2000 ; public mipmap : boolean = false ; public videoMode : string = '720p5000' ; } /***/ export class Flash { bufferDepth : string | number = 'auto' ; } /***/ export class TemplateHost { public _type : string = 'template-host' ; public videoMode : string = '' ; public filename : string = '' ; public width : number | null = null ; public height : number | null = null ; } /***/ export class Osc { public defaultPort : number = 6250 ; public predefinedClients : Array < OscClient > = [ ] ; } /***/ export const defaultAMCPController = { _type : new v2xx . Controller ( ) . _type , port : 5250 , protocol : 'AMCP' } ; } /***/ export namespace v207 { /***/ export class CasparCGConfigVO extends v2xx . CasparCGConfigVO { public _version : number ; public paths : v207 . Paths = new v207 . Paths ( ) ; public channels : Array < v207 . Channel > = [ new v2xx . Channel ( ) ] ; public controllers : Array < v2xx . Controller > = [ v2xx . defaultAMCPController ] ; public mixer : v207 . Mixer = new v207 . Mixer ( ) ; public logLevel : string = 'trace' ; public autoDeinterlace : boolean = true ; public autoTranscode : boolean = true ; public pipelineTokens : number = 2 ; public thumbnails : v207 . Thumbnails = new v207 . Thumbnails ( ) ; public osc : v2xx . Osc = new v2xx . Osc ( ) ; public audio : v207 . Audio = new v207 . Audio ( ) ; } /***/ export class Channel extends v2xx . Channel { public consumers : Array < v207 . Consumer > = [ ] ; } /***/ export class Paths { mediaPath : string = 'media\\' ; logPath : string = 'log\\' ; dataPath : string = 'data\\' ; templatePath : string = 'templates\\' ; thumbnailsPath : string = 'thumbnails\\' ; } /***/ export class Consumer extends v2xx . Consumer { } /***/ export class DecklinkConsumer extends v2xx . DecklinkConsumer { public customAllocator : boolean = true ; } /***/ export class BluefishConsumer extends v2xx . BluefishConsumer { } /***/ export class SystemAudioConsumer extends v2xx . SystemAudioConsumer { } /***/ export class ScreenConsumer extends v2xx . ScreenConsumer { public name : string = 'Screen Consumer' ; } /***/ export class NewtekIvgaConsumer extends v2xx . NewtekIvgaConsumer { public channelLayout : string = 'stereo' ; public provideSync : boolean = true ; } /***/ export class FileConsumer extends v2xx . Consumer { _type = 'file' ; public path : string = '' ; public vcodec : string = 'libx264' ; public separateKey : boolean = false ; } /***/ export class StreamConsumer extends v2xx . Consumer { _type = 'stream' ; public path : string = '' ; public args : string = '' ; } /***/ export class Thumbnails extends v2xx . Thumbnails { } /***/ export class Mixer extends v2xx . Mixer { public chromaKey : boolean = false ; } /***/ export class Osc extends v2xx . Osc { } /***/ export class ChannelLayout { public _type : string = 'channel-layout' ; public name : string = '' ; public type : string = '' ; public numChannels : number | null = null ; public channels : string = '' ; } /***/ export class MixConfig { public _type : string = 'mix-config' ; public from : string = '' ; public to : string = '' ; public mix : string = '' ; public mappings : Array < string > = [ ] ; } /***/ export class Audio { public channelLayouts : Array < v207 . ChannelLayout > = [ ] ; public mixConfigs : Array < v207 . MixConfig > = [ ] ; } } /***/ export namespace v21x { export const defaultLOGController = { _type : new v2xx . Controller ( ) . _type , port : 3250 , protocol : 'LOG' } ; /***/ export class CasparCGConfigVO extends v2xx . CasparCGConfigVO { public _version : number ; public paths : v21x . Paths = new v21x . Paths ( ) ; public channels : Array < v21x . Channel > = [ new v2xx . Channel ( ) ] ; public controllers : Array < v2xx . Controller > = [ v2xx . defaultAMCPController , v21x . defaultLOGController ] ; public lockClearPhrase : string = 'secret' ; public mixer : v21x . Mixer = new v21x . Mixer ( ) ; public logLevel : string = 'info' ; public logCategories : string = 'communication' ; public forceDeinterlace : boolean = false ; public accelerator : string = 'auto' ; public thumbnails : v21x . Thumbnails = new v21x . Thumbnails ( ) ; public html : v21x . Html = new v21x . Html ( ) ; public osc : v21x . Osc = new v21x . Osc ( ) ; public audio : v21x . Audio = new v21x . Audio ( ) ; } /***/ export class Channel extends v2xx . Channel { public consumers : Array < v21x . Consumer > = [ ] ; } /***/ export class Paths { mediaPath : string = 'media/' ; logPath : string = 'log/' ; dataPath : string = 'data/' ; templatePath : string = 'template/' ; thumbnailPath : string = 'thumbnail/' ; fontPath : string = 'font/' ; } /***/ export class Consumer extends v2xx . Consumer { } /***/ export class DecklinkConsumer extends v2xx . DecklinkConsumer { } /***/ export class BluefishConsumer extends v2xx . BluefishConsumer { } /***/ export class SystemAudioConsumer extends v2xx . SystemAudioConsumer { public channelLayout : string = 'stereo' ; public latency : number = 200 ; } /***/ export class ScreenConsumer extends v2xx . ScreenConsumer { public interactive : boolean = true ; } /***/ export class NewtekIvgaConsumer extends v2xx . NewtekIvgaConsumer { } /***/ export class FfmpegConsumer extends v2xx . Consumer { _type = 'ffmpeg' ; public path : string = '' ; public args : string = '' ; public separateKey : boolean = false ; public monoStreams : boolean = false ; } /***/ export class SynctoConsumer extends v2xx . Consumer { _type = 'syncto' ; public channelId : Number | null = null ; } /***/ export class Mixer extends v2xx . Mixer { } /***/ export class Thumbnails extends v2xx . Thumbnails { public mipmap : boolean = true ; } /***/ export class Html { remoteDebuggingPort : number | null = null ; } /***/ export class Osc extends v2xx . Osc { public disableSendToAmcpClients : boolean = false ; } /***/ export class ChannelLayout { public _type : string = 'channel-layout' ; public name : string = '' ; public type : string = '' ; public numChannels : number | null = null ; public channelOrder : string = '' ; } /***/ export class MixConfig { public _type : string = 'mix-config' ; public fromType : string = '' ; public toTypes : string = '' ; public mix : string = '' ; } /***/ export class Audio { public channelLayouts : Array < v21x . ChannelLayout > = [ ] ; public mixConfigs : Array < v21x . MixConfig > = [ ] ; } } /***/ export namespace Utils { export type factoryMembers = 'config' | 'channel' | 'decklink' | 'bluefish' | 'system-audio' | 'screen' | 'newtek-ivga' | 'ffmpeg' | 'file' | 'ffmpeg' | 'stream' | 'syncto' | 'tcp' | 'predefined-client' | 'template-host' | 'channel-layout' | 'mix-config' ; export type FactyoryTypes = v207 . CasparCGConfigVO | v21x . CasparCGConfigVO | v2xx . Consumer | v2xx . Channel | v2xx . Controller | v2xx . OscClient | v2xx . TemplateHost | v207 . ChannelLayout | v207 . MixConfig | v21x . ChannelLayout | v21x . MixConfig | undefined ; export function configMemberFactory ( version , memberName , initValues ? ) { let member = undefined ; switch ( memberName ) { case 'config' : if ( version < 2100 ) { member = new v207 . CasparCGConfigVO ( ) ; } else { member = new v21x . CasparCGConfigVO ( ) ; } break ; case 'channel' : if ( version < 2100 ) { member = new v207 . Channel ( ) ; } else { member = new v21x . Channel ( ) ; } break ; case 'decklink' : if ( version < 2100 ) { member = new v207 . DecklinkConsumer ( ) ; } else { member = new v21x . DecklinkConsumer ( ) ; } break ; case 'bluefish' : member = new v2xx . BluefishConsumer ( ) ; break ; case 'system-audio' : if ( version < 2100 ) { member = new v207 . SystemAudioConsumer ( ) ; } else { member = new v21x . SystemAudioConsumer ( ) ; } break ; case 'screen' : if ( version < 2100 ) { member = new v207 . ScreenConsumer ( ) ; } else { member = new v21x . ScreenConsumer ( ) ; } break ; case 'newtek-ivga' : if ( version < 2100 ) { member = new v207 . NewtekIvgaConsumer ( ) ; } else { member = new v21x . NewtekIvgaConsumer ( ) ; } break ; case 'ffmpeg' : if ( version > 2100 ) { member = new v21x . FfmpegConsumer ( ) ; } break ; case 'file' : if ( version < 2100 ) { member = new v207 . FileConsumer ( ) ; } break ; case 'stream' : if ( version < 2100 ) { member = new v207 . StreamConsumer ( ) ; } break ; case 'syncto' : if ( version > 2100 ) { member = new v21x . SynctoConsumer ( ) ; } break ; case 'tcp' : member = new v2xx . Controller ( ) ; break ; case 'predefined-client' : member = new v2xx . OscClient ( ) ; break ; case 'template-host' : member = new v2xx . TemplateHost ( ) ; break ; case 'channel-layout' : if ( version < 2100 ) { member = new v207 . ChannelLayout ( ) ; } else { member = new v21x . ChannelLayout ( ) ; } break ; case 'mix-config' : if ( version < 2100 ) { member = new v207 . MixConfig ( ) ; } else { member = new v21x . MixConfig ( ) ; } break ; } if ( member && initValues ) { for ( let key in initValues ) { if ( member . hasOwnProperty ( key ) ) { if ( typeof ( member as any ) [ key ] === ( ( typeof ( initValues as any ) [ key ] ) || undefined ) ) { ( member as any ) [ key ] = ( initValues as any ) [ key ] ; } } } } return member ; } } /***/ export namespace Intermediate { import Config207VO = v207 . CasparCGConfigVO ; import Config210VO = v21x . CasparCGConfigVO ; /***/ export class Audio { public channelLayouts : Array < v21x . ChannelLayout > = [ ] ; public mixConfigs : Array < Intermediate . MixConfig > = [ ] ; } /***/ export class MixConfig { public _type : string = 'mix-config' ; public fromType : string = '' ; public toTypes : string = '' ; public mix : { mixType : string ; destinations : { [ destination ] : Array < { source : string ; expression : string ; } > ; } ; } ; } /***/ export class Mixer extends v207 . Mixer { chromaKey : boolean ; } /***/ export interface ICasparCGConfig { paths : v21x . Paths ; channels : Array < v2xx . Channel > ; controllers : Array < v2xx . Controller > ; lockClearPhrase : string | null ; mixer : Intermediate . Mixer ; logLevel : string ; logCategories : string ; channelGrid : boolean ; forceDeinterlace : boolean ; autoDeinterlace : boolean ; autoTranscode : boolean ; pipelineTokens : number ; accelerator : string ; thumbnails : v21x . Thumbnails ; flash : v2xx . Flash ; html : v21x . Html ; templateHosts : Array < v2xx . TemplateHost > ; osc : v2xx . Osc ; audio : Intermediate . Audio ; readonly VO : v207 . CasparCGConfigVO | v21x . CasparCGConfigVO ; readonly vo : v207 . CasparCGConfigVO | v21x . CasparCGConfigVO ; readonly v207VO : v207 . CasparCGConfigVO ; readonly v210VO : v21x . CasparCGConfigVO ; readonly XML : Object | null ; readonly xml : Object | null ; readonly v207XML : Object ; readonly v210XML : Object ; readonly XMLString : string ; readonly v207XMLString : string ; readonly v210XMLString : string ; readonly _version : CasparCGVersion ; import ( configVO ) : void ; importFromV207VO ( configVO ) : void ; importFromV210VO ( configVO ) : void ; } /***/ export class CasparCGConfig implements ICasparCGConfig { public paths : v21x . Paths = new v21x . Paths ( ) ; public channels : Array < v2xx . Channel > = [ ] ; public controllers : Array < v2xx . Controller > = [ ] ; public lockClearPhrase : string | null = null ; public mixer : Intermediate . Mixer = new Intermediate . Mixer ( ) ; public logLevel : string = 'info' ; public logCategories : string = 'communication' ; public channelGrid : boolean = false ; public forceDeinterlace : boolean = false ; public autoDeinterlace : boolean = true ; public autoTranscode : boolean = true ; public pipelineTokens : number = 2 ; public accelerator : string = 'auto' ; public thumbnails : v21x . Thumbnails = new v21x . Thumbnails ( ) ; public flash : v2xx . Flash = new v2xx . Flash ( ) ; public html : v21x . Html = new v21x . Html ( ) ; public templateHosts : Array < v2xx . TemplateHost > = [ ] ; public osc : v21x . Osc = new v21x . Osc ( ) ; public audio : Intermediate . Audio = new Intermediate . Audio ( ) ; private __version : CasparCGVersion ; /***/ public constructor ( initVersionOrConfigVO ) { if ( typeof initVersionOrConfigVO === 'number' ) { if ( initVersionOrConfigVO >= 2100 ) { this . __version = CasparCGVersion . V210 ; } else if ( initVersionOrConfigVO === 2007 ) { this . __version = CasparCGVersion . V207 ; } return ; } if ( initVersionOrConfigVO ) { if ( initVersionOrConfigVO instanceof Config207VO ) { this . __version = CasparCGVersion . V207 ; } else if ( initVersionOrConfigVO instanceof Config210VO ) { this . __version = CasparCGVersion . V210 ; } else if ( ( typeof initVersionOrConfigVO === 'object' ) && ( initVersionOrConfigVO as any ) [ '_version' ] ) { if ( ( initVersionOrConfigVO as any ) [ '_version' ] >= 2100 ) { this . __version = CasparCGVersion . V210 ; } else if ( ( initVersionOrConfigVO as any ) [ '_version' ] >= 2007 ) { this . __version = CasparCGVersion . V207 ; } } this . import ( initVersionOrConfigVO ) ; } } /***/ static addFormattedXMLChildsFromObject ( root , data , blacklist ? ) { blacklist && blacklist . push ( 'arrayNo' , 'array-no' ) ; for ( let key in data ) { if ( ( key === 'constructor' ) || ( blacklist && blacklist . indexOf ( key ) > - 1 ) ) { continue ; } let value = data [ key ] ; key = CasparCGConfig . mixedCaseToDashed ( key ) ; root . ele . call ( root , key , value ) ; } return root ; } /***/ static addFormattedXMLChildsFromArray ( root , data , whitelist ? ) { if ( whitelist ) { whitelist . forEach ( ( key ) => { if ( data . hasOwnProperty ( key ) ) { let value = data [ key ] ; let keyBlocks = key . split ( /(?=[A-Z])/ ) ; key = keyBlocks . map ( ( i ) => i . toLowerCase ( ) ) . join ( '-' ) ; root . ele . call ( root , key , value ) ; } } ) ; } return root ; } /***/ static dashedToMixedCase ( rawString ) { let keyBlocks = rawString . split ( /-/ ) ; if ( keyBlocks . length > 1 ) { return keyBlocks . map ( ( i , o ) => { if ( o > 0 ) { i = i . toLowerCase ( ) ; i = i . slice ( 0 , 1 ) . toUpperCase ( ) + i . slice ( 1 ) ; } else { i = i . toLowerCase ( ) ; } return i ; } ) . join ( '' ) ; } else { return rawString ; } } /***/ static dashedToCamelCase ( rawString ) { let keyBlocks = rawString . split ( /-/ ) ; if ( keyBlocks . length > 1 ) { return keyBlocks . map ( ( i ) => { i = i . toLowerCase ( ) ; i = i . slice ( 0 , 1 ) . toUpperCase ( ) + i . slice ( 1 ) ; return i ; } ) . join ( '' ) ; } else { return rawString ; } } /***/ static mixedCaseToDashed ( mixedCased ) { let keyBlocks = mixedCased . split ( /(?=[A-Z])/ ) ; return keyBlocks . map ( ( i ) => i . toLowerCase ( ) ) . join ( '-' ) ; } /***/ public import ( configVO ) { let version = configVO . _version || this . _version ; if ( version === CasparCGVersion . V207 ) { this . importFromV207VO ( configVO ) ; } else if ( version === CasparCGVersion . V210 ) { this . importFromV210VO ( configVO ) ; } else { throw new Error ( `Unsupported CasparCGVersion in 'configVO': {$version}` ) ; } } /***/ public importFromV207VO ( configVO ) { this . importValues ( configVO , this , [ 'log-level' , 'channel-grid' , 'auto-deinterlace' , 'auto-transcode' , 'pipeline-tokens' ] ) ; this . importValues ( configVO . paths , this . paths , [ 'media-path' , 'log-path' , 'data-path' , 'template-path' , 'thumbnails-path' ] ) ; this . findListMembers ( configVO , 'channels' ) . forEach ( ( i ) => { let channel = new v2xx . Channel ( ) ; this . importValues ( i , channel , [ 'video-mode' , 'channel-layout' , 'straight-alpha-output' ] ) ; this . findListMembers ( i , 'consumers' ) . forEach ( ( o ) => { let consumerName = CasparCGConfig . dashedToCamelCase ( o [ '_type' ] ) + 'Consumer' ; this . importListMembers ( o , consumerName , v21x ) ; channel . consumers . push ( o as v2xx . Consumer ) ; } ) ; this . channels . push ( channel ) ; } ) ; this . findListMembers ( configVO , 'controllers' ) . forEach ( ( i ) => { let controller = new v2xx . Controller ( ) ; this . importAllValues ( i , controller ) ; this . controllers . push ( controller ) ; } ) ; this . importValues ( configVO . mixer , this . mixer , [ 'blend-modes' , 'mipmapping-default-on' , 'straight-alpha' , 'chroma-key' ] ) ; this . findListMembers ( configVO , 'template-hosts' ) . forEach ( ( i ) => { let templateHost = new v2xx . TemplateHost ( ) ; this . importAllValues ( i , templateHost ) ; this . templateHosts . push ( templateHost ) ; } ) ; this . importValues ( configVO . flash , this . flash , [ 'buffer-depth' ] ) ; this . importValues ( configVO . thumbnails , this . thumbnails , [ 'generate-thumbnails' , 'width' , 'height' , 'video-grid' , 'scan-interval-millis' , 'generate-delay-millis' , 'video-mode' , 'mipmap' ] ) ; this . importValues ( configVO . osc , this . osc , [ 'default-port' ] ) ; this . findListMembers ( configVO . osc , 'predefined-clients' ) . forEach ( ( i ) => { let client = new v2xx . OscClient ( ) ; this . importAllValues ( i , client ) ; this . osc . predefinedClients . push ( client ) ; } ) ; if ( configVO . hasOwnProperty ( 'audio' ) ) { if ( configVO [ 'audio' ] . hasOwnProperty ( 'channelLayouts' ) ) { this . audio . channelLayouts = new Array < v21x . ChannelLayout > ( ) ; configVO [ 'audio' ] [ 'channelLayouts' ] . forEach ( ( i ) => { let channelLayout = new v21x . ChannelLayout ( ) ; channelLayout . _type = i . _type ; channelLayout . channelOrder = i . channels ; channelLayout . name = i . name ; channelLayout . numChannels = i . numChannels ; channelLayout . type = i . type ; this . audio . channelLayouts . push ( channelLayout ) ; } ) ; } if ( configVO [ 'audio' ] . hasOwnProperty ( 'mixConfigs' ) ) { this . audio . mixConfigs = new Array < Intermediate . MixConfig > ( ) ; configVO [ 'audio' ] [ 'mixConfigs' ] . forEach ( ( i ) => { let mixConfig = new Intermediate . MixConfig ( ) ; mixConfig . _type = i . _type ; mixConfig . fromType = i . from ; mixConfig . toTypes = i . to ; mixConfig . mix = { mixType : i . mix , destinations : { } } ; let destinations = { } ; let mapSections ; for ( let o = 0 ; o < i . mappings . length ; o ++ ) { mapSections = i . mappings [ o ] . match ( /(\S+)\s+(\S+)\s+(\S+)/ ) ; if ( mapSections !== null ) { let src = mapSections [ 1 ] ; let dst = mapSections [ 2 ] ; let expr = mapSections [ 3 ] ; if ( ! destinations . hasOwnProperty ( dst ) ) { destinations [ dst ] = [ ] ; } destinations [ dst ] . push ( { source : src , expression : expr } ) ; } } mixConfig . mix . destinations = destinations ; this . audio . mixConfigs . push ( mixConfig ) ; } ) ; } } } /***/ public importFromV210VO ( configVO ) { this . importValues ( configVO , this , [ 'lockClear-phrase' , 'log-level' , 'log-categories' , 'force-deinterlace' , 'channel-grid' , 'accelerator' ] ) ; this . importValues ( configVO . paths , this . paths , [ 'media-path' , 'log-path' , 'data-path' , 'template-path' , 'thumbnail-path' , 'font-path' ] ) ; this . findListMembers ( configVO , 'channels' ) . forEach ( ( i ) => { let channel = new v2xx . Channel ( ) ; this . importValues ( i , channel , [ 'video-mode' , 'channel-layout' , 'straight-alpha-output' ] ) ; this . findListMembers ( i , 'consumers' ) . forEach ( ( o ) => { let consumerName = CasparCGConfig . dashedToCamelCase ( o [ '_type' ] ) + 'Consumer' ; this . importListMembers ( o , consumerName , v21x ) ; channel . consumers . push ( o as v2xx . Consumer ) ; } ) ; this . channels . push ( channel ) ; } ) ; this . findListMembers ( configVO , 'controllers' ) . forEach ( ( i ) => { let controller = new v2xx . Controller ( ) ; this . importAllValues ( i , controller ) ; this . controllers . push ( controller ) ; } ) ; this . importValues ( configVO [ 'mixer' ] , this . mixer , [ 'blend-modes' , 'mipmapping-default-on' , 'straight-alpha' ] ) ; this . findListMembers ( configVO , 'template-hosts' ) . forEach ( ( i ) => { let templateHost = new v2xx . TemplateHost ( ) ; this . importAllValues ( i , templateHost ) ; this . templateHosts . push ( templateHost ) ; } ) ; this . importValues ( configVO . flash , this . flash , [ 'buffer-depth' ] ) ; this . importValues ( configVO . html , this . html , [ 'remote-debugging-port' ] ) ; this . importValues ( configVO . thumbnails , this . thumbnails , [ 'generate-thumbnails' , 'width' , 'height' , 'video-grid' , 'scan-interval-millis' , 'generate-delay-millis' , 'video-mode' , 'mipmap' ] ) ; this . importValues ( configVO . osc , this . osc , [ 'default-port' , 'disable-send-to-amcp-clients' ] ) ; this . findListMembers ( configVO . osc , 'predefined-clients' ) . forEach ( ( i ) => { let client = new v2xx . OscClient ( ) ; this . importAllValues ( i , client ) ; this . osc . predefinedClients . push ( client ) ; } ) ; if ( configVO . hasOwnProperty ( 'audio' ) ) { if ( configVO [ 'audio' ] . hasOwnProperty ( 'channelLayouts' ) ) { this . audio . channelLayouts = configVO [ 'audio' ] [ 'channelLayouts' ] ; } if ( configVO [ 'audio' ] . hasOwnProperty ( 'mixConfigs' ) ) { this . audio . mixConfigs = new Array < Intermediate . MixConfig > ( ) ; configVO [ 'audio' ] [ 'mixConfigs' ] . forEach ( ( i ) => { let mixConfig = new Intermediate . MixConfig ( ) ; mixConfig . _type = i . _type ; mixConfig . fromType = i . fromType ; mixConfig . toTypes = i . toTypes ; let destinations = { } ; let mixType = i . mix . match ( /\&lt\;|\</g ) !== null ? 'average' : 'add' ; let src ; let dest ; let expr ; i . mix . split ( '|' ) . map ( ( i ) => i . replace ( /^\s*|\s*$/g , '' ) ) . forEach ( ( o ) => { let srcDstSplit = o . split ( /\&lt\;|\<|\=/ ) ; dest = srcDstSplit [ 0 ] . replace ( /^\s*|\s*$/g , '' ) ; destinations [ dest ] = [ ] ; srcDstSplit [ 1 ] . split ( '+' ) . forEach ( ( u ) => { let exprSplit = u . split ( '*' ) ; if ( exprSplit . length > 1 ) { expr = exprSplit [ 0 ] . replace ( /^\s*|\s*$/g , '' ) ; src = exprSplit [ 1 ] . replace ( /^\s*|\s*$/g , '' ) ; } else { src = exprSplit [ 0 ] . replace ( /^\s*|\s*$/g , '' ) ; expr = '1.0' ; } destinations [ dest ] . push ( { source : src , expression : expr } ) ; } ) ; } ) ; mixConfig . mix = { mixType : mixType , destinations : destinations } ; this . audio . mixConfigs . push ( mixConfig ) ; } ) ; } } } /***/ public get VO ( ) : Config207VO | Config210VO { if ( this . _version === CasparCGVersion . V207 ) { return this . v207VO ; } else if ( this . _version === CasparCGVersion . V210 ) { return this . v210VO ; } throw new Error ( '@todo' ) ; } /***/ public get vo ( ) : Config207VO | Config210VO { return this . VO ; } /***/ public get v207VO ( ) : Config207VO { let configVO = new Config207VO ( ) ; configVO . _version = this . _version ; configVO . paths = new v207 . Paths ( ) ; configVO . paths . dataPath = this . paths . dataPath ; configVO . paths . logPath = this . paths . logPath ; configVO . paths . mediaPath = this . paths . mediaPath ; configVO . paths . templatePath = this . paths . templatePath ; configVO . paths . thumbnailsPath = this . paths . thumbnailPath ; configVO . channels = this . channels ; configVO . controllers = this . controllers ; configVO . logLevel = this . logLevel ; configVO . autoDeinterlace = this . autoDeinterlace ; configVO . autoTranscode = this . autoTranscode ; configVO . pipelineTokens = this . pipelineTokens ; configVO . channelGrid = this . channelGrid ; configVO . mixer = new v207 . Mixer ( ) ; configVO . mixer . blendModes = this . mixer . blendModes ; if ( this . mixer . chromaKey ) configVO . mixer . chromaKey = this . mixer . chromaKey ; configVO . mixer . mipmappingDefaultOn = this . mixer . mipmappingDefaultOn ; configVO . mixer . straightAlpha = this . mixer . straightAlpha ; configVO . flash = this . flash ; configVO . templateHosts = this . templateHosts ; configVO . thumbnails = this . thumbnails ; configVO . osc = new v2xx . Osc ( ) ; if ( this . osc . defaultPort ) configVO . osc . defaultPort = this . osc . defaultPort ; if ( this . osc . predefinedClients ) configVO . osc . predefinedClients = this . osc . predefinedClients ; configVO . audio = new v207 . Audio ( ) ; this . audio . channelLayouts . forEach ( ( i ) => { let channelLayout = new v207 . ChannelLayout ( ) ; channelLayout . name = i . name ; channelLayout . numChannels = i . numChannels ; channelLayout . type = i . type ; channelLayout . channels = i . channelOrder ; configVO . audio . channelLayouts . push ( channelLayout ) ; } ) ; this . audio . mixConfigs . forEach ( ( i ) => { let mixConfig = new v207 . MixConfig ( ) ; mixConfig . from = i . fromType ; mixConfig . to = i . toTypes ; mixConfig . mix = i . mix . mixType ; for ( let o in i . mix . destinations ) { i . mix . destinations [ o ] . forEach ( ( u ) => { mixConfig . mappings . push ( [ u . source , o , u . expression ] . join ( ' ' ) ) ; } ) ; } configVO . audio . mixConfigs . push ( mixConfig ) ; } ) ; return configVO ; } /***/ public get v210VO ( ) : Config210VO { let configVO = new Config210VO ( ) ; configVO . _version = this . _version ; configVO . paths = this . paths ; configVO . channels = this . channels ; configVO . controllers = this . controllers ; if ( typeof this . lockClearPhrase === 'string' ) configVO . lockClearPhrase = this . lockClearPhrase ; configVO . logLevel = this . logLevel ; configVO . logCategories = this . logCategories ; configVO . forceDeinterlace = this . forceDeinterlace ; configVO . channelGrid = this . channelGrid ; configVO . accelerator = this . accelerator ; configVO . mixer = new v21x . Mixer ( ) ; configVO . mixer . blendModes = this . mixer . blendModes ; configVO . mixer . mipmappingDefaultOn = this . mixer . mipmappingDefaultOn ; configVO . mixer . straightAlpha = this . mixer . straightAlpha ; configVO . flash = this . flash ; configVO . html = this . html ; configVO . templateHosts = this . templateHosts ; configVO . thumbnails = this . thumbnails ; configVO . osc = this . osc ; configVO . audio = new v21x . Audio ( ) ; configVO . audio . channelLayouts = this . audio . channelLayouts ; this . audio . mixConfigs . forEach ( ( i ) => { let mixConfig = new v21x . MixConfig ( ) ; mixConfig . fromType = i . fromType ; mixConfig . toTypes = i . toTypes ; let mixOperator ; let destinationStrings = [ ] ; for ( let o in i . mix . destinations ) { let destinationSubStrings = [ ] ; let destinations = i . mix . destinations [ o ] ; mixOperator = ( destinations . length > 1 && i . mix . mixType === 'average' ) ? '<' : '=' ; destinations . forEach ( ( u ) => { destinationSubStrings . push ( u . expression === '1.0' ? u . source : u . expression + '*' + u . source ) ; } ) ; destinationStrings . push ( o + ' ' + mixOperator + ' ' + destinationSubStrings . join ( ' + ' ) ) ; } mixConfig . mix = destinationStrings . join ( ' | ' ) ; configVO . audio . mixConfigs . push ( mixConfig ) ; } ) ; return configVO ; } /***/ public get XML ( ) : Object | null { if ( this . _version === CasparCGVersion . V207 ) { return this . v207XML ; } else if ( this . _version === CasparCGVersion . V210 ) { return this . v210XML ; } return null ; } /***/ public get xml ( ) : Object | null { return this . XML ; } /***/ public get v207XML ( ) : any { let xml = XMLBuilder ( 'configuration' ) ; let paths = new v207 . Paths ( ) ; paths . dataPath = this . paths . dataPath ; paths . logPath = this . paths . logPath ; paths . mediaPath = this . paths . mediaPath ; paths . templatePath = this . paths . templatePath ; paths . thumbnailsPath = this . paths . thumbnailPath ; CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'paths' ) , paths ) ; let channels = xml . ele ( 'channels' ) ; this . channels . forEach ( ( i ) => { let channel = channels . ele ( 'channel' ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( channel , i , [ '_type' , 'consumers' , '_consumers' ] ) ; let consumers = channel . ele ( 'consumers' ) ; i . consumers . forEach ( ( i ) => { let consumer = consumers . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( consumer , i , [ '_type' ] ) ; } ) ; } ) ; let controllers = xml . ele ( 'controllers' ) ; this . controllers . forEach ( ( i ) => { let controller = controllers . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( controller , i , [ '_type' ] ) ; } ) ; CasparCGConfig . addFormattedXMLChildsFromArray ( xml , this , [ 'logLevel' , 'autoDeinterlace' , 'autoTranscode' , 'pipelineTokens' , 'channelGrid' ] ) ; if ( this . mixer ) { CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'mixer' ) , this . mixer ) ; } if ( this . flash ) { CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'flash' ) , this . flash ) ; } if ( this . templateHosts && this . templateHosts . length > 0 ) { let templateHosts = xml . ele ( 'template-hosts' ) ; this . templateHosts . forEach ( ( i ) => { let templatehost = templateHosts . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( templatehost , i , [ '_type' ] ) ; } ) ; } if ( this . thumbnails ) { CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'thumbnails' ) , this . thumbnails ) ; } if ( this . osc ) { let osc = xml . ele ( 'osc' ) ; osc . ele ( 'default-port' , this . osc . defaultPort ) ; if ( this . osc . predefinedClients && this . osc . predefinedClients . length > 0 ) { let predefinedClients = osc . ele ( 'predefined-clients' ) ; this . osc . predefinedClients . forEach ( ( i ) => { let client = predefinedClients . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( client , i , [ '_type' ] ) ; } ) ; } } if ( this . audio && ( ( this . audio . channelLayouts && this . audio . channelLayouts . length > 0 ) || ( this . audio . mixConfigs && this . audio . mixConfigs . length > 0 ) ) ) { let audio = xml . ele ( 'audio' ) ; if ( this . audio . channelLayouts && this . audio . channelLayouts . length > 0 ) { let channelLayouts = audio . ele ( 'channel-layouts' ) ; this . audio . channelLayouts . forEach ( ( i ) => { let channelLayout = channelLayouts . ele ( 'channel-layout' ) ; if ( i . name ) channelLayout . att ( 'name' , i . name ) ; if ( i . type ) channelLayout . att ( 'type' , i . type ) ; if ( i . numChannels ) channelLayout . att ( 'num-channels' , i . numChannels ) ; if ( i . channelOrder ) channelLayout . att ( 'channels' , i . channelOrder ) ; } ) ; } if ( this . audio . mixConfigs && this . audio . mixConfigs . length > 0 ) { let mixConfigs = audio . ele ( 'mix-configs' ) ; this . audio . mixConfigs . forEach ( ( i ) => { let mixConfig = mixConfigs . ele ( 'mix-config' ) ; mixConfig . ele ( 'from' , i . fromType ) ; mixConfig . ele ( 'to' , i . toTypes ) ; mixConfig . ele ( 'mix' , i . mix . mixType ) ; let mappings = mixConfig . ele ( 'mappings' ) ; for ( let o in i . mix . destinations ) { let destination = i . mix . destinations [ o ] ; destination . forEach ( ( u ) => { mappings . ele ( 'mapping' , u . source + ' ' + o + ' ' + u . expression ) ; } ) ; } } ) ; } } return xml ; } /***/ public get v210XML ( ) : any { let xml = XMLBuilder ( 'configuration' ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'paths' ) , this . paths ) ; let channels = xml . ele ( 'channels' ) ; this . channels . forEach ( ( i ) => { let channel = channels . ele ( 'channel' ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( channel , i , [ '_type' , 'consumers' , '_consumers' ] ) ; let consumers = channel . ele ( 'consumers' ) ; i . consumers . forEach ( ( i ) => { let consumer = consumers . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( consumer , i , [ '_type' ] ) ; } ) ; } ) ; let controllers = xml . ele ( 'controllers' ) ; this . controllers . forEach ( ( i ) => { let controller = controllers . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( controller , i , [ '_type' ] ) ; } ) ; CasparCGConfig . addFormattedXMLChildsFromArray ( xml , this , [ 'lockClearPhrase' , 'logLevel' , 'logCategories' , 'forceDeinterlace' , 'channelGrid' , 'accelerator' ] ) ; if ( this . mixer ) { let mixer = xml . ele ( 'mixer' ) ; mixer . ele ( 'blend-modes' , this . mixer . blendModes ) ; mixer . ele ( 'mipmapping-default-on' , this . mixer . mipmappingDefaultOn ) ; mixer . ele ( 'straight-alpha' , this . mixer . straightAlpha ) ; } if ( this . flash ) { CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'flash' ) , this . flash ) ; } if ( this . html ) { CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'html' ) , this . html ) ; } if ( this . templateHosts && this . templateHosts . length > 0 ) { let templateHosts = xml . ele ( 'template-hosts' ) ; this . templateHosts . forEach ( ( i ) => { let templatehost = templateHosts . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( templatehost , i , [ '_type' ] ) ; } ) ; } if ( this . thumbnails ) { CasparCGConfig . addFormattedXMLChildsFromObject ( xml . ele ( 'thumbnails' ) , this . thumbnails ) ; } if ( this . osc ) { let osc = xml . ele ( 'osc' ) ; CasparCGConfig . addFormattedXMLChildsFromArray ( osc , this . osc , [ 'defaultPort' , 'disableSendToAmcpClients' ] ) ; if ( this . osc . predefinedClients && this . osc . predefinedClients . length > 0 ) { let predefinedClients = osc . ele ( 'predefined-clients' ) ; this . osc . predefinedClients . forEach ( ( i ) => { let client = predefinedClients . ele ( i . _type ) ; CasparCGConfig . addFormattedXMLChildsFromObject ( client , i , [ '_type' ] ) ; } ) ; } } if ( this . audio && ( ( this . audio . channelLayouts && this . audio . channelLayouts . length > 0 ) || ( this . audio . mixConfigs && this . audio . mixConfigs . length > 0 ) ) ) { let audio = xml . ele ( 'audio' ) ; if ( this . audio . channelLayouts && this . audio . channelLayouts . length > 0 ) { let channelLayouts = audio . ele ( 'channel-layouts' ) ; this . audio . channelLayouts . forEach ( ( i ) => { let channelLayout = channelLayouts . ele ( 'channel-layout' ) ; if ( i . name ) channelLayout . att ( 'name' , i . name ) ; if ( i . type ) channelLayout . att ( 'type' , i . type ) ; if ( i . numChannels ) channelLayout . att ( 'num-channels' , i . numChannels ) ; if ( i . channelOrder ) channelLayout . att ( 'channel-order' , i . channelOrder ) ; } ) ; } if ( this . audio . mixConfigs && this . audio . mixConfigs . length > 0 ) { let mixConfigs = audio . ele ( 'mix-configs' ) ; this . audio . mixConfigs . forEach ( ( i ) => { let mixStrings = [ ] ; let mixOperator = i . mix . mixType === 'average' ? '<' : i . mix . mixType === 'add' ? '=' : '' ; let destination ; for ( let o in i . mix . destinations ) { destination = i . mix . destinations [ o ] ; if ( destination . length > 1 ) { let subSourceStrings = [ ] ; destination . forEach ( ( u ) => { subSourceStrings . push ( u . expression === '1.0' ? u . source : ( u . expression . toString ( ) + '*' + u . source ) ) ; } ) ; mixStrings . push ( o + ' ' + mixOperator + ' ' + subSourceStrings . join ( ' + ' ) ) ; } else { mixStrings . push ( o + ' = ' + ( destination [ 0 ] . expression === '1.0' ? destination [ 0 ] . source : ( destination [ 0 ] . expression . toString ( ) + '*' + destination [ 0 ] . source ) ) ) ; } } mixConfigs . ele ( 'mix-config' ) . att ( 'from-type' , i . fromType ) . att ( 'to-types' , i . toTypes ) . att ( 'mix' , mixStrings . join ( ' | ' ) ) ; } ) ; } } return xml ; } /***/ public get XMLString ( ) : string { if ( this . _version === CasparCGVersion . V207 ) { return this . v207XMLString ; } else if ( this . _version === CasparCGVersion . V210 ) { return this . v210XMLString ; } return '' ; } /***/ public get v207XMLString ( ) : string { return this . v207XML . end ( { pretty : true } ) ; } /***/ public get v210XMLString ( ) : string { return this . v210XML . end ( { pretty : true } ) ; } /***/ public get _version ( ) : CasparCGVersion { return this . __version ; } /***/ private importAllValues ( sourceRoot , destRoot ) { let keys = [ ] ; for ( let i in sourceRoot ) { keys . push ( i ) ; } this . importValues ( sourceRoot , destRoot , keys ) ; } /***/ private importValues ( sourceRoot , destRoot , values ) { values . forEach ( ( dashedKey ) => { let camelKey = CasparCGConfig . dashedToMixedCase ( dashedKey ) ; if ( sourceRoot && sourceRoot . hasOwnProperty ( dashedKey ) && sourceRoot [ dashedKey ] !== undefined && sourceRoot [ dashedKey ] !== null ) { if ( destRoot && destRoot . hasOwnProperty ( camelKey ) ) { destRoot [ camelKey ] = sourceRoot [ dashedKey ] ; } } else if ( sourceRoot && sourceRoot . hasOwnProperty ( camelKey ) && sourceRoot [ camelKey ] !== undefined && sourceRoot [ camelKey ] !== null ) { if ( destRoot && destRoot . hasOwnProperty ( camelKey ) ) { destRoot [ camelKey ] = sourceRoot [ camelKey ] ; } } } ) ; } /***/ private findListMembers ( root , childKey ) { let pairs = [ ] ; for ( let i in root ) { pairs . push ( [ i , root [ i ] ] ) ; } childKey = CasparCGConfig . dashedToMixedCase ( childKey ) ; for ( let i of pairs ) { let outerKey = CasparCGConfig . dashedToMixedCase ( i [ 0 ] . toString ( ) ) ; let outerValue = i [ 1 ] ; if ( childKey === outerKey ) { let flatArray = [ ] ; for ( let innerKey in outerValue ) { let innerValue = outerValue [ innerKey ] ; if ( typeof innerValue === 'object' ) { if ( Array . isArray ( innerValue ) ) { innerValue . forEach ( ( o ) => { if ( typeof o !== 'object' ) { o = { } ; } if ( ! o [ '_type' ] ) { o [ '_type' ] = innerKey ; } flatArray . push ( o ) ; } ) ; } else { if ( ! innerValue [ '_type' ] ) { innerValue [ '_type' ] = innerKey ; } flatArray . push ( innerValue ) ; } } else { flatArray . push ( { _type : innerKey } ) ; } } return flatArray ; } } return [ ] ; } /***/ private importListMembers ( root , memberName , restrictedNamespace ? ) { let namespace ; if ( restrictedNamespace ) { namespace = restrictedNamespace ; } else { if ( ( v21x as any ) [ memberName ] ) { namespace = v2xx ; } else if ( ( v207 as any ) [ memberName ] ) { namespace = v207 ; } else if ( ( v2xx as any ) [ memberName ] ) { namespace = v2xx ; } } if ( namespace && namespace . hasOwnProperty ( memberName ) ) { let member = new namespace [ memberName ] ( ) ; this . importAllValues ( root , member ) ; } } } } }