#region usings using System; using System.Net; using System.Globalization; using System.Threading; using System.Collections; using System.Collections.Generic; using System.ComponentModel.Composition; using VVVV.PluginInterfaces.V1; using VVVV.PluginInterfaces.V2; using VVVV.PluginInterfaces.V2.Graph; using VVVV.Utils.OSC; using VVVV.Core.Logging; using VVVV.Core; #endregion usings namespace VVVV.Nodes { enum AcceptMode {None, OnlyExposed, OnlyCached, ExposedAndCached, Any}; #region PluginInfo [PluginInfo(Name = "Server", Category = "VVVV", Help = "Accepts values for pins via OSC", Tags = "remote", AutoEvaluate = true)] #endregion PluginInfo public class VVVVServerNode: IPluginEvaluate, IDisposable { #region fields & pins #pragma warning disable 0649 [Input("Listening UDP Port", IsSingle = true, DefaultValue = 44444)] IDiffSpread FUDPPort; [Input("Accept", IsSingle = true, DefaultEnumEntry = "OnlyExposed")] IDiffSpread FAcceptMode; [Input("Clear Cache", IsSingle = true, IsBang = true)] IDiffSpread FClearCache; [Input("Feedback Accepted", IsSingle = true, DefaultValue = 0)] ISpread FFeedback; [Input("Feedback Target IP", IsSingle = true, DefaultString = "127.0.0.1")] IDiffSpread FTargetIP; [Input("Feedback Target UDP Port", IsSingle = true, DefaultValue = 55555)] IDiffSpread FTargetPort; [Output("Exposed Pins")] ISpread FExposedPinsOut; [Output("Cached Pins")] ISpread FCachedPinsOut; [Import()] ILogger FLogger; [Import()] #pragma warning restore IHDEHost FHDEHost; private OSCReceiver FOSCReceiver; private bool FListening; private Thread FThread; private OSCTransmitter FOSCTransmitter; private IPAddress FIP; private Dictionary FCachedPins = new Dictionary(); private Dictionary FExposedPins = new Dictionary(); private List FMessageQueue = new List(); private bool FDisposed; #endregion fields & pins #region constructor/destructor [ImportingConstructor] public VVVVServerNode(IHDEHost host) { FHDEHost = host; FHDEHost.ExposedNodeService.NodeAdded += NodeAddedCB; FHDEHost.ExposedNodeService.NodeRemoved += NodeRemovedCB; //get initial list of exposed ioboxes foreach (var node in FHDEHost.ExposedNodeService.Nodes) { var pinName = PinNameFromNode(node); var pin = node.FindPin(pinName); pin.Changed += PinChanged; FExposedPins.Add(node.GetNodePath(false) + "/" + pinName, pin); } } ~VVVVServerNode() { Dispose(false); } public void Dispose() { Dispose(true); } protected void Dispose(bool disposing) { // Check to see if Dispose has already been called. if(!FDisposed) { if(disposing) { // Dispose managed resources. FHDEHost.ExposedNodeService.NodeAdded -= NodeAddedCB; FHDEHost.ExposedNodeService.NodeRemoved -= NodeRemovedCB; StopListeningOSC(); } // Release unmanaged resources. If disposing is false, // only the following code is executed. } FDisposed = true; } #endregion private void NodeAddedCB(INode2 node) { var pinName = PinNameFromNode(node); var pin = node.FindPin(pinName); FExposedPins.Add(node.GetNodePath(false) + "/" + pinName, pin); if (pin != null) pin.Changed += PinChanged; } private void NodeRemovedCB(INode2 node) { var pinName = PinNameFromNode(node); var pin = node.FindPin(pinName); FExposedPins.Remove(node.GetNodePath(false) + "/" + pinName); if (pin != null) pin.Changed -= PinChanged; } private string PinNameFromNode(INode2 node) { string pinName = ""; if (node.NodeInfo.Systemname == "IOBox (Value Advanced)") pinName = "Y Input Value"; else if (node.NodeInfo.Systemname == "IOBox (String)") pinName = "Input String"; else if (node.NodeInfo.Systemname == "IOBox (Color)") pinName = "Color Input"; else if (node.NodeInfo.Systemname == "IOBox (Enumerations)") pinName = "Input Enum"; else if (node.NodeInfo.Systemname == "IOBox (Node)") pinName = "Input Node"; return pinName; } private void PinChanged(object sender, EventArgs e) { if ((FOSCTransmitter != null) && FFeedback[0]) { var pin = sender as IPin2; var pinPath = pin.ParentNode.GetNodePath(false) + "/" + pin.Name; var bundle = new OSCBundle(); var message = new OSCMessage(pinPath); for (int i = 0; i < pin.SliceCount; i++) message.Append(pin[i]); bundle.Append(message); try { FOSCTransmitter.Send(bundle); } catch (Exception ex) { FLogger.Log(LogType.Warning, "PinServer: " + ex.Message); } } } #region Network Input private void StartListeningOSC() { FOSCReceiver = new OSCReceiver(FUDPPort[0]); FListening = true; FThread = new Thread(new ThreadStart(ListenToOSC)); FThread.Start(); } private void StopListeningOSC() { if (FThread != null && FThread.IsAlive) { FListening = false; //FOSCReceiver is blocking the thread //so waiting would freeze //shouldn't be necessary here anyway... //FThread.Join(); } if (FOSCReceiver != null) FOSCReceiver.Close(); FOSCReceiver = null; } private void ListenToOSC() { while(FListening) { try { OSCPacket packet = FOSCReceiver.Receive(); if (packet != null) { if (packet.IsBundle()) { ArrayList messages = packet.Values; lock(FMessageQueue) for (int i=0; i