Skip to content

Commit

Permalink
Use semaphore to send frames while preparing the next capture.
Browse files Browse the repository at this point in the history
  • Loading branch information
bitbound committed Dec 20, 2020
1 parent 36ead2e commit f87a301
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 38 deletions.
90 changes: 54 additions & 36 deletions Desktop.Core/Services/ScreenCaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,50 @@ namespace Remotely.Desktop.Core.Services
{
public class ScreenCaster : IScreenCaster
{
private readonly Conductor _conductor;
private readonly ICursorIconWatcher _cursorIconWatcher;
private readonly ISessionIndicator _sessionIndicator;
private readonly IShutdownService _shutdownService;

public ScreenCaster(Conductor conductor,
ICursorIconWatcher cursorIconWatcher,
ISessionIndicator sessionIndicator,
IShutdownService shutdownService)
{
Conductor = conductor;
CursorIconWatcher = cursorIconWatcher;
SessionIndicator = sessionIndicator;
ShutdownService = shutdownService;
_conductor = conductor;
_cursorIconWatcher = cursorIconWatcher;
_sessionIndicator = sessionIndicator;
_shutdownService = shutdownService;
}

private Conductor Conductor { get; }
private ICursorIconWatcher CursorIconWatcher { get; }
private ISessionIndicator SessionIndicator { get; }
private IShutdownService ShutdownService { get; }

public async Task BeginScreenCasting(ScreenCastRequest screenCastRequest)
{

try
{
var sendFramesLock = new SemaphoreSlim(1, 1);
Bitmap currentFrame = null;
Bitmap previousFrame = null;
byte[] encodedImageBytes;
var fpsQueue = new Queue<DateTimeOffset>();

var viewer = ServiceContainer.Instance.GetRequiredService<Viewer>();
viewer.Name = screenCastRequest.RequesterName;
viewer.ViewerConnectionID = screenCastRequest.ViewerID;

Logger.Write($"Starting screen cast. Requester: {viewer.Name}. " +
$"Viewer ID: {viewer.ViewerConnectionID}. App Mode: {Conductor.Mode}");
$"Viewer ID: {viewer.ViewerConnectionID}. App Mode: {_conductor.Mode}");

Conductor.Viewers.AddOrUpdate(viewer.ViewerConnectionID, viewer, (id, v) => viewer);
_conductor.Viewers.AddOrUpdate(viewer.ViewerConnectionID, viewer, (id, v) => viewer);

if (Conductor.Mode == AppMode.Normal)
if (_conductor.Mode == AppMode.Normal)
{
Conductor.InvokeViewerAdded(viewer);
_conductor.InvokeViewerAdded(viewer);
}

if (Conductor.Mode == AppMode.Unattended && screenCastRequest.NotifyUser)
if (_conductor.Mode == AppMode.Unattended && screenCastRequest.NotifyUser)
{
SessionIndicator.Show();
_sessionIndicator.Show();
}

await viewer.SendViewerConnected();
Expand All @@ -73,7 +74,7 @@ await viewer.SendScreenData(
await viewer.SendScreenSize(viewer.Capturer.CurrentScreenBounds.Width,
viewer.Capturer.CurrentScreenBounds.Height);

await viewer.SendCursorChange(CursorIconWatcher.GetCurrentCursor());
await viewer.SendCursorChange(_cursorIconWatcher.GetCurrentCursor());

await viewer.SendWindowsSessions();

Expand Down Expand Up @@ -114,7 +115,7 @@ await viewer.SendScreenCapture(
// Viewer isn't responding. Abort sending.
break;
}

if (EnvironmentHelper.IsDebug)
{
while (fpsQueue.Any() && DateTimeOffset.Now - fpsQueue.Peek() > TimeSpan.FromSeconds(1))
Expand Down Expand Up @@ -143,22 +144,8 @@ await viewer.SendScreenCapture(
continue;
}

foreach (var diffArea in diffAreas)
{
using var newImage = currentFrame.Clone(diffArea, PixelFormat.Format32bppArgb);
if (viewer.Capturer.CaptureFullscreen)
{
viewer.Capturer.CaptureFullscreen = false;
}

encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams);

if (encodedImageBytes?.Length > 0)
{
await viewer.SendScreenCapture(encodedImageBytes, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height);
}
}

await sendFramesLock.WaitAsync();
SendFrames((Bitmap)currentFrame.Clone(), diffAreas, viewer, sendFramesLock);
}
catch (Exception ex)
{
Expand All @@ -167,7 +154,7 @@ await viewer.SendScreenCapture(
}

Logger.Write($"Ended screen cast. Requester: {viewer.Name}. Viewer ID: {viewer.ViewerConnectionID}.");
Conductor.Viewers.TryRemove(viewer.ViewerConnectionID, out _);
_conductor.Viewers.TryRemove(viewer.ViewerConnectionID, out _);
viewer.Dispose();
}
catch (Exception ex)
Expand All @@ -177,12 +164,43 @@ await viewer.SendScreenCapture(
finally
{
// Close if no one is viewing.
if (Conductor.Viewers.IsEmpty && Conductor.Mode == AppMode.Unattended)
if (_conductor.Viewers.IsEmpty && _conductor.Mode == AppMode.Unattended)
{
Logger.Write("No more viewers. Calling shutdown service.");
await ShutdownService.Shutdown();
await _shutdownService.Shutdown();
}
}
}

private void SendFrames(Bitmap currentFrame, List<Rectangle> diffAreas, Viewer viewer, SemaphoreSlim sendFramesLock)
{
_ = Task.Run(async () =>
{
try
{
foreach (var diffArea in diffAreas)
{
using var newImage = currentFrame.Clone(diffArea, PixelFormat.Format32bppArgb);

if (viewer.Capturer.CaptureFullscreen)
{
viewer.Capturer.CaptureFullscreen = false;
}

var encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams);

if (encodedImageBytes?.Length > 0)
{
await viewer.SendScreenCapture(encodedImageBytes, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height);
}
}
}
finally
{
sendFramesLock.Release();
currentFrame.Dispose();
}
});
}
}
}
2 changes: 1 addition & 1 deletion Desktop.Core/Services/Viewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ public void ThrottleIfNeeded()
{
UpdateImageQuality();

return PendingSentFrames.Count < 10 &&
return PendingSentFrames.Count < 7 &&
(
!PendingSentFrames.TryPeek(out var result) || DateTimeOffset.Now - result < TimeSpan.FromSeconds(1)
);
Expand Down
2 changes: 1 addition & 1 deletion Desktop.Win/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static async void CursorIconWatcher_OnChange(object sender, CursorInfo cu
}
}
[STAThread]
public static async Task Main(string[] args)
public static void Main(string[] args)
{
try
{
Expand Down

0 comments on commit f87a301

Please sign in to comment.