aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.WebRTC
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-22 00:04:44 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-03-22 00:04:44 +0200
commitd48b2d23515d06a21ad241380986bf8f31773195 (patch)
treeebbb6b2bc874773ec58a4c999a1f6eb61a572592 /Software/Visual_Studio/Tango.WebRTC
parent8c094ceeaa538fdb5dc1d69b6ac73f8574cecb66 (diff)
downloadTango-d48b2d23515d06a21ad241380986bf8f31773195.tar.gz
Tango-d48b2d23515d06a21ad241380986bf8f31773195.zip
Implemented WebRtcTransportAdapter.
Implemented FileSystem via WebRTC. Improved FileSystemControl keyboard control. Implemented FileSystemControl context menu. Improved Transported custom request handler registration. Implemented FS copy/move/delete. Implemented InputBox.
Diffstat (limited to 'Software/Visual_Studio/Tango.WebRTC')
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateRequest.cs13
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateResponse.cs12
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/Network/OfferRequest.cs13
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/Network/OfferResponse.cs13
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj15
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs307
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterDisconnectedException.cs16
-rw-r--r--Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterMode.cs14
8 files changed, 403 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateRequest.cs b/Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateRequest.cs
new file mode 100644
index 000000000..b65a8d6d4
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateRequest.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.WebRTC.Network
+{
+ public class IceCandidateRequest
+ {
+ public IceCandidate IceCandidate { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateResponse.cs b/Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateResponse.cs
new file mode 100644
index 000000000..a9daad732
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/Network/IceCandidateResponse.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.WebRTC.Network
+{
+ public class IceCandidateResponse
+ {
+ }
+}
diff --git a/Software/Visual_Studio/Tango.WebRTC/Network/OfferRequest.cs b/Software/Visual_Studio/Tango.WebRTC/Network/OfferRequest.cs
new file mode 100644
index 000000000..0d82310db
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/Network/OfferRequest.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.WebRTC.Network
+{
+ public class OfferRequest
+ {
+ public Offer Offer { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.WebRTC/Network/OfferResponse.cs b/Software/Visual_Studio/Tango.WebRTC/Network/OfferResponse.cs
new file mode 100644
index 000000000..2207c31a6
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/Network/OfferResponse.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.WebRTC.Network
+{
+ public class OfferResponse
+ {
+ public Answer Answer { get; set; }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj b/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj
index d9cea42dc..5edff1e71 100644
--- a/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj
+++ b/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj
@@ -48,11 +48,18 @@
<Compile Include="DataMessageReceivedEventArgs.cs" />
<Compile Include="ErrorEventArgs.cs" />
<Compile Include="IceCandidate.cs" />
+ <Compile Include="Network\IceCandidateRequest.cs" />
+ <Compile Include="Network\IceCandidateResponse.cs" />
+ <Compile Include="Network\OfferRequest.cs" />
+ <Compile Include="Network\OfferResponse.cs" />
<Compile Include="NewIceCandidateEventArgs.cs" />
<Compile Include="Offer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VideoFrameReceivedEventArgs.cs" />
<Compile Include="WebRtcClient.cs" />
+ <Compile Include="WebRtcTransportAdapter.cs" />
+ <Compile Include="WebRtcTransportAdapterDisconnectedException.cs" />
+ <Compile Include="WebRtcTransportAdapterMode.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SideChains\WebRtc.NET\WebRtc.NET.vcxproj">
@@ -63,6 +70,14 @@
<Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
<Name>Tango.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{BC932DBD-7CDB-488C-99E4-F02CF441F55E}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Tango.Transport\Tango.Transport.csproj">
+ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project>
+ <Name>Tango.Transport</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs
new file mode 100644
index 000000000..850ddb3de
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs
@@ -0,0 +1,307 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Tango.Core;
+using Tango.Core.Threading;
+using Tango.Transport;
+using Tango.Transport.Adapters;
+using Tango.WebRTC.Network;
+
+namespace Tango.WebRTC
+{
+ public class WebRtcTransportAdapter : TransportAdapterBase
+ {
+ private WebRtcClient _client;
+ private bool _answerReceived;
+ private List<IceCandidate> _queuedIceCandidates;
+
+ public event EventHandler Ready;
+
+ public ITransporter SignalingTransporter { get; set; }
+
+ public WebRtcTransportAdapterMode Mode { get; set; }
+
+ public String DataChannelName { get; set; }
+
+ public WebRtcTransportAdapter(ITransporter signalingTransporter, WebRtcTransportAdapterMode mode) : this(signalingTransporter, mode, null)
+ {
+
+ }
+
+ public WebRtcTransportAdapter(ITransporter signalingTransporter, WebRtcTransportAdapterMode mode, String dataChannelName)
+ {
+ SignalingTransporter = signalingTransporter;
+ Mode = mode;
+ DataChannelName = dataChannelName;
+ Address = dataChannelName;
+ ComponentName = $"WebRTC Adapter {_component_counter++}";
+
+ SignalingTransporter.RegisterRequestHandler<IceCandidateRequest>(OnIceCandidateRequestReceived);
+ SignalingTransporter.RegisterRequestHandler<OfferRequest>(OnOfferRequestReceived);
+ }
+
+ public override void Write(byte[] data, bool immidiate = false)
+ {
+ ThrowIfDisposed();
+
+ try
+ {
+ _client.SendBinary(data);
+ }
+ catch (Exception ex)
+ {
+ OnFailed(ex);
+ }
+ }
+
+ public override Task Connect()
+ {
+ ThrowIfDisposed();
+
+ TaskCompletionSource<object> completionSource = new TaskCompletionSource<object>();
+ bool completed = false;
+
+ _queuedIceCandidates = new List<IceCandidate>();
+ _answerReceived = false;
+
+ ThreadFactory.StartNew(async () =>
+ {
+ if (State != TransportComponentState.Connected)
+ {
+ try
+ {
+ _client = new WebRtcClient();
+
+ if (DataChannelName != null)
+ {
+ _client.DataChannelName = DataChannelName;
+ }
+
+ Address = _client.DataChannelName;
+
+ _client.NewIceCandidate += WebRtc_NewIceCandidate;
+ _client.Disconnected += WebRtc_Disconnected;
+ _client.BinaryMessageReceived += WebRtc_BinaryMessageReceived;
+ _client.Ready += (x, e) =>
+ {
+ if (!completed)
+ {
+ LogManager.Log("WebRTC Active Transport Adapter is ready.");
+ completed = true;
+ State = TransportComponentState.Connected;
+ completionSource.SetResult(true);
+ Ready?.Invoke(this, new EventArgs());
+ }
+
+ if (Mode == WebRtcTransportAdapterMode.Passive)
+ {
+ LogManager.Log("WebRTC Passive Transport Adapter is ready.");
+ Ready?.Invoke(this, new EventArgs());
+ }
+ };
+
+ LogManager.Log("Initializing WebRTC client...");
+ await _client.Init();
+
+ if (Mode == WebRtcTransportAdapterMode.Active)
+ {
+ LogManager.Log("Creating WebRTC offer...");
+ var offer = await _client.CreateOffer();
+
+ LogManager.Log("Sending WebRTC offer via signaling transporter...");
+ var response = await SignalingTransporter.SendGenericRequest<OfferRequest, OfferResponse>(new OfferRequest() { Offer = offer }, new TransportRequestConfig()
+ {
+ Timeout = TimeSpan.FromSeconds(30),
+ ShouldLog = true
+ });
+
+ LogManager.Log("WebRTC offer sent and responded with an answer. Setting WebRTC answer...");
+ _client.SetAnswer(response.Answer);
+ _answerReceived = true;
+
+ foreach (var ice in _queuedIceCandidates.ToList())
+ {
+ LogManager.Log("Sending existing ice candidate...");
+
+ try
+ {
+ await SignalingTransporter.SendGenericRequest<IceCandidateRequest, IceCandidateResponse>(new IceCandidateRequest() { IceCandidate = ice }, new TransportRequestConfig()
+ {
+ Timeout = TimeSpan.FromSeconds(30),
+ ShouldLog = true
+ });
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error sending ice candidate.");
+ }
+ }
+ }
+ else
+ {
+ LogManager.Log("Waiting for offer...");
+ completed = true;
+ State = TransportComponentState.Connected;
+ completionSource.SetResult(true);
+ }
+ }
+ catch (Exception ex)
+ {
+ completionSource.SetException(ex);
+ }
+ }
+ else
+ {
+ completionSource.SetResult(true);
+ }
+ });
+
+ if (Mode == WebRtcTransportAdapterMode.Active)
+ {
+ TimeoutTask.StartNew(() =>
+ {
+ if (!completed)
+ {
+ completed = true;
+ completionSource.SetException(new TimeoutException("Could not reach the remote peer using the WebRTC adapter."));
+ }
+
+ }, TimeSpan.FromSeconds(30));
+ }
+
+ return completionSource.Task;
+ }
+
+ private void WebRtc_BinaryMessageReceived(object sender, DataMessageReceivedEventArgs<byte[]> e)
+ {
+ OnDataAvailable(e.Data);
+ }
+
+ private async void OnOfferRequestReceived(ITransporter transporter, OfferRequest request, string token)
+ {
+ if (Mode == WebRtcTransportAdapterMode.Passive)
+ {
+ var answer = await _client.CreateAnswer(request.Offer);
+ await SignalingTransporter.SendGenericResponse(new OfferResponse() { Answer = answer }, token);
+ _answerReceived = true;
+
+ foreach (var ice in _queuedIceCandidates.ToList())
+ {
+ LogManager.Log("Sending existing ice candidate...");
+
+ try
+ {
+ await SignalingTransporter.SendGenericRequest<IceCandidateRequest, IceCandidateResponse>(new IceCandidateRequest() { IceCandidate = ice }, new TransportRequestConfig()
+ {
+ Timeout = TimeSpan.FromSeconds(30),
+ ShouldLog = true
+ });
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error sending ice candidate to remote peer.");
+ }
+ }
+ }
+ }
+
+ private async void WebRtc_NewIceCandidate(object sender, NewIceCandidateEventArgs e)
+ {
+ try
+ {
+ if (_answerReceived)
+ {
+ LogManager.Log("New WebRTC candidate available. Sending ice to remote peer...");
+
+ await SignalingTransporter.SendGenericRequest<IceCandidateRequest, IceCandidateResponse>(new IceCandidateRequest() { IceCandidate = e.IceCandidate }, new TransportRequestConfig()
+ {
+ Timeout = TimeSpan.FromSeconds(30),
+ ShouldLog = true
+ });
+ }
+ else
+ {
+ if (Mode == WebRtcTransportAdapterMode.Active)
+ {
+ LogManager.Log("New WebRTC candidate available. Will be sent after an answer is received...");
+ }
+ else
+ {
+ LogManager.Log("New WebRTC candidate available. Will be sent after an offer is received...");
+ }
+
+ _queuedIceCandidates.Add(e.IceCandidate);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error sending ice candidate to remote peer.");
+ }
+ }
+
+ private async void OnIceCandidateRequestReceived(ITransporter transporter, IceCandidateRequest request, string token)
+ {
+ try
+ {
+ LogManager.Log("Ice candidate request received from the remote peer.");
+ await SignalingTransporter.SendGenericResponse(new IceCandidateResponse() { }, token);
+
+ LogManager.Log("Adding ice candidate...");
+ _client.AddIceCandidate(request.IceCandidate);
+ LogManager.Log("Ice candidate added.");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error occurred on ice candidate received handling.");
+ }
+ }
+
+ private void WebRtc_Disconnected(object sender, EventArgs e)
+ {
+ OnFailed(new WebRtcTransportAdapterDisconnectedException("WebRtc Transport Adapter RTC client has disconnected."));
+ }
+
+ public override Task Disconnect()
+ {
+ TaskCompletionSource<object> completionSource = new TaskCompletionSource<object>();
+
+ ThreadFactory.StartNew(() =>
+ {
+ if (State != TransportComponentState.Disconnected)
+ {
+ if (_client != null)
+ {
+ LogManager.Log("Disposing WebRTC client...");
+
+ _client.NewIceCandidate -= WebRtc_NewIceCandidate;
+ _client.Disconnected -= WebRtc_Disconnected;
+ _client.BinaryMessageReceived -= WebRtc_BinaryMessageReceived;
+
+ try
+ {
+ _client.Dispose();
+ _client = null;
+ LogManager.Log("WebRTC client disposed.");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, "Error disposing WebRTC client.");
+ }
+ }
+
+ State = TransportComponentState.Disconnected;
+ completionSource.SetResult(true);
+ }
+ else
+ {
+ completionSource.SetResult(true);
+ }
+ });
+
+ return completionSource.Task;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterDisconnectedException.cs b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterDisconnectedException.cs
new file mode 100644
index 000000000..bd82a3233
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterDisconnectedException.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.WebRTC
+{
+ public class WebRtcTransportAdapterDisconnectedException : Exception
+ {
+ public WebRtcTransportAdapterDisconnectedException(String message) : base(message)
+ {
+
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterMode.cs b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterMode.cs
new file mode 100644
index 000000000..8068697f5
--- /dev/null
+++ b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapterMode.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.WebRTC
+{
+ public enum WebRtcTransportAdapterMode
+ {
+ Active,
+ Passive
+ }
+}