Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSC Status Updates #24

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,42 @@ For now docs are in the source only.

var CasparCG = require("caspar-cg");

ccg = new CasparCG("localhost", 5250);
ccg.connect(function () {
ccg.info(function (err, serverInfo) {
ccg = new CasparCG({
host: "localhost",
port: 5250,
debug: true,
osc: true, // osc status updates are opt in
oscThrottle: 250 // throttles status updates in ms
});

ccg.connect(() => {
ccg.info((err, serverInfo) => {
console.log(serverInfo);
});

ccg.play("1-1", "AMB");
ccg.loadTemplate("1-20", "NTSC-TEST-60", true);

setTimeout(function () {
setTimeout(() => {
ccg.clear("1");
ccg.disconnect();
}, 10 * 1000);
}, 60 * 1000);
});

ccg.on("connected", function () {
ccg.on("connected", () => {
console.log("Connected");
});

## Changelog
// must opt in to osc
ccg.on("status", status => {
console.log(JSON.stringify(status));
});

## Change log

###v0.1.1

* Adds OSC Status updates

### v0.1.0

Expand Down
7 changes: 7 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ var ccg = module.exports = function (host, port) {
this.options.port = port;
}

// osc server
require("./lib/osc")(this);

this.index = count++;
};

Expand All @@ -29,6 +32,10 @@ ccg.prototype.options = {
reconnect: true,
host: "localhost",
port: 5250,
osc: false,
oscPort: 6250,
oscThrottle: 250,
oscTimeout: 1000,
debug: false
};

Expand Down
189 changes: 189 additions & 0 deletions lib/osc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"use strict";

const osc = require("node-osc");
const _ = require("underscore");

module.exports = function (ccg) {
if (!ccg.options.osc) return;

const oscServer = new osc.Server(ccg.options.oscPort, "0.0.0.0");

let channels = {};
let channelTimeouts = {};
const oscTimeout = ccg.options.oscTimeout;

let emit = ccg.emit.bind(ccg);

if (ccg.options.oscThrottle) {
emit = _.throttle(emit, ccg.options.oscThrottle);
}

oscServer.on("message", function (msg, rinfo) {
try {
msg.shift(); // bundle
msg.shift(); // OSC Time Tag (not parsed correctly)

let message;
while (msg.length > 0) {
message = msg.shift();
parseMessage(message[0], message[1], message[2] || false);
}

const now = new Date().getTime();
Object.keys(channelTimeouts).forEach(channelNumber => {
const channelTimeout = channelTimeouts[channelNumber];
Object.keys(channelTimeout).forEach(layerNumber => {
const layerTimeout = channelTimeout[layerNumber];

if (layerTimeout.ts + oscTimeout < now) {
delete channels[channelNumber].layers[layerNumber];
delete channelTimeout[layerNumber];
return;
}

if (layerTimeout.file + oscTimeout < now) {
delete channels[channelNumber].layers[layerNumber].file;
delete channelTimeout[layerNumber].file;
return;
}

if (layerTimeout.file + oscTimeout < now) {
delete channels[channelNumber].layers[layerNumber].host;
delete channelTimeout[layerNumber].host;
return;
}
});
});

emit("status", channels);
} catch (err) {
ccg.log("OSC Parsing Error", err);
}
});

// clear all when disconnected
ccg.on("disconnected", () => {
channels = {};
channelTimeouts = {};
});

function parseMessage(message, value, value2) {
const now = new Date().getTime();
const parts = message.split("/");
parts.shift();

if (parts.length <= 0) return console.log("too short", parts);
if (parts[0] !== "channel") return console.log("not channel", parts);

const channel = channels[parts[1]] = channels[parts[1]] || {
layers: {},
audioChannels: {}
};
const channelTimeout = channelTimeouts[parts[1]] = channelTimeouts[parts[1]] || {};

if (parts[2] === "stage") {
if (parts[3] === "layer") {
if (parts.length < 6) return console.log("too short", parts);
const layer = channel.layers[parts[4]] = channel.layers[parts[4]] || {};
channelTimeout[parts[4]] = channelTimeout[parts[4]] || {};
channelTimeout[parts[4]].ts = now;

switch (parts[5]) {
case "time":
layer.time = value;
return;
case "frame":
layer.frame = value;
return;
case "type":
layer.type = value;
return;
case "paused":
layer.paused = value;
return;
case "buffer":
layer.buffer = value;
return;
case "loop":
layer.loop = value;
return;
case "profiler":
switch (parts[6]) {
case "time":
layer.profiler = {
actual: value,
expected: value2
};
return;
}
return;
case "host":
const host = layer.host = layer.host || {};
channelTimeout[parts[4]].host = now;
switch (parts[6]) {
case "width":
host.width = value;
return;
case "height":
host.height = value;
return;
case "path":
if (value.indexOf("\\\\") >= 0) {
value = value.split("\\\\")[1];
}

host.path = value;
return;
case "fps":
host.fps = value;
return;
}
break;
case "file":
const file = layer.file = layer.file || {};
channelTimeout[parts[4]].file = now;
switch (parts[6]) {
case "time":
file.time = value;
file.totalTime = value2;
return;
case "frame":
file.frame = value;
file.totalFrames = value2;
return;
case "fps":
file.fps = value;
return;
case "path":
file.path = value;
return;
case "loop":
file.loop = value;
return;
}
break;
}
}
}

if (parts[2] === "mixer") {
if (parts[3] === "audio") {
if (parts[4] === "nb_channels") {
channel.nbChannels = value;
return;
}

const audioChannel = channel.audioChannels[parts[4]] = channel.audioChannels[parts[4]] || {};

switch (parts[5]) {
case "pFS":
audioChannel.pFS = value;
return;
case "dBFS":
audioChannel.dBFS = value;
return;
}
}
}
}
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"test": "grunt mochaTest"
},
"dependencies": {
"node-osc": "respectTheCode/node-osc",
"underscore": "~1.8.3",
"sax": "~1.1.1"
},
Expand All @@ -20,7 +21,7 @@
"grunt-contrib-clean": "~0.4.0",
"grunt-contrib-watch": "~0.3.1",
"grunt-mocha-test": "~0.6.3",
"grunt-contrib-jshint": "~0.7.1",
"grunt-contrib-jshint": "1.0.0",
"grunt-jscs": "2.8.0",
"jshint-stylish": "~0.1.3",
"load-grunt-tasks": "~0.2.0",
Expand Down