diff --git a/Desktop.Linux/Desktop.Linux.csproj b/Desktop.Linux/Desktop.Linux.csproj
index 6512eaff..a407431b 100644
--- a/Desktop.Linux/Desktop.Linux.csproj
+++ b/Desktop.Linux/Desktop.Linux.csproj
@@ -8,7 +8,6 @@
AnyCPU;x64;x86
-
%(Filename)
@@ -16,6 +15,10 @@
Designer
+
+
+
+
diff --git a/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml b/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml
index d1c51966..269443d4 100644
--- a/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml
+++ b/Desktop.Linux/Properties/PublishProfiles/linux-x64.pubxml
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
- Any CPU
+ x64
netcoreapp3.1
..\Server\wwwroot\Downloads
linux-x64
diff --git a/Desktop.Linux/ViewModels/MainWindowViewModel.cs b/Desktop.Linux/ViewModels/MainWindowViewModel.cs
index b8933c89..a9637642 100644
--- a/Desktop.Linux/ViewModels/MainWindowViewModel.cs
+++ b/Desktop.Linux/ViewModels/MainWindowViewModel.cs
@@ -10,7 +10,7 @@ using Remotely.ScreenCast.Core.Capture;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Core.Models;
using Remotely.ScreenCast.Core.Services;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
using Remotely.ScreenCast.Linux.Capture;
using Remotely.ScreenCast.Linux.Services;
using Remotely.Shared.Models;
diff --git a/Desktop.Win/Desktop.Win.csproj b/Desktop.Win/Desktop.Win.csproj
index 8e4670c5..33b38add 100644
--- a/Desktop.Win/Desktop.Win.csproj
+++ b/Desktop.Win/Desktop.Win.csproj
@@ -15,6 +15,7 @@
Translucency Software
Remotely Desktop
https://remotely.lucency.co
+ AnyCPU;x86;x64
diff --git a/Desktop.Win/Properties/PublishProfiles/win-x64.pubxml b/Desktop.Win/Properties/PublishProfiles/win-x64.pubxml
index 70fe84fb..0f03c150 100644
--- a/Desktop.Win/Properties/PublishProfiles/win-x64.pubxml
+++ b/Desktop.Win/Properties/PublishProfiles/win-x64.pubxml
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
- Any CPU
+ x64
netcoreapp3.1
..\Server\wwwroot\Downloads\Win-x64\
win-x64
diff --git a/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml b/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml
index 01cbf211..00e6cbd6 100644
--- a/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml
+++ b/Desktop.Win/Properties/PublishProfiles/win-x86.pubxml
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
- Any CPU
+ x86
netcoreapp3.1
..\Server\wwwroot\Downloads\Win-x86\
win-x86
diff --git a/Desktop.Win/ViewModels/MainWindowViewModel.cs b/Desktop.Win/ViewModels/MainWindowViewModel.cs
index 2c1735a9..90cce8b2 100644
--- a/Desktop.Win/ViewModels/MainWindowViewModel.cs
+++ b/Desktop.Win/ViewModels/MainWindowViewModel.cs
@@ -18,7 +18,7 @@ using System.Security.Principal;
using System.Windows.Input;
using Remotely.ScreenCast.Win.Services;
using Remotely.ScreenCast.Core.Interfaces;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
namespace Remotely.Desktop.Win.ViewModels
{
diff --git a/Remotely.sln b/Remotely.sln
index ce93755d..ac5f6ed1 100644
--- a/Remotely.sln
+++ b/Remotely.sln
@@ -43,7 +43,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Folder", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenCast.Win", "ScreenCast.Win\ScreenCast.Win.csproj", "{8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Desktop.Win", "Desktop.Win\Desktop.Win.csproj", "{6B726FC4-A907-4813-BF38-3342E02AA8D2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Win", "Desktop.Win\Desktop.Win.csproj", "{6B726FC4-A907-4813-BF38-3342E02AA8D2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -129,28 +129,28 @@ Global
{FF7FD66A-B3E2-4D39-A457-A00C94EDE9E6}.Release|x86.Build.0 = Release|x86
{8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x64.Build.0 = Debug|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x86.Build.0 = Debug|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|Any CPU.Build.0 = Release|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x64.ActiveCfg = Release|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x64.Build.0 = Release|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x86.ActiveCfg = Release|Any CPU
- {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x86.Build.0 = Release|Any CPU
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x64.ActiveCfg = Debug|x64
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x64.Build.0 = Debug|x64
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x86.ActiveCfg = Debug|x86
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Debug|x86.Build.0 = Debug|x86
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|Any CPU.ActiveCfg = Release|x64
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|Any CPU.Build.0 = Release|x64
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x64.ActiveCfg = Release|x64
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x64.Build.0 = Release|x64
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x86.ActiveCfg = Release|x86
+ {8D9EA0C3-EC7F-48AC-A2ED-9C60DD5A3987}.Release|x86.Build.0 = Release|x86
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x64.Build.0 = Debug|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x86.Build.0 = Debug|Any CPU
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x64.ActiveCfg = Debug|x64
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x64.Build.0 = Debug|x64
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x86.ActiveCfg = Debug|x86
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Debug|x86.Build.0 = Debug|x86
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|Any CPU.Build.0 = Release|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x64.ActiveCfg = Release|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x64.Build.0 = Release|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x86.ActiveCfg = Release|Any CPU
- {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x86.Build.0 = Release|Any CPU
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x64.ActiveCfg = Release|x64
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x64.Build.0 = Release|x64
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x86.ActiveCfg = Release|x86
+ {6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/ScreenCast.Core/Capture/ScreenCasterBase.cs b/ScreenCast.Core/Capture/ScreenCasterBase.cs
index b571882a..5442b98d 100644
--- a/ScreenCast.Core/Capture/ScreenCasterBase.cs
+++ b/ScreenCast.Core/Capture/ScreenCasterBase.cs
@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.SignalR.Client;
using Remotely.ScreenCast.Core.Models;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
using Remotely.ScreenCast.Core.Services;
using System;
using System.Collections.Generic;
@@ -25,9 +25,11 @@ namespace Remotely.ScreenCast.Core.Capture
string requesterName,
ICapturer capturer)
{
- var conductor = Conductor.Current;
+ var viewers = Conductor.Current.Viewers;
+ var mode = Conductor.Current.Mode;
+ var casterSocket = Conductor.Current.CasterSocket;
- Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {conductor.Mode}");
+ Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {mode}");
byte[] encodedImageBytes;
var fpsQueue = new Queue();
@@ -41,26 +43,30 @@ namespace Remotely.ScreenCast.Core.Capture
HasControl = true
};
+ viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer);
- conductor.Viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer);
-
- if (conductor.Mode == Enums.AppMode.Normal)
+ if (mode == Enums.AppMode.Normal)
{
- conductor.InvokeViewerAdded(viewer);
+ Conductor.Current.InvokeViewerAdded(viewer);
}
- await conductor.CasterSocket.SendMachineName(Environment.MachineName, viewerID);
+ if (OSUtils.IsWindows)
+ {
+ await InitializeWebRtc(viewer, casterSocket);
+ }
- await conductor.CasterSocket.SendScreenCount(
+ await casterSocket.SendMachineName(Environment.MachineName, viewerID);
+
+ await casterSocket.SendScreenCount(
capturer.SelectedScreen,
capturer.GetScreenCount(),
viewerID);
- await conductor.CasterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
+ await casterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);
capturer.ScreenChanged += async (sender, bounds) =>
{
- await conductor.CasterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID);
+ await casterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID);
};
while (!viewer.DisconnectRequested)
@@ -125,9 +131,17 @@ namespace Remotely.ScreenCast.Core.Capture
if (encodedImageBytes?.Length > 0)
{
- await conductor.CasterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);
- viewer.Latency += 300;
- viewer.OutputBuffer += encodedImageBytes.Length;
+ if (viewer.RtcSession.IsDataChannelOpen)
+ {
+ viewer.RtcSession.SendCaptureFrame(diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, encodedImageBytes);
+
+ }
+ else
+ {
+ await casterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);
+ viewer.Latency += 300;
+ viewer.OutputBuffer += encodedImageBytes.Length;
+ }
}
}
}
@@ -143,16 +157,37 @@ namespace Remotely.ScreenCast.Core.Capture
Logger.Write($"Ended screen cast. Requester: {requesterName}. Viewer ID: {viewerID}.");
- conductor.Viewers.TryRemove(viewerID, out _);
+ viewers.TryRemove(viewerID, out _);
capturer.Dispose();
// Close if no one is viewing.
- if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended)
+ if (viewers.Count == 0 && mode == Enums.AppMode.Unattended)
{
- await conductor.CasterSocket.Disconnect();
+ await casterSocket.Disconnect();
Environment.Exit(0);
}
}
+
+ private async Task InitializeWebRtc(Viewer viewer, CasterSocket casterSocket)
+ {
+ try
+ {
+ viewer.RtcSession = new WebRtcSession();
+ viewer.RtcSession.LocalSdpReady += async (sender, sdp) =>
+ {
+ await casterSocket.SendRtcOfferToBrowser(sdp, viewer.ViewerConnectionID);
+ };
+ viewer.RtcSession.IceCandidateReady += async (sender, args) =>
+ {
+ await casterSocket.SendIceCandidateToBrowser(args.candidate, args.sdpMlineIndex, args.sdpMid, viewer.ViewerConnectionID);
+ };
+ await viewer.RtcSession.Init();
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
}
}
diff --git a/ScreenCast.Core/Sockets/CasterSocket.cs b/ScreenCast.Core/Communication/CasterSocket.cs
similarity index 90%
rename from ScreenCast.Core/Sockets/CasterSocket.cs
rename to ScreenCast.Core/Communication/CasterSocket.cs
index ec301343..d790a9e5 100644
--- a/ScreenCast.Core/Sockets/CasterSocket.cs
+++ b/ScreenCast.Core/Communication/CasterSocket.cs
@@ -14,10 +14,9 @@ using System.Net;
using Remotely.ScreenCast.Core.Services;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.Shared.Win32;
-using Remotely.ScreenCast.Core.Interfaces;
using Microsoft.Extensions.DependencyInjection;
-namespace Remotely.ScreenCast.Core.Sockets
+namespace Remotely.ScreenCast.Core.Communication
{
public class CasterSocket
{
@@ -113,6 +112,11 @@ namespace Remotely.ScreenCast.Core.Sockets
await Connection.SendAsync("SendMachineName", machineName, viewerID);
}
+ public async Task SendRtcOfferToBrowser(string sdp, string viewerID)
+ {
+ await Connection.SendAsync("SendRtcOfferToBrowser", sdp, viewerID);
+ }
+
public async Task SendScreenCapture(byte[] captureBytes, string viewerID, int left, int top, int width, int height, DateTime captureTime)
{
await Connection.SendAsync("SendScreenCapture", captureBytes, viewerID, left, top, width, height, captureTime);
@@ -133,6 +137,10 @@ namespace Remotely.ScreenCast.Core.Sockets
await Connection.SendAsync("SendViewerRemoved", viewerID);
}
+ public async Task SendIceCandidateToBrowser(string candidate, int sdpMlineIndex, string sdpMid, string viewerConnectionID)
+ {
+ await Connection.SendAsync("SendIceCandidateToBrowser", candidate, sdpMlineIndex, sdpMid, viewerConnectionID);
+ }
private void ApplyConnectionHandlers()
{
var conductor = Conductor.Current;
@@ -142,6 +150,37 @@ namespace Remotely.ScreenCast.Core.Sockets
return Task.CompletedTask;
};
+ Connection.On("ReceiveIceCandidate", (string candidate, int sdpMlineIndex, string sdpMid, string viewerID) =>
+ {
+ try
+ {
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ {
+ viewer.RtcSession.AddIceCandidate(sdpMid, sdpMlineIndex, candidate);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+
+ });
+
+ Connection.On("ReceiveRtcAnswer", (string sdp, string viewerID) =>
+ {
+ try
+ {
+ if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
+ {
+ viewer.RtcSession.SetRemoteDescription("answer", sdp);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ });
+
Connection.On("ClipboardTransfer", (string transferText, bool typeText, string viewerID) =>
{
try
diff --git a/ScreenCast.Core/Communication/WebRtcSession.cs b/ScreenCast.Core/Communication/WebRtcSession.cs
new file mode 100644
index 00000000..b3caec1d
--- /dev/null
+++ b/ScreenCast.Core/Communication/WebRtcSession.cs
@@ -0,0 +1,111 @@
+using MessagePack;
+using Microsoft.MixedReality.WebRTC;
+using Remotely.ScreenCast.Core.Models;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Remotely.ScreenCast.Core.Communication
+{
+ public class WebRtcSession
+ {
+ public event EventHandler<(string candidate, int sdpMlineIndex, string sdpMid)> IceCandidateReady;
+
+ public event EventHandler LocalSdpReady;
+
+ public bool IsDataChannelOpen => CaptureChannel?.State == DataChannel.ChannelState.Open;
+ private DataChannel CaptureChannel { get; set; }
+ private PeerConnection PeerConnection { get; set; }
+ public void AddIceCandidate(string sdpMid, int sdpMlineIndex, string candidate)
+ {
+ PeerConnection.AddIceCandidate(sdpMid, sdpMlineIndex, candidate);
+ }
+
+ public async Task Init()
+ {
+ PeerConnection = new PeerConnection();
+
+ var config = new PeerConnectionConfiguration()
+ {
+ IceServers = new List
+ {
+ new IceServer{ Urls = { "stun:stun.l.google.com:19302" } },
+ new IceServer{ Urls = { "stun:stun4.l.google.com:19302" } }
+ }
+ };
+
+ await PeerConnection.InitializeAsync(config);
+
+ PeerConnection.LocalSdpReadytoSend += PeerConnection_LocalSdpReadytoSend;
+ PeerConnection.Connected += PeerConnection_Connected;
+ PeerConnection.IceStateChanged += PeerConnection_IceStateChanged;
+ PeerConnection.IceCandidateReadytoSend += PeerConnection_IceCandidateReadytoSend;
+ CaptureChannel = await PeerConnection.AddDataChannelAsync("ScreenCapture", true, true);
+ CaptureChannel.BufferingChanged += DataChannel_BufferingChanged;
+ CaptureChannel.MessageReceived += CaptureChannel_MessageReceived;
+ CaptureChannel.StateChanged += CaptureChannel_StateChanged;
+ PeerConnection.CreateOffer();
+ }
+
+ public void SendCaptureFrame(int left, int top, int width, int height, byte[] imageBytes)
+ {
+ CaptureChannel.SendMessage(MessagePackSerializer.Serialize(new FrameInfo()
+ {
+ Left = left,
+ Top = top,
+ Width = width,
+ Height = height,
+ ImageBytes = imageBytes
+ }));
+ }
+
+ public void SetRemoteDescription(string type, string sdp)
+ {
+ PeerConnection.SetRemoteDescription(type, sdp);
+ if (type == "offer")
+ {
+ PeerConnection.CreateAnswer();
+ }
+ }
+
+ private void CaptureChannel_MessageReceived(byte[] obj)
+ {
+ Debug.WriteLine($"DataChannel message received. Size: {obj.Length}");
+ }
+
+ private void CaptureChannel_StateChanged()
+ {
+ Debug.WriteLine($"DataChannel state changed. New State: {CaptureChannel.State}");
+ }
+
+ private void DataChannel_BufferingChanged(ulong previous, ulong current, ulong limit)
+ {
+ Debug.WriteLine($"DataChannel buffering changed. Previous: {previous}. Current: {current}. Limit: {limit}.");
+ }
+
+ private void PeerConnection_Connected()
+ {
+ Debug.WriteLine("PeerConnection connected.");
+ }
+
+ private void PeerConnection_IceCandidateReadytoSend(string candidate, int sdpMlineindex, string sdpMid)
+ {
+ Debug.WriteLine("Ice candidate ready to send.");
+ IceCandidateReady?.Invoke(this, (candidate, sdpMlineindex, sdpMid));
+ }
+
+ private void PeerConnection_IceStateChanged(IceConnectionState newState)
+ {
+ Debug.WriteLine($"Ice state changed to {newState}.");
+ }
+
+ private void PeerConnection_LocalSdpReadytoSend(string type, string sdp)
+ {
+ Debug.WriteLine($"Local SDP ready.");
+ LocalSdpReady?.Invoke(this, sdp);
+ }
+ }
+}
diff --git a/ScreenCast.Core/Conductor.cs b/ScreenCast.Core/Conductor.cs
index bc07a7ee..5f8f4047 100644
--- a/ScreenCast.Core/Conductor.cs
+++ b/ScreenCast.Core/Conductor.cs
@@ -4,7 +4,7 @@ using Remotely.Shared.Models;
using Remotely.ScreenCast.Core.Enums;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Core.Models;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
using Remotely.ScreenCast.Core.Services;
using System;
using System.Collections.Concurrent;
diff --git a/ScreenCast.Core/Models/FrameInfo.cs b/ScreenCast.Core/Models/FrameInfo.cs
new file mode 100644
index 00000000..d204a7bd
--- /dev/null
+++ b/ScreenCast.Core/Models/FrameInfo.cs
@@ -0,0 +1,22 @@
+using MessagePack;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Remotely.ScreenCast.Core.Models
+{
+ [MessagePackObject]
+ public class FrameInfo
+ {
+ [Key("Left")]
+ public int Left { get; set; }
+ [Key("Top")]
+ public int Top { get; set; }
+ [Key("Width")]
+ public int Width { get; set; }
+ [Key("Height")]
+ public int Height { get; set; }
+ [Key("ImageBytes")]
+ public byte[] ImageBytes { get; set; }
+ }
+}
diff --git a/ScreenCast.Core/Models/Viewer.cs b/ScreenCast.Core/Models/Viewer.cs
index 98c21aba..4d3815a0 100644
--- a/ScreenCast.Core/Models/Viewer.cs
+++ b/ScreenCast.Core/Models/Viewer.cs
@@ -1,4 +1,5 @@
using Remotely.ScreenCast.Core.Capture;
+using Remotely.ScreenCast.Core.Communication;
using Remotely.ScreenCast.Core.Interfaces;
using System;
using System.Collections.Generic;
@@ -54,6 +55,7 @@ namespace Remotely.ScreenCast.Core.Models
public double Latency { get; set; } = 1;
public string Name { get; set; }
public int OutputBuffer { get; set; }
+ public WebRtcSession RtcSession { get; set; }
public string ViewerConnectionID { get; set; }
}
}
diff --git a/ScreenCast.Core/ScreenCast.Core.csproj b/ScreenCast.Core/ScreenCast.Core.csproj
index 04365782..a893240d 100644
--- a/ScreenCast.Core/ScreenCast.Core.csproj
+++ b/ScreenCast.Core/ScreenCast.Core.csproj
@@ -34,6 +34,7 @@
+
diff --git a/ScreenCast.Linux/Program.cs b/ScreenCast.Linux/Program.cs
index cac0029d..260382fa 100644
--- a/ScreenCast.Linux/Program.cs
+++ b/ScreenCast.Linux/Program.cs
@@ -4,7 +4,7 @@ using System;
using System.Threading;
using Remotely.ScreenCast.Linux.Services;
using Remotely.ScreenCast.Linux.Capture;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
namespace Remotely.ScreenCast.Linux
{
diff --git a/ScreenCast.Win/Program.cs b/ScreenCast.Win/Program.cs
index 258be1a1..20aaf152 100644
--- a/ScreenCast.Win/Program.cs
+++ b/ScreenCast.Win/Program.cs
@@ -10,7 +10,7 @@ using System.Threading;
using Remotely.ScreenCast.Win.Services;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Win.Capture;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
namespace Remotely.ScreenCast.Win
{
diff --git a/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml b/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml
index c413acfa..64dd4e1e 100644
--- a/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml
+++ b/ScreenCast.Win/Properties/PublishProfiles/win-x64.pubxml
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
- Any CPU
+ x64
netcoreapp3.1
..\Agent\bin\Release\netcoreapp3.1\win10-x64\publish\ScreenCast
false
diff --git a/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml b/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml
index bfff9bca..b27a15ad 100644
--- a/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml
+++ b/ScreenCast.Win/Properties/PublishProfiles/win-x86.pubxml
@@ -6,7 +6,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
FileSystem
Release
- Any CPU
+ x86
netcoreapp3.1
..\Agent\bin\Release\netcoreapp3.1\win10-x86\publish\ScreenCast
win-x86
diff --git a/ScreenCast.Win/ScreenCast.Win.csproj b/ScreenCast.Win/ScreenCast.Win.csproj
index 2905b0a1..2b448c98 100644
--- a/ScreenCast.Win/ScreenCast.Win.csproj
+++ b/ScreenCast.Win/ScreenCast.Win.csproj
@@ -13,6 +13,7 @@
Allows unattended remote control via the Remotely server.
Copyright © 2020 Translucency Software
https://remotely.lucency.co
+ AnyCPU;x86;x64
@@ -33,12 +34,9 @@
-
-
-
-
+
-
+
diff --git a/ScreenCast.Win/Services/WinClipboardService.cs b/ScreenCast.Win/Services/WinClipboardService.cs
index f9984be5..c8a095f7 100644
--- a/ScreenCast.Win/Services/WinClipboardService.cs
+++ b/ScreenCast.Win/Services/WinClipboardService.cs
@@ -1,6 +1,6 @@
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Core.Services;
-using Remotely.ScreenCast.Core.Sockets;
+using Remotely.ScreenCast.Core.Communication;
using Remotely.Shared.Win32;
using System;
using System.Collections.Generic;
diff --git a/Server/Server.csproj b/Server/Server.csproj
index 158e459a..a5717348 100644
--- a/Server/Server.csproj
+++ b/Server/Server.csproj
@@ -40,12 +40,14 @@
+
+
@@ -142,12 +144,14 @@
+
+
diff --git a/Server/Services/RCBrowserSocketHub.cs b/Server/Services/RCBrowserSocketHub.cs
index 46c43702..88a8f7bd 100644
--- a/Server/Services/RCBrowserSocketHub.cs
+++ b/Server/Services/RCBrowserSocketHub.cs
@@ -247,5 +247,15 @@ namespace Remotely.Server.Services
{
await RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("TouchUp", Context.ConnectionId);
}
+
+ public async Task SendIceCandidateToAgent(string candidate, int sdpMlineIndex, string sdpMid)
+ {
+ await RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("ReceiveIceCandidate", candidate, sdpMlineIndex, sdpMid, Context.ConnectionId);
+ }
+
+ public async Task SendRtcAnswerToAgent(string sdp)
+ {
+ await RCDeviceHub.Clients.Client(ScreenCasterID).SendAsync("ReceiveRtcAnswer", sdp, Context.ConnectionId);
+ }
}
}
diff --git a/Server/Services/RCDeviceSocketHub.cs b/Server/Services/RCDeviceSocketHub.cs
index 326b4f63..3a1c6261 100644
--- a/Server/Services/RCDeviceSocketHub.cs
+++ b/Server/Services/RCDeviceSocketHub.cs
@@ -154,6 +154,7 @@ namespace Remotely.Server.Services
SessionInfo.MachineName = machineName;
SessionInfo.DeviceID = deviceID;
}
+
public async Task SendAudioSample(byte[] buffer, List viewerIDs)
{
await RCBrowserHub.Clients.Clients(viewerIDs).SendAsync("AudioSample", buffer);
@@ -163,6 +164,7 @@ namespace Remotely.Server.Services
{
await RCBrowserHub.Clients.Clients(viewerIDs).SendAsync("ClipboardTextChanged", clipboardText);
}
+
public async Task SendConnectionFailedToViewers(List viewerIDs)
{
await RCBrowserHub.Clients.Clients(viewerIDs).SendAsync("ConnectionFailed");
@@ -177,6 +179,16 @@ namespace Remotely.Server.Services
{
await RCBrowserHub.Clients.Client(viewerID).SendAsync("ReceiveMachineName", machineName);
}
+
+ public async Task SendRtcOfferToBrowser(string sdp, string viewerID)
+ {
+ await RCBrowserHub.Clients.Client(viewerID).SendAsync("ReceiveRtcOffer", sdp);
+ }
+ public async Task SendIceCandidateToBrowser(string candidate, int sdpMlineIndex, string sdpMid, string viewerID)
+ {
+ await RCBrowserHub.Clients.Client(viewerID).SendAsync("ReceiveIceCandidate", candidate, sdpMlineIndex, sdpMid);
+ }
+
public Task SendScreenCapture(byte[] captureBytes, string rcBrowserHubConnectionID, int left, int top, int width, int height, DateTime captureTime)
{
if (AppConfig.RecordRemoteControlSessions)
diff --git a/Server/package-lock.json b/Server/package-lock.json
index 4fb8e263..e2c897bd 100644
--- a/Server/package-lock.json
+++ b/Server/package-lock.json
@@ -25,6 +25,11 @@
"msgpack5": "^4.0.2"
}
},
+ "@msgpack/msgpack": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-1.11.0.tgz",
+ "integrity": "sha512-gR/NgUeQGARNabGVAjS59lagyxsCgD0zd4F5oKf9uKt8XNLu4awFBNO/Nstr2q1Iu1UPC5EeJeLZSNdP30m7zQ=="
+ },
"@types/bootstrap": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-4.3.1.tgz",
diff --git a/Server/wwwroot/scripts/Models/FrameInfo.js b/Server/wwwroot/scripts/Models/FrameInfo.js
new file mode 100644
index 00000000..7e07c2ba
--- /dev/null
+++ b/Server/wwwroot/scripts/Models/FrameInfo.js
@@ -0,0 +1 @@
+//# sourceMappingURL=FrameInfo.js.map
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/Models/FrameInfo.js.map b/Server/wwwroot/scripts/Models/FrameInfo.js.map
new file mode 100644
index 00000000..20668393
--- /dev/null
+++ b/Server/wwwroot/scripts/Models/FrameInfo.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"FrameInfo.js","sourceRoot":"","sources":["FrameInfo.ts"],"names":[],"mappings":""}
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/Models/FrameInfo.ts b/Server/wwwroot/scripts/Models/FrameInfo.ts
new file mode 100644
index 00000000..0b34153b
--- /dev/null
+++ b/Server/wwwroot/scripts/Models/FrameInfo.ts
@@ -0,0 +1,7 @@
+declare interface FrameInfo {
+ Left: number;
+ Top: number;
+ Width: number;
+ Height: number;
+ ImageBytes: Uint8Array;
+}
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/Main.js b/Server/wwwroot/scripts/RemoteControl/Main.js
index 5335132d..cbb1bb5f 100644
--- a/Server/wwwroot/scripts/RemoteControl/Main.js
+++ b/Server/wwwroot/scripts/RemoteControl/Main.js
@@ -1,10 +1,12 @@
import * as Utilities from "../Utilities.js";
import { RCBrowserSockets } from "./RCBrowserSockets.js";
+import { RtcSession } from "./RtcSession.js";
import * as UI from "./UI.js";
import { RemoteControlMode } from "../Enums/RemoteControlMode.js";
var queryString = Utilities.ParseSearchString();
export const RemoteControl = {
RCBrowserSockets: new RCBrowserSockets(),
+ RtcSession: new RtcSession(),
ClientID: queryString["clientID"] ? decodeURIComponent(queryString["clientID"]) : "",
ServiceID: queryString["serviceID"] ? decodeURIComponent(queryString["serviceID"]) : "",
RequesterName: queryString["requesterName"] ? decodeURIComponent(queryString["requesterName"]) : "",
diff --git a/Server/wwwroot/scripts/RemoteControl/Main.js.map b/Server/wwwroot/scripts/RemoteControl/Main.js.map
index 3ec1b4f1..824577ad 100644
--- a/Server/wwwroot/scripts/RemoteControl/Main.js.map
+++ b/Server/wwwroot/scripts/RemoteControl/Main.js.map
@@ -1 +1 @@
-{"version":3,"file":"Main.js","sourceRoot":"","sources":["Main.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,IAAI,WAAW,GAAG,SAAS,CAAC,iBAAiB,EAAE,CAAC;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAG;IAEzB,gBAAgB,EAAE,IAAI,gBAAgB,EAAE;IACxC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACpF,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACvF,aAAa,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnG,IAAI,EAAE,iBAAiB,CAAC,IAAI;IAE5B,IAAI,EAAE,GAAG,EAAE;QACP,EAAE,CAAC,kBAAkB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;QAEtD,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE;YACzB,aAAa,CAAC,IAAI,GAAG,iBAAiB,CAAC,UAAU,CAAC;YAClD,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;YACrC,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;SAC5C;aACI,IAAI,WAAW,CAAC,WAAW,CAAC,EAAE;YAC/B,EAAE,CAAC,cAAc,CAAC,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;YACvE,IAAI,WAAW,CAAC,eAAe,CAAC,EAAE;gBAC9B,EAAE,CAAC,kBAAkB,CAAC,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC;gBAC/E,IAAI,CAAC,eAAe,EAAE,CAAC;aAC1B;SACJ;IACL,CAAC;IACD,eAAe,EAAE,GAAG,EAAE;QAClB,EAAE,CAAC,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC;QACjC,aAAa,CAAC,QAAQ,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrE,aAAa,CAAC,aAAa,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC;QAC1D,aAAa,CAAC,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC;QAC9C,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;QACzC,EAAE,CAAC,aAAa,CAAC,SAAS,GAAG,+BAA+B,CAAC;IACjE,CAAC;CACJ,CAAA;AAED,MAAM,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC"}
\ No newline at end of file
+{"version":3,"file":"Main.js","sourceRoot":"","sources":["Main.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGlE,IAAI,WAAW,GAAG,SAAS,CAAC,iBAAiB,EAAE,CAAC;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAG;IAEzB,gBAAgB,EAAE,IAAI,gBAAgB,EAAE;IACxC,UAAU,EAAE,IAAI,UAAU,EAAE;IAC5B,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACpF,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACvF,aAAa,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;IACnG,IAAI,EAAE,iBAAiB,CAAC,IAAI;IAE5B,IAAI,EAAE,GAAG,EAAE;QACP,EAAE,CAAC,kBAAkB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;QAEtD,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE;YACzB,aAAa,CAAC,IAAI,GAAG,iBAAiB,CAAC,UAAU,CAAC;YAClD,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;YACrC,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;SAC5C;aACI,IAAI,WAAW,CAAC,WAAW,CAAC,EAAE;YAC/B,EAAE,CAAC,cAAc,CAAC,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;YACvE,IAAI,WAAW,CAAC,eAAe,CAAC,EAAE;gBAC9B,EAAE,CAAC,kBAAkB,CAAC,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC;gBAC/E,IAAI,CAAC,eAAe,EAAE,CAAC;aAC1B;SACJ;IACL,CAAC;IACD,eAAe,EAAE,GAAG,EAAE;QAClB,EAAE,CAAC,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC;QACjC,aAAa,CAAC,QAAQ,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrE,aAAa,CAAC,aAAa,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC;QAC1D,aAAa,CAAC,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC;QAC9C,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;QACzC,EAAE,CAAC,aAAa,CAAC,SAAS,GAAG,+BAA+B,CAAC;IACjE,CAAC;CACJ,CAAA;AAED,MAAM,CAAC,eAAe,CAAC,GAAG,aAAa,CAAC"}
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/Main.ts b/Server/wwwroot/scripts/RemoteControl/Main.ts
index 195873c4..4d9eb3c6 100644
--- a/Server/wwwroot/scripts/RemoteControl/Main.ts
+++ b/Server/wwwroot/scripts/RemoteControl/Main.ts
@@ -1,5 +1,6 @@
import * as Utilities from "../Utilities.js";
import { RCBrowserSockets } from "./RCBrowserSockets.js";
+import { RtcSession } from "./RtcSession.js";
import * as UI from "./UI.js";
import { RemoteControlMode } from "../Enums/RemoteControlMode.js";
@@ -9,6 +10,7 @@ var queryString = Utilities.ParseSearchString();
export const RemoteControl = {
RCBrowserSockets: new RCBrowserSockets(),
+ RtcSession: new RtcSession(),
ClientID: queryString["clientID"] ? decodeURIComponent(queryString["clientID"]) : "",
ServiceID: queryString["serviceID"] ? decodeURIComponent(queryString["serviceID"]) : "",
RequesterName: queryString["requesterName"] ? decodeURIComponent(queryString["requesterName"]) : "",
diff --git a/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js b/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js
index 35c0f03e..ce0bcd27 100644
--- a/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js
+++ b/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js
@@ -33,6 +33,14 @@ export class RCBrowserSockets {
});
}
;
+ SendIceCandidate(candidate) {
+ if (candidate) {
+ this.Connection.invoke("SendIceCandidateToAgent", candidate.candidate, candidate.sdpMLineIndex, candidate.sdpMid);
+ }
+ }
+ SendRtcAnswer(sessionDescription) {
+ this.Connection.invoke("SendRtcAnswerToAgent", sessionDescription.sdp);
+ }
SendScreenCastRequestToDevice() {
this.Connection.invoke("SendScreenCastRequestToDevice", RemoteControl.ClientID, RemoteControl.RequesterName, RemoteControl.Mode);
}
@@ -187,6 +195,19 @@ export class RCBrowserSockets {
hubConnection.on("RequestingScreenCast", () => {
UI.ShowMessage("Requesting remote control...");
});
+ hubConnection.on("ReceiveRtcOffer", async (sdp) => {
+ console.log("Rtc offer SDP received.");
+ RemoteControl.RtcSession.Init();
+ await RemoteControl.RtcSession.ReceiveRtcOffer(sdp);
+ });
+ hubConnection.on("ReceiveIceCandidate", (candidate, sdpMlineIndex, sdpMid) => {
+ console.log("Ice candidate received.");
+ RemoteControl.RtcSession.ReceiveCandidate({
+ candidate: candidate,
+ sdpMLineIndex: sdpMlineIndex,
+ sdpMid: sdpMid
+ });
+ });
}
}
//# sourceMappingURL=RCBrowserSockets.js.map
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js.map b/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js.map
index 3c8401ad..a45fb264 100644
--- a/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js.map
+++ b/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.js.map
@@ -1 +1 @@
-{"version":3,"file":"RCBrowserSockets.js","sourceRoot":"","sources":["RCBrowserSockets.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"RCBrowserSockets.js","sourceRoot":"","sources":["RCBrowserSockets.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.ts b/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.ts
index f97e6d68..b1e3e03b 100644
--- a/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.ts
+++ b/Server/wwwroot/scripts/RemoteControl/RCBrowserSockets.ts
@@ -46,6 +46,17 @@ export class RCBrowserSockets {
UI.ConnectBox.style.removeProperty("display");
});
};
+
+ SendIceCandidate(candidate: RTCIceCandidate) {
+ if (candidate) {
+ this.Connection.invoke("SendIceCandidateToAgent", candidate.candidate, candidate.sdpMLineIndex, candidate.sdpMid);
+ }
+ }
+ SendRtcAnswer(sessionDescription: RTCSessionDescription) {
+ this.Connection.invoke("SendRtcAnswerToAgent", sessionDescription.sdp);
+ }
+
+
SendScreenCastRequestToDevice() {
this.Connection.invoke("SendScreenCastRequestToDevice", RemoteControl.ClientID, RemoteControl.RequesterName, RemoteControl.Mode);
}
@@ -205,5 +216,20 @@ export class RCBrowserSockets {
hubConnection.on("RequestingScreenCast", () => {
UI.ShowMessage("Requesting remote control...");
});
+
+ hubConnection.on("ReceiveRtcOffer", async (sdp: string) => {
+ console.log("Rtc offer SDP received.");
+ RemoteControl.RtcSession.Init();
+ await RemoteControl.RtcSession.ReceiveRtcOffer(sdp);
+
+ });
+ hubConnection.on("ReceiveIceCandidate", (candidate: string, sdpMlineIndex: number, sdpMid: string) => {
+ console.log("Ice candidate received.");
+ RemoteControl.RtcSession.ReceiveCandidate({
+ candidate: candidate,
+ sdpMLineIndex: sdpMlineIndex,
+ sdpMid: sdpMid
+ } as any);
+ });
}
}
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/RtcSession.js b/Server/wwwroot/scripts/RemoteControl/RtcSession.js
new file mode 100644
index 00000000..95d14867
--- /dev/null
+++ b/Server/wwwroot/scripts/RemoteControl/RtcSession.js
@@ -0,0 +1,73 @@
+import * as UI from "./UI.js";
+import * as Utilities from "../Utilities.js";
+import { RemoteControl } from "./Main.js";
+export class RtcSession {
+ constructor() {
+ this.MsgPack5 = new window['msgpack5']();
+ }
+ Init() {
+ this.PeerConnection = new RTCPeerConnection({
+ iceServers: [
+ { urls: "stun: stun.l.google.com:19302" },
+ { urls: "stun:stun4.l.google.com:19302" }
+ ]
+ });
+ this.PeerConnection.ondatachannel = (ev) => {
+ console.log("Data channel received.");
+ this.DataChannel = ev.channel;
+ this.DataChannel.onbufferedamountlow = (ev) => {
+ console.log("Buffer amount low.");
+ };
+ this.DataChannel.onclose = (ev) => {
+ console.log("Data channel closed.");
+ };
+ this.DataChannel.onerror = (ev) => {
+ console.log("Data channel error.", ev.error);
+ };
+ this.DataChannel.onmessage = (ev) => {
+ var frameInfo = this.MsgPack5.decode(ev.data);
+ console.debug("Data channel message.");
+ var url = window.URL.createObjectURL(new Blob([frameInfo.ImageBytes]));
+ var img = document.createElement("img");
+ img.onload = () => {
+ UI.Screen2DContext.drawImage(img, frameInfo.Left, frameInfo.Top, frameInfo.Width, frameInfo.Height);
+ window.URL.revokeObjectURL(url);
+ };
+ img.src = url;
+ };
+ this.DataChannel.onopen = (ev) => {
+ console.log("Data channel opened.");
+ };
+ };
+ this.PeerConnection.onconnectionstatechange = function (ev) {
+ console.log("Connection state changed to " + this.connectionState);
+ };
+ this.PeerConnection.oniceconnectionstatechange = function (ev) {
+ console.log("Connection state changed to " + this.iceConnectionState);
+ };
+ this.PeerConnection.onicecandidate = async (ev) => {
+ await RemoteControl.RCBrowserSockets.SendIceCandidate(ev.candidate);
+ };
+ }
+ Disconnect() {
+ this.PeerConnection.close();
+ }
+ async ReceiveRtcOffer(sdp) {
+ await this.PeerConnection.setRemoteDescription({ type: "offer", sdp: sdp });
+ Utilities.When(() => {
+ return this.PeerConnection.remoteDescription.sdp.length > 0;
+ }).then(async () => {
+ await this.PeerConnection.setLocalDescription(await this.PeerConnection.createAnswer());
+ await RemoteControl.RCBrowserSockets.SendRtcAnswer(this.PeerConnection.localDescription);
+ });
+ }
+ async ReceiveCandidate(candidate) {
+ Utilities.When(() => {
+ return this.PeerConnection.remoteDescription.sdp.length > 0;
+ }).then(async () => {
+ await this.PeerConnection.addIceCandidate(candidate);
+ console.log("Set ICE candidate.");
+ });
+ }
+}
+//# sourceMappingURL=RtcSession.js.map
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/RtcSession.js.map b/Server/wwwroot/scripts/RemoteControl/RtcSession.js.map
new file mode 100644
index 00000000..26da2985
--- /dev/null
+++ b/Server/wwwroot/scripts/RemoteControl/RtcSession.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"RtcSession.js","sourceRoot":"","sources":["RtcSession.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/Server/wwwroot/scripts/RemoteControl/RtcSession.ts b/Server/wwwroot/scripts/RemoteControl/RtcSession.ts
new file mode 100644
index 00000000..c77b9d06
--- /dev/null
+++ b/Server/wwwroot/scripts/RemoteControl/RtcSession.ts
@@ -0,0 +1,77 @@
+import * as UI from "./UI.js";
+import * as Utilities from "../Utilities.js";
+import { RemoteControl } from "./Main.js";
+
+
+export class RtcSession {
+ PeerConnection: RTCPeerConnection;
+ DataChannel: RTCDataChannel;
+ MsgPack5: any = new window['msgpack5']();
+ Init() {
+ this.PeerConnection = new RTCPeerConnection({
+ iceServers: [
+ { urls: "stun: stun.l.google.com:19302" },
+ { urls: "stun:stun4.l.google.com:19302" }
+ ]
+ });
+
+ this.PeerConnection.ondatachannel = (ev) => {
+ console.log("Data channel received.");
+ this.DataChannel = ev.channel;
+ this.DataChannel.onbufferedamountlow = (ev) => {
+ console.log("Buffer amount low.");
+ };
+ this.DataChannel.onclose = (ev) => {
+ console.log("Data channel closed.");
+ };
+ this.DataChannel.onerror = (ev) => {
+ console.log("Data channel error.", ev.error);
+ };
+ this.DataChannel.onmessage = (ev) => {
+ var frameInfo = this.MsgPack5.decode(ev.data) as FrameInfo;
+ console.debug("Data channel message.");
+ var url = window.URL.createObjectURL(new Blob([frameInfo.ImageBytes]));
+ var img = document.createElement("img");
+ img.onload = () => {
+ UI.Screen2DContext.drawImage(img, frameInfo.Left, frameInfo.Top, frameInfo.Width, frameInfo.Height);
+ window.URL.revokeObjectURL(url);
+ };
+ img.src = url;
+ };
+ this.DataChannel.onopen = (ev) => {
+ console.log("Data channel opened.");
+ };
+ };
+ this.PeerConnection.onconnectionstatechange = function (ev) {
+ console.log("Connection state changed to " + this.connectionState);
+ }
+
+ this.PeerConnection.oniceconnectionstatechange = function (ev) {
+ console.log("Connection state changed to " + this.iceConnectionState);
+ }
+ this.PeerConnection.onicecandidate = async (ev) => {
+ await RemoteControl.RCBrowserSockets.SendIceCandidate(ev.candidate);
+ };
+ }
+ Disconnect() {
+ this.PeerConnection.close();
+ }
+ async ReceiveRtcOffer(sdp: string) {
+ await this.PeerConnection.setRemoteDescription({ type: "offer", sdp: sdp });
+
+ Utilities.When(() => {
+ return this.PeerConnection.remoteDescription.sdp.length > 0;
+ }).then(async () => {
+ await this.PeerConnection.setLocalDescription(await this.PeerConnection.createAnswer());
+ await RemoteControl.RCBrowserSockets.SendRtcAnswer(this.PeerConnection.localDescription);
+ })
+ }
+ async ReceiveCandidate(candidate: RTCIceCandidate) {
+ Utilities.When(() => {
+ return this.PeerConnection.remoteDescription.sdp.length > 0;
+ }).then(async () => {
+ await this.PeerConnection.addIceCandidate(candidate);
+ console.log("Set ICE candidate.");
+ })
+ }
+}