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."); + }) + } +}