public void Close() { //Debug.Log( "CLOSE" ); if (_socket != null) { // Drop multicast group. if (!string.IsNullOrEmpty(_multicastAddress)) { IPAddress multicastIp = IPAddress.Parse(_multicastAddress); try { if (multicastIp.AddressFamily == AddressFamily.InterNetwork) { MulticastOption mcOpt = new MulticastOption(multicastIp); _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, mcOpt); } else { StringBuilder sb = OscDebug.BuildText(this); sb.Append("IvP6 not supported\n"); Debug.LogWarning(sb.ToString()); } } catch { // Ignore. } } // Close. _socket.Close(); } _socket = null; _isOpen = false; }
/// <summary> /// Tries to evaluate byte count prefix of a blob and evaluate it. /// </summary> // TODO When .Net 4.5 becomes available in Unity: Replace IList<T> with IReadOnlyList<T> since we want to pass Array where number and order of list elements is read-only. public static bool TryReadAndEvaluateByteCountPrefix(IList <byte> data, int index, out int byteCountPrefixValue) { FourByteOscData byteCountPrefix; if (!FourByteOscData.TryReadFrom(data, ref index, out byteCountPrefix)) { // Not enough space for byte count prefix in data array. byteCountPrefixValue = 0; StringBuilder sb = OscDebug.BuildText(); sb.Append("Blob is missing byte count prefix.\n"); Debug.LogWarning(sb.ToString()); return(false); } int multipleOfFourByteCount = ((byteCountPrefix.intValue + 3) / 4) * 4; // Multiple of four bytes. if (index + multipleOfFourByteCount > data.Count) { // Not enough space for blob in data array. byteCountPrefixValue = 0; StringBuilder sb = OscDebug.BuildText(); sb.Append("Blob data is incomplete.\n"); Debug.LogWarning(sb.ToString()); return(false); } byteCountPrefixValue = byteCountPrefix.intValue; return(true); }
void ReceiveComplete(IAsyncResult asyncResult) { if (_socket == null) { return; } try { // Get the data and copy it to another buffer for exposure. int byteCount = _socket.EndReceiveFrom(asyncResult, ref _tempRemoteEndPoint); Buffer.BlockCopy(_buffer, 0, _exposedBuffer, 0, byteCount); // Immediately start receving again. if (_isOpen) { BeginRecieve(); } // Invoke callback with the exposed buffer. if (byteCount > 0) { _onDatagramReceivedAsyncCallback(_exposedBuffer, byteCount); } } catch (Exception e) { if (e is ObjectDisposedException) { // Ignore. } else { StringBuilder sb = OscDebug.BuildText(this); sb.Append("Error occurred while receiving message.\n"); sb.Append(e); Debug.LogWarning(sb.ToString()); } } }
public bool Open(int port, string multicastAddress = "") { //Debug.Log( "OPEN " + Application.isPlaying ); if (_isOpen) { Close(); } // "Do not attempt to reuse the Socket after closing". // https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.shutdown?view=netframework-4.7.2 _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // Ensure that we can have multiple OscIn objects listening to the same port. Must be set before bind. // Note that only one OscIn object will receive the packet anyway: http://stackoverflow.com/questions/22810511/bind-multiple-listener-to-the-same-port _socket.ExclusiveAddressUse = false; _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _port = port; _multicastAddress = multicastAddress; try { // "Before calling BeginReceiveFrom, you must explicitly bind the Socket to a local endpoint using the Bind method," // https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.beginreceivefrom?view=netframework-4.7.2 IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, _port); _socket.Bind(localEndPoint); // Join multicast group if in multicast mode. if (!string.IsNullOrEmpty(_multicastAddress)) { IPAddress multicastIp = IPAddress.Parse(_multicastAddress); if (multicastIp.AddressFamily == AddressFamily.InterNetwork) { MulticastOption mcOpt = new MulticastOption(multicastIp); _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, mcOpt); } else { StringBuilder sb = OscDebug.BuildText(this); sb.Append("IvP6 not supported\n"); Debug.LogWarning(sb.ToString()); return(false); } _socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, OscConst.timeToLive); } // Let's begin! BeginRecieve(); } catch (Exception e) { // Socket error reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx Debug.Log(e); if (e is SocketException && (e as SocketException).ErrorCode == 10048) // "Address already in use" { StringBuilder sb = OscDebug.BuildText(this); sb.Append("Could not open port "); sb.Append(_port); sb.Append(" because another application is listening on it.\n"); Debug.LogWarning(sb.ToString()); } else if (e is SocketException && !string.IsNullOrEmpty(multicastAddress)) { StringBuilder sb = OscDebug.BuildText(this); sb.Append("Could not subscribe to multicast group. Perhaps you are offline, or your router does not support multicast."); sb.Append((e as SocketException).ErrorCode); sb.Append(": "); sb.Append(e.ToString()); Debug.LogWarning(sb.ToString()); } else if (e.Data is ArgumentOutOfRangeException) { StringBuilder sb = OscDebug.BuildText(this); sb.Append("Could not open port "); sb.Append(_port); sb.Append(". Invalid Port Number.\n"); sb.Append(e); Debug.LogWarning(sb.ToString()); } else { //Debug.Log( e ); } Close(); return(false); } _isOpen = true; return(true); }
public override void OnInspectorGUI() { string currentControlName; bool deselect; // Check for key down before drawing any fields because they might consume the event. bool enterKeyDown = Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return; // Load serialized object. serializedObject.Update(); // Port field. EditorGUI.BeginChangeCheck(); GUI.SetNextControlName(portControlName); int newPort = EditorGUILayout.IntField(_portLabel, _oscOut.port); if (EditorGUI.EndChangeCheck()) { _portProp.intValue = newPort; if (_oscOut.isOpen) { _oscOut.Close(); // Close socket while editing } } currentControlName = GUI.GetNameOfFocusedControl(); bool enterKeyDownPort = enterKeyDown && currentControlName == portControlName; if (enterKeyDownPort) { UnfocusAndUpdateUI(); } deselect = _prevControlName == portControlName && currentControlName != portControlName; if ((deselect || enterKeyDownPort) && !_oscOut.isOpen) { if (_oscOut.Open(_portProp.intValue, _remoteIpAddressProp.stringValue)) { _tempPort = _portProp.intValue; } else { _portProp.intValue = _tempPort; // Undo _oscOut.Open(_portProp.intValue, _remoteIpAddressProp.stringValue); } } // Mode field. EditorGUI.BeginChangeCheck(); OscSendMode newMode = (OscSendMode)EditorGUILayout.EnumPopup(_modeLabel, _oscOut.mode); if (EditorGUI.EndChangeCheck() && newMode != _oscOut.mode) { switch (newMode) { case OscSendMode.UnicastToSelf: _oscOut.Open(_oscOut.port); break; case OscSendMode.Unicast: _oscOut.Open(_oscOut.port, OscConst.unicastAddressDefault); break; case OscSendMode.Multicast: _oscOut.Open(_oscOut.port, OscConst.multicastAddressDefault); break; case OscSendMode.Broadcast: _oscOut.Open(_oscOut.port, IPAddress.Broadcast.ToString()); break; } UpdateStatusInEditMode(); } // IP Address field. EditorGUI.BeginChangeCheck(); GUI.SetNextControlName(ipAddressControlName); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(_remoteIpAddressLabel); string newIp = EditorGUILayout.TextField(_oscOut.remoteIpAddress); // Field if (EditorGUI.EndChangeCheck()) { IPAddress ip; if (IPAddress.TryParse(newIp, out ip)) { _remoteIpAddressProp.stringValue = newIp; // Accept only valid ip addresses } if (_oscOut.isOpen) { _oscOut.Close(); // Close socket while editing } if (!Application.isPlaying) { if (_pingEnumerator != null) { _pingEnumerator = null; // Don't update ping coroutine while editing } if (_statusInEditMode != OscRemoteStatus.Unknown) { _statusInEditMode = OscRemoteStatus.Unknown; } } } GUILayout.FlexibleSpace(); Rect rect = GUILayoutUtility.GetRect(16, 5); rect.width = 5; rect.x += 3; rect.y += 7; OscRemoteStatus status = Application.isPlaying ? _oscOut.remoteStatus : _statusInEditMode; EditorGUI.DrawRect(rect, StatusToColor(status)); EditorGUILayout.EndHorizontal(); GUILayoutUtility.GetRect(1, 2); // vertical spacing currentControlName = GUI.GetNameOfFocusedControl(); bool enterKeyDownIp = enterKeyDown && currentControlName == ipAddressControlName; if (enterKeyDownIp) { UnfocusAndUpdateUI(); } deselect = _prevControlName == ipAddressControlName && currentControlName != ipAddressControlName; if ((deselect || enterKeyDownIp) && !_oscOut.isOpen) // All this mess to check for end edit, OMG!!! Not cool. { if (_oscOut.Open(_portProp.intValue, _remoteIpAddressProp.stringValue)) { _tempIPAddress = _remoteIpAddressProp.stringValue; UpdateStatusInEditMode(); } else { _remoteIpAddressProp.stringValue = _tempIPAddress; // Undo } } // Is Open field. EditorGUI.BeginDisabledGroup(true); EditorGUILayout.Toggle(_isOpenLabel, _oscOut.isOpen); EditorGUI.EndDisabledGroup(); // Open On Awake field. EditorGUI.BeginDisabledGroup(Application.isPlaying); EditorGUILayout.PropertyField(_openOnAwakeProp, _openOnAwakeLabel); EditorGUI.EndDisabledGroup(); // Settings ... _settingsFoldoutProp.boolValue = EditorGUILayout.Foldout(_settingsFoldoutProp.boolValue, _settingsFoldLabel, true); if (_settingsFoldoutProp.boolValue) { EditorGUI.indentLevel++; // Udp Buffer Size field. EditorGUI.BeginChangeCheck(); int newBufferSize = EditorGUILayout.IntField(_udpBufferSizeLabel, _udpBufferSizeProp.intValue); if (EditorGUI.EndChangeCheck()) { if (newBufferSize >= OscConst.udpBufferSizeMin) { _udpBufferSizeProp.intValue = newBufferSize; _oscOut.udpBufferSize = newBufferSize; // This will reopen OscOut } } // Bundle messages automatically. EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(_bundleMessagesAutomaticallyLabel, GUILayout.Width(220)); GUILayout.FlexibleSpace(); _bundleMessagesAutomaticallyProp.boolValue = EditorGUILayout.Toggle(_bundleMessagesAutomaticallyProp.boolValue, GUILayout.Width(30)); EditorGUILayout.EndHorizontal(); if (!_bundleMessagesAutomaticallyProp.boolValue) { EditorGUILayout.HelpBox("Unbundled messages that are send successively are prone to be lost. Only disable this setting if your receiving end does not support OSC bundles.", MessageType.Warning); } EditorGUI.indentLevel--; } // Monitor ... EditorGUI.BeginDisabledGroup(!_oscOut.isOpen); _sb.Clear(); _sb.Append("Messages (").Append(_oscOut.messageCountSendLastFrame).Append(',').Append(OscDebug.GetPrettyByteSize(_oscOut.byteCountSendLastFrame)).Append(')'); GUIContent messagesFoldContent = new GUIContent(_sb.ToString(), "Messages received last update"); _messagesFoldoutProp.boolValue = EditorGUILayout.Foldout(_messagesFoldoutProp.boolValue, messagesFoldContent, true); if (_messagesFoldoutProp.boolValue) { EditorGUI.indentLevel++; if (_messageMonitorText.Length > 0) { _messageMonitorText.Remove(_messageMonitorText.Length - 1, 1); // Trim last new line temporarily. } EditorGUILayout.HelpBox(_messageMonitorText.ToString(), MessageType.None); if (_messageMonitorText.Length > 0) { _messageMonitorText.Append('\n'); } EditorGUI.indentLevel--; } EditorGUI.EndDisabledGroup(); // Apply serializedObject.ApplyModifiedProperties(); // Request OnInspectorGUI to be called every frame as long as inspector is active EditorUtility.SetDirty(target); // Update ping coroutine manually in Edit Mode. (Unity does not run coroutines in Edit Mode) if (!Application.isPlaying && _pingEnumerator != null) { OscHelper.UpdateCoroutineInEditMode(_pingEnumerator, ref _lastPingTime); } // Store name of focused control to detect unfocus events _prevControlName = GUI.GetNameOfFocusedControl(); }
public override void OnInspectorGUI() { Rect rect; string currentControlName; // Check for key down before drawing any fields because they might consume the event. bool enterKeyDown = Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return; // Load serialized object serializedObject.Update(); // Port field EditorGUI.BeginChangeCheck(); GUI.SetNextControlName(portControlName); int newPort = EditorGUILayout.IntField(_portLabel, _oscIn.port); if (EditorGUI.EndChangeCheck()) { _portProp.intValue = newPort; if (_oscIn.isOpen) { _oscIn.Close(); // Close UDPReceiver while editing } } currentControlName = GUI.GetNameOfFocusedControl(); bool enterKeyDownPort = enterKeyDown && currentControlName == portControlName; if (enterKeyDownPort) { UnfocusAndUpdateUI(); } bool deselect = _prevControlName == portControlName && currentControlName != portControlName; if ((deselect || enterKeyDownPort) && !_oscIn.isOpen) { if (_oscIn.Open(_portProp.intValue)) { _tempPort = _portProp.intValue; } else { _portProp.intValue = _tempPort; // undo _oscIn.Open(_portProp.intValue); } } // Mode field EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(_modeProp, _modeLabel); if (EditorGUI.EndChangeCheck()) { switch ((OscReceiveMode)_modeProp.enumValueIndex) { case OscReceiveMode.UnicastBroadcast: _oscIn.Open(_oscIn.port, string.Empty); _multicastAddressProp.stringValue = string.Empty; break; case OscReceiveMode.UnicastBroadcastMulticast: _oscIn.Open(_oscIn.port, OscConst.multicastAddressDefault); _multicastAddressProp.stringValue = OscConst.multicastAddressDefault; break; } } // Multicast field if (_oscIn.mode == OscReceiveMode.UnicastBroadcastMulticast) { EditorGUI.BeginChangeCheck(); GUI.SetNextControlName(multicastAddressControlName); EditorGUILayout.PropertyField(_multicastAddressProp, _multicastIpAddressLabel); if (EditorGUI.EndChangeCheck()) { if (_oscIn.isOpen) { _oscIn.Close(); // Close socket while editing } } currentControlName = GUI.GetNameOfFocusedControl(); bool enterKeyDownMulticastIpAddress = enterKeyDown && currentControlName == multicastAddressControlName; if (enterKeyDownMulticastIpAddress) { UnfocusAndUpdateUI(); } deselect = _prevControlName == multicastAddressControlName && currentControlName != multicastAddressControlName; if ((deselect || enterKeyDownMulticastIpAddress) && !_oscIn.isOpen) { if (_oscIn.Open(_portProp.intValue, _multicastAddressProp.stringValue)) { _tempMulticastAddress = _multicastAddressProp.stringValue; } else { _multicastAddressProp.stringValue = _tempMulticastAddress; // undo _oscIn.Open(_portProp.intValue, _multicastAddressProp.stringValue); } } } // IP Address field. EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(_localIpAddressLabel); EditorGUILayout.LabelField(" "); rect = GUILayoutUtility.GetLastRect(); // UI voodoo to position the selectable label perfectly EditorGUI.SelectableLabel(rect, OscIn.localIpAddress); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); // Alternative IP Addresses field. if (OscIn.localIpAddressAlternatives.Count > 0) { int i = 0; foreach (string ip in OscIn.localIpAddressAlternatives) { EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(new GUIContent(_localIpAddressAlternativesLabel.text + "[" + i + "]", _localIpAddressAlternativesLabel.tooltip)); EditorGUILayout.LabelField(" "); rect = GUILayoutUtility.GetLastRect(); // UI voodoo to position the selectable label perfectly EditorGUI.SelectableLabel(rect, ip); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); i++; } } // Is Open field EditorGUI.BeginDisabledGroup(true); EditorGUILayout.Toggle(_isOpenLabel, _oscIn.isOpen); EditorGUI.EndDisabledGroup(); // Open On Awake field EditorGUI.BeginDisabledGroup(Application.isPlaying); EditorGUILayout.PropertyField(_openOnAwakeProp, _openOnAwakeLabel); EditorGUI.EndDisabledGroup(); // Settings ... _settingsFoldoutProp.boolValue = EditorGUILayout.Foldout(_settingsFoldoutProp.boolValue, _settingsFoldLabel, true); if (_settingsFoldoutProp.boolValue) { EditorGUI.indentLevel++; // Udp Buffer Size field. EditorGUI.BeginChangeCheck(); int newBufferSize = EditorGUILayout.IntField(_udpBufferSizeLabel, _udpBufferSizeProp.intValue); if (EditorGUI.EndChangeCheck()) { if (newBufferSize >= OscConst.udpBufferSizeMin) { _udpBufferSizeProp.intValue = newBufferSize; _oscIn.udpBufferSize = newBufferSize; // This will reopen OscIn } } // Filter Duplicates field BoolSettingsField(_filterDuplicatesProp, _filterDuplicatesLabel); // Add Time Tags To Bundled Messages field. BoolSettingsField(_addTimeTagsToBundledMessagesProp, _addTimeTagsToBundledMessagesLabel); EditorGUI.indentLevel--; } // Mappings ... string mappingsFoldLabel = "Mappings (" + _mappingsProp.arraySize + ")"; _mappingsFoldoutProp.boolValue = EditorGUILayout.Foldout(_mappingsFoldoutProp.boolValue, mappingsFoldLabel, true); if (_mappingsFoldoutProp.boolValue) { EditorGUI.indentLevel++; EditorGUI.BeginDisabledGroup(Application.isPlaying); // Mapping elements .. int removeIndexRequsted = -1; for (int m = 0; m < _mappingsProp.arraySize; m++) { SerializedProperty mappingProp = _mappingsProp.GetArrayElementAtIndex(m); // Mapping field (using custom property drawer) EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(mappingProp); if (EditorGUI.EndChangeCheck()) { SerializedProperty addressProp = mappingProp.FindPropertyRelative(mappingAddressFieldName); addressProp.stringValue = GetSanitizedAndUniqueAddress(_mappingsProp, m, addressProp.stringValue); } // Remove mapping button rect = GUILayoutUtility.GetLastRect(); rect = EditorGUI.IndentedRect(GUILayoutUtility.GetLastRect()); rect.x = rect.x + rect.width - OscMappingDrawer.removeButtonWidth - 7; rect.y += 6; rect.width = OscMappingDrawer.removeButtonWidth; rect.height = OscMappingDrawer.removeButtonHeight; if (GUI.Button(rect, _removeMappingButtonLabel)) { removeIndexRequsted = m; } } // Handle mapping removal .. if (removeIndexRequsted != -1) { _mappingsProp.DeleteArrayElementAtIndex(removeIndexRequsted); } // Add mapping button rect = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 30)); if (GUI.Button(rect, _addMappingButtonLabel)) { string newAddress = GetSanitizedAndUniqueAddress(_mappingsProp, -1, "/"); FieldInfo meppingsInfo = serializedObject.targetObject.GetType().GetField(_mappingsProp.propertyPath, BindingFlags.Instance | BindingFlags.NonPublic); List <OscMapping> mappings = (List <OscMapping>)meppingsInfo.GetValue(serializedObject.targetObject); OscMapping mapping = new OscMapping(newAddress, OscMessageType.OscMessage); mapping.AddEmptyEntry(); mappings.Add(mapping); } EditorGUILayout.Space(); EditorGUI.EndDisabledGroup(); EditorGUI.indentLevel--; } // Messages ... _sb.Clear(); _sb.Append("Messages (").Append(_oscIn.messageCountReceivedLastFrame).Append(",").Append(OscDebug.GetPrettyByteSize(_oscIn.byteCountReceivedLastFrame)).Append(")"); GUIContent messagesFoldContent = new GUIContent(_sb.ToString(), "Messages received last update"); _messagesFoldoutProp.boolValue = EditorGUILayout.Foldout(_messagesFoldoutProp.boolValue, messagesFoldContent, true); if (_messagesFoldoutProp.boolValue) { EditorGUI.indentLevel++; if (_messageMonitorText.Length > 0) { _messageMonitorText.Remove(_messageMonitorText.Length - 1, 1); // Trim last new line temporarily. } EditorGUILayout.HelpBox(_messageMonitorText.ToString(), MessageType.None); if (_messageMonitorText.Length > 0) { _messageMonitorText.Append('\n'); } EditorGUI.indentLevel--; } // Apply serializedObject.ApplyModifiedProperties(); // Request OnInspectorGUI to be called every frame as long as inspector is active EditorUtility.SetDirty(target); // Store name of focused control to detect unfocus events _prevControlName = GUI.GetNameOfFocusedControl(); }
public bool TrySendBuffer(byte[] buffer, int byteCount) { if (_endPoint == null) { return(false); } try { //Debug.Log( $"Actually sending { string.Join( ",", _cache ) }" ); //Debug.Log( "Sending bytes: " + byteCount + ". Frame: " + Time.frameCount + "\n"); //Debug.Log( "Sending to " + _endPoint ); // Send!! _socket.SendTo(buffer, byteCount, SocketFlags.None, _endPoint); // Socket error reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx } catch (SocketException ex) { if (ex.ErrorCode == 10051) // "Network is unreachable" // Ignore. We get this when broadcasting while having no access to a network. { } else if (ex.ErrorCode == 10065) // "No route to host" // Ignore. We get this sometimes when unicasting. { } else if (ex.ErrorCode == 10049) // "The requested address is not valid in this context" // Ignore. We get this when we broadcast and have no access to the local network. For example if we are using a VPN. { } else if (ex.ErrorCode == 10061) // "Connection refused" // Ignore. { } else if (ex.ErrorCode == 10064) // "Host is down" // Ignore. We get this when the remote target is not found. { } else if (ex.ErrorCode == 10040) // "Message too long" { if (OscGlobals.logWarnings) { Debug.LogWarning( OscDebug.BuildText(this).Append("Failed to send message. Packet size at ") .AppendGarbageFree(byteCount).Append(" bytes exceeds udp buffer size at ") .AppendGarbageFree(_socket.SendBufferSize) .Append(" Try increasing the buffer size.\n").Append(ex) ); } } else { if (OscGlobals.logWarnings) { Debug.LogWarning( OscDebug.BuildText(this).Append("Failed to send message to ") .Append(_endPoint.Address).Append(" on port ").AppendGarbageFree(_endPoint.Port) .Append(".\n").Append(ex) ); } } return(false); } catch (Exception ex) { if (OscGlobals.logWarnings) { Debug.LogWarning( OscDebug.BuildText(this).Append("Failed to send message to ") .Append(_endPoint.Address).Append(" on port ").AppendGarbageFree(_endPoint.Port) .Append(".\n").Append(ex) ); } return(false); } return(true); }