Skip to content

Commit

Permalink
Add "stream mode" as an option for WebRTC video.
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbound committed Aug 7, 2020
1 parent 86305c3 commit 1e1dd57
Show file tree
Hide file tree
Showing 29 changed files with 772 additions and 592 deletions.
58 changes: 30 additions & 28 deletions Desktop.Core/Models/Viewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ namespace Remotely.Desktop.Core.Models
{
public class Viewer : IDisposable
{
private readonly int defaultImageQuality = 60;
private int imageQuality;
private DateTimeOffset lastQualityAdjustment;
private readonly int defaultImageQuality = 60;

public Viewer(CasterSocket casterSocket,
IScreenCapturer screenCapturer,
IClipboardService clipboardService,
Expand Down Expand Up @@ -68,6 +67,30 @@ public int ImageQuality
}

public bool IsConnected => CasterSocket.IsConnected;
public bool IsStalled
{
get
{
return PendingSentFrames.TryPeek(out var result) && DateTimeOffset.Now - result > TimeSpan.FromSeconds(15);
}
}

public bool IsUsingWebRtc
{
get
{
return RtcSession?.IsPeerConnected == true && RtcSession?.IsDataChannelOpen == true;
}
}

public bool IsUsingWebRtcVideo
{
get
{
return RtcSession?.IsPeerConnected == true && RtcSession?.IsVideoTrackConnected == true;
}
}

public string Name { get; set; }
public ConcurrentQueue<DateTimeOffset> PendingSentFrames { get; } = new ConcurrentQueue<DateTimeOffset>();
public WebRtcSession RtcSession { get; set; }
Expand Down Expand Up @@ -106,31 +129,6 @@ public async Task InitializeWebRtc()
Logger.Write(ex);
}
}

public bool IsUsingWebRtcVideo
{
get
{
return RtcSession?.IsPeerConnected == true && RtcSession?.IsVideoTrackConnected == true;
}
}

public bool IsStalled
{
get
{
return PendingSentFrames.TryPeek(out var result) && DateTimeOffset.Now - result > TimeSpan.FromSeconds(15);
}
}

public bool IsUsingWebRtc
{
get
{
return RtcSession?.IsPeerConnected == true && RtcSession?.IsDataChannelOpen == true;
}
}

public async Task SendAudioSample(byte[] audioSample)
{
await SendToViewer(() => RtcSession.SendAudioSample(audioSample),
Expand Down Expand Up @@ -203,14 +201,18 @@ public void ThrottleIfNeeded()
ImageQuality = defaultImageQuality;
}
}

TaskHelper.DelayUntil(() => PendingSentFrames.Count < 5 &&
(
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result < TimeSpan.FromSeconds(1)
),
TimeSpan.MaxValue);
}

public void ToggleWebRtcVideo(bool toggleOn)
{
RtcSession.ToggleWebRtcVideo(toggleOn);
}
private async void AudioCapturer_AudioSampleReady(object sender, byte[] sample)
{
await SendAudioSample(sample);
Expand Down
8 changes: 8 additions & 0 deletions Desktop.Core/Services/CasterSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,14 @@ private void ApplyConnectionHandlers()
}
});

Connection.On("ToggleWebRtcVideo", (bool toggleOn, string viewerID) =>
{
if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
{
viewer.ToggleWebRtcVideo(toggleOn);
}
});

Connection.On("TouchDown", (string viewerID) =>
{
if (conductor.Viewers.TryGetValue(viewerID, out var viewer) && viewer.HasControl)
Expand Down
11 changes: 11 additions & 0 deletions Desktop.Core/Services/RtcMessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ public async Task ParseMessage(byte[] message)
case BinaryDtoType.ToggleBlockInput:
ToggleBlockInput(message);
break;
case BinaryDtoType.ToggleWebRtcVideo:
ToggleWebRtcVideo(message);
break;
case BinaryDtoType.ClipboardTransfer:
ClipboardTransfer(message);
break;
Expand Down Expand Up @@ -180,6 +183,7 @@ private void HandleFrameReceived()
}
}
}

private void KeyDown(byte[] message)
{
var dto = MessagePackSerializer.Deserialize<KeyDownDto>(message);
Expand Down Expand Up @@ -260,6 +264,7 @@ private void SetKeyStatesUp()
{
KeyboardMouseInput.SetKeyStatesUp();
}

private void Tap(byte[] message)
{
var dto = MessagePackSerializer.Deserialize<TapDto>(message);
Expand All @@ -278,5 +283,11 @@ private void ToggleBlockInput(byte[] message)
var dto = MessagePackSerializer.Deserialize<ToggleBlockInputDto>(message);
KeyboardMouseInput.ToggleBlockInput(dto.ToggleOn);
}

private void ToggleWebRtcVideo(byte[] message)
{
var dto = MessagePackSerializer.Deserialize<ToggleWebRtcVideoDto>(message);
Viewer.ToggleWebRtcVideo(dto.ToggleOn);
}
}
}
37 changes: 24 additions & 13 deletions Desktop.Core/Services/WebRtcSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ public WebRtcSession(Viewer viewer, IRtcMessageHandler rtcMessageHandler)
public ulong CurrentBuffer { get; private set; }
public bool IsDataChannelOpen => CaptureChannel?.State == DataChannel.ChannelState.Open;
public bool IsPeerConnected => PeerSession?.IsConnected == true;
private DataChannel CaptureChannel { get; set; }
private IceServerModel[] IceServers { get; set; }
private PeerConnection PeerSession { get; set; }
private IRtcMessageHandler RtcMessageHandler { get; }
private Transceiver Transceiver { get; set; }
private ExternalVideoTrackSource VideoSource { get; set; }
private Viewer Viewer { get; }

public bool IsVideoTrackConnected
{
get
Expand All @@ -44,6 +36,13 @@ public bool IsVideoTrackConnected
}
}

private DataChannel CaptureChannel { get; set; }
private IceServerModel[] IceServers { get; set; }
private PeerConnection PeerSession { get; set; }
private IRtcMessageHandler RtcMessageHandler { get; }
private Transceiver Transceiver { get; set; }
private ExternalVideoTrackSource VideoSource { get; set; }
private Viewer Viewer { get; }
public void AddIceCandidate(string sdpMid, int sdpMlineIndex, string candidate)
{
PeerSession.AddIceCandidate(new IceCandidate()
Expand Down Expand Up @@ -106,10 +105,6 @@ public async Task Init(IceServerModel[] iceServers)

VideoSource = ExternalVideoTrackSource.CreateFromArgb32Callback(GetCaptureFrame);
Transceiver = PeerSession.AddTransceiver(MediaKind.Video);
Transceiver.LocalVideoTrack = LocalVideoTrack.CreateFromSource(VideoSource, new LocalVideoTrackInitConfig()
{
trackName = "ScreenCapture"
});

PeerSession.CreateOffer();
}
Expand Down Expand Up @@ -195,12 +190,28 @@ await PeerSession.SetRemoteDescriptionAsync(new SdpMessage()
}
}

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)
{
Logger.Debug($"DataChannel message received. Size: {obj.Length}");
await RtcMessageHandler.ParseMessage(obj);
}

private async void CaptureChannel_StateChanged()
{
Logger.Debug($"DataChannel state changed. New State: {CaptureChannel.State}");
Expand Down
5 changes: 5 additions & 0 deletions Server/Hubs/RCBrowserHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ public Task SendToggleBlockInput(bool toggleOn)
{
return CasterHubContext.Clients.Client(ScreenCasterID).SendAsync("ToggleBlockInput", toggleOn, Context.ConnectionId);
}
public Task SendToggleWebRtcVideo(bool toggleOn)
{
return CasterHubContext.Clients.Client(ScreenCasterID).SendAsync("ToggleWebRtcVideo", toggleOn, Context.ConnectionId);
}

public Task Tap(double percentX, double percentY)
{
return CasterHubContext.Clients.Client(ScreenCasterID).SendAsync("Tap", percentX, percentY, Context.ConnectionId);
Expand Down
63 changes: 51 additions & 12 deletions Server/Pages/RemoteControl.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,35 @@
</div>

<div>
<button id="clipboardTransferButton" class="option-button">Clipboard <i class="fas fa-clipboard"></i></button>
<button id="blockInputButton" class="option-button">Block Remote Input <i class="fas fa-mouse"></i></button>
<button id="clipboardTransferButton" class="option-button" title="Type the current clipboard text on the remote computer.">
Clipboard <i class="fas fa-clipboard"></i>
</button>

<button id="blockInputButton" class="option-button" title="Prevent remote user from using keyboard and mouse.">
Block Remote Input <i class="fas fa-mouse"></i>
</button>

<button id="inviteButton" class="option-button">Invite Others <i class="fas fa-user-plus"></i></button>
<button id="audioButton" class="option-button">Audio <i class="fas fa-volume-up"></i></button>
<button id="fileTransferButton" class="option-button">File Transfer <i class="fas fa-file-upload"></i></button>
<button id="ctrlAltDelButton" class="option-button">Ctrl+Alt+Del <i class="fas fa-sign-in-alt"></i></button>
<button id="keyboardButton" hidden="hidden" class="option-button">Keyboard <i class="fas fa-keyboard"></i></button>
<button id="disconnectButton" class="option-button">Disconnect <i class="fas fa-window-close"></i></button>

<button id="audioButton" class="option-button" title="Windows only. Stream the remote audio to the browser.">
Audio <i class="fas fa-volume-up"></i>
</button>

<button id="fileTransferButton" class="option-button" title="Transfer files to the remote computer.">
File Transfer <i class="fas fa-file-upload"></i>
</button>

<button id="ctrlAltDelButton" class="option-button" title="Simulate the Ctrl+Alt+Del command on the remote computer.">
Ctrl+Alt+Del <i class="fas fa-sign-in-alt"></i>
</button>

<button id="keyboardButton" hidden="hidden" class="option-button" title="Invoke the mobile touch keyboard.">
Keyboard <i class="fas fa-keyboard"></i>
</button>

<button id="disconnectButton" class="option-button" title="Disconnect from the current session.">
Disconnect <i class="fas fa-window-close"></i>
</button>
</div>


Expand All @@ -110,9 +131,21 @@
</div>

<div>
<button id="changeScreenButton" class="option-button">Monitors <i class="fas fa-desktop"></i></button>
<button id="fitToScreenButton" class="toggled option-button">Fit <i class="fas fa-expand"></i></button>
<button id="qualityButton" class="option-button">Quality <i class="far fa-image"></i></button>
<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>

<button id="fitToScreenButton" class="toggled option-button" title="If toggled, will resize image to fit in the window.">
Fit <i class="fas fa-expand"></i>
</button>

<button id="qualityButton" class="option-button" title="Adjust the image quality when not in Stream Mode.">
Quality <i class="far fa-image"></i>
</button>
</div>


Expand All @@ -121,15 +154,21 @@
</div>

<div>
<button id="recordSessionButton" class="option-button">Start <i class="fas fa-record-vinyl"></i></button>
<button id="downloadRecordingButton" class="option-button">Download <i class="fas fa-download"></i></button>
<button id="recordSessionButton" class="option-button" title="Record session as a WEBM video in the browser.">
Start <i class="fas fa-record-vinyl"></i>
</button>

<button id="downloadRecordingButton" class="option-button" title="Download the recorded session as a WEBM file.">
Download <i class="fas fa-download"></i>
</button>
</div>

<div class="menu-options-header">
Windows Session
</div>
<div>
<select id="windowsSessionSelect"
title="Switch to a different Windows session."
class="option-button"
style="height: 30px; width: 90%; margin: 5px 0;"></select>
</div>
Expand Down
1 change: 1 addition & 0 deletions Server/wwwroot/scripts/Enums/BinaryDtoType.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Server/wwwroot/scripts/Enums/BinaryDtoType.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Server/wwwroot/scripts/Enums/BinaryDtoType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
File = 22,
WindowsSessions = 23,
SetKeyStatesUp = 24,
FrameReceived = 25
FrameReceived = 25,
ToggleWebRtcVideo = 26
}
22 changes: 18 additions & 4 deletions Server/wwwroot/scripts/RemoteControl/InputEventHandlers.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

0 comments on commit 1e1dd57

Please sign in to comment.