diff --git a/Desktop.Core/Desktop.Core.csproj b/Desktop.Core/Desktop.Core.csproj index 66f9c71f..9d9b077c 100644 --- a/Desktop.Core/Desktop.Core.csproj +++ b/Desktop.Core/Desktop.Core.csproj @@ -46,8 +46,10 @@ - + + + diff --git a/Desktop.Core/Services/CasterSocket.cs b/Desktop.Core/Services/CasterSocket.cs index d0eb4d02..eb67c609 100644 --- a/Desktop.Core/Services/CasterSocket.cs +++ b/Desktop.Core/Services/CasterSocket.cs @@ -28,7 +28,7 @@ namespace Remotely.Desktop.Core.Services Task SendCtrlAltDelToAgent(); Task SendDeviceInfo(string serviceID, string machineName, string deviceID); Task SendDtoToViewer(T baseDto, string viewerId); - Task SendIceCandidateToBrowser(string candidate, int sdpMlineIndex, string sdpMid, string viewerConnectionID); + Task SendIceCandidateToBrowser(string candidateJson, string viewerConnectionID); Task SendMessageToViewer(string viewerID, string message); Task SendRtcOfferToBrowser(string sdp, string viewerID, IceServerModel[] iceServers); Task SendViewerConnected(string viewerConnectionId); @@ -164,9 +164,9 @@ namespace Remotely.Desktop.Core.Services var serializedDto = MessagePack.MessagePackSerializer.Serialize(baseDto); return Connection.SendAsync("SendDtoToBrowser", serializedDto, viewerId); } - public async Task SendIceCandidateToBrowser(string candidate, int sdpMlineIndex, string sdpMid, string viewerConnectionID) + public async Task SendIceCandidateToBrowser(string candidateJson, string viewerConnectionID) { - await Connection.SendAsync("SendIceCandidateToBrowser", candidate, sdpMlineIndex, sdpMid, viewerConnectionID); + await Connection.SendAsync("SendIceCandidateToBrowser", candidateJson, viewerConnectionID); } public async Task SendRtcOfferToBrowser(string sdp, string viewerID, IceServerModel[] iceServers) @@ -237,13 +237,13 @@ namespace Remotely.Desktop.Core.Services }); - Connection.On("ReceiveIceCandidate", (string candidate, int sdpMlineIndex, string sdpMid, string viewerID) => + Connection.On("ReceiveIceCandidate", (string candidateJson, string viewerID) => { try { if (conductor.Viewers.TryGetValue(viewerID, out var viewer)) { - viewer.RtcSession.AddIceCandidate(sdpMid, sdpMlineIndex, candidate); + viewer.RtcSession.AddIceCandidate(candidateJson); } } catch (Exception ex) diff --git a/Desktop.Core/Services/DtoMessageHandler.cs b/Desktop.Core/Services/DtoMessageHandler.cs index 1be60778..e5f796e9 100644 --- a/Desktop.Core/Services/DtoMessageHandler.cs +++ b/Desktop.Core/Services/DtoMessageHandler.cs @@ -97,9 +97,6 @@ namespace Remotely.Desktop.Core.Services case BaseDtoType.ToggleBlockInput: ToggleBlockInput(message); break; - case BaseDtoType.ToggleWebRtcVideo: - ToggleWebRtcVideo(message, viewer); - break; case BaseDtoType.ClipboardTransfer: await ClipboardTransfer(message); break; @@ -250,11 +247,5 @@ namespace Remotely.Desktop.Core.Services var dto = MessagePackSerializer.Deserialize(message); KeyboardMouseInput.ToggleBlockInput(dto.ToggleOn); } - - private void ToggleWebRtcVideo(byte[] message, Viewer viewer) - { - var dto = MessagePackSerializer.Deserialize(message); - viewer.ToggleWebRtcVideo(dto.ToggleOn); - } } } diff --git a/Desktop.Core/Services/ScreenCaster.cs b/Desktop.Core/Services/ScreenCaster.cs index c4b2e4ad..b2f63159 100644 --- a/Desktop.Core/Services/ScreenCaster.cs +++ b/Desktop.Core/Services/ScreenCaster.cs @@ -106,7 +106,7 @@ namespace Remotely.Desktop.Core.Services } - if (EnvironmentHelper.IsWindows && screenCastRequest.UseWebRtc) + if (screenCastRequest.UseWebRtc) { await viewer.InitializeWebRtc(); } @@ -118,11 +118,6 @@ namespace Remotely.Desktop.Core.Services { try { - if (viewer.IsUsingWebRtcVideo) - { - Thread.Sleep(100); - continue; - } if (viewer.IsStalled) { // Viewer isn't responding. Abort sending. diff --git a/Desktop.Core/Services/Viewer.cs b/Desktop.Core/Services/Viewer.cs index e482bf64..1e168631 100644 --- a/Desktop.Core/Services/Viewer.cs +++ b/Desktop.Core/Services/Viewer.cs @@ -11,8 +11,7 @@ using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Threading.Tasks; -using System.Diagnostics; -using System.Threading; +using System.Text.Json; namespace Remotely.Desktop.Core.Services { @@ -59,14 +58,6 @@ namespace Remotely.Desktop.Core.Services } } - public bool IsUsingWebRtcVideo - { - get - { - return RtcSession?.IsPeerConnected == true && RtcSession?.IsVideoTrackConnected == true; - } - } - public string Name { get; set; } public double AverageBytesPerSecond { get; set; } @@ -109,11 +100,12 @@ namespace Remotely.Desktop.Core.Services RtcSession.LocalSdpReady += async (sender, sdp) => { - await CasterSocket.SendRtcOfferToBrowser(sdp.Content, ViewerConnectionID, iceServers); + await CasterSocket.SendRtcOfferToBrowser(sdp.sdp, ViewerConnectionID, iceServers); }; RtcSession.IceCandidateReady += async (sender, candidate) => { - await CasterSocket.SendIceCandidateToBrowser(candidate.Content, candidate.SdpMlineIndex, candidate.SdpMid, ViewerConnectionID); + var candidateJson = JsonSerializer.Serialize(candidate); + await CasterSocket.SendIceCandidateToBrowser(candidateJson, ViewerConnectionID); }; await RtcSession.Init(iceServers); @@ -306,11 +298,6 @@ namespace Remotely.Desktop.Core.Services TimeSpan.FromSeconds(10)); } - public void ToggleWebRtcVideo(bool toggleOn) - { - RtcSession.ToggleWebRtcVideo(toggleOn); - } - private async void AudioCapturer_AudioSampleReady(object sender, byte[] sample) { await SendAudioSample(sample); diff --git a/Desktop.Core/Services/WebRtcSession.cs b/Desktop.Core/Services/WebRtcSession.cs index 26a2fd1a..03f1c954 100644 --- a/Desktop.Core/Services/WebRtcSession.cs +++ b/Desktop.Core/Services/WebRtcSession.cs @@ -1,5 +1,4 @@ using MessagePack; -using Microsoft.MixedReality.WebRTC; using Remotely.Shared.Utilities; using Remotely.Shared.Models; using Remotely.Shared.Models.RemoteControlDtos; @@ -7,240 +6,175 @@ using System; using System.Drawing; using System.Linq; using System.Threading.Tasks; -using System.Threading; +using SIPSorcery.Net; +using System.Timers; +using System.Collections.Generic; +using System.Text.Json; namespace Remotely.Desktop.Core.Services { public class WebRtcSession : IDisposable { - public WebRtcSession(Services.Viewer viewer, IDtoMessageHandler rtcMessageHandler) + public WebRtcSession(Viewer viewer, IDtoMessageHandler rtcMessageHandler) { Viewer = viewer; RtcMessageHandler = rtcMessageHandler; + DataChannelBufferMonitor = new Timer(500); + DataChannelBufferMonitor.Elapsed += DataChannelBufferMonitor_Elapsed; + DataChannelBufferMonitor.Start(); } - public event EventHandler IceCandidateReady; - public event EventHandler LocalSdpReady; + + public event EventHandler IceCandidateReady; + + public event EventHandler LocalSdpReady; public ulong CurrentBuffer { get; private set; } - public bool IsDataChannelOpen => CaptureChannel?.State == DataChannel.ChannelState.Open; - public bool IsPeerConnected => PeerSession?.IsConnected == true; - public bool IsVideoTrackConnected - { - get - { - return Transceiver?.LocalVideoTrack?.Enabled == true; - } - } + public bool IsDataChannelOpen => CaptureChannel?.readyState == RTCDataChannelState.open; + public bool IsPeerConnected => PeerSession?.connectionState == RTCPeerConnectionState.connected; - private DataChannel CaptureChannel { get; set; } + private RTCDataChannel CaptureChannel { get; set; } private IceServerModel[] IceServers { get; set; } - private PeerConnection PeerSession { get; set; } + private RTCPeerConnection PeerSession { get; set; } private IDtoMessageHandler RtcMessageHandler { get; } - private Transceiver Transceiver { get; set; } - private ExternalVideoTrackSource VideoSource { get; set; } - private Services.Viewer Viewer { get; } - public void AddIceCandidate(string sdpMid, int sdpMlineIndex, string candidate) + private Timer DataChannelBufferMonitor { get; } + private Viewer Viewer { get; } + public void AddIceCandidate(string candidateJson) { - PeerSession.AddIceCandidate(new IceCandidate() - { - Content = candidate, - SdpMid = sdpMid, - SdpMlineIndex = sdpMlineIndex - }); + var candidate = JsonSerializer.Deserialize(candidateJson); + PeerSession.addIceCandidate(candidate); } public void Dispose() { try { - // Unable to exit process until DataChannel is removed/disposed, - // and this throws internally (at least in 2.0 version). - PeerSession?.RemoveDataChannel(CaptureChannel); + PeerSession?.DataChannels?.Clear(); + CaptureChannel?.close(); + DataChannelBufferMonitor?.Dispose(); } catch { } - PeerSession.Transceivers.RemoveAll(x => true); - Disposer.TryDisposeAll(new IDisposable[] - { - Transceiver?.LocalVideoTrack, - VideoSource, - PeerSession - }); + + PeerSession?.Dispose(); GC.SuppressFinalize(this); } - public async Task Init(IceServerModel[] iceServers) + public Task Init(IceServerModel[] iceServers) { Logger.Write("Starting WebRTC connection."); IceServers = iceServers; - PeerSession = new PeerConnection(); - - var iceList = IceServers.Select(x => new IceServer() + var config = new RTCConfiguration() { - Urls = { x.Url }, - TurnPassword = x.TurnPassword ?? string.Empty, - TurnUserName = x.TurnUsername ?? string.Empty - }).ToList(); + iceServers = iceServers.Select(x => new RTCIceServer() + { + credential = x.Credential, + credentialType = RTCIceCredentialType.password, + urls = x.Urls, + username = x.Username - var config = new PeerConnectionConfiguration() - { - IceServers = iceList + }).ToList() }; - await PeerSession.InitializeAsync(config); + PeerSession = new RTCPeerConnection(config); - PeerSession.LocalSdpReadytoSend += PeerSession_LocalSdpReadytoSend; - PeerSession.Connected += PeerConnection_Connected; - PeerSession.IceStateChanged += PeerConnection_IceStateChanged; - PeerSession.IceCandidateReadytoSend += PeerSession_IceCandidateReadytoSend; + PeerSession.oniceconnectionstatechange += PeerSession_oniceconnectionstatechange; + PeerSession.onicecandidate += PeerSession_onicecandidate; - CaptureChannel = await PeerSession.AddDataChannelAsync("ScreenCapture", true, true); - CaptureChannel.BufferingChanged += DataChannel_BufferingChanged; - CaptureChannel.MessageReceived += CaptureChannel_MessageReceived; - CaptureChannel.StateChanged += CaptureChannel_StateChanged; + var dataChannelInit = new RTCDataChannelInit(); + CaptureChannel = PeerSession.createDataChannel("RemoteControl", dataChannelInit); - VideoSource = ExternalVideoTrackSource.CreateFromArgb32Callback(GetCaptureFrame); - Transceiver = PeerSession.AddTransceiver(MediaKind.Video); + CaptureChannel.onDatamessage += CaptureChannel_onDatamessage; + CaptureChannel.onclose += CaptureChannel_onclose; + CaptureChannel.onopen += CaptureChannel_onopen; + CaptureChannel.onerror += CaptureChannel_onerror; - PeerSession.CreateOffer(); + var offer = PeerSession.createOffer(new RTCOfferOptions()); + LocalSdpReady?.Invoke(this, offer); + + return Task.CompletedTask; } - public Task SendDto(T dto) where T : BaseDto + + public async Task SendDto(T dto) where T : BaseDto { - return Task.Run(() => - { - CaptureChannel.SendMessage(MessagePackSerializer.Serialize(dto)); - while (CurrentBuffer > 64_000) - { - Thread.Sleep(10); - } - }); + await CaptureChannel.sendasync(MessagePackSerializer.Serialize(dto)); } - public async Task SetRemoteDescription(string type, string sdp) + public Task SetRemoteDescription(string type, string sdp) { - if (!Enum.TryParse(type, true, out var sdpMessageType)) + if (!Enum.TryParse(type, true, out var sdpMessageType)) { Logger.Write("Unable to parse remote WebRTC description type."); - return; + return Task.CompletedTask; } - await PeerSession.SetRemoteDescriptionAsync(new SdpMessage() + PeerSession.setRemoteDescription(new RTCSessionDescriptionInit() { - Content = sdp, - Type = sdpMessageType + type = sdpMessageType, + sdp = sdp }); - if (sdpMessageType == SdpMessageType.Offer) + + if (sdpMessageType == RTCSdpType.offer) { - PeerSession.CreateAnswer(); + PeerSession.createAnswer(new RTCAnswerOptions()); } + + return Task.CompletedTask; } - public void ToggleWebRtcVideo(bool toggleOn) - { - if (Transceiver?.LocalVideoTrack != null) - { - Transceiver.LocalVideoTrack.Dispose(); - Transceiver.LocalVideoTrack = null; - } - - if (toggleOn) - { - Transceiver.LocalVideoTrack = LocalVideoTrack.CreateFromSource(VideoSource, new LocalVideoTrackInitConfig() - { - trackName = "ScreenCapture" - }); - } - } - - private async void CaptureChannel_MessageReceived(byte[] obj) + private async void CaptureChannel_onDatamessage(byte[] obj) { await RtcMessageHandler.ParseMessage(Viewer, obj); } - private async void CaptureChannel_StateChanged() + + + + private async void CaptureChannel_onerror(string obj) { // Clear the queue when WebRTC state changes. Viewer.PendingSentFrames.Clear(); - Logger.Write($"DataChannel state changed. New State: {CaptureChannel.State}"); - if (CaptureChannel.State == DataChannel.ChannelState.Closed) - { - await Init(IceServers); - } + Logger.Write($"DataChannel error: {obj}"); + await Init(IceServers); } - private void DataChannel_BufferingChanged(ulong previous, ulong current, ulong limit) + private void CaptureChannel_onopen() { - CurrentBuffer = current; + // Clear the queue when WebRTC state changes. + Viewer.PendingSentFrames.Clear(); + Logger.Write("DataChannel opened."); } - private void GetCaptureFrame(in FrameRequest request) + private async void CaptureChannel_onclose() { - try - { - if (!IsVideoTrackConnected) - { - return; - } - - using var currentFrame = Viewer.Capturer.GetNextFrame(); - if (currentFrame == null) - { - return; - } - - var bitmapData = currentFrame.LockBits( - new Rectangle(Point.Empty, Viewer.Capturer.CurrentScreenBounds.Size), - System.Drawing.Imaging.ImageLockMode.ReadOnly, - System.Drawing.Imaging.PixelFormat.Format32bppArgb); - - try - { - var frame = new Argb32VideoFrame() - { - data = bitmapData.Scan0, - height = (uint)currentFrame.Height, - width = (uint)currentFrame.Width, - stride = bitmapData.Stride - }; - request.CompleteRequest(in frame); - } - finally - { - currentFrame.UnlockBits(bitmapData); - } - } - catch (Exception ex) - { - Logger.Write(ex); - } - + // Clear the queue when WebRTC state changes. + Viewer.PendingSentFrames.Clear(); + Logger.Write("DataChannel closed."); + await Init(IceServers); } - private void PeerConnection_Connected() - { - Logger.Write("PeerConnection connected."); - } - - private void PeerConnection_IceStateChanged(IceConnectionState newState) + private void PeerSession_oniceconnectionstatechange(RTCIceConnectionState newState) { // Clear the queue when WebRTC state changes. Viewer.PendingSentFrames.Clear(); Logger.Write($"Ice state changed to {newState}."); } - private void PeerSession_IceCandidateReadytoSend(IceCandidate candidate) + private void PeerSession_onicecandidate(RTCIceCandidate candidate) { Logger.Write("Ice candidate ready to send."); IceCandidateReady?.Invoke(this, candidate); } - private void PeerSession_LocalSdpReadytoSend(SdpMessage message) + + private void DataChannelBufferMonitor_Elapsed(object sender, ElapsedEventArgs e) { - Logger.Write($"Local SDP ready."); - LocalSdpReady?.Invoke(this, message); + if (CaptureChannel is not null) + { + CurrentBuffer = CaptureChannel.bufferedAmount; + } } } } diff --git a/Desktop.Win/Desktop.Win.csproj b/Desktop.Win/Desktop.Win.csproj index 8fef046d..da215d70 100644 --- a/Desktop.Win/Desktop.Win.csproj +++ b/Desktop.Win/Desktop.Win.csproj @@ -34,7 +34,6 @@ - diff --git a/Server/Hubs/CasterHub.cs b/Server/Hubs/CasterHub.cs index f39764ed..6c5c5fdf 100644 --- a/Server/Hubs/CasterHub.cs +++ b/Server/Hubs/CasterHub.cs @@ -168,11 +168,11 @@ namespace Remotely.Server.Hubs return ViewerHubContext.Clients.Client(viewerId).SendAsync("SendDtoToBrowser", dto); } - public Task SendIceCandidateToBrowser(string candidate, int sdpMlineIndex, string sdpMid, string viewerID) + public Task SendIceCandidateToBrowser(string candidateJson, string viewerID) { if (_appConfig.UseWebRtc) { - return ViewerHubContext.Clients.Client(viewerID).SendAsync("ReceiveIceCandidate", candidate, sdpMlineIndex, sdpMid); + return ViewerHubContext.Clients.Client(viewerID).SendAsync("ReceiveIceCandidate", candidateJson); } return Task.CompletedTask; diff --git a/Server/Hubs/ViewerHub.cs b/Server/Hubs/ViewerHub.cs index 5ff1fb0f..f1694770 100644 --- a/Server/Hubs/ViewerHub.cs +++ b/Server/Hubs/ViewerHub.cs @@ -122,9 +122,9 @@ namespace Remotely.Server.Hubs return base.OnDisconnectedAsync(exception); } - public Task SendIceCandidateToAgent(string candidate, int sdpMlineIndex, string sdpMid) + public Task SendIceCandidateToAgent(string candidateJson) { - return CasterHubContext.Clients.Client(ScreenCasterID).SendAsync("ReceiveIceCandidate", candidate, sdpMlineIndex, sdpMid, Context.ConnectionId); + return CasterHubContext.Clients.Client(ScreenCasterID).SendAsync("ReceiveIceCandidate", candidateJson, Context.ConnectionId); } public Task SendRtcAnswerToAgent(string sdp) diff --git a/Server/Pages/RemoteControl.cshtml b/Server/Pages/RemoteControl.cshtml index e9a9ab67..8878c3aa 100644 --- a/Server/Pages/RemoteControl.cshtml +++ b/Server/Pages/RemoteControl.cshtml @@ -134,10 +134,6 @@
- - diff --git a/Server/Services/ApplicationConfig.cs b/Server/Services/ApplicationConfig.cs index cf454bb4..7ced7fc1 100644 --- a/Server/Services/ApplicationConfig.cs +++ b/Server/Services/ApplicationConfig.cs @@ -40,8 +40,8 @@ namespace Remotely.Server.Services { private readonly IceServerModel[] fallbackIceServers = new IceServerModel[] { - new IceServerModel() { Url = "stun:stun.l.google.com:19302"}, - new IceServerModel() { Url = "stun:stun4.l.google.com:19302"} + new IceServerModel() { Urls = "stun:stun.l.google.com:19302"}, + new IceServerModel() { Urls = "stun:stun4.l.google.com:19302"} }; public ApplicationConfig(IConfiguration config) diff --git a/Server/appsettings.json b/Server/appsettings.json index dee994ec..98e3250f 100644 --- a/Server/appsettings.json +++ b/Server/appsettings.json @@ -18,14 +18,14 @@ "EnforceAttendedAccess": false, "IceServers": [ { - "Url": "stun:stun.l.google.com:19302", - "TurnPassword": "", - "TurnUsername": "" + "Urls": "stun:stun.l.google.com:19302", + "Credential": null, + "Username": null }, { - "Url": "stun:stun4.l.google.com:19302", - "TurnPassword": "", - "TurnUsername": "" + "Urls": "stun:stun4.l.google.com:19302", + "Credential": null, + "Username": null } ], "KnownProxies": [], diff --git a/Server/wwwroot/src/RemoteControl/Enums/BaseDtoType.ts b/Server/wwwroot/src/RemoteControl/Enums/BaseDtoType.ts index 808911ce..68f7b050 100644 --- a/Server/wwwroot/src/RemoteControl/Enums/BaseDtoType.ts +++ b/Server/wwwroot/src/RemoteControl/Enums/BaseDtoType.ts @@ -23,6 +23,5 @@ WindowsSessions = 23, SetKeyStatesUp = 24, FrameReceived = 25, - ToggleWebRtcVideo = 26, OpenFileTransferWindow = 27 } \ No newline at end of file diff --git a/Server/wwwroot/src/RemoteControl/InputEventHandlers.ts b/Server/wwwroot/src/RemoteControl/InputEventHandlers.ts index e00804f0..35aad20a 100644 --- a/Server/wwwroot/src/RemoteControl/InputEventHandlers.ts +++ b/Server/wwwroot/src/RemoteControl/InputEventHandlers.ts @@ -24,11 +24,9 @@ RecordSessionButton, DownloadRecordingButton, VideoScreenViewer, - StreamVideoButton, FileTransferBar, FileUploadButtton, FileDownloadButton, - UpdateStreamingToggled, ViewOnlyButton, FullScreenButton } from "./UI.js"; @@ -215,15 +213,6 @@ export function ApplyInputHandlers() { ev.stopPropagation(); MenuButton.style.top = `${ev.touches[0].clientY}px`; }); - StreamVideoButton.addEventListener("click", (ev) => { - var toggleOn = !StreamVideoButton.classList.contains("toggled"); - - ViewerApp.Settings.streamModeEnabled = toggleOn; - SetSettings(ViewerApp.Settings); - - UpdateStreamingToggled(toggleOn); - ViewerApp.MessageSender.SendToggleWebRtcVideo(toggleOn); - }); [ ScreenViewer, VideoScreenViewer ].forEach(viewer => { viewer.addEventListener("pointermove", function (e: PointerEvent) { diff --git a/Server/wwwroot/src/RemoteControl/Interfaces/Dtos.ts b/Server/wwwroot/src/RemoteControl/Interfaces/Dtos.ts index 2167bf53..83d30f78 100644 --- a/Server/wwwroot/src/RemoteControl/Interfaces/Dtos.ts +++ b/Server/wwwroot/src/RemoteControl/Interfaces/Dtos.ts @@ -201,16 +201,6 @@ export class ToggleBlockInputDto implements BaseDto { DtoType: BaseDtoType = BaseDtoType.ToggleBlockInput; } -export class ToggleWebRtcVideoDto implements BaseDto { - constructor(toggleOn: boolean) { - this.ToggleOn = toggleOn; - } - - ToggleOn: boolean; - DtoType: BaseDtoType = BaseDtoType.ToggleWebRtcVideo; -} - - export class WindowsSessionsDto implements BaseDto { WindowsSessions: Array; diff --git a/Server/wwwroot/src/RemoteControl/Interfaces/Settings.ts b/Server/wwwroot/src/RemoteControl/Interfaces/Settings.ts index 885f8dda..ec2daddd 100644 --- a/Server/wwwroot/src/RemoteControl/Interfaces/Settings.ts +++ b/Server/wwwroot/src/RemoteControl/Interfaces/Settings.ts @@ -1,4 +1,3 @@ export interface Settings { - streamModeEnabled: boolean; - displayName: string; + } \ No newline at end of file diff --git a/Server/wwwroot/src/RemoteControl/MessageSender.ts b/Server/wwwroot/src/RemoteControl/MessageSender.ts index a2f4917e..fa65dec9 100644 --- a/Server/wwwroot/src/RemoteControl/MessageSender.ts +++ b/Server/wwwroot/src/RemoteControl/MessageSender.ts @@ -15,8 +15,7 @@ import { ClipboardTransferDto, FileDto, WindowsSessionsDto, - GenericDto, - ToggleWebRtcVideoDto + GenericDto } from "./Interfaces/Dtos.js"; import { CreateGUID, When } from "./Utilities.js"; import { FileTransferProgress } from "./UI.js"; @@ -139,11 +138,6 @@ export class MessageSender { this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto), () => ViewerApp.ViewerHubConnection.SendDtoToClient(dto)); } - SendToggleWebRtcVideo(toggleOn: boolean) { - var dto = new ToggleWebRtcVideoDto(toggleOn); - this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto), - () => ViewerApp.ViewerHubConnection.SendDtoToClient(dto)); - } SendClipboardTransfer(text: string, typeText: boolean) { var dto = new ClipboardTransferDto(text, typeText); this.SendToAgent(() => ViewerApp.RtcSession.SendDto(dto), diff --git a/Server/wwwroot/src/RemoteControl/Models/IceServerModel.ts b/Server/wwwroot/src/RemoteControl/Models/IceServerModel.ts index fbdd551c..ccc1b831 100644 --- a/Server/wwwroot/src/RemoteControl/Models/IceServerModel.ts +++ b/Server/wwwroot/src/RemoteControl/Models/IceServerModel.ts @@ -1,5 +1,5 @@ export class IceServerModel { - Url: string; - TurnPassword: string; - TurnUsername: string; + Urls: string; + Credential: string; + Username: string; } \ No newline at end of file diff --git a/Server/wwwroot/src/RemoteControl/RtcSession.ts b/Server/wwwroot/src/RemoteControl/RtcSession.ts index 3b4b4489..0971a546 100644 --- a/Server/wwwroot/src/RemoteControl/RtcSession.ts +++ b/Server/wwwroot/src/RemoteControl/RtcSession.ts @@ -1,23 +1,26 @@ import * as UI from "./UI.js"; -import * as Utilities from "./Utilities.js"; import { ViewerApp } from "./App.js"; -import { IceServerModel } from "./Models/IceServerModel.js"; +import { IceServerModel } from "../Shared/Models/IceServerModel.js"; +import { When } from "../Shared/Utilities.js"; export class RtcSession { PeerConnection: RTCPeerConnection; DataChannel: RTCDataChannel; MessagePack: any = window['MessagePack']; Init(iceServers: IceServerModel[]) { - + + var servers = iceServers.map(x => { + return { + urls: x.Urls, + username: x.Username, + credential: x.Credential, + credentialType: "password" + + } as RTCIceServer + }); + this.PeerConnection = new RTCPeerConnection({ - iceServers: iceServers.map(x => { - return { - urls: x.Url, - username: x.TurnUsername, - credential: x.TurnPassword, - credentialType: "password" - } - }) + iceServers: servers }); this.PeerConnection.ondatachannel = (ev) => { @@ -29,7 +32,6 @@ export class RtcSession { UI.ConnectionP2PIcon.style.display = "none"; UI.ConnectionRelayedIcon.style.display = "unset"; - UI.StreamVideoButton.setAttribute("hidden", "hidden"); UI.ScreenViewer.removeAttribute("hidden"); UI.VideoScreenViewer.setAttribute("hidden", "hidden"); }; @@ -38,7 +40,6 @@ export class RtcSession { UI.ConnectionP2PIcon.style.display = "none"; UI.ConnectionRelayedIcon.style.display = "unset"; - UI.StreamVideoButton.setAttribute("hidden", "hidden"); UI.ScreenViewer.removeAttribute("hidden"); UI.VideoScreenViewer.setAttribute("hidden", "hidden"); }; @@ -51,13 +52,6 @@ export class RtcSession { console.log("Data channel opened."); UI.ConnectionP2PIcon.style.display = "unset"; UI.ConnectionRelayedIcon.style.display = "none"; - - UI.StreamVideoButton.removeAttribute("hidden"); - - if (ViewerApp.Settings.streamModeEnabled) { - UI.UpdateStreamingToggled(true); - ViewerApp.MessageSender.SendToggleWebRtcVideo(true); - } }; }; this.PeerConnection.onconnectionstatechange = function (ev) { @@ -91,8 +85,10 @@ export class RtcSession { console.log("Set RTC offer."); } async ReceiveCandidate(candidate: RTCIceCandidate) { - await this.PeerConnection.addIceCandidate(candidate); - console.log("Set ICE candidate."); + When(() => !!this.PeerConnection).then(async () => { + await this.PeerConnection.addIceCandidate(candidate); + console.log("Set ICE candidate.", candidate); + }); } SendDto(dto: any) { diff --git a/Server/wwwroot/src/RemoteControl/SettingsService.ts b/Server/wwwroot/src/RemoteControl/SettingsService.ts index d2bcf821..20bb7d12 100644 --- a/Server/wwwroot/src/RemoteControl/SettingsService.ts +++ b/Server/wwwroot/src/RemoteControl/SettingsService.ts @@ -1,8 +1,7 @@ import { Settings } from "./Interfaces/Settings.js"; const defaultSettings = { - streamModeEnabled: false, - displayName: "" + }; diff --git a/Server/wwwroot/src/RemoteControl/UI.ts b/Server/wwwroot/src/RemoteControl/UI.ts index e9f79037..a035b8b1 100644 --- a/Server/wwwroot/src/RemoteControl/UI.ts +++ b/Server/wwwroot/src/RemoteControl/UI.ts @@ -22,7 +22,6 @@ export var ScreenSelectBar = document.getElementById("screenSelectBar") as HTMLD export var ActionsBar = document.getElementById("actionsBar") as HTMLDivElement; export var ViewBar = document.getElementById("viewBar") as HTMLDivElement; export var ChangeScreenButton = document.getElementById("changeScreenButton") as HTMLButtonElement; -export var StreamVideoButton = document.getElementById("streamVideoButton") as HTMLButtonElement; export var FitToScreenButton = document.getElementById("fitToScreenButton") as HTMLButtonElement; export var BlockInputButton = document.getElementById("blockInputButton") as HTMLButtonElement; export var DisconnectButton = document.getElementById("disconnectButton") as HTMLButtonElement; @@ -118,13 +117,7 @@ export function ToggleConnectUI(shown: boolean) { Screen2DContext.clearRect(0, 0, ScreenViewer.width, ScreenViewer.height); ScreenViewer.setAttribute("hidden", "hidden"); VideoScreenViewer.setAttribute("hidden", "hidden"); - if (ViewerApp.Mode == RemoteControlMode.Normal) { - ConnectBox.style.removeProperty("display"); - } - else { - DisconnectedBox.style.removeProperty("display"); - } - StreamVideoButton.classList.remove("toggled"); + ConnectBox.style.removeProperty("display"); BlockInputButton.classList.remove("toggled"); AudioButton.classList.remove("toggled"); } @@ -172,19 +165,6 @@ export function UpdateDisplays(selectedDisplay: string, displayNames: string[]) } } -export function UpdateStreamingToggled(toggleOn: boolean) { - if (toggleOn) { - StreamVideoButton.classList.add("toggled"); - VideoScreenViewer.removeAttribute("hidden"); - ScreenViewer.setAttribute("hidden", "hidden"); - } - else { - StreamVideoButton.classList.remove("toggled"); - ScreenViewer.removeAttribute("hidden"); - VideoScreenViewer.setAttribute("hidden", "hidden"); - } -} - export function UpdateWindowsSessions(windowsSessions: Array) { while (WindowsSessionSelect.options.length > 0) { WindowsSessionSelect.options.remove(0); diff --git a/Server/wwwroot/src/RemoteControl/ViewerHubConnection.ts b/Server/wwwroot/src/RemoteControl/ViewerHubConnection.ts index 191e8a86..a6c7c499 100644 --- a/Server/wwwroot/src/RemoteControl/ViewerHubConnection.ts +++ b/Server/wwwroot/src/RemoteControl/ViewerHubConnection.ts @@ -55,10 +55,10 @@ export class ViewerHubConnection { SendIceCandidate(candidate: RTCIceCandidate) { if (candidate) { - this.Connection.invoke("SendIceCandidateToAgent", candidate.candidate, candidate.sdpMLineIndex, candidate.sdpMid); + this.Connection.invoke("SendIceCandidateToAgent", JSON.stringify(candidate)); } else { - this.Connection.invoke("SendIceCandidateToAgent", "", 0, ""); + this.Connection.invoke("SendIceCandidateToAgent", "{}"); } } SendRtcAnswer(sessionDescription: RTCSessionDescription) { @@ -147,13 +147,10 @@ export class ViewerHubConnection { await ViewerApp.RtcSession.ReceiveRtcOffer(sdp); }); - hubConnection.on("ReceiveIceCandidate", (candidate: string, sdpMlineIndex: number, sdpMid: string) => { - console.log("Ice candidate received."); - ViewerApp.RtcSession.ReceiveCandidate({ - candidate: candidate, - sdpMLineIndex: sdpMlineIndex, - sdpMid: sdpMid - } as any); + hubConnection.on("ReceiveIceCandidate", async (candidateJson: string) => { + var candidate = JSON.parse(candidateJson); + console.log("Ice candidate received.", candidate); + await ViewerApp.RtcSession.ReceiveCandidate(candidate); }); hubConnection.on("ShowMessage", (message: string) => { ShowMessage(message); diff --git a/Shared/Enums/BaseDtoType.cs b/Shared/Enums/BaseDtoType.cs index 5ecbab68..43444401 100644 --- a/Shared/Enums/BaseDtoType.cs +++ b/Shared/Enums/BaseDtoType.cs @@ -53,8 +53,6 @@ namespace Remotely.Shared.Enums SetKeyStatesUp = 24, [EnumMember(Value = "FrameReceived")] FrameReceived = 25, - [EnumMember(Value = "ToggleWebRtcVideo")] - ToggleWebRtcVideo = 26, [EnumMember(Value = "OpenFileTransferWindow")] OpenFileTransferWindow = 27 } diff --git a/Shared/Models/IceServerModel.cs b/Shared/Models/IceServerModel.cs index e6afaa33..18d4bf5b 100644 --- a/Shared/Models/IceServerModel.cs +++ b/Shared/Models/IceServerModel.cs @@ -2,8 +2,8 @@ { public class IceServerModel { - public string Url { get; set; } - public string TurnPassword { get; set; } - public string TurnUsername { get; set; } + public string Urls { get; set; } + public string Credential { get; set; } + public string Username { get; set; } } } diff --git a/Shared/Models/RemoteControlDtos/ToggleWebRtcVideoDto.cs b/Shared/Models/RemoteControlDtos/ToggleWebRtcVideoDto.cs deleted file mode 100644 index 8ab705cf..00000000 --- a/Shared/Models/RemoteControlDtos/ToggleWebRtcVideoDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Remotely.Shared.Enums; -using System.Runtime.Serialization; - -namespace Remotely.Shared.Models.RemoteControlDtos -{ - [DataContract] - public class ToggleWebRtcVideoDto : BaseDto - { - [DataMember(Name = "ToggleOn")] - public bool ToggleOn { get; set; } - - [DataMember(Name = "DtoType")] - public new BaseDtoType DtoType { get; } = BaseDtoType.ToggleWebRtcVideo; - } -}