public async Task SctpError() { // Setup var config = new PeerConnectionConfiguration(); var pc1 = new PeerConnection(); var pc2 = new PeerConnection(); await pc1.InitializeAsync(config); await pc2.InitializeAsync(config); pc1.LocalSdpReadytoSend += async(string type, string sdp) => { await pc2.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += async(string type, string sdp) => { await pc1.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); // Connect { var c1 = new ManualResetEventSlim(false); var c2 = new ManualResetEventSlim(false); pc1.Connected += () => c1.Set(); pc2.Connected += () => c2.Set(); Assert.True(pc1.CreateOffer()); Assert.True(c1.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(pc1.IsConnected); Assert.True(pc1.IsConnected); } // Try to add a data channel. This should fail because SCTP was not negotiated. Assert.ThrowsAsync <SctpNotNegotiatedException>(async() => await pc1.AddDataChannelAsync("dummy", false, false)); Assert.ThrowsAsync <SctpNotNegotiatedException>(async() => await pc1.AddDataChannelAsync(42, "dummy", false, false)); // Clean-up pc1.Close(); pc1.Dispose(); pc2.Close(); pc2.Dispose(); }
protected async Task MakeICECall(PeerConnection pc1, PeerConnection pc2) { var evExchangeCompleted = new ManualResetEventSlim(initialState: false); pc1.LocalSdpReadytoSend += async(SdpMessage message) => { await pc2.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc2.CreateAnswer(); } else { evExchangeCompleted.Set(); } }; pc2.LocalSdpReadytoSend += async(SdpMessage message) => { await pc1.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc1.CreateAnswer(); } else { evExchangeCompleted.Set(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; var pcConfig = new PeerConnectionConfiguration(); await pc1.InitializeAsync(pcConfig); await pc2.InitializeAsync(pcConfig); var ev1 = new ManualResetEventSlim(initialState: false); var ev2 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => ev1.Set(); pc2.Connected += () => ev2.Set(); evExchangeCompleted.Reset(); pc1.CreateOffer(); ev1.Wait(millisecondsTimeout: 5000); ev2.Wait(millisecondsTimeout: 5000); evExchangeCompleted.Wait(millisecondsTimeout: 5000); }
public async void PeerConnectionLocalConnect() { using (var pc1 = new PeerConnection()) { await pc1.InitializeAsync(); using (var pc2 = new PeerConnection()) { await pc2.InitializeAsync(); // Prepare SDP event handlers pc1.LocalSdpReadytoSend += async(string type, string sdp) => { await pc2.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += async(string type, string sdp) => { await pc1.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); // Connect var conn1 = new ManualResetEventSlim(initialState: false); var conn2 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => conn1.Set(); pc2.Connected += () => conn2.Set(); pc1.CreateOffer(); WaitForSdpExchangeCompleted(conn1, conn2); pc1.Close(); pc2.Close(); } } }
public async void PeerConnectionLocalConnect() { using (var pc1 = new PeerConnection()) { await pc1.InitializeAsync(); using (var pc2 = new PeerConnection()) { await pc2.InitializeAsync(); // Prepare SDP event handlers pc1.LocalSdpReadytoSend += async(SdpMessage message) => { await pc2.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += async(SdpMessage message) => { await pc1.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (IceCandidate candidate) => pc2.AddIceCandidate(candidate); pc2.IceCandidateReadytoSend += (IceCandidate candidate) => pc1.AddIceCandidate(candidate); // Connect var conn1 = new ManualResetEventSlim(initialState: false); var conn2 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => conn1.Set(); pc2.Connected += () => conn2.Set(); pc1.CreateOffer(); WaitForSdpExchangeCompleted(conn1, conn2); pc1.Close(); pc2.Close(); } } }
protected async Task MakeICECall(PeerConnection pc1, PeerConnection pc2) { pc1.LocalSdpReadytoSend += (string type, string sdp) => { pc2.SetRemoteDescription(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += (string type, string sdp) => { pc1.SetRemoteDescription(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; var pcConfig = new PeerConnectionConfiguration(); await pc1.InitializeAsync(pcConfig); await pc2.InitializeAsync(pcConfig); var ev1 = new ManualResetEventSlim(initialState: false); var ev2 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => ev1.Set(); pc2.Connected += () => ev2.Set(); pc1.CreateOffer(); ev1.Wait(millisecondsTimeout: 5000); ev2.Wait(millisecondsTimeout: 5000); }
public async void PeerConnectionLocalConnect() { using (var pc1 = new PeerConnection()) { await pc1.InitializeAsync(); using (var pc2 = new PeerConnection()) { await pc2.InitializeAsync(); // Prepare SDP event handlers var completed = new ManualResetEventSlim(initialState: false); pc1.LocalSdpReadytoSend += async(SdpMessage message) => { // Send caller offer to callee await pc2.SetRemoteDescriptionAsync(message); Assert.AreEqual(SdpMessageType.Offer, message.Type); pc2.CreateAnswer(); }; pc2.LocalSdpReadytoSend += async(SdpMessage message) => { // Send callee answer back to caller await pc1.SetRemoteDescriptionAsync(message); Assert.AreEqual(SdpMessageType.Answer, message.Type); completed.Set(); }; pc1.IceCandidateReadytoSend += (IceCandidate candidate) => pc2.AddIceCandidate(candidate); pc2.IceCandidateReadytoSend += (IceCandidate candidate) => pc1.AddIceCandidate(candidate); // Connect pc1.CreateOffer(); WaitForSdpExchangeCompleted(completed); pc1.Close(); pc2.Close(); } } }
private async void DssSignaler_OnMessage(NodeDssSignaler.Message message) { Logger.Log($"DSS received message: {message.MessageType}"); // Ensure that the filtering values are up to date before passing the message on. //UpdateCodecFilters(); //_peerConnection.PreferredAudioCodec = PreferredAudioCodec; //_peerConnection.PreferredAudioCodecExtraParamsRemote = PreferredAudioCodecExtraParamsRemoteTextBox.Text; //_peerConnection.PreferredAudioCodecExtraParamsLocal = PreferredAudioCodecExtraParamsLocalTextBox.Text; //_peerConnection.PreferredVideoCodec = PreferredVideoCodec; //_peerConnection.PreferredVideoCodecExtraParamsRemote = PreferredVideoCodecExtraParamsRemoteTextBox.Text; //_peerConnection.PreferredVideoCodecExtraParamsLocal = PreferredVideoCodecExtraParamsLocalTextBox.Text; switch (message.MessageType) { case NodeDssSignaler.Message.WireMessageType.Offer: await ApplyRemoteOfferAsync(message.Data); // If we get an offer, we immediately send an answer back once the offer is applied _peerConnection.CreateAnswer(); break; case NodeDssSignaler.Message.WireMessageType.Answer: await ApplyRemoteAnswerAsync(message.Data); break; case NodeDssSignaler.Message.WireMessageType.Ice: // TODO - This is NodeDSS-specific // this "parts" protocol is defined above, in OnIceCandidateReadyToSend listener var parts = message.Data.Split(new string[] { message.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); // Note the inverted arguments; candidate is last here, but first in OnIceCandidateReadyToSend _peerConnection.AddIceCandidate(parts[2], int.Parse(parts[1]), parts[0]); break; default: throw new InvalidOperationException($"Unhandled signaler message type '{message.MessageType}'"); } }
private async void DssSignaler_OnMessage(NodeDssSignaler.Message message) { Logger.Log($"DSS received message: {message.MessageType}"); // Ensure that the filtering values are up to date before passing the message on. //UpdateCodecFilters(); //_peerConnection.PreferredAudioCodec = PreferredAudioCodec; //_peerConnection.PreferredAudioCodecExtraParamsRemote = PreferredAudioCodecExtraParamsRemoteTextBox.Text; //_peerConnection.PreferredAudioCodecExtraParamsLocal = PreferredAudioCodecExtraParamsLocalTextBox.Text; //_peerConnection.PreferredVideoCodec = PreferredVideoCodec; //_peerConnection.PreferredVideoCodecExtraParamsRemote = PreferredVideoCodecExtraParamsRemoteTextBox.Text; //_peerConnection.PreferredVideoCodecExtraParamsLocal = PreferredVideoCodecExtraParamsLocalTextBox.Text; switch (message.MessageType) { case NodeDssSignaler.Message.WireMessageType.Offer: await ApplyRemoteOfferAsync(message.Data); // If we get an offer, we immediately send an answer back once the offer is applied _peerConnection.CreateAnswer(); break; case NodeDssSignaler.Message.WireMessageType.Answer: await ApplyRemoteAnswerAsync(message.Data); break; case NodeDssSignaler.Message.WireMessageType.Ice: // TODO - This is NodeDSS-specific _peerConnection.AddIceCandidate(message.ToIceCandidate()); break; default: throw new InvalidOperationException($"Unhandled signaler message type '{message.MessageType}'"); } }
public void AddIceCandidate(IceCandidate candidate) { _peerConnection.AddIceCandidate(candidate.ToNative()); }
public async Task <string> InitiateCallRTC() { var list = new List <string>(); list.Add(this.Configuration.GetSection("Key")["iceServer"]); AudioTrackSource microphoneSource = null; LocalAudioTrack localAudioTrack = null; Transceiver audioTransceiver = null; var iceServer = new IceServer { Urls = list, TurnPassword = this.Configuration.GetSection("Key")["turnPwd"], TurnUserName = this.Configuration.GetSection("Key")["turnUser"] }; var serverList = new List <IceServer>(); serverList.Add(iceServer); var connectionConfig = new PeerConnectionConfiguration { IceServers = serverList, IceTransportType = IceTransportType.All, BundlePolicy = BundlePolicy.Balanced, SdpSemantic = SdpSemantic.UnifiedPlan }; var connection = new PeerConnection(); await connection.InitializeAsync(connectionConfig); microphoneSource = await DeviceAudioTrackSource.CreateAsync(); var audioTrackConfig = new LocalAudioTrackInitConfig { trackName = "microphone_track" }; localAudioTrack = LocalAudioTrack.CreateFromSource(microphoneSource, audioTrackConfig); audioTransceiver = connection.AddTransceiver(MediaKind.Audio); audioTransceiver.LocalAudioTrack = localAudioTrack; audioTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; var signaler = new NamedPipeSignaler.NamedPipeSignaler(connection, "testpipe"); connection.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; signaler.SdpMessageReceived += async(SdpMessage message) => { // Note: we use 'await' to ensure the remote description is applied // before calling CreateAnswer(). Failing to do so will prevent the // answer from being generated, and the connection from establishing. await connection.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { connection.CreateAnswer(); } }; await signaler.StartAsync(); signaler.IceCandidateReceived += (IceCandidate candidate) => { connection.AddIceCandidate(candidate); }; connection.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); connection.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } return(connection.IsConnected + "-" + connection.Name + "-"); }
static async Task Main(string[] args) { DataChannel dataChannel = null; try { // Create a new peer connection automatically disposed at the end of the program using var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); Console.WriteLine("Opening data channel"); dataChannel = await pc.AddDataChannelAsync("data", true, true); // Setup signaling Console.WriteLine("Starting signaling..."); var signaler = new NamedPipeSignaler.NamedPipeSignaler(pc, "testpipe"); signaler.SdpMessageReceived += (string type, string sdp) => { pc.SetRemoteDescription(type, sdp); if (type == "offer") { pc.CreateAnswer(); } }; signaler.IceCandidateReceived += (string sdpMid, int sdpMlineindex, string candidate) => { pc.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; await signaler.StartAsync(); // Start peer connection pc.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; pc.DataChannelAdded += (DataChannel c) => { Console.WriteLine("DataChannel added"); c.MessageReceived += (byte[] _msg) => { Console.WriteLine("received {0} bytes", _msg.Length); }; }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); pc.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } Console.WriteLine("Press a 'S' to send data. 'Esc' to exit ..."); ConsoleKeyInfo key; while ((key = Console.ReadKey(true)).Key != ConsoleKey.Escape) { if (key.Key == ConsoleKey.S) { Console.WriteLine("Sending data"); dataChannel.SendMessage(new byte[3000]); } } signaler.Stop(); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Program termined."); }
private async void OnLoaded(object sender, RoutedEventArgs e) { // Request access to microphone and camera var settings = new MediaCaptureInitializationSettings(); settings.StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo; var capture = new MediaCapture(); await capture.InitializeAsync(settings); // Retrieve a list of available video capture devices (webcams). List <VideoCaptureDevice> deviceList = await PeerConnection.GetVideoCaptureDevicesAsync(); // Get the device list and, for example, print them to the debugger console foreach (var device in deviceList) { // This message will show up in the Output window of Visual Studio Debugger.Log(0, "", $"Webcam {device.name} (id: {device.id})\n"); } _peerConnection = new PeerConnection(); var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await _peerConnection.InitializeAsync(config); Debugger.Log(0, "", "Peer connection initialized successfully.\n"); await _peerConnection.AddLocalAudioTrackAsync(); if (Settings.m_showLocal) { //LocalVideoTrack _localVideoTrack; await _peerConnection.AddLocalVideoTrackAsync(); _peerConnection.I420LocalVideoFrameReady += Peer_LocalI420AFrameReady; await _peerConnection.AddLocalAudioTrackAsync(); remoteVideoPlayerElement.Visibility = Visibility.Visible; } else { _peerConnection.Connected += () => { Debugger.Log(0, "", "PeerConnection: connected.\n"); }; _peerConnection.IceStateChanged += (IceConnectionState newState) => { Debugger.Log(0, "", $"ICE state: {newState}\n"); }; _peerConnection.I420RemoteVideoFrameReady += Peer_RemoteI420AFrameReady; _peerConnection.LocalSdpReadytoSend += Peer_LocalSdpReadytoSend; _peerConnection.IceCandidateReadytoSend += Peer_IceCandidateReadytoSend; // Initialize the signaler _signaler = new NodeDssSignaler() { HttpServerAddress = "http://10.44.160.22:3000/", LocalPeerId = "DINF-D60015-43A", RemotePeerId = "HOLOLENS-RO2J0", }; _signaler.OnMessage += (NodeDssSignaler.Message msg) => { switch (msg.MessageType) { case NodeDssSignaler.Message.WireMessageType.Offer: _peerConnection.SetRemoteDescription("offer", msg.Data); _peerConnection.CreateAnswer(); break; case NodeDssSignaler.Message.WireMessageType.Answer: _peerConnection.SetRemoteDescription("answer", msg.Data); break; case NodeDssSignaler.Message.WireMessageType.Ice: var parts = msg.Data.Split(new string[] { msg.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); // Note the inverted arguments for historical reasons. // 'candidate' is last in AddIceCandidate(), but first in the message. string sdpMid = parts[2]; int sdpMlineindex = int.Parse(parts[1]); string candidate = parts[0]; _peerConnection.AddIceCandidate(sdpMid, sdpMlineindex, candidate); break; } }; _signaler.StartPollingAsync(); } // Interactions Debug.WriteLine("[Playback::start] Waiting for a connection..."); m_dsUdpSocket = new DatagramSocket(); m_dsUdpSocket.MessageReceived += Socket_MessageReceived; // Initialization UDP communication try { await m_dsUdpSocket.ConnectAsync(new EndpointPair(new HostName(Settings.m_sIPLocalUDP), Settings.m_sPortLocalUDP, new HostName(Settings.m_sIPRemoteUDP), Settings.m_sPortRemoteUDP)); m_output = new DataWriter(m_dsUdpSocket.OutputStream); Debug.WriteLine("[Playback::start] UDP connection initialization ok"); } catch (Exception) { Debug.WriteLine("[Playback::start] Error - UDP connection initialization "); } }
static async Task Main(string[] args) { try { bool needVideo = Array.Exists(args, arg => (arg == "-v") || (arg == "--video")); bool needAudio = Array.Exists(args, arg => (arg == "-a") || (arg == "--audio")); // Asynchronously retrieve a list of available video capture devices (webcams). var deviceList = await PeerConnection.GetVideoCaptureDevicesAsync(); // For example, print them to the standard output foreach (var device in deviceList) { Console.WriteLine($"Found webcam {device.name} (id: {device.id})"); } // Create a new peer connection automatically disposed at the end of the program using var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); // Record video from local webcam, and send to remote peer if (needVideo) { Console.WriteLine("Opening local webcam..."); await pc.AddLocalVideoTrackAsync(); } // Record audio from local microphone, and send to remote peer if (needAudio) { Console.WriteLine("Opening local microphone..."); await pc.AddLocalAudioTrackAsync(); } // Setup signaling Console.WriteLine("Starting signaling..."); var signaler = new NamedPipeSignaler.NamedPipeSignaler(pc, "testpipe"); signaler.SdpMessageReceived += (string type, string sdp) => { pc.SetRemoteDescription(type, sdp); if (type == "offer") { pc.CreateAnswer(); } }; signaler.IceCandidateReceived += (string sdpMid, int sdpMlineindex, string candidate) => { pc.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; await signaler.StartAsync(); // Start peer connection pc.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; int numFrames = 0; pc.I420RemoteVideoFrameReady += (I420AVideoFrame frame) => { ++numFrames; if (numFrames % 60 == 0) { Console.WriteLine($"Received video frames: {numFrames}"); } }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); pc.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } Console.WriteLine("Press a key to stop recording..."); Console.ReadKey(true); signaler.Stop(); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Program termined."); }
private async void Window_Initialized(object sender, EventArgs e) { _peerConnection = new PeerConnection(); var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "turn:35.193.0.31:3478" }, TurnPassword = "******", TurnUserName = "******" } } }; _peerConnection.Connected += () => { Debugger.Log(0, "", "Peerconnection: DONE"); }; _peerConnection.IceStateChanged += (IceConnectionState newState) => { Debugger.Log(0, "", $"ICE state: {newState}\n"); }; await _peerConnection.InitializeAsync(config); _dc = await _peerConnection.AddDataChannelAsync(14, "vzgo", true, true); Debugger.Log(0, "", "Peer connection initialized successfully.\n"); _peerConnection.LocalSdpReadytoSend += Peer_LocalSdpReadytoSendAsync; _peerConnection.IceCandidateReadytoSend += Peer_IceCandidateReadytoSend; _hubConnection = new HubConnectionBuilder() .WithUrl(new Uri(SignallerConstants.SignallerUrl)) .AddJsonProtocol() .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) }) .Build(); _hubConnection.On <string>("Message", (message) => { var msg = JsonConvert.DeserializeObject <SignallingMessage>(message); switch (msg.MessageType) { case SignallingMessage.WireMessageType.Offer: _peerConnection.SetRemoteDescription("offer", msg.Data); _peerConnection.CreateAnswer(); break; case SignallingMessage.WireMessageType.Answer: _peerConnection.SetRemoteDescription("answer", msg.Data); break; case SignallingMessage.WireMessageType.Ice: var parts = msg.Data.Split(new string[] { msg.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); // Note the inverted arguments for historical reasons. // 'candidate' is last in AddIceCandidate(), but first in the message. string sdpMid = parts[2]; int sdpMlineindex = int.Parse(parts[1]); string candidate = parts[0]; _peerConnection.AddIceCandidate(sdpMid, sdpMlineindex, candidate); break; } }); await _hubConnection.StartAsync(); await _hubConnection.InvokeAsync("JoinRoom", SignallerConstants.RoomName); }
public async Task SetupAsync(Signaler signaler, bool isServer, uint clientNodeId = 0) { await pc.InitializeAsync(new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { signaler.IceServerUrl } } } }); var tcs = new TaskCompletionSource <bool>(); // Do signaling // https://microsoft.github.io/MixedReality-WebRTC/manual/cs/cs-signaling.html // https://microsoft.github.io/MixedReality-WebRTC/manual/cs/helloworld-cs-signaling-core3.html pc.LocalSdpReadytoSend += (SdpMessage sdpMessage) => { // ここはawaitではなくWaitにしないとSocketが切れる.スレッドセーフ関係? signaler.SendSdpAsync(sdpMessage.Type == SdpMessageType.Offer, sdpMessage.Content, clientNodeId).Wait(); }; pc.IceCandidateReadytoSend += (IceCandidate candidate) => { signaler.SendIceAsync(candidate.SdpMid, candidate.SdpMlineIndex, candidate.Content, clientNodeId).Wait(); }; pc.IceStateChanged += (IceConnectionState state) => { Logger.Debug("Connection", $"ICE state changed to {state}"); // https://microsoft.github.io/MixedReality-WebRTC/versions/release/2.0/api/Microsoft.MixedReality.WebRTC.IceConnectionState.html if (state == IceConnectionState.Connected) { Connected = true; } if (state == IceConnectionState.Closed || state == IceConnectionState.Disconnected || state == IceConnectionState.Failed) { Connected = false; OnDisconnect(); } if (!isServer && state == IceConnectionState.Failed) { tcs.SetException(new ConnectionException("Failed to establish a WebRTC connection")); } }; signaler.SdpReceived += async(bool isOffer, string sdp, uint cid) => { if (isServer && cid != clientNodeId) { // ignore messages for other clients return; } await pc.SetRemoteDescriptionAsync(new SdpMessage { Type = isOffer ? SdpMessageType.Offer : SdpMessageType.Answer, Content = sdp }); if (isOffer) { pc.CreateAnswer(); } }; signaler.IceReceived += (string sdpMid, int sdpMLineIndex, string candidate, uint cid) => { if (isServer && cid != clientNodeId) { // ignore messages for other clients return; } pc.AddIceCandidate(new IceCandidate { SdpMid = sdpMid, SdpMlineIndex = sdpMLineIndex, Content = candidate }); //Logger.Write((isServer ? "Server: " : "Client: ") + $"{sdpMid} {sdpMLineIndex} {candidate}"); }; if (isServer) { TaskCompletionSource <DataChannel>[] completionSources = channelTypes.Select( _ => new TaskCompletionSource <DataChannel>() ).ToArray(); pc.DataChannelAdded += (dc) => { foreach (var type in channelTypes) { if (dc.Label == channelLabels[(int)type]) { completionSources[(int)type].SetResult(dc); } } }; Logger.Debug("Connection", "Server is ready for signaling"); await signaler.NotifyReadyAsync(clientNodeId); Logger.Debug("Connection", "Server: Waiting for DC"); foreach (var type in channelTypes) { channels[(int)type] = await completionSources[(int)type].Task; } } else { // Define channels // Sync channel (unreliable) channels[(int)ChannelType.Sync] = await pc.AddDataChannelAsync( channelLabels[(int)ChannelType.Sync], ordered : false, reliable : false); // Message channel (reliable but order is not guaranteed) channels[(int)ChannelType.Control] = await pc.AddDataChannelAsync( channelLabels[(int)ChannelType.Control], ordered : false, reliable : true); // Blob channel (reliable and ordered) channels[(int)ChannelType.Blob] = await pc.AddDataChannelAsync( channelLabels[(int)ChannelType.Blob], ordered : true, reliable : true); // Audio channel (unreliable) channels[(int)ChannelType.Audio] = await pc.AddDataChannelAsync( channelLabels[(int)ChannelType.Audio], ordered : false, reliable : false); Logger.Debug("Connection", "Client: Waiting for server ready"); await signaler.WaitReadyAsync(); pc.CreateOffer(); } foreach (var(dc, idx) in channels.Select((dc, idx) => (dc, idx))) { dc.MessageReceived += (data) => { threadChannels[idx].Writer.TryWrite(data); // Always succeeds because the Channel is unbounded }; dc.StateChanged += () => { Logger.Debug("Connection", $"DC {(ChannelType)idx} state changed to {dc.State}"); if (dc.State == DataChannel.ChannelState.Closing) { // Disconnect handling Connected = false; } }; } //await Task.Delay(5000); if (!isServer) { // FIXME: Waiting pc.Connected not work in server (cannot establish a connection to client) // In server, should wait until all DataChannels are added? pc.Connected += () => { tcs.SetResult(true); }; await tcs.Task; } }
static private async Task StartStend() { var autoEvent = new AutoResetEvent(false); bool video_translator = true; bool file_created = false; FileStream file = null; Quartus quartus = Quartus.GetInstance(); Microcontroller arduino = Microcontroller.Create(); if (video_translator) { // Asynchronously retrieve a list of available video capture devices (webcams). var deviceList = await DeviceVideoTrackSource.GetCaptureDevicesAsync(); // For example, print them to the standard output foreach (var device in deviceList) { Console.WriteLine($"Found webcam {device.name} (id: {device.id})"); } } // Create a new peer connection automatically disposed at the end of the program var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = SystemConfiguration.PeerConnectionSettings; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); //var chen = await pc.AddDataChannelAsync("sendDataChannel", true, true, cancellationToken: default); Console.WriteLine("Opening local webcam..."); // pc - PeerConnection object Transceiver videoTransceiver = null; VideoTrackSource videoTrackSource = null; LocalVideoTrack localVideoTrack = null; LocalVideoDeviceInitConfig c = new LocalVideoDeviceInitConfig(); await VideoDeviceSelection(); videoTrackSource = await Camera.CreateAsync(SystemConfiguration.VideoDeviceSettings); WebSocketSharp.WebSocket signaling = new WebSocketSharp.WebSocket(CreateSignalingServerUrl(), "id_token", "alpine"); pc.LocalSdpReadytoSend += (SdpMessage message) => { //Console.WriteLine(SdpMessage.TypeToString(message.Type)); Console.WriteLine(message.Content); //Console.WriteLine(HttpUtility.JavaScriptStringEncode(message.Content)); Console.WriteLine("Sdp offer to send: {\"data\":{\"description\":{\"type\":\"" + SdpMessage.TypeToString(message.Type) + "\",\"sdp\":\"" + HttpUtility.JavaScriptStringEncode(message.Content) + "\"}}}"); signaling.Send(message.ToABJson()); }; pc.RenegotiationNeeded += () => { Console.WriteLine("Regotiation needed"); bool OfferCreated = pc.CreateOffer(); Console.WriteLine("OfferCreated? {0}", OfferCreated); }; pc.DataChannelAdded += (DataChannel channel) => { Console.WriteLine("Added data channel ID: {0}, Label: {1}; Reliable: {2}, Ordered: {3}", channel.ID, channel.Label, channel.Reliable, channel.Ordered); if (channel.Label == "sendDataChannel") { channel.MessageReceived += (byte[] mess) => { try { CTP_packet command = JsonSerializer.Deserialize <CTP_packet>(mess); Console.WriteLine(arduino.SendCTP_Command(command)); } catch (Exception e) { Console.WriteLine(e.Message); } }; } else { if (file_created == false) { file = new FileStream(channel.Label, FileMode.Append); file_created = true; } channel.MessageReceived += async(byte[] mess) => { // Console.WriteLine(System.Text.Encoding.Default.GetString(mess)); if (mess.Length == 3 && System.Text.Encoding.Default.GetString(mess) == "EOF") { string file_name = file.Name; file.Close(); string t = await quartus.RunQuartusCommandAsync($"quartus_pgm -m jtag –o \"p;{file_name}@1\""); File.Delete(file_name); file_created = false; } else { WriteFileSegment(mess, file); } }; } channel.StateChanged += () => { Console.WriteLine("State change: {0}", channel.State); }; }; pc.IceCandidateReadytoSend += (IceCandidate candidate) => { //Console.WriteLine("Content: {0}, SdpMid: {1}, SdpMlineIndex: {2}", candidate.Content, candidate.SdpMid, candidate.SdpMlineIndex); try { Console.WriteLine("Candidate to send: Content: {0}, SdpMid: {1}, SdpMlineIndex: {2}", candidate.Content, candidate.SdpMid, candidate.SdpMlineIndex); signaling.Send(candidate.ToABJson()); } catch (Exception e) { Console.WriteLine("Error to send local ice candidate"); } }; //videoTrackSource.I420AVideoFrameReady += (frame) => //{ // Console.WriteLine("Argb32 frame ready. {0} : {1}", frame.width, frame.height); // Console.WriteLine("DataA: {0}, DataU: {1}, DataV: {2}, DataY: {3}", Marshal.SizeOf(frame.dataA), // Marshal.SizeOf(frame.dataU), // Marshal.SizeOf(frame.dataV), // Marshal.SizeOf(frame.dataY)); //}; signaling.OnMessage += async(sender, message) => { (string header, string correct_message) = message.Data.DivideHeaderAndOriginalJSON(); Console.WriteLine("Correct message: {0}", correct_message); Console.WriteLine("Header: {0}", header); if (header == "{\"data\":{\"getRemoteMedia\":" && correct_message == "true") { Console.WriteLine("Create local video track..."); var trackSettings = new LocalVideoTrackInitConfig { trackName = "webcam_track" }; localVideoTrack = LocalVideoTrack.CreateFromSource(videoTrackSource, new LocalVideoTrackInitConfig { trackName = "webcam_track" }); Console.WriteLine("Create video transceiver and add webcam track..."); TransceiverInitSettings option = new TransceiverInitSettings(); option.Name = "webcam_track"; option.StreamIDs = new List <string> { "webcam_name" }; videoTransceiver = pc.AddTransceiver(MediaKind.Video, option); videoTransceiver.DesiredDirection = Transceiver.Direction.SendOnly; videoTransceiver.LocalVideoTrack = localVideoTrack; bool OfferCreated = pc.CreateOffer(); Console.WriteLine("OfferCreated? {0}", OfferCreated); } //Console.WriteLine(message.Data); if (header.IndexOf("candidate") != -1 && correct_message != "null") { try { var candidate = JsonSerializer.Deserialize <ICEJavaScriptNotation>(correct_message); Console.WriteLine("Content of ice: {0}, SdpMid: {1}, SdpMLineIndex: {2}", candidate.candidate, candidate.sdpMid, candidate.sdpMLineIndex); pc.AddIceCandidate(candidate.ToMRNetCoreNotation()); Console.WriteLine("Deserialized by ice_candidate"); //return; } catch (Exception) { Console.WriteLine("Could not deserialize as ice candidate"); } } if (header.IndexOf("description") != -1) { try { SdpMessage received_description = JsonSerializer.Deserialize <SDPJavaScriptNotation>(correct_message).ToMRNetCoreNotation(); await pc.SetRemoteDescriptionAsync(received_description); if (received_description.Type == SdpMessageType.Offer) { bool res = pc.CreateAnswer(); Console.WriteLine("Answer created? {0}", res); } Console.WriteLine("Deserialized by sdp_message"); } catch (Exception) { Console.WriteLine("Could not deserialize as sdp message"); } } }; pc.Connected += () => { Console.WriteLine("Connected"); }; pc.IceStateChanged += (IceConnectionState newState) => { if (newState == IceConnectionState.Disconnected) { Console.WriteLine("Disconected"); } }; signaling.Connect(); if (!video_translator) { signaling.Send("{\"data\":{\"getRemoteMedia\":true}}"); } //Console.WriteLine("Press a key to terminate the application..."); Console.ReadKey(true); Console.WriteLine("Program termined."); file?.Close(); pc?.Close(); signaling?.Close(); //arduino?.Close(); //(var a, var b) = ConvertString("{\"data\":{\"candidate\":null}}"); //Console.WriteLine("{0}, {1}", a, b); }
//Loaded-EventHandler of ui: executes after ui-loading private async void OnLoaded(object sender, RoutedEventArgs e) { //Request access to mic and cam MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings(); settings.StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo; MediaCapture capture = new MediaCapture(); await capture.InitializeAsync(settings); //Get list of cams camList = await PeerConnection.GetVideoCaptureDevicesAsync(); //Print list to log foreach (var cam in camList) { Debugger.Log(0, "", $"Webcam: {cam.name} (id: {cam.id})\n"); } //Ask user for ids (show MessageBox) await ShowIdInputBoxAsync(); //New PeerConnection (Access to WebRTC) peerConnection = new PeerConnection(); //Create PeerConnection-config PeerConnectionConfiguration config = new PeerConnectionConfiguration() { IceServers = new List <IceServer>() { //Using google stun server for testing new IceServer() { Urls = { "stun:stun.l.google.com:19302" } } } }; //Initialize PeerContection await peerConnection.InitializeAsync(config); //Event fires, when local video frame is captured and ready for rendering peerConnection.I420LocalVideoFrameReady += Peer_LocalI420FrameReady; //Event fires, when remote video frame is receved and ready for rendering peerConnection.I420RemoteVideoFrameReady += Peer_RemoteI420FrameReady; //Events fires, when SdpMessage is ready for sending peerConnection.LocalSdpReadytoSend += Peer_LocalSdpReadytoSend; //Event fires, when IceCandidate is ready for sending peerConnection.IceCandidateReadytoSend += Peer_IceCandidateReadytoSend; //Set DebuggingLog-messages peerConnection.Connected += () => Debugger.Log(0, "", "PeerConnection: connected\n"); peerConnection.IceStateChanged += (IceConnectionState newState) => Debugger.Log(0, "", $"ICE state: {newState}\n"); Debugger.Log(0, "", "Peer conection initialized successfully\n"); //Adds cam-tracks from standart (first) devices [add parameter to specify cam-device or -specifications] await peerConnection.AddLocalVideoTrackAsync(new PeerConnection.LocalVideoTrackSettings() { videoDevice = cam }); //Same for mic [no specifications possible: always uses the first mic in list] await peerConnection.AddLocalAudioTrackAsync(); //Initialize the signaler (Properties from MessageBox) signaler = new NodeDssSignaler() { HttpServerAddress = nodeDssServerIp, LocalPeerId = localId, RemotePeerId = remoteId }; signaler.OnMessage += (NodeDssSignaler.Message msg) => { switch (msg.MessageType) { case NodeDssSignaler.Message.WireMessageType.Offer: peerConnection.SetRemoteDescription("offer", msg.Data); peerConnection.CreateAnswer(); break; case NodeDssSignaler.Message.WireMessageType.Answer: peerConnection.SetRemoteDescription("answer", msg.Data); break; case NodeDssSignaler.Message.WireMessageType.Ice: string[] parts = msg.Data.Split(new string[] { msg.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); //Changing order of parts string sdpMid = parts[2]; int sdpMlineindex = int.Parse(parts[1]); string candidate = parts[0]; peerConnection.AddIceCandidate(sdpMid, sdpMlineindex, candidate); break; } }; signaler.StartPollingAsync(); }
public void AddIceCandidate(RTCIceCandidate iceCandidate) { MustNotDisposed(); _peerConnectionImpl.AddIceCandidate(iceCandidate); }
static async Task Main(string[] args) { Transceiver audioTransceiver = null; Transceiver videoTransceiver = null; AudioTrackSource audioTrackSource = null; VideoTrackSource videoTrackSource = null; LocalAudioTrack localAudioTrack = null; LocalVideoTrack localVideoTrack = null; try { bool needVideo = Array.Exists(args, arg => (arg == "-v") || (arg == "--video")); bool needAudio = Array.Exists(args, arg => (arg == "-a") || (arg == "--audio")); // Asynchronously retrieve a list of available video capture devices (webcams). var deviceList = await PeerConnection.GetVideoCaptureDevicesAsync(); // For example, print them to the standard output foreach (var device in deviceList) { Console.WriteLine($"Found webcam {device.name} (id: {device.id})"); } // Create a new peer connection automatically disposed at the end of the program using var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); // Record video from local webcam, and send to remote peer if (needVideo) { Console.WriteLine("Opening local webcam..."); videoTrackSource = await DeviceVideoTrackSource.CreateAsync(); Console.WriteLine("Create local video track..."); var trackSettings = new LocalVideoTrackInitConfig { trackName = "webcam_track" }; localVideoTrack = LocalVideoTrack.CreateFromSource(videoTrackSource, trackSettings); Console.WriteLine("Create video transceiver and add webcam track..."); videoTransceiver = pc.AddTransceiver(MediaKind.Video); videoTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; videoTransceiver.LocalVideoTrack = localVideoTrack; } // Record audio from local microphone, and send to remote peer if (needAudio) { Console.WriteLine("Opening local microphone..."); audioTrackSource = await DeviceAudioTrackSource.CreateAsync(); Console.WriteLine("Create local audio track..."); var trackSettings = new LocalAudioTrackInitConfig { trackName = "mic_track" }; localAudioTrack = LocalAudioTrack.CreateFromSource(audioTrackSource, trackSettings); Console.WriteLine("Create audio transceiver and add mic track..."); audioTransceiver = pc.AddTransceiver(MediaKind.Audio); audioTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; audioTransceiver.LocalAudioTrack = localAudioTrack; } // Setup signaling Console.WriteLine("Starting signaling..."); var signaler = new NamedPipeSignaler.NamedPipeSignaler(pc, "testpipe"); signaler.SdpMessageReceived += async(SdpMessage message) => { await pc.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc.CreateAnswer(); } }; signaler.IceCandidateReceived += (IceCandidate candidate) => { pc.AddIceCandidate(candidate); }; await signaler.StartAsync(); // Start peer connection pc.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; int numFrames = 0; pc.VideoTrackAdded += (RemoteVideoTrack track) => { track.I420AVideoFrameReady += (I420AVideoFrame frame) => { ++numFrames; if (numFrames % 60 == 0) { Console.WriteLine($"Received video frames: {numFrames}"); } }; }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); pc.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } Console.WriteLine("Press a key to stop recording..."); Console.ReadKey(true); signaler.Stop(); } catch (Exception e) { Console.WriteLine(e.Message); } localAudioTrack?.Dispose(); localVideoTrack?.Dispose(); Console.WriteLine("Program termined."); localAudioTrack.Dispose(); localVideoTrack.Dispose(); audioTrackSource.Dispose(); videoTrackSource.Dispose(); }
protected override async void OnMessage(MessageEventArgs e) { var msg = e.Data; var jsonMsg = JObject.Parse(msg); Util.WriteLine($"WebSocketSignaller.OnMessage {Util.PrettyPrint(msg, 20)}..."); if ((string)jsonMsg["type"] == "ice") { while (!peer.Initialized) { // This delay is needed due to an initialise bug in the Microsoft.MixedReality.WebRTC // nuget packages up to version 0.2.3. On master awaiting pc.InitializeAsync does end // up with the pc object being ready. Util.WriteLine("WebSocketSignaller.peer.NotInitialized - Sleeping for 1s while peer connection is initialising..."); await Task.Delay(1000); } Util.WriteLine("WebSocketSignaller.AddIceCandidate"); peer.AddIceCandidate((string)jsonMsg["sdpMLineindex"], (int)jsonMsg["sdpMid"], (string)jsonMsg["candidate"]); } else if ((string)jsonMsg["type"] == "sdp") { Util.WriteLine("WebSocketSignaller.OnMessage - Received SDP offer."); peer.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { var iceCandidate = new JObject { { "type", "ice" }, { "candidate", candidate }, { "sdpMLineindex", sdpMlineindex }, { "sdpMid", sdpMid } }.ToString(); Util.WriteLine($"WebSocketSignaller.SendIceCandidate - {Util.PrettyPrint(iceCandidate, 20)}"); Context.WebSocket.Send(iceCandidate); }; peer.LocalSdpReadytoSend += (string type, string sdp) => { var msgType = receivedOffer ? "answer" : "offer"; var sdpAnswer = new JObject { { "type", "sdp" }, { msgType, sdp } }.ToString(); Util.WriteLine($"WebSocketSignaller.SendSDP - {Util.PrettyPrint(sdpAnswer, 20)}"); Context.WebSocket.Send(sdpAnswer); }; if (!peer.Initialized) { Util.WriteLine($"WebSocketSignaller.peer.InitializeAsync"); await peer.InitializeAsync(PeerConnectionConfig.Default); } if (jsonMsg.ContainsKey("answer")) { var answer = (string)jsonMsg["answer"]; Util.WriteLine($"WebSocketSignaller.SetRemoteDescription - answer='{Util.PrettyPrint(answer, 20)}...'"); await peer.SetRemoteDescriptionAsync("answer", answer); } else if (jsonMsg.ContainsKey("offer")) { var offer = (string)jsonMsg["offer"]; Util.WriteLine($"WebSocketSignaller.SetRemoteDescription - offer='{Util.PrettyPrint(offer, 20)}...'"); await peer.SetRemoteDescriptionAsync("offer", offer); receivedOffer = true; Util.WriteLine($"WebSocketSignaller.CreateAnswer"); if (!peer.CreateAnswer()) { Console.WriteLine("WebSocketSignaller - Failed to create peer connection answer, closing peer connection."); Dispose(); } } else { throw new Exception("Unknown message " + msg); } Util.WriteLine("WebSocketSignaller.Complete"); } }
public async Task InBand() { // Setup var config = new PeerConnectionConfiguration(); var pc1 = new PeerConnection(); var pc2 = new PeerConnection(); await pc1.InitializeAsync(config); await pc2.InitializeAsync(config); pc1.LocalSdpReadytoSend += (string type, string sdp) => { pc2.SetRemoteDescription(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += (string type, string sdp) => { pc1.SetRemoteDescription(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); // Add dummy out-of-band data channel to force SCTP negotiating. // Otherwise after connecting AddDataChannelAsync() will fail. await pc1.AddDataChannelAsync(42, "dummy", false, false); await pc2.AddDataChannelAsync(42, "dummy", false, false); // Connect { var c1 = new ManualResetEventSlim(false); var c2 = new ManualResetEventSlim(false); pc1.Connected += () => c1.Set(); pc2.Connected += () => c2.Set(); Assert.True(pc1.CreateOffer()); Assert.True(c1.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(pc1.IsConnected); Assert.True(pc1.IsConnected); } // Negotiate data channel in-band DataChannel data1 = null; DataChannel data2 = null; { var c2 = new ManualResetEventSlim(false); pc2.DataChannelAdded += (DataChannel channel) => { data2 = channel; c2.Set(); }; data1 = await pc1.AddDataChannelAsync("test_data_channel", true, true); Assert.IsNotNull(data1); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); Assert.IsNotNull(data2); Assert.AreEqual(data1.Label, data2.Label); // Do not test DataChannel.ID; at this point for in-band channels the ID has not // been agreed upon with the remote peer yet. } // Send data { var c2 = new ManualResetEventSlim(false); string sentText = "Some sample text"; byte[] msg = Encoding.UTF8.GetBytes(sentText); data2.MessageReceived += (byte[] _msg) => { var receivedText = Encoding.UTF8.GetString(_msg); Assert.AreEqual(sentText, receivedText); c2.Set(); }; data1.SendMessage(msg); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); } // Clean-up pc1.Close(); pc1.Dispose(); pc2.Close(); pc2.Dispose(); }
public void AddIceCandidate(Core.IceCandidate iceCandidate) => _peerConnection.AddIceCandidate(iceCandidate.ToPlatformNative());
private void OnIceCandidateReadytoSend2(string candidate, int sdpMlineindex, string sdpMid) { pc1_.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }
private void OnIceCandidateReadytoSend2(IceCandidate candidate) { pc1_.AddIceCandidate(candidate); }