private void Signaler_MessageFromPeer(object sender, Peer peer)
        {
            var message = peer.Message;

            if (message.Contains("OpenDataChannel"))
            {
                // A peer has let us know that they have begun initiating a data channel.  In this scenario,
                // we are the "remote" peer so make sure _isInitiator is false.  Begin gathering ice candidates.
                _isInitiator = false;
                RemotePeer   = peer;
                OpenDataChannel(peer);    // TODO: This is incorrect - message is definitely not the peer's name.
                return;
            }

            if (message.Contains("IceCandidate"))
            {
                var remoteCandidate = RTCIceCandidate.FromJsonString(message);
                _ice.AddRemoteCandidate(remoteCandidate);

                // TODO: Notify the ice transport when gathering is complete via the line below so it can change state.
                //_ice.AddRemoteCandidate(new RTCIceCandidateComplete());
                return;
            }

            if (message.Contains("IceParameters"))
            {
                var iceParameters = RTCIceParameters.FromJsonString(message);
                // Start the ice transport with the appropriate role based on whether this is the initiator of the call.
                var role = _isInitiator ? RTCIceRole.Controlling : RTCIceRole.Controlled;
                _ice.Start(_gatherer, iceParameters, role);
                return;
            }

            if (message.Contains("DtlsParameters"))
            {
                var dtlsParameters = RTCDtlsParameters.FromJsonString(message);
                _dtls.Start(dtlsParameters);
                Debug.WriteLine("Dtls start called.");
                return;
            }

            // this order guarantees:
            if (message.Contains("SctpCapabilities"))
            {
                // Message ordering: alice -> bob; bob.start(); bob -> alice; alice.start(); alice -> datachannel -> bob
                var sctpCaps = RTCSctpCapabilities.FromJsonString(message);

                if (!_isInitiator)
                {
                    Debug.WriteLine("Receiver: Waiting for OnDataChannel event and starting sctp.");

                    // The remote side will receive notification when the data channel is opened.
                    _sctp.OnDataChannel += Sctp_OnDataChannel;
                    _sctp.OnStateChange += Sctp_OnStateChange;

                    _sctp.Start(sctpCaps);

                    var caps = RTCSctpTransport.GetCapabilities();
                    _signaler.SendToPeer(RemotePeer.Id, caps.ToJsonString());
                }
                else
                {
                    // The initiator has received sctp caps back from the remote peer, which means the remote peer
                    // has already called sctp.start().  It's now safe to open a data channel, which will fire the
                    // Sctp_OnDataChannel event on the remote side.
                    Debug.WriteLine("Initiator: Creating the data channel and starting sctp.");

                    _sctp.OnStateChange += Sctp_OnStateChange;
                    _sctp.Start(sctpCaps);
                    _dataChannel                = new RTCDataChannel(_sctp, _dataChannelParams);
                    _dataChannel.OnMessage     += DataChannel_OnMessage;
                    _dataChannel.OnError       += DataChannel_OnError;
                    _dataChannel.OnStateChange += DataChannel_OnStateChange;

                    Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        IsSendEnabled = true;
                    });
                }
            }
        }
        public void HandleMessageFromPeer(string message)
        {
            if (message.StartsWith("{\"candidate"))
            {
                Debug.WriteLine("contains IceCandidate (or IceCandidateComplete)");

                Json jsonMessage = new Json(message);
                RTCIceGathererCandidate remoteCandidate = RTCIceGathererCandidate.Create(jsonMessage);
                _ice.AddRemoteCandidate(remoteCandidate);
                return;
            }
            if (message.StartsWith("{\"RTCIceParameters\":"))
            {
                Debug.WriteLine("contains IceParameters");

                Json             jsonMessage   = new Json(message);
                RTCIceParameters iceParameters = new RTCIceParameters(jsonMessage);

                // Start the ice transport with the appropriate role based on whether this is the initiator of the call.
                var role = _isInitiator ? RTCIceRole.Controlling : RTCIceRole.Controlled;
                _ice.Start(_gatherer, iceParameters, role);
                return;
            }
            if (message.StartsWith("{\"RTCDtlsParameters\":"))
            {
                Debug.WriteLine("contains DtlsParameters");

                Json jsonMessage = new Json(message);
                RTCDtlsParameters dtlsParameters = new RTCDtlsParameters(jsonMessage);

                _dtls.Start(dtlsParameters);
                Debug.WriteLine("Dtls start called.");
                return;
            }
            // this order guarantees:
            if (message.StartsWith("{\"RTCSctpCapabilities\":"))
            {
                Debug.WriteLine("contains SctpCapabilities");
                Json jsonMessage = new Json(message);
                // Message ordering: alice -> bob; bob.start(); bob -> alice; alice.start(); alice -> datachannel -> bob
                RTCSctpCapabilities sctpCaps = new RTCSctpCapabilities(jsonMessage);

                if (!_isInitiator)
                {
                    Debug.WriteLine("Receiver: Waiting for OnDataChannel event and starting sctp.");

                    // The remote side will receive notification when the data channel is opened.
                    _sctp.OnDataChannel += Sctp_OnDataChannel;
                    _sctp.OnStateChange += Sctp_OnStateChange;

                    _sctp.Start(sctpCaps);

                    RTCSctpCapabilities caps = RTCSctpTransport.GetCapabilities();

                    OnSignalMessageToPeer(caps.ToJson().ToString());
                }
                else
                {
                    // The initiator has received sctp caps back from the remote peer,
                    // which means the remote peer has already called sctp.start().
                    // It's now safe to open a data channel, which will fire the
                    // Sctp_OnDataChannel event on the remote side.
                    Debug.WriteLine("Initiator: Creating the data channel and starting sctp.");

                    _sctp.OnStateChange += Sctp_OnStateChange;
                    _sctp.Start(sctpCaps);

                    RTCDataTransport data = RTCDataTransport.Cast(_sctp);

                    _dataChannel            = new RTCDataChannel(data, _dataChannelParams);
                    _dataChannel.OnMessage += DataChannel_OnMessage;
                    _dataChannel.OnError   += DataChannel_OnError;
                    _dataChannel.OnOpen    += DataChannel_OnOpen;
                    _dataChannel.OnClose   += DataChannel_OnClose;
                }
            }
        }