// Send an OSC message or bundle public bool Send(OscData messageOrBundle) { // Usage: Send(new OscMessage("/address", arg1, arg2, arg3)); // Usage: Send(new OscBundle(OscBundle.TIMESTAMP_NOW, element1, element2, element3)); // Check parameters are valid if (messageOrBundle == null) { throw new ArgumentNullException("messageOrBundle", "Message or bundle parameter is null."); } if (messageOrBundle.Buffer == null) { throw new ArgumentException("Message or bundle has null data.", "messageOrBundle"); } if (messageOrBundle.Buffer.Length == 0) { throw new ArgumentException("Message or bundle has zero-length data.", "messageOrBundle"); } // Send UDP packet int sent = socket.SendTo(messageOrBundle.Buffer, endPoint); // Return true if successful return(sent == messageOrBundle.Buffer.Length); }
// UDP listening thread private void Listener() { while (!quitReceiver) { try { // Receive UDP packet byte[] buffer = udpClient.Receive(ref endPoint); if (quitReceiver) { break; } // Create OscData object OscData messageOrBundle = null; try { messageOrBundle = OscData.FromByteArray(buffer); } catch (Exception ex) { Console.Error.WriteLine("ERROR: Problem creating OscData from message (" + ex.Message + ")."); } if (messageOrBundle != null) { if (messageOrBundle is OscMessage) { OscMessage message = (OscMessage)messageOrBundle; DateTime timestamp = DateTime.UtcNow; OnReceivedMessage(new OscMessageEventArgs(timestamp, message)); } else if (messageOrBundle is OscBundle) { OscBundle bundle = (OscBundle)messageOrBundle; DateTime timestamp = (bundle.Timestamp == OscData.TIMESTAMP_NOW) ? DateTime.UtcNow : OscData.DateTimeFromTimestamp(bundle.Timestamp); OnReceivedBundle(new OscBundleEventArgs(timestamp, bundle)); } } } catch (ThreadInterruptedException) { Console.Error.WriteLine("WARNING: ThreadInterruptedException in Listener..."); if (quitReceiver) { break; } } catch (SocketException) { Console.Error.WriteLine("WARNING: SocketException in Listener..."); if (quitReceiver) { break; } } } udpClient.Close(); }
// Create an OSC bundle object for the specified binary buffer public OscBundle(byte[] buffer) { string tag; ulong timestamp = OscData.TIMESTAMP_NOW; List <OscData> parts = new List <OscData>(); if (buffer == null) { throw new ArgumentNullException("buffer", "Buffer must not be null."); } using (MemoryStream stream = new MemoryStream(buffer)) { tag = stream.ReadOscString(); if (tag != OscBundle.BUNDLE_ADDRESS) { throw new ArgumentException("Unrecognized bundle type.", "buffer"); } timestamp = (ulong)stream.ReadOscLong(); while (stream.Position < stream.Length) { int length = stream.ReadOscInt(); if (length < 0) { throw new Exception("Bundle part has invalid length (<0)."); } if (length > buffer.Length - stream.Position) { throw new Exception("Bundle part has invalid length."); } byte[] partBytes = new byte[length]; int offset = 0; while (offset < length) { int read = stream.Read(partBytes, offset, length - offset); if (read <= 0) { throw new Exception("EOF in bundle part."); } offset += read; } OscData part = OscData.FromByteArray(partBytes); if (part == null) { break; } parts.Add(part); } } this.Buffer = buffer; this.Timestamp = timestamp; this.Parts = parts.ToArray(); }
// Send an OSC message or bundle public bool Send(OscData messageOrBundle) { // Usage: Send(new OscMessage("/address", arg1, arg2, arg3)); // Usage: Send(new OscBundle(OscBundle.TIMESTAMP_NOW, element1, element2, element3)); // Check parameters are valid if (messageOrBundle == null) { throw new ArgumentNullException("messageOrBundle", "Message or bundle parameter is null."); } if (messageOrBundle.Buffer == null) { throw new ArgumentException("Message or bundle has null data.", "messageOrBundle"); } if (messageOrBundle.Buffer.Length == 0) { throw new ArgumentException("Message or bundle has zero-length data.", "messageOrBundle"); } // Send UDP packet int sent = socket.SendTo(messageOrBundle.Buffer, endPoint); // Return true if successful return (sent == messageOrBundle.Buffer.Length); }
// Create a binary OSC message for the specified address from the specified parameters public OscMessage(string address, IEnumerable <object> arguments) { // Check parameters are valid if (address == null) { throw new ArgumentNullException("address", "Address must not be null."); } if (!address.StartsWith(OscMessage.ADDRESS_PREFIX.ToString())) { throw new ArgumentException("Address must begin with a forward-slash ('/').", "address"); } if (address.IndexOfAny(OscMessage.ADDRESS_DISALLOWED_CHARS) >= 0) { throw new ArgumentException("Address contains one or more invalid characters.", "address"); } if (arguments == null) { throw new ArgumentNullException("arguments", "Arguments array must not be null."); } // Store address and arguments this.Address = address; int numArguments = 0; foreach (object o in arguments) { numArguments++; } this.Arguments = new object[numArguments]; numArguments = 0; foreach (object o in arguments) { this.Arguments[numArguments++] = o; } // Memory stream for OSC message using (MemoryStream stream = new MemoryStream()) { // Write address stream.WriteOscString(address); // Write param type tag: ",iiii\0" (i = 32-bit integer) StringBuilder typeTag = new StringBuilder(); typeTag.Append(','); // comma indicates start of parameter type tag list foreach (object o in Arguments) { if (o is SByte || o is Byte || o is Int16 || o is UInt16 || o is Int32 || o is UInt32) { typeTag.Append(OscMessage.TYPE_INT); } // signed two's complement int32 (big-endian) else if (o is Int64 || o is UInt64) { typeTag.Append(OscMessage.TYPE_LONG); } // (non-standard long int-64 type) else if (o is Single) { typeTag.Append(OscMessage.TYPE_FLOAT); } // IEEE 32-bit float (big-endian) else if (o is Double) { typeTag.Append(OscMessage.TYPE_DOUBLE); } // (non-standard double type) else if (o is Char) { typeTag.Append(OscMessage.TYPE_CHAR); } // (non-standard char type) else if (o is String) { typeTag.Append(OscMessage.TYPE_STRING); } // ASCII null-terminated string else if (o is byte[]) { typeTag.Append(OscMessage.TYPE_BLOB); } // blob (byte[]) with size else if (o is Boolean) { typeTag.Append((bool)o ? OscMessage.TYPE_TRUE : OscMessage.TYPE_FALSE); } // true or false type else if (o == null) { typeTag.Append(OscMessage.TYPE_NULL); } // null else if (o is DateTime) { typeTag.Append(OscMessage.TYPE_TIME); } // time tag (RFC-1305 NTP Timestamp format - upper 32 bits is the number of seconds since midnight on January 1, 1900, lower 32 bits specify the fractional part of a second) else if (o.Equals(typeof(Object))) { typeTag.Append(OscMessage.TYPE_IMPULSE); } // impulse (not sure of a good .NET representation for this) else if (o is Array) { throw new ArgumentException("Arrays not yet supported.", "arguments"); } else { throw new ArgumentException("One or more arguments are of an unhandled type.", "arguments"); } } stream.WriteOscString(typeTag.ToString()); // Values (all values are big-endian and will be padded to 4 bytes) foreach (object o in Arguments) { if (o is SByte) { stream.WriteOscInt((int)(SByte)o); } else if (o is Byte) { stream.WriteOscInt((int)(Byte)o); } else if (o is Int16) { stream.WriteOscInt((int)(Int16)o); } else if (o is UInt16) { stream.WriteOscInt((int)(UInt16)o); } else if (o is Int32) { stream.WriteOscInt((int)(Int32)o); } else if (o is UInt32) { stream.WriteOscInt((int)(UInt32)o); } else if (o is Int64) { stream.WriteOscLong((long)(Int64)o); } // (non-standard long int-64 type) else if (o is UInt64) { stream.WriteOscLong((long)(UInt64)o); } // (non-standard long int-64 type) else if (o is Single) { stream.WriteOscFloat((float)(Single)o); } else if (o is Double) { stream.WriteOscDouble((float)(Double)o); } // (non-standard double type) else if (o is Char) { stream.WriteOscInt((int)(Char)o); } // (non-standard char type, written as int-32) else if (o is String) { stream.WriteOscString((String)o); } else if (o is byte[]) { stream.WriteOscBlob((byte[])o); } else if (o is Boolean) { } // true or false type -- neither has data else if (o == null) { } // null type -- no data else if (o is DateTime) { stream.WriteOscLong((long)OscData.TimestampFromDateTime((DateTime)o)); } else if (o.Equals(typeof(Object))) { } // impulse (not sure of a good .NET representation for this) else if (o is Array) { throw new ArgumentException("Arrays not yet supported.", "arguments"); } else { throw new ArgumentException("One or more arguments are of an unhandled type.", "arguments"); } } // Return message bytes Buffer = stream.ToArray(); } }
// Create an OSC message object for the specified binary buffer public OscMessage(byte[] buffer) { string address; List <object> arguments = new List <object>(); if (buffer == null) { throw new ArgumentNullException("buffer", "Buffer must not be null."); } using (MemoryStream stream = new MemoryStream(buffer)) { address = stream.ReadOscString(); if (address == null) { throw new ArgumentException("Missing address.", "buffer"); } if (address[0] != OscMessage.ADDRESS_PREFIX) { throw new ArgumentException("Invalid address.", "buffer"); } string typeTagString = stream.ReadOscString(); if (typeTagString.Length == 0 || typeTagString[0] != TYPE_PREFIX) { throw new ArgumentException("ERROR: This implementation requires the OSC type-tag string.", "buffer"); } typeTagString = typeTagString.Substring(1); // Remove prefix for (int i = 0; i < typeTagString.Length; i++) { switch (typeTagString[i]) { // OSC 1.0 types case OscMessage.TYPE_INT: arguments.Add(stream.ReadOscInt()); break; case OscMessage.TYPE_FLOAT: arguments.Add(stream.ReadOscFloat()); break; case OscMessage.TYPE_STRING: arguments.Add(stream.ReadOscString()); break; case OscMessage.TYPE_BLOB: arguments.Add(stream.ReadOscBlob()); break; // OSC 1.1 types case OscMessage.TYPE_TRUE: arguments.Add((Boolean)true); break; case OscMessage.TYPE_FALSE: arguments.Add((Boolean)false); break; case OscMessage.TYPE_NULL: arguments.Add(null); break; case OscMessage.TYPE_IMPULSE: arguments.Add(typeof(Object)); break; // Not really sure how to represent an 'impulse' object case OscMessage.TYPE_TIME: arguments.Add(OscData.DateTimeFromTimestamp((ulong)stream.ReadOscLong())); break; // Non-standard/optional types case OscMessage.TYPE_SYMBOL: arguments.Add(stream.ReadOscString()); break; case OscMessage.TYPE_LONG: arguments.Add(stream.ReadOscLong()); break; case OscMessage.TYPE_DOUBLE: arguments.Add(stream.ReadOscDouble()); break; case OscMessage.TYPE_CHAR: arguments.Add((char)stream.ReadOscInt()); break; case OscMessage.TYPE_RGBA: arguments.Add(stream.ReadOscInt()); break; case OscMessage.TYPE_MIDI: arguments.Add(stream.ReadOscInt()); break; case OscMessage.TYPE_ARRAY_OPEN: break; // ignore for now case OscMessage.TYPE_ARRAY_CLOSE: break; // ignore for now default: throw new ArgumentException("Unknown OSC type tag '" + typeTagString[i] + "'", "buffer"); } } } this.Buffer = buffer; this.Address = address; this.Arguments = arguments.ToArray(); }