private async Task InitializeORTC() { var gatherOptions = new RTCIceGatherOptions() { IceServers = new List <RTCIceServer>() { new RTCIceServer { Urls = new string[] { "stun.l.google.com:19302" } }, new RTCIceServer { Username = "******", Credential = "redmond123", CredentialType = RTCIceGathererCredentialType.Password, Urls = new string[] { "turn:turn-testdrive.cloudapp.net:3478?transport=udp" } } } }; _gatherer = new RTCIceGatherer(gatherOptions); _gatherer.OnStateChange += IceGatherer_OnStateChange; _gatherer.OnLocalCandidate += async(candidate) => { await _signaler.SendToPeer(RemotePeer.Id, candidate.Candidate.ToJsonString()); }; var cert = await RTCCertificate.GenerateCertificate(); _ice = new RTCIceTransport(_gatherer); _ice.OnStateChange += IceTransport_OnStateChange; _dtls = new RTCDtlsTransport(_ice, new RTCCertificate[] { cert }); _dtls.OnStateChange += Dtls_OnStateChange; _sctp = new RTCSctpTransport(_dtls); }
protected virtual void Dispose(bool disposing) { // clean all unmanaged resources (if any) if (disposing) { // clean all managed resources if (_dataChannel != null) { _dataChannel.Close(); _dataChannel = null; } if (_sctp != null) { _sctp.Stop(); _sctp = null; } if (_dtls != null) { _dtls.Stop(); _dtls = null; } if (_ice != null) { _ice.Stop(); _ice = null; } if (_gatherer != null) { _gatherer.Close(); _gatherer = null; } } }
private async Task InitializeORTC() { var gatherOptions = new RTCIceGatherOptions() { IceServers = new List <RTCIceServer>() { new RTCIceServer { Urls = new string[] { _stunUrl } }, new RTCIceServer { Username = _turnUsername, Credential = _turnCredential, CredentialType = RTCIceCredentialType.Password, Urls = new string[] { _turnUrl } } } }; _gatherer = new RTCIceGatherer(gatherOptions); _gatherer.OnStateChange += IceGatherer_OnStateChange; _gatherer.OnLocalCandidate += (@event) => { OnSignalMessageToPeer(@event.Candidate.ToJson().ToString()); }; _gatherer.OnLocalCandidateComplete += (@event) => { OnSignalMessageToPeer(@event.Candidate.ToJson().ToString()); }; _ice = new RTCIceTransport(_gatherer); _ice.OnStateChange += IceTransport_OnStateChange; _dtls = new RTCDtlsTransport(_ice, new RTCCertificate[] { await RTCCertificate.GenerateCertificate() }); _dtls.OnStateChange += Dtls_OnStateChange; _sctp = new RTCSctpTransport(_dtls); _gatherer.Gather(null); }
/// <summary> /// Establishes a DataChannel with the parameter peer. /// </summary> private void OpenDataChannel() { Debug.WriteLine($"Opening data channel to peer id: {RemotePeer.Id}"); var iceParams = _gatherer.LocalParameters; OnSignalMessageToPeer(iceParams.ToJson().ToString()); // this order guarantees: alice -> bob; bob.start(); bob -> alice; alice.start(); alice -> datachannel -> bob if (_isInitiator) { var sctpCaps = RTCSctpTransport.GetCapabilities(); OnSignalMessageToPeer(sctpCaps.ToJson().ToString()); } var dtlsParams = _dtls.LocalParameters; OnSignalMessageToPeer(dtlsParams.ToJson().ToString()); }
/// <summary> /// Estabilishes a DataChannel with the parameter peer. /// </summary> private async Task OpenDataChannel(Peer peer) { Debug.WriteLine($"Opening data channel to peer: {peer.Name}"); Conversation = string.Empty; Debug.WriteLine("Ice: Gathering candidates."); _gatherer.Gather(null); var iceParams = _gatherer.GetLocalParameters(); await _signaler.SendToPeer(peer.Id, iceParams.ToJsonString()); // this order guarantees: alice -> bob; bob.start(); bob -> alice; alice.start(); alice -> datachannel -> bob if (_isInitiator) { var sctpCaps = RTCSctpTransport.GetCapabilities(); await _signaler.SendToPeer(peer.Id, sctpCaps.ToJsonString()); } var dtlsParams = _dtls.GetLocalParameters(); await _signaler.SendToPeer(peer.Id, dtlsParams.ToJsonString()); }
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; } } }