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();
        }
Esempio n. 2
0
	/// <summary>
	/// Open to send messages to specified port and (optional) IP address.
	/// If no IP address is given, messages will be send locally on this device.
	/// Returns success status.
	/// </summary>
	public bool Open( int port, string remoteIpAddress = "" )
	{
		// TODO this should be moved to a UdpSender class.

		// Close and stop pinging.
		if( _udpClient != null ) Close();

		// Validate IP.
		IPAddress ip;
		if( string.IsNullOrEmpty( remoteIpAddress ) ) remoteIpAddress = IPAddress.Loopback.ToString();
		if( remoteIpAddress == IPAddress.Any.ToString() || !IPAddress.TryParse( remoteIpAddress, out ip ) ){
			StringBuilder sb = OscDebug.BuildText( this );
			sb.Append( "Open failed. Invalid IP address " ); sb.Append( remoteIpAddress ); sb.Append( ".\n" );
			Debug.LogWarning( sb.ToString() );
			return false;
		}
		if( ip.AddressFamily != AddressFamily.InterNetwork ){
			StringBuilder sb = OscDebug.BuildText( this );
			sb.Append( "Open failed. Only IPv4 addresses are supported. " ); sb.Append( remoteIpAddress );
			sb.Append( " is " ); sb.Append( ip.AddressFamily ); sb.Append( ".\n" );
			Debug.LogWarning( sb.ToString() );
			return false;
		}
		_remoteIpAddress = remoteIpAddress;

		// Detect and set transmission mode.
		if( _remoteIpAddress == IPAddress.Loopback.ToString() ){
			_mode = OscSendMode.UnicastToSelf;
		} else if( _remoteIpAddress == IPAddress.Broadcast.ToString() ){
			_mode = OscSendMode.Broadcast;
		} else if( Regex.IsMatch( _remoteIpAddress, OscConst.multicastAddressPattern ) ){
			_mode = OscSendMode.Multicast;
		} else {
			_mode = OscSendMode.Unicast;
		}

		// Validate port number range
		if( port < OscConst.portMin || port > OscConst.portMax ){
			StringBuilder sb = OscDebug.BuildText( this );
			sb.Append( "Open failed. Port " ); sb.Append( port ); sb.Append( " is out of range.\n" );
			Debug.LogWarning( sb.ToString() );
			return false;
		}
		_port = port;

		// Create new client and end point.
		_udpClient = new UdpClient();
		_endPoint = new CachedIpEndPoint( ip, _port );

		// Multicast senders do not need to join a multicast group, but we need to set a few options.
		if( _mode == OscSendMode.Multicast )
		{
			 // Set a time to live, indicating how many routers the messages is allowed to be forwarded by.
			_udpClient.Client.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, OscConst.timeToLive );

			// Apply out multicastLoopback field.
			_udpClient.MulticastLoopback = _multicastLoopback;
		}

		// Set time to live to max. I haven't observed any difference, but we better be safe.
		_udpClient.Ttl = OscConst.timeToLive;

		// If an outgoing packet happen to exceeds the MTU (Maximum Transfer Unit) then throw an error instead of fragmenting.
		_udpClient.DontFragment = true;

		// Set buffer size.
		_udpClient.Client.SendBufferSize = _udpBufferSize;

		// DO NOT CONNECT UDP CLIENT!
		//_udpClient.Connect( _endPoint );

		// Note to self about connecting UdpClient:
		// We do not use udpClient.Connect(). Instead we pass the IPEndPoint directly to _udpClient.Send().
		// This is because a connected UdpClient purposed for sending will throw a number of (for our use) unwanted exceptions and in some cases disconnect.
		//		10061: SocketException: Connection refused 									- When we attempt to unicast to loopback address when no application is listening.
		//		10049: SocketException: The requested address is not valid in this context	- When we attempt to broadcast while having no access to the local network.
		//		10051: SocketException: Network is unreachable								- When we pass a unicast or broadcast target to udpClient.Connect() while having no access to a network.

		// Handle pinging
		if( Application.isPlaying )
		{
			_remoteStatus = _mode == OscSendMode.UnicastToSelf ? OscRemoteStatus.Connected : OscRemoteStatus.Unknown;
			if( _mode == OscSendMode.Unicast ){
				_pingCoroutine = PingCoroutine();
				StartCoroutine( _pingCoroutine );
			}
		}

		// Create cache buffer.
		if( _cache == null || _cache.Length != _udpBufferSize ) _cache = new byte[_udpBufferSize];

		// Log
		if( Application.isPlaying ){
			string addressTypeString = string.Empty;
			switch( _mode ){
			case OscSendMode.Broadcast: addressTypeString = "broadcast"; break;
			case OscSendMode.Multicast: addressTypeString = "multicast"; break;
			case OscSendMode.Unicast: addressTypeString = "IP"; break;
			case OscSendMode.UnicastToSelf: addressTypeString = "local"; break;
			}

			StringBuilder sb = OscDebug.BuildText( this );
			sb.Append( "Ready to send to " ); sb.Append( addressTypeString );
			sb.Append( " address " ); sb.Append( _remoteIpAddress );
			sb.Append( " on port " ); sb.Append( port ); sb.Append( ".\n" );
			Debug.Log( sb.ToString() );
		}

		return true;
	}
Esempio n. 3
0
        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())
            {
                _port.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(_port.intValue, _remoteIpAddress.stringValue))
                {
                    _tempPort = _port.intValue;
                }
                else
                {
                    _port.intValue = _tempPort;                     // Undo
                    _oscOut.Open(_port.intValue, _remoteIpAddress.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))
                {
                    _remoteIpAddress.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(_port.intValue, _remoteIpAddress.stringValue))
                {
                    _tempIPAddress = _remoteIpAddress.stringValue;
                    UpdateStatusInEditMode();
                }
                else
                {
                    _remoteIpAddress.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(_openOnAwake, _openOnAwakeLabel);
            EditorGUI.EndDisabledGroup();


            // Settings ...
            _settingsFoldout.boolValue = EditorGUILayout.Foldout(_settingsFoldout.boolValue, _settingsFoldLabel, true);
            if (_settingsFoldout.boolValue)
            {
                EditorGUI.indentLevel++;

                // Multicast loopback field.
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField(_multicastLoopbackLabel, GUILayout.Width(150));
                GUILayout.FlexibleSpace();
                EditorGUI.BeginChangeCheck();
                _multicastLoopback.boolValue = EditorGUILayout.Toggle(_multicastLoopback.boolValue, GUILayout.Width(30));
                if (EditorGUI.EndChangeCheck() && _oscOut.mode == OscSendMode.Multicast)
                {
                    _oscOut.multicastLoopback = _multicastLoopback.boolValue;
                }
                EditorGUILayout.EndHorizontal();

                // Bundle Messages On End Of Frame field.
                BoolSettingsField(_bundleMessagesOnEndOfFrame, _bundleMessagesOnEndOfFrameLabel);

                // Split Bundles Avoiding Buffer Overflow field.
                BoolSettingsField(_splitBundlesAvoidingBufferOverflow, _splitBundlesAvoidingBufferOverflowLabel);

                // Udp Buffer Size field. (UI horror get get a end changed event).
                GUI.SetNextControlName(bufferSizeControlName);
                EditorGUI.BeginChangeCheck();
                int newBufferSize = EditorGUILayout.IntField(_udpBufferSizeLabel, _udpBufferSize.intValue);
                if (EditorGUI.EndChangeCheck())
                {
                    _tempBufferSize = Mathf.Clamp(newBufferSize, OscConst.udpBufferSizeMin, OscConst.udpBufferSizeMax);
                }
                currentControlName = GUI.GetNameOfFocusedControl();
                bool enterKeyDownBufferSize = enterKeyDown && currentControlName == bufferSizeControlName;
                if (enterKeyDownBufferSize)
                {
                    UnfocusAndUpdateUI();
                }
                deselect = _prevControlName == bufferSizeControlName && currentControlName != bufferSizeControlName;
                if (enterKeyDownBufferSize || deselect)
                {
                    if (_tempBufferSize != _udpBufferSize.intValue)
                    {
                        _udpBufferSize.intValue = _tempBufferSize;
                        _oscOut.udpBufferSize   = _tempBufferSize;                       // This will reopen OscOut
                    }
                }

                EditorGUI.indentLevel--;
            }

            // Messages ...
            EditorGUI.BeginDisabledGroup(!_oscOut.isOpen);
            GUIContent messagesFoldContent = new GUIContent("Messages (" + _oscOut.messageCount + ")", "Messages received since last update");

            _messagesFoldout.boolValue = EditorGUILayout.Foldout(_messagesFoldout.boolValue, messagesFoldContent, true);
            if (_messagesFoldout.boolValue)
            {
                EditorGUI.indentLevel++;

                _sb.Clear();
                _messageStringQueue.CopyTo(_messageStringBuffer, 0);                   // Copy to array so we can iterate backswards.
                for (int i = _messageStringBuffer.Length - 1; i >= 0; i--)
                {
                    _sb.AppendLine(_messageStringBuffer[i]);
                }
                EditorGUILayout.HelpBox(_sb.ToString(), MessageType.None);

                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();
        }
Esempio n. 4
0
    /// <summary>
    /// Open to send messages to specified port and (optional) IP address.
    /// If no IP address is given, messages will be send locally on this device.
    /// Returns success status.
    /// </summary>
    public bool Open(int port, string ipAddress = "")
    {
        // Close and stop pinging.
        if (_udpClient != null)
        {
            Close();
        }

        // Validate IP.
        IPAddress ip;

        if (string.IsNullOrEmpty(ipAddress))
        {
            ipAddress = IPAddress.Loopback.ToString();
        }
        if (ipAddress == IPAddress.Any.ToString() || !IPAddress.TryParse(ipAddress, out ip))
        {
            Debug.LogWarning(logPrepend + "Open failed. Invalid IP address " + ipAddress + "." + Environment.NewLine);
            return(false);
        }
        else if (ip.AddressFamily != AddressFamily.InterNetwork)
        {
            Debug.LogWarning(logPrepend + "Open failed. Only IPv4 addresses are supported. " + ipAddress + " is " + ip.AddressFamily + "." + Environment.NewLine);
            return(false);
        }
        _ipAddress = ipAddress;

        // Detect and set transmission mode.
        if (_ipAddress == IPAddress.Loopback.ToString())
        {
            _mode = OscSendMode.UnicastToSelf;
        }
        else if (_ipAddress == IPAddress.Broadcast.ToString())
        {
            _mode = OscSendMode.Broadcast;
        }
        else if (Regex.IsMatch(_ipAddress, OscHelper.multicastAddressPattern))
        {
            _mode = OscSendMode.Multicast;
        }
        else
        {
            _mode = OscSendMode.Unicast;
        }

        // Validate port number range
        if (port < OscHelper.portMin || port > OscHelper.portMax)
        {
            Debug.LogWarning(logPrepend + "Open failed. Port " + port + " is out of range." + Environment.NewLine);
            return(false);
        }
        _port = port;

        // Create new client and end point.
        _udpClient = new UdpClient();
        _endPoint  = new IPEndPoint(ip, _port);

        // Multicast senders do not need to join a multicast group, but we need to set a few options.
        if (_mode == OscSendMode.Multicast)
        {
            // Set a time to live, indicating how many routers the messages is allowed to be forwarded by.
            _udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, OscHelper.timeToLiveMax);

            // Apply out multicastLoopback field.
            _udpClient.MulticastLoopback = _multicastLoopback;
        }

        // Set time to live to max. I haven't observed any difference, but we better be safe.
        _udpClient.Ttl = OscHelper.timeToLiveMax;

        // If an outgoing packet happen to exceeds the MTU (Maximum Transfer Unit) then throw an error instead of fragmenting.
        _udpClient.DontFragment = true;

        // Set buffer size to windows limit since we can't tell the actual limit.
        _udpClient.Client.SendBufferSize = 20384;

        // Note to self about buffer size:
        // We can't get the MTU when Unity is using scripting backend ".NET 2.0 Subset" (in Unity 5.3).
        // https://msdn.microsoft.com/en-us/library/system.net.networkinformation.ipv4interfaceproperties.mtu(v=vs.110).aspx
        // Also, this method gives a "NotSupportedException: This platform is not supported"
        // https://msdn.microsoft.com/en-us/library/system.net.networkinformation.ipv4interfaceproperties.mtu(v=vs.110).aspx

        // DO NOT CONNECT UDP CLIENT!
        //_udpClient.Connect( _endPoint );

        // Note to self about connecting UdpClient:
        // We do not use udpClient.Connect(). Instead we pass the IPEndPoint directly to _udpClient.Send().
        // This is because a connected UdpClient purposed for sending will throw a number of (for our use) unwanted exceptions and in some cases disconnect.
        //		10061: SocketException: Connection refused                                  - When we attempt to unicast to loopback address when no application is listening.
        //		10049: SocketException: The requested address is not valid in this context	- When we attempt to broadcast while having no access to the local network.
        //		10051: SocketException: Network is unreachable								- When we pass a unicast or broadcast target to udpClient.Connect() while having no access to a network.

        // Handle pinging
        if (Application.isPlaying)
        {
            _remoteStatus = _mode == OscSendMode.UnicastToSelf ? OscRemoteStatus.Connected : OscRemoteStatus.Unknown;
            if (_mode == OscSendMode.Unicast)
            {
                _pingCoroutine = PingCoroutine();
                StartCoroutine(_pingCoroutine);
            }
        }

        // Log
        if (Application.isPlaying)
        {
            string addressTypeString = string.Empty;
            switch (_mode)
            {
            case OscSendMode.Broadcast: addressTypeString = "broadcast"; break;

            case OscSendMode.Multicast: addressTypeString = "multicast"; break;

            case OscSendMode.Unicast: addressTypeString = "IP"; break;

            case OscSendMode.UnicastToSelf: addressTypeString = "local"; break;
            }
            Debug.Log(
                logPrepend + "Ready to send to " + addressTypeString + " address " + ipAddress + " on port " + port + "." + Environment.NewLine                // +
                //"Buffer size: " + _udpClient.Client.SendBufferSize + " bytes."
                );
        }

        return(true);
    }
    /// <summary>
    /// Open to send messages to specified port and (optional) IP address.
    /// If no IP address is given, messages will be send locally on this device.
    /// Returns success status.
    /// </summary>
    public bool Open(int port, string remoteIpAddress = "")
    {
        // Validate IP.
        IPAddress ip;

        if (string.IsNullOrEmpty(remoteIpAddress))
        {
            remoteIpAddress = IPAddress.Loopback.ToString();
        }
        if (remoteIpAddress == IPAddress.Any.ToString() || !IPAddress.TryParse(remoteIpAddress, out ip))
        {
            if (OscGlobals.logWarnings)
            {
                Debug.LogWarning(string.Format("{0}Open failed. Invalid IP address {1}\n", logPrepend, remoteIpAddress));
            }
            return(false);
        }
        if (ip.AddressFamily != AddressFamily.InterNetwork)
        {
            if (OscGlobals.logWarnings)
            {
                Debug.LogWarning(string.Format("{0}Open failed. Only IPv4 addresses are supported. {1} is {2}\n", logPrepend, remoteIpAddress, ip.AddressFamily));
            }
            return(false);
        }
        _remoteIpAddress = remoteIpAddress;

        // Detect and set transmission mode.
        if (_remoteIpAddress == IPAddress.Loopback.ToString())
        {
            _mode = OscSendMode.UnicastToSelf;
        }
        else if (_remoteIpAddress == IPAddress.Broadcast.ToString())
        {
            _mode = OscSendMode.Broadcast;
        }
        else if (Regex.IsMatch(_remoteIpAddress, OscConst.multicastAddressPattern))
        {
            _mode = OscSendMode.Multicast;
        }
        else
        {
            _mode = OscSendMode.Unicast;
        }

        // Validate port number range
        if (port < OscConst.portMin || port > OscConst.portMax)
        {
            if (OscGlobals.logWarnings)
            {
                StringBuilder sb = OscDebug.BuildText(this);
                sb.Append("Open failed. Port "); sb.Append(port); sb.Append(" is out of range.\n");
                Debug.LogWarning(sb.ToString());
            }
            return(false);
        }
        _port = port;

        // Create new client and end point.
        if (_sender == null)
        {
            _sender = new UdpSender(_udpBufferSize);
        }
        _sender.SetRemoteTarget(_port, ip);

        // Handle pinging
        if (Application.isPlaying)
        {
            _remoteStatus = _mode == OscSendMode.UnicastToSelf ? OscRemoteStatus.Connected : OscRemoteStatus.Unknown;
            if (_mode == OscSendMode.Unicast)
            {
                _pingCoroutine = PingCoroutine();
                StartCoroutine(_pingCoroutine);
            }
        }

        // Log
        if (Application.isPlaying)
        {
            string addressTypeString = string.Empty;
            switch (_mode)
            {
            case OscSendMode.Broadcast: addressTypeString = "broadcast"; break;

            case OscSendMode.Multicast: addressTypeString = "multicast"; break;

            case OscSendMode.Unicast: addressTypeString = "IP"; break;

            case OscSendMode.UnicastToSelf: addressTypeString = "local"; break;
            }

            if (OscGlobals.logStatuses)
            {
                StringBuilder sb = OscDebug.BuildText(this);
                sb.Append("Ready to send to "); sb.Append(addressTypeString);
                sb.Append(" address "); sb.Append(_remoteIpAddress);
                sb.Append(" on port "); sb.Append(port); sb.Append(".\n");
                Debug.Log(sb.ToString());
            }
        }

        return(true);
    }
Esempio n. 6
0
        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())
            {
                _port.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(_port.intValue, _ipAddress.stringValue))
                {
                    tempPort = _port.intValue;
                }
                else
                {
                    _port.intValue = tempPort;                     // Undo
                    oscOut.Open(_port.intValue, _ipAddress.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, OscHelper.unicastAddressDefault); break;

                case OscSendMode.Multicast:                     oscOut.Open(oscOut.port, OscHelper.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(_ipAdrressLabel);
            string newIp = EditorGUILayout.TextField(oscOut.ipAddress);               // Field

            if (EditorGUI.EndChangeCheck())
            {
                System.Net.IPAddress ip;
                if (System.Net.IPAddress.TryParse(newIp, out ip))
                {
                    _ipAddress.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(_port.intValue, _ipAddress.stringValue))
                {
                    tempIPAddress = _ipAddress.stringValue;
                    UpdateStatusInEditMode();
                }
                else
                {
                    _ipAddress.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(_openOnAwake, _openOnAwakeLabel);
            EditorGUI.EndDisabledGroup();

            EditorGUI.indentLevel++;

            // Settings ...
            _settingsFoldout.boolValue = EditorGUILayout.Foldout(_settingsFoldout.boolValue, _settingsFoldLabel);
            if (_settingsFoldout.boolValue)
            {
                // Multicast loopback field.
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField(_multicastLoopbackLabel, GUILayout.Width(150));
                GUILayout.FlexibleSpace();
                EditorGUI.BeginChangeCheck();
                _multicastLoopback.boolValue = EditorGUILayout.Toggle(_multicastLoopback.boolValue, GUILayout.Width(30));
                if (EditorGUI.EndChangeCheck() && oscOut.mode == OscSendMode.Multicast)
                {
                    oscOut.multicastLoopback = _multicastLoopback.boolValue;
                }
                EditorGUILayout.EndHorizontal();

                // Bundle Messages On End Of Frame field.
                BoolSettingsField(_bundleMessagesOnEndOfFrame, _bundleMessagesOnEndOfFrameLabel);
            }

            // Messages ...
            EditorGUI.BeginDisabledGroup(!oscOut.isOpen);
            GUIContent messagesFoldContent = new GUIContent("Messages (" + oscOut.messageCount + ")", "Messages received since last update");

            _messagesFoldout.boolValue = EditorGUILayout.Foldout(_messagesFoldout.boolValue, messagesFoldContent);
            if (_messagesFoldout.boolValue)
            {
                OscMessage[]  messages     = messageBuffer.ToArray();
                StringBuilder messagesText = new StringBuilder();
                for (int m = messages.Length - 1; m >= 0; m--)
                {
                    messagesText.Append((m != messages.Length - 1 ? Environment.NewLine : "") + messages[m].ToString());
                }
                EditorGUILayout.HelpBox(messagesText.ToString(), MessageType.None);
            }
            EditorGUI.EndDisabledGroup();

            EditorGUI.indentLevel--;

            // 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();
        }
Esempio n. 7
0
    /// <summary>
    /// Open to send messages to specified port and (optional) IP address.
    /// If no IP address is given, messages will be send locally on this device.
    /// Returns success status.
    /// </summary>
    public bool Open( int port, string ipAddress = "" )
    {
        // Close and stop pinging
        if( _udpClient != null ) Close();

        // Validate IP
        IPAddress ip;
        if( string.IsNullOrEmpty( ipAddress ) ) ipAddress = IPAddress.Loopback.ToString();
        if( ipAddress == IPAddress.Any.ToString() || !IPAddress.TryParse( ipAddress, out ip ) ){
            Debug.LogWarning( "[OscOut] Open failed. Invalid IP address " + ipAddress + "." + Environment.NewLine );
            return false;
        } else if( ip.AddressFamily != AddressFamily.InterNetwork ){
            Debug.LogWarning( "[OscOut] Open failed. Only IPv4 addresses are supported. " + ipAddress + " is " + ip.AddressFamily + "." + Environment.NewLine );
            return false;
        }
        _ipAddress = ipAddress;

        // Detect and set transmission mode
        if( _ipAddress == IPAddress.Loopback.ToString() ){
            _mode = OscSendMode.UnicastToSelf;
        } else if( _ipAddress == IPAddress.Broadcast.ToString() ){
            _mode = OscSendMode.Broadcast;
        } else if( Regex.IsMatch( _ipAddress, OscHelper.multicastAddressPattern ) ){
            _mode = OscSendMode.Multicast;
        } else {
            _mode = OscSendMode.Unicast;
        }

        // Validate port number range
        if( port < OscHelper.portMin || port > OscHelper.portMax ){
            Debug.LogWarning( "[OscOut] Open failed. Port " + port + " is out of range." + Environment.NewLine );
            return false;
        }
        _port = port;

        // Create new client and end point
        _udpClient = new UdpClient();
        _endPoint = new IPEndPoint( ip, _port );

        // Multicast senders do not need to join a multicast group, but we need to set a few options.
        if( _mode == OscSendMode.Multicast )
        {
             // Set a time to live, indicating how many routers the messages is allowed to be forwarded by.
            _udpClient.Client.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, OscHelper.timeToLiveMax );

            // Apply out multicastLoopback field
            _udpClient.MulticastLoopback = _multicastLoopback;
        }

        // Set time to live to max. I haven't observed any difference, but we better be safe.
        _udpClient.Ttl = OscHelper.timeToLiveMax;

        // If an outgoing packet happen to exceeds the MTU (Maximum Transfer Unit) then throw an error instead of fragmenting.
        _udpClient.DontFragment = true;

        // Set buffer size to windows limit since we can't tell the actual limit.
        _udpClient.Client.SendBufferSize = OscHelper.udpPacketSizeMaxOnWindows;

        // Note to self about buffer size:
        // We can't get the MTU when Unity is using scripting backend ".NET 2.0 Subset" (in Unity 5.3).
        // https://msdn.microsoft.com/en-us/library/system.net.networkinformation.ipv4interfaceproperties.mtu(v=vs.110).aspx
        // Also, this method gives a "NotSupportedException: This platform is not supported"
        // https://msdn.microsoft.com/en-us/library/system.net.networkinformation.ipv4interfaceproperties.mtu(v=vs.110).aspx

        // DO NOT CONNECT UDP CLIENT!
        //_udpClient.Connect( _endPoint );

        // Note to self about connecting UdpClient:
        // We do not use udpClient.Connect(). Instead we pass the IPEndPoint directly to _udpClient.Send().
        // This is because a connected UdpClient purposed for sending will throw a number of (for our use) unwanted exceptions and in some cases disconnect.
        //		10061: SocketException: Connection refused 									- When we attempt to unicast to loopback address when no application is listening.
        //		10049: SocketException: The requested address is not valid in this context	- When we attempt to broadcast while having no access to the local network.
        //		10051: SocketException: Network is unreachable								- When we pass a unicast or broadcast target to udpClient.Connect() while having no access to a network.

        // Handle pinging
        if( Application.isPlaying )
        {
            _remoteStatus = _mode == OscSendMode.UnicastToSelf ? OscRemoteStatus.Connected : OscRemoteStatus.Unknown;
            if( _mode == OscSendMode.Unicast ){
                _pingCoroutine = PingCoroutine();
                StartCoroutine( _pingCoroutine );
            }
        }

        // Log
        if( Application.isPlaying ){
            string addressTypeString = string.Empty;
            switch( _mode ){
            case OscSendMode.Broadcast: addressTypeString = "broadcast"; break;
            case OscSendMode.Multicast: addressTypeString = "multicast"; break;
            case OscSendMode.Unicast: addressTypeString = "IP"; break;
            case OscSendMode.UnicastToSelf: addressTypeString = "local"; break;
            }
            Debug.Log(
                "[OscOut] Ready to send to " + addressTypeString + " address " + ipAddress + " on port " + port + "." + Environment.NewLine// +
                //"Buffer size: " + _udpClient.Client.SendBufferSize + " bytes."
            );
        }

        return true;
    }