diff --git a/Desktop.Core/Services/ScreenCaster.cs b/Desktop.Core/Services/ScreenCaster.cs index f53b7338..babf5d6b 100644 --- a/Desktop.Core/Services/ScreenCaster.cs +++ b/Desktop.Core/Services/ScreenCaster.cs @@ -40,7 +40,6 @@ namespace Remotely.Desktop.Core.Services public async Task BeginScreenCasting(ScreenCastRequest screenCastRequest) { - try { var sendFramesLock = new SemaphoreSlim(1, 1); @@ -49,6 +48,7 @@ namespace Remotely.Desktop.Core.Services var currentQuality = _maxQuality; Bitmap currentFrame = null; Bitmap previousFrame = null; + var sw = Stopwatch.StartNew(); var viewer = ServiceContainer.Instance.GetRequiredService(); viewer.Name = screenCastRequest.RequesterName; @@ -118,6 +118,9 @@ namespace Remotely.Desktop.Core.Services { try { + TaskHelper.DelayUntil(() => sw.Elapsed.TotalMilliseconds > 40, TimeSpan.FromSeconds(5)); + sw.Restart(); + if (viewer.IsUsingWebRtcVideo) { Thread.Sleep(100); diff --git a/Desktop.Win/Models/DirectXOutput.cs b/Desktop.Win/Models/DirectXOutput.cs index 3be8ccc5..4896a25c 100644 --- a/Desktop.Win/Models/DirectXOutput.cs +++ b/Desktop.Win/Models/DirectXOutput.cs @@ -10,17 +10,20 @@ namespace Remotely.Desktop.Win.Models public DirectXOutput(Adapter1 adapter, SharpDX.Direct3D11.Device device, OutputDuplication outputDuplication, - Texture2D texture2D) + Texture2D texture2D, + DisplayModeRotation rotation) { Adapter = adapter; Device = device; OutputDuplication = outputDuplication; Texture2D = texture2D; + Rotation = rotation; } public Adapter1 Adapter { get; } public SharpDX.Direct3D11.Device Device { get; } public OutputDuplication OutputDuplication { get; } + public DisplayModeRotation Rotation { get; } public Texture2D Texture2D { get; } public void Dispose() diff --git a/Desktop.Win/Services/ScreenCapturerWin.cs b/Desktop.Win/Services/ScreenCapturerWin.cs index fd3fb210..bd301bec 100644 --- a/Desktop.Win/Services/ScreenCapturerWin.cs +++ b/Desktop.Win/Services/ScreenCapturerWin.cs @@ -34,6 +34,7 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; @@ -91,15 +92,14 @@ namespace Remotely.Desktop.Win.Services Logger.Write("Init needed in GetNextFrame."); Init(); } - + // Sometimes DX will result in a timeout, even when there are changes // on the screen. I've observed this when a laptop lid is closed, or // on some machines that aren't connected to a monitor. This will // have it fall back to BitBlt in those cases. // TODO: Make DX capture work with changed screen orientation. - if (_directxScreens.ContainsKey(SelectedScreen) && - SystemInformation.ScreenOrientation != ScreenOrientation.Angle270 && - SystemInformation.ScreenOrientation != ScreenOrientation.Angle90) + if (_directxScreens.TryGetValue(SelectedScreen, out var dxDisplay) && + dxDisplay.Rotation == DisplayModeRotation.Identity) { var (result, frame) = GetDirectXFrame(); @@ -337,7 +337,8 @@ namespace Remotely.Desktop.Win.Services new DirectXOutput(adapter, device, output1.DuplicateOutput(device), - texture2D)); + texture2D, + output1.Description.Rotation)); } catch (Exception ex) { diff --git a/Shared/Win32/User32.cs b/Shared/Win32/User32.cs index 4ce0befb..04daa734 100644 --- a/Shared/Win32/User32.cs +++ b/Shared/Win32/User32.cs @@ -1054,6 +1054,79 @@ namespace Remotely.Shared.Win32 MAPVK_VK_TO_VSC_EX = 4 } + [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] + public struct DEVMODE + { + public const int CCHDEVICENAME = 32; + public const int CCHFORMNAME = 32; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)] + [FieldOffset(0)] + public string dmDeviceName; + [FieldOffset(32)] + public Int16 dmSpecVersion; + [FieldOffset(34)] + public Int16 dmDriverVersion; + [FieldOffset(36)] + public Int16 dmSize; + [FieldOffset(38)] + public Int16 dmDriverExtra; + [FieldOffset(40)] + public short dmFields; + + [FieldOffset(44)] + Int16 dmOrientation; + [FieldOffset(46)] + Int16 dmPaperSize; + [FieldOffset(48)] + Int16 dmPaperLength; + [FieldOffset(50)] + Int16 dmPaperWidth; + [FieldOffset(52)] + Int16 dmScale; + [FieldOffset(54)] + Int16 dmCopies; + [FieldOffset(56)] + Int16 dmDefaultSource; + [FieldOffset(58)] + Int16 dmPrintQuality; + + [FieldOffset(44)] + public POINT dmPosition; + [FieldOffset(52)] + public Int32 dmDisplayOrientation; + [FieldOffset(56)] + public Int32 dmDisplayFixedOutput; + + [FieldOffset(60)] + public short dmColor; // See note below! + [FieldOffset(62)] + public short dmDuplex; // See note below! + [FieldOffset(64)] + public short dmYResolution; + [FieldOffset(66)] + public short dmTTOption; + [FieldOffset(68)] + public short dmCollate; // See note below! + [FieldOffset(70)] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)] + public string dmFormName; + [FieldOffset(102)] + public Int16 dmLogPixels; + [FieldOffset(104)] + public Int32 dmBitsPerPel; + [FieldOffset(108)] + public Int32 dmPelsWidth; + [FieldOffset(112)] + public Int32 dmPelsHeight; + [FieldOffset(116)] + public Int32 dmDisplayFlags; + [FieldOffset(116)] + public Int32 dmNup; + [FieldOffset(120)] + public Int32 dmDisplayFrequency; + } + #endregion #region Structs @@ -1070,10 +1143,11 @@ namespace Remotely.Shared.Win32 [StructLayout(LayoutKind.Sequential)] public struct POINT { - public Int32 x; - public Int32 y; + public int x; + public int y; } + [StructLayout(LayoutKind.Sequential)] public struct CursorInfo { @@ -1185,6 +1259,9 @@ namespace Remotely.Shared.Win32 [DllImport("user32.dll")] public static extern bool EnumDesktopsA(IntPtr hwinsta, EnumDesktopsDelegate lpEnumFunc, IntPtr lParam); + [DllImport("user32.dll")] + public static extern bool EnumDisplaySettingsEx(string lpszDeviceName, uint iModeNum, out DEVMODE lpDevMode, uint dwFlags); + [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, ACCESS_MASK dwDesiredAccess);