I have a Node-Webkit based application, which does some heavy WebGL work (enough to stress out a high-end GPU), a fairly significant amount of JS processing, and I'm sending OSC
data on the order of ~4kb/s with the node dgram
module to an scsynth
child process to control audio.
The OSC data is contained in one bundle every 10 frames of animation and the audio is fairly tolerant of some latency or irregularity in the messages it receives, but not on the scale I'm experiencing.
Unfortunately I find that significantly often, there is a large delay between calling socket.send(...)
and the data actually being sent. It seems that under certain circumstances the scheduler places such a low priority on actually sending the data that each new packet becomes stalled almost indefinitely, before being suddenly released in large uncontrolled bursts that overflow the scsynth
command queue.
I cannot put the udp code into a WebWorker as node.js
objects do not work in that context. I'm considering attempting setting up a separate window (and as such, process) solely responsible for forwarding data received via window.postMessage
to UDP (and vice-versa), but since postMessage
itself is also asynchronous, and the other window itself will probably have low priority if it's not visible, I wonder if this is likely to provide much benefit.
I'm pretty sure that the main problem lies in the scheduling of work in Javascript rather than anywhere else in the process; I see no particular implication of trouble at the receiving end, although perhaps this could be assessed more closely.
Here's a brief snippet showing how the socket is setup and used (including gathering some basic stats on the send callback).
udp = require('dgram').createSocket('udp4');
//...
var udpStats = {lastSendDelay: 0, minSendDelay:Number.MAX_VALUE, maxSendDelay:-1, meanSendDelay:undefined};
var udpSend = function(buf) {
var t = new Date();
var wasSent = function(timeOfRequest) {
return function(err) {
if ((err)) sclog("UDP send Error: " + err);
var t2 = new Date();
var dt = t2 - timeOfRequest;
udpStats.lastSendDelay = dt;
udpStats.minSendDelay = Math.min(dt, udpStats.minSendDelay);
udpStats.maxSendDelay = Math.max(dt, udpStats.maxSendDelay);
udpStats.meanSendDelay = udpStats.meanSendDelay === undefined ? dt : (udpStats.meanSendDelay+dt)/2;
};
};
udp.send(buf, 0, buf.length, UDP_PORT, 'localhost', wasSent(t));
};