Replace MR WebRTC with SIPSorcery.

This commit is contained in:
Jared 2021-03-06 13:09:42 -08:00 committed by Jared Goodwin
parent a1943365c6
commit 3a5471b553
25 changed files with 145 additions and 315 deletions

View File

@ -46,8 +46,10 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="5.0.0" />
<PackageReference Include="Microsoft.MixedReality.WebRTC" Version="2.0.2" />
<PackageReference Include="SkiaSharp" Version="2.80.2" />
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.80.2" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
<PackageReference Include="SIPSorcery" Version="5.1.1" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
</ItemGroup>

View File

@ -28,7 +28,7 @@ namespace Remotely.Desktop.Core.Services
Task SendCtrlAltDelToAgent();
Task SendDeviceInfo(string serviceID, string machineName, string deviceID);
Task SendDtoToViewer<T>(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)

View File

@ -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<ToggleBlockInputDto>(message);
KeyboardMouseInput.ToggleBlockInput(dto.ToggleOn);
}
private void ToggleWebRtcVideo(byte[] message, Viewer viewer)
{
var dto = MessagePackSerializer.Deserialize<ToggleWebRtcVideoDto>(message);
viewer.ToggleWebRtcVideo(dto.ToggleOn);
}
}
}

View File

@ -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.

View File

@ -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);

View File

@ -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<IceCandidate> IceCandidateReady;
public event EventHandler<SdpMessage> LocalSdpReady;
public event EventHandler<RTCIceCandidate> IceCandidateReady;
public event EventHandler<RTCSessionDescriptionInit> 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<RTCIceCandidateInit>(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>(T dto) where T : BaseDto
public async Task SendDto<T>(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<SdpMessageType>(type, true, out var sdpMessageType))
if (!Enum.TryParse<RTCSdpType>(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;
}
}
}
}

View File

@ -34,7 +34,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.MixedReality.WebRTC" Version="2.0.2" />
<PackageReference Include="NAudio" Version="2.0.0" />
<PackageReference Include="SharpDX" Version="4.2.0" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />

View File

@ -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;

View File

@ -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)

View File

@ -134,10 +134,6 @@
</div>
<div>
<button id="streamVideoButton" class="option-button" hidden title="Reduce bandwidth and increase FPS, but increase input delay.">
Stream Mode <i class="fas fa-video"></i>
</button>
<button id="changeScreenButton" class="option-button" title="Switch monitors on remote multi-monitor setups.">
Monitors <i class="fas fa-desktop"></i>
</button>

View File

@ -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)

View File

@ -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": [],

View File

@ -23,6 +23,5 @@
WindowsSessions = 23,
SetKeyStatesUp = 24,
FrameReceived = 25,
ToggleWebRtcVideo = 26,
OpenFileTransferWindow = 27
}

View File

@ -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) {

View File

@ -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<WindowsSession>;

View File

@ -1,4 +1,3 @@
export interface Settings {
streamModeEnabled: boolean;
displayName: string;
}

View File

@ -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),

View File

@ -1,5 +1,5 @@
export class IceServerModel {
Url: string;
TurnPassword: string;
TurnUsername: string;
Urls: string;
Credential: string;
Username: string;
}

View File

@ -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) {

View File

@ -1,8 +1,7 @@
import { Settings } from "./Interfaces/Settings.js";
const defaultSettings = {
streamModeEnabled: false,
displayName: ""
};

View File

@ -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<WindowsSession>) {
while (WindowsSessionSelect.options.length > 0) {
WindowsSessionSelect.options.remove(0);

View File

@ -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);

View File

@ -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
}

View File

@ -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; }
}
}

View File

@ -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;
}
}