Skip to content

Commit

Permalink
feat(Inputs): implement InPr (read) and CInL (write) commands
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Van Camp committed Apr 28, 2018
1 parent 8978d49 commit 17e1688
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/atem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
TransitionProperties,
WipeTransitionSettings
} from './state/video'
import {InputChannel} from "./state/input";

export interface AtemOptions {
localPort?: number,
Expand Down Expand Up @@ -184,6 +185,13 @@ export class Atem extends EventEmitter {
return this.sendCommand(command)
}

setInputSettings (newProps: Partial<InputChannel>, input = 0) {
const command = new Commands.InputPropertiesCommand()
command.inputId = input
command.updateProps(newProps)
return this.sendCommand(command)
}

private _mutateState (command: AbstractCommand) {
command.applyToState(this.state)
this.emit('stateChanged', this.state, command)
Expand Down
70 changes: 70 additions & 0 deletions src/commands/Inputs/InputPropertiesCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import AbstractCommand from '../AbstractCommand'
import { AtemState } from '../../state'
import { InputChannel } from '../../state/input'
import { ExternalPorts, ExternalPortType } from '../../enums'
import { Util } from '../../lib/atemUtil'

export class InputPropertiesCommand extends AbstractCommand {
rawName = 'InPr'
inputId: number
MaskFlags = {
longName: 1 << 0,
shortName: 1 << 1,
isExternal: 1 << 2
}

properties: InputChannel

updateProps (newProps: Partial<InputChannel>) {
this._updateProps(newProps)
}

deserialize (rawCommand: Buffer) {
this.inputId = rawCommand.readUInt16BE(0)

const externalPortsMask = rawCommand[29]
const externalPorts: ExternalPortType[] = []
if (externalPortsMask & ExternalPorts.SDI) {
externalPorts.push(ExternalPortType.SDI)
}
if (externalPortsMask & ExternalPorts.HDMI) {
externalPorts.push(ExternalPortType.HDMI)
}
if (externalPortsMask & ExternalPorts.Component) {
externalPorts.push(ExternalPortType.Component)
}
if (externalPortsMask & ExternalPorts.Composite) {
externalPorts.push(ExternalPortType.Composite)
}
if (externalPortsMask & ExternalPorts.SVideo) {
externalPorts.push(ExternalPortType.SVideo)
}

this.properties = {
longName: Util.bufToNullTerminatedString(rawCommand, 2, 20),
shortName: Util.bufToNullTerminatedString(rawCommand, 22, 4),
externalPorts: externalPorts.length > 0 ? externalPorts : null,
isExternal: rawCommand[28] === 0,
externalPortType: rawCommand.readUInt8(31),
internalPortType: rawCommand.readUInt8(32),
sourceAvailability: rawCommand.readUInt8(34),
meAvailability: rawCommand.readUInt8(35)
}
}

serialize () {
const buffer = Buffer.alloc(24)
buffer.writeUInt16BE(this.flag, 0)
buffer.writeUInt16BE(this.inputId, 2)
buffer.write(this.properties.longName, 4)
buffer.write(this.properties.shortName, 24)
buffer.writeUInt16BE(this.properties.externalPortType, 28)
return Buffer.concat([Buffer.from('CInL', 'ascii'), buffer])
}

applyToState (state: AtemState) {
state.inputs[this.inputId] = {
...this.properties
}
}
}
1 change: 1 addition & 0 deletions src/commands/Inputs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './InputPropertiesCommand'
3 changes: 2 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './DownstreamKey'
export * from './DeviceProfile'
export * from './DownstreamKey'
export * from './Inputs'
export * from './Macro'
export * from './Media'
export * from './MixEffects'
Expand Down
50 changes: 50 additions & 0 deletions src/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,53 @@ export enum MacroAction {
Continue = 4,
Delete = 5
}

export enum ExternalPorts {
None = 0,
SDI = 1 << 0,
HDMI = 1 << 1,
Component = 1 << 2,
Composite = 1 << 3,
SVideo = 1 << 4,
All = SDI | HDMI | Component | Composite | SVideo
}

export enum ExternalPortType {
Internal = 0,
SDI = 1,
HDMI = 2,
Composite = 3,
Component = 4,
SVideo = 5
}

export enum InternalPortType {
External = 0,
Black = 1,
ColorBars = 2,
ColorGenerator = 3,
MediaPlayerFill = 4,
MediaPlayerKey = 5,
SuperSource = 6,

MEOutput = 128,
Auxiliary = 129,
Mask = 130
}

export enum SourceAvailability {
None = 0,
Auxiliary = 1 << 0,
Multiviewer = 1 << 1,
SuperSourceArt = 1 << 2,
SuperSourceBox = 1 << 3,
KeySource = 1 << 4,
All = Auxiliary | Multiviewer | SuperSourceArt | SuperSourceBox | KeySource
}

export enum MeAvailability {
None = 0,
Me1 = 1 << 0,
Me2 = 1 << 1,
All = Me1 | Me2
}
6 changes: 6 additions & 0 deletions src/lib/atemUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export namespace Util {
return array
}

export function bufToNullTerminatedString (buffer: Buffer, start: number, length: number): string {
const slice = buffer.slice(start, start + length)
const nullIndex = slice.indexOf('\0')
return slice.toString('ascii', 0, nullIndex < 0 ? slice.length : nullIndex)
}

export const COMMAND_CONNECT_HELLO = Buffer.from([
0x10, 0x14, 0x53, 0xAB,
0x00, 0x00, 0x00, 0x00,
Expand Down
2 changes: 2 additions & 0 deletions src/state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DeviceInfo } from './info'
import { AtemVideoState } from './video'
import { AtemAudioState } from './audio'
import { MediaState } from './media'
import { InputChannel } from './input'

export class AtemState {
info = new DeviceInfo()
Expand All @@ -13,4 +14,5 @@ export class AtemState {
tallies: Array<number> = []
audio: AtemAudioState = new AtemAudioState()
media: MediaState = new MediaState()
inputs: Array<InputChannel> = []
}
17 changes: 17 additions & 0 deletions src/state/input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
ExternalPortType,
InternalPortType,
MeAvailability,
SourceAvailability
} from '../enums'

export interface InputChannel {
longName: string
shortName: string
isExternal: boolean
readonly externalPorts: Array<ExternalPortType> | null
externalPortType: ExternalPortType
readonly internalPortType: InternalPortType
readonly sourceAvailability: SourceAvailability
readonly meAvailability: MeAvailability
}

0 comments on commit 17e1688

Please sign in to comment.