/// <summary> /// Initializes a new instance of the <see cref="WebRTCAdapter"/> class. /// </summary> /// <param name="signalingTransporter">The signaling transporter.</param> /// <param name="role">The adapter role.</param> public WebRTCAdapter(IResonanceTransporter signalingTransporter, WebRTCAdapterRole role) : this() { Role = role; _signalingTransporter = signalingTransporter; _signalingTransporter.RegisterRequestHandler <WebRTCIceCandidateRequest, WebRTCIceCandidateResponse>(OnWebRTCCandidateRequest); _signalingTransporter.RegisterRequestHandler <WebRTCOfferRequest, WebRTCOfferResponse>(OnWebRTCOfferRequest); }
private async void _server_ConnectionRequest(object sender, ResonanceListeningServerConnectionRequestEventArgs <BluetoothAdapter> e) { IResonanceTransporter transporter = ResonanceTransporter.Builder .Create() .WithAdapter(e.Accept()) .WithJsonTranscoding() .Build(); transporter.StateChanged += (x, ee) => { if (ee.NewState != ResonanceComponentState.Connected) { InvokeUI(() => { ConnectedDevices.Remove(transporter); }); } }; transporter.RegisterRequestHandler <ChatMessageRequest, ChatMessageResponse>(OnChatRequest); await transporter.ConnectAsync(); InvokeUI(() => { ConnectedDevices.Add(transporter); if (SelectedDevice == null) { SelectedDevice = transporter; } }); }
/// <summary> /// Registers for a WebRTC offer request. /// Should be used only from a 'Signaling' transporter. /// </summary> /// <param name="transporter">The transporter.</param> /// <param name="callback">Callback method with the Offer request.</param> public static void OnWebRtcOffer(this IResonanceTransporter transporter, Action <ResonanceMessage <WebRTCOfferRequest> > callback) { transporter.RegisterRequestHandler <WebRTCOfferRequest>((_, request) => { callback?.Invoke(request); }); }
/// <summary> /// Starts a SignalR session and WebRTC session with the selected client. /// </summary> private async void StartSession() { if (!IsInSession) { try { IsFree = false; Logger.LogInformation($"Starting SignalR session with {SelectedClient.ServiceId} for signaling..."); _signalingTransporter = ResonanceTransporter.Builder .Create() .WithSignalRAdapter(SignalRMode.Legacy) .WithCredentials(new DemoCredentials() { Name = ClientID }) .WithServiceId(SelectedClient.ServiceId) .WithUrl(HubUrl) .WithJsonTranscoding() .Build(); _signalingTransporter.ConnectionLost += OnSignalingConnectionLost; await _signalingTransporter.ConnectAsync(); Logger.LogInformation("SignalR session started."); Logger.LogInformation("Initiating WebRTC session..."); _webRtcTransporter = ResonanceTransporter.Builder .Create() .WithWebRTCAdapter() .WithSignalingTransporter(_signalingTransporter) .WithRole(WebRTCAdapterRole.Connect) .WithDefaultIceServers() .WithJsonTranscoding() .Build(); _webRtcTransporter.ConnectionLost += OnWebRTCConnectionLost; _webRtcTransporter.RegisterRequestHandler <EchoTextRequest, EchoTextResponse>(OnEchoTextMessageReceived); Logger.LogInformation("Connecting WebRTC transporter."); await _webRtcTransporter.ConnectAsync(); IsInSession = true; Logger.LogInformation("WebRTC transporter connected!"); } catch (Exception ex) { Logger.LogError(ex, ex.Message); } finally { IsFree = true; } } }
/// <summary> /// Handles incoming signaling connection request from the registered listening service. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="ConnectionRequestEventArgs{DemoCredentials, DemoAdapterInformation}"/> instance containing the event data.</param> private async void OnServiceConnectionRequest(object sender, ConnectionRequestEventArgs <DemoCredentials, DemoAdapterInformation> e) { Logger.LogInformation($"Connection request from {e.RemoteAdapterInformation.Name}."); if (IsInSession) { Logger.LogInformation($"Already in session. Connection request declined."); e.Decline(); return; } try { Logger.LogInformation("Starting SignalR session for signaling..."); SelectedClient = ConnectedClients.FirstOrDefault(x => x.ServiceId == e.RemoteAdapterInformation.Name); IsFree = false; _signalingTransporter = ResonanceTransporter.Builder .Create() .WithAdapter(e.Accept()) .WithJsonTranscoding() .Build(); _signalingTransporter.ConnectionLost += OnSignalingConnectionLost; await _signalingTransporter.ConnectAsync(); Logger.LogInformation("SignalR session started. Waiting for WebRTC offer..."); Logger.LogInformation("Connecting WebRTC transporter..."); _webRtcTransporter = ResonanceTransporter.Builder .Create() .WithWebRTCAdapter() .WithSignalingTransporter(_signalingTransporter) .WithRole(WebRTCAdapterRole.Accept) .WithDefaultIceServers() .WithJsonTranscoding() .Build(); _webRtcTransporter.ConnectionLost += OnWebRTCConnectionLost; _webRtcTransporter.RegisterRequestHandler <EchoTextRequest, EchoTextResponse>(OnEchoTextMessageReceived); await _webRtcTransporter.ConnectAsync(); IsInSession = true; IsFree = true; Logger.LogInformation("WebRTC transporter connected!"); } catch (Exception ex) { IsFree = true; Logger.LogError(ex, ""); } }
private async void Connect() { if (!IsConnected) { try { IsFree = false; _transporter = ResonanceTransporter.Builder .Create() .WithTcpAdapter() .WithAddress(SelectedService.Address) .WithPort(SelectedService.DiscoveryInfo.Port) .WithJsonTranscoding() .Build(); _transporter.ConnectionLost += ConnectionLost; _transporter.RegisterRequestHandler <JoinSessionRequest>(OnJoinSessionRequest); _transporter.RegisterRequestHandler <NotifyAvailableClientsRequest>(OnNotifyAvailableClientsRequest); _transporter.RegisterRequestHandler <EchoTextRequest, EchoTextResponse>(OnEchoTextRequest); _transporter.RegisterRequestHandler <LeaveSessionRequest>(OnLeaveSessionRequest); await _transporter.ConnectAsync(); await _transporter.SendRequestAsync <LoginRequest, LoginResponse>(new LoginRequest() { ClientID = ClientID }); await _discoveryClient.StopAsync(); IsConnected = true; } catch (Exception ex) { Logger.LogError(ex, ex.Message); } finally { IsFree = true; } } }
/// <summary> /// Initializes a new instance of the <see cref="WebRTCAdapter"/> class. /// </summary> /// <param name="signalingTransporter">The signaling transporter.</param> /// <param name="role">The adapter role.</param> public WebRTCAdapterNative(IResonanceTransporter signalingTransporter, WebRTCAdapterRole role) : this() { Role = role; _signalingTransporter = signalingTransporter; if (_offerRequest == null) { _signalingTransporter.RegisterRequestHandler <WebRTCOfferRequest, WebRTCOfferResponse>(OnWebRTCOfferRequest); } }
private async void Connect() { try { using (UserDialogs.Instance.Loading("Connecting...")) { _transporter = ResonanceTransporter.Builder .Create() .WithAdapter(new BluetoothAdapter(SelectedDevice)) .WithJsonTranscoding() .Build(); _transporter.StateChanged += (x, e) => { InvokeUI(async() => { SendCommand.ChangeCanExecute(); if (e.PreviousState == ResonanceComponentState.Connected && e.NewState == ResonanceComponentState.Failed) { await Navigation.PopAsync(); UserDialogs.Instance.Toast($"Connection lost.\n{_transporter.FailedStateException}"); } }); }; _transporter.RegisterRequestHandler <ChatMessageRequest, ChatMessageResponse>(OnChatRequest); await _transporter.ConnectAsync(); SelectedDevice.Refresh(); Logs.Clear(); } await Navigation.PushAsync(new ChatPage(), true); } catch (Exception ex) { UserDialogs.Instance.Toast($"Error connecting to the selected device.\n{ex.Message}"); } }
public void Stress_Test_With_Small_Data_Volume() { if (IsRunningOnAzurePipelines) { return; } IResonanceTransporter signal1 = ResonanceTransporter.Builder .Create() .WithInMemoryAdapter() .WithAddress("TST") .WithJsonTranscoding() .Build(); IResonanceTransporter signal2 = ResonanceTransporter.Builder .Create() .WithInMemoryAdapter() .WithAddress("TST") .WithJsonTranscoding() .Build(); signal1.Connect(); signal2.Connect(); WebRTCAdapter adapter1 = null; signal1.RegisterRequestHandler <WebRTCOfferRequest>(async(_, request) => { adapter1 = new WebRTCAdapter(signal1, request.Object, request.Token); await adapter1.ConnectAsync(); }); WebRTCAdapter adapter2 = new WebRTCAdapter(signal2, WebRTCAdapterRole.Connect); adapter2.Connect(); IResonanceTransporter t1 = ResonanceTransporter.Builder .Create() .WithAdapter(adapter1) .WithJsonTranscoding() .Build(); IResonanceTransporter t2 = ResonanceTransporter.Builder .Create() .WithAdapter(adapter2) .WithJsonTranscoding() .Build(); t2.RequestReceived += (x, e) => { t2.SendResponseAsync(new LargeMessageResponse() { Data = (e.Message.Object as LargeMessageRequest).Data }, e.Message.Token); }; t1.Connect(); t2.Connect(); t1.DefaultRequestTimeout = TimeSpan.FromSeconds(60); for (int i = 0; i < 100; i++) { byte[] data = TestHelper.GetRandomByteArray(2); var response = t1.SendRequest <LargeMessageRequest, LargeMessageResponse>(new LargeMessageRequest() { Data = data }); Assert.IsTrue(data.SequenceEqual(response.Data)); } t1.Dispose(); t2.Dispose(); signal1.Dispose(); signal2.Dispose(); }
public void Message_Larger_Than_16_KB_Splits() { if (IsRunningOnAzurePipelines) { return; } IResonanceTransporter signal1 = ResonanceTransporter.Builder .Create() .WithInMemoryAdapter() .WithAddress("TST") .WithJsonTranscoding() .Build(); IResonanceTransporter signal2 = ResonanceTransporter.Builder .Create() .WithInMemoryAdapter() .WithAddress("TST") .WithJsonTranscoding() .Build(); signal1.Connect(); signal2.Connect(); WebRTCAdapter adapter1 = null; signal1.RegisterRequestHandler <WebRTCOfferRequest>(async(_, request) => { adapter1 = new WebRTCAdapter(signal1, request.Object, request.Token); await adapter1.ConnectAsync(); }); WebRTCAdapter adapter2 = new WebRTCAdapter(signal2, WebRTCAdapterRole.Connect); adapter2.Connect(); IResonanceTransporter t1 = ResonanceTransporter.Builder .Create() .WithAdapter(adapter1) .WithJsonTranscoding() .Build(); IResonanceTransporter t2 = ResonanceTransporter.Builder .Create() .WithAdapter(adapter2) .WithJsonTranscoding() .Build(); t2.RequestReceived += (x, e) => { t2.SendResponseAsync(new LargeMessageResponse() { Data = (e.Message.Object as LargeMessageRequest).Data }, e.Message.Token); }; t1.Connect(); t2.Connect(); byte[] data = TestHelper.GetRandomByteArray(200); var response = t1.SendRequest <LargeMessageRequest, LargeMessageResponse>(new LargeMessageRequest() { Data = data }); Assert.IsTrue(data.SequenceEqual(response.Data)); t1.Dispose(); t2.Dispose(); signal1.Dispose(); signal2.Dispose(); }
public void Create_Adapter_From_Offer() { if (IsRunningOnAzurePipelines) { return; } IResonanceTransporter signal1 = ResonanceTransporter.Builder .Create() .WithInMemoryAdapter() .WithAddress("TST") .WithJsonTranscoding() .Build(); IResonanceTransporter signal2 = ResonanceTransporter.Builder .Create() .WithInMemoryAdapter() .WithAddress("TST") .WithJsonTranscoding() .Build(); signal1.Connect(); signal2.Connect(); WebRTCAdapter adapter1 = null; signal1.RegisterRequestHandler <WebRTCOfferRequest>(async(_, request) => { adapter1 = new WebRTCAdapter(signal1, request.Object, request.Token); await adapter1.ConnectAsync(); }); WebRTCAdapter adapter2 = new WebRTCAdapter(signal2, WebRTCAdapterRole.Connect); adapter2.Connect(); IResonanceTransporter t1 = ResonanceTransporter.Builder .Create() .WithAdapter(adapter1) .WithJsonTranscoding() .Build(); IResonanceTransporter t2 = ResonanceTransporter.Builder .Create() .WithAdapter(adapter2) .WithJsonTranscoding() .Build(); t2.RequestReceived += (x, e) => { t2.SendResponseAsync(new CalculateResponse() { Sum = 15 }, e.Message.Token); }; t1.Connect(); t2.Connect(); var response = t1.SendRequest <CalculateRequest, CalculateResponse>(new CalculateRequest() { A = 10, B = 5 }); Assert.IsTrue(response.Sum == 15); t1.Dispose(); t2.Dispose(); signal1.Dispose(); signal2.Dispose(); }
public void Transporters_Router_Standard_Routes_Data() { IResonanceTransporter receiver1 = null; IResonanceTransporter client1 = null; IResonanceTransporter receiver2 = null; IResonanceTransporter client2 = null; TransporterRouter router = null; ResonanceTcpServer server = new ResonanceTcpServer(1333); server.ConnectionRequest += (x, e) => { if (receiver1 == null) { receiver1 = ResonanceTransporter.Builder.Create() .WithAdapter(e.Accept()) .WithJsonTranscoding() .Build(); receiver1.Connect(); } else { receiver2 = ResonanceTransporter.Builder.Create() .WithAdapter(e.Accept()) .WithJsonTranscoding() .Build(); receiver2.Connect(); router = new TransporterRouter(receiver1, receiver2, RoutingMode.TwoWay, WritingMode.Standard); router.Bind(); } }; server.Start(); client1 = ResonanceTransporter.Builder.Create() .WithTcpAdapter() .WithAddress("127.0.0.1") .WithPort(1333) .WithJsonTranscoding() .Build(); client1.Connect(); client2 = ResonanceTransporter.Builder.Create() .WithTcpAdapter() .WithAddress("127.0.0.1") .WithPort(1333) .WithJsonTranscoding() .Build(); client2.Connect(); client2.RegisterRequestHandler <CalculateRequest, CalculateResponse>((request) => { return(new CalculateResponse() { Sum = request.A + request.B }); }); client1.RegisterRequestHandler <CalculateRequest, CalculateResponse>((request) => { return(new CalculateResponse() { Sum = request.A + request.B }); }); Thread.Sleep(1000); receiver1.RequestReceived += (_, __) => { Assert.Fail(); }; receiver2.RequestReceived += (_, __) => { Assert.Fail(); }; var response = client1.SendRequest <CalculateRequest, CalculateResponse>(new CalculateRequest() { A = 10, B = 5 }); Assert.AreEqual(response.Sum, 15); response = client2.SendRequest <CalculateRequest, CalculateResponse>(new CalculateRequest() { A = 11, B = 5 }); Assert.AreEqual(response.Sum, 16); client1.Dispose(); client2.Dispose(); receiver1.Dispose(); receiver2.Dispose(); server.Dispose(); router.Dispose(); }
protected override Task OnConnect() { _connectionCompleted = false; _closeConnection = false; _receivedSegments = new List <byte[]>(); _expectedSegments = 0; _expectedSegmentsCheckSum = null; _incomingQueue = new ProducerConsumerQueue <byte[]>(); _conductorInitialized = false; _connectionCompletionSource = new TaskCompletionSource <object>(); _signalingTransporter.RegisterRequestHandler <WebRTCIceCandidateRequest, WebRTCIceCandidateResponse>(OnWebRTCCandidateRequest); Logger.LogDebug("Initializing adapter with role '{Role}'.", Role); if (Role == WebRTCAdapterRole.Accept) { ThreadFactory.StartNew(async() => { try { await InitConnection(); if (_offerRequest != null) { Logger.LogDebug("Adapter initialized by an offer request. sending answer..."); var response = await OnWebRTCOfferRequest(_offerRequest); if (_closeConnection) { return; } _signalingTransporter.SendResponse(response.Response, _offerRequestToken); } else { Logger.LogDebug("Waiting for WebRTC offer..."); } } catch (Exception ex) { if (!_connectionCompleted) { _connectionCompleted = true; _connectionCompletionSource.SetException(new ResonanceWebRTCConnectionFailedException(ex)); _closeConnection = true; } } }); } else { ThreadFactory.StartNew(async() => { try { await InitConnection(); var offer = await CreateOffer(); var response = await _signalingTransporter.SendRequestAsync <WebRTCOfferRequest, WebRTCOfferResponse>(new WebRTCOfferRequest() { Offer = offer, }, new ResonanceRequestConfig() { Timeout = TimeSpan.FromSeconds(30) }); _conductor.OnOfferReply("answer", response.Answer.Sdp); FlushIceCandidates(); } catch (Exception ex) { if (!_connectionCompleted) { _connectionCompleted = true; _connectionCompletionSource.SetException(new ResonanceWebRTCConnectionFailedException(ex)); _closeConnection = true; } } }); } TimeoutTask.StartNew(() => { if (!_connectionCompleted) { _connectionCompleted = true; _connectionCompletionSource.SetException(new ResonanceWebRTCConnectionFailedException(new TimeoutException("Could not initialize the connection within the given timeout."))); _closeConnection = true; } }, ConnectionTimeout); return(_connectionCompletionSource.Task); }
public void Tcp_Connect_Send_And_Receive_100_Concurrent_Transporters() { if (IsRunningOnAzurePipelines) { return; } List <IResonanceTransporter> receivers = new List <IResonanceTransporter>(); ResonanceTcpServer server = new ResonanceTcpServer(4321); server.ConnectionRequest += (x, e) => { IResonanceTransporter t = ResonanceTransporter.Builder.Create() .WithAdapter(e.Accept()) .WithJsonTranscoding() .Build(); receivers.Add(t); t.RegisterRequestHandler <CalculateRequest, CalculateResponse>((request) => { return(new CalculateResponse() { Sum = request.A + request.B }); }); t.Connect(); }; server.Start(); List <Thread> threads = new List <Thread>(); for (int i = 0; i < 100; i++) { var t = ThreadFactory.StartNew(() => { IResonanceTransporter client = ResonanceTransporter.Builder.Create() .WithTcpAdapter() .WithAddress("127.0.0.1") .WithPort(4321) .WithJsonTranscoding() .Build(); client.Connect(); var request = new CalculateRequest() { A = 10, B = 15 }; var response = client.SendRequest <CalculateRequest, CalculateResponse>(request, new ResonanceRequestConfig() { Timeout = TimeSpan.FromSeconds(5) }); Assert.AreEqual(response.Sum, request.A + request.B); client.Dispose(); }); threads.Add(t); } TestHelper.WaitWhile(() => threads.Count < 100 || receivers.Count < 100, TimeSpan.FromSeconds(30)); threads.ForEach(x => x.Join()); receivers.ForEach(x => x.Dispose()); server.Dispose(); }