Exemple #1
0
        public void AddCapturer(ICapturer capturer)
        {
            object[] attributes = capturer.GetType().GetCustomAttributes(false);
            foreach (Object attribute in attributes)
            {
                if (attribute is Captures)
                {
                    Captures     cap            = (Captures)attribute;
                    CapturerInfo capturableInfo = new CapturerInfo();
                    capturableInfo.Capturer   = capturer;
                    capturableInfo.Capturable = cap.Name;
                    capturableInfo.AddTo(_capturers);
                    break;
                }
            }


            //TODO: Throw exception: [Captures] attribute is missing
        }
        public async Task BeginScreenCasting(string viewerID,
                                             string requesterName,
                                             ICapturer capturer)
        {
            var conductor    = ServiceContainer.Instance.GetRequiredService <Conductor>();
            var viewers      = conductor.Viewers;
            var mode         = conductor.Mode;
            var casterSocket = ServiceContainer.Instance.GetRequiredService <CasterSocket>();

            Logger.Write($"Starting screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}.  App Mode: {mode}");

            byte[] encodedImageBytes;
            var    fpsQueue = new Queue <DateTime>();

            var viewer = new Viewer()
            {
                Capturer            = capturer,
                DisconnectRequested = false,
                Name = requesterName,
                ViewerConnectionID = viewerID,
                HasControl         = true
            };

            viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer);

            if (mode == Enums.AppMode.Normal)
            {
                conductor.InvokeViewerAdded(viewer);
            }

            if (OSUtils.IsWindows)
            {
                await InitializeWebRtc(viewer, casterSocket);
            }

            await casterSocket.SendMachineName(Environment.MachineName, viewerID);

            await casterSocket.SendScreenCount(
                capturer.SelectedScreen,
                capturer.GetScreenCount(),
                viewerID);

            await casterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);

            capturer.ScreenChanged += async(sender, bounds) =>
            {
                await casterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID);
            };

            while (!viewer.DisconnectRequested)
            {
                try
                {
                    if (viewer.IsStalled())
                    {
                        // Viewer isn't responding.  Abort sending.
                        break;
                    }

                    if (conductor.IsDebug)
                    {
                        while (fpsQueue.Any() && DateTime.Now - fpsQueue.Peek() > TimeSpan.FromSeconds(1))
                        {
                            fpsQueue.Dequeue();
                        }
                        fpsQueue.Enqueue(DateTime.Now);
                        Debug.WriteLine($"Capture FPS: {fpsQueue.Count}");
                    }

                    await viewer.ThrottleIfNeeded();


                    capturer.GetNextFrame();

                    var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);

                    if (diffArea.IsEmpty)
                    {
                        continue;
                    }

                    using (var newImage = capturer.CurrentFrame.Clone(diffArea, PixelFormat.Format32bppArgb))
                    {
                        if (capturer.CaptureFullscreen)
                        {
                            capturer.CaptureFullscreen = false;
                        }

                        if (viewer.ShouldAdjustQuality())
                        {
                            var quality = (int)(viewer.ImageQuality * 1000 / viewer.Latency);
                            Logger.Debug($"Auto-adjusting image quality. Latency: {viewer.Latency}. Quality: {quality}");
                            encodedImageBytes = ImageUtils.EncodeBitmap(newImage, new EncoderParameters()
                            {
                                Param = new[]
                                {
                                    new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality)
                                }
                            });
                        }
                        else
                        {
                            encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams);
                        }

                        if (encodedImageBytes?.Length > 0)
                        {
                            if (viewer.IsUsingWebRtc())
                            {
                                viewer.RtcSession.SendCaptureFrame(diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, encodedImageBytes);
                                viewer.WebSocketBuffer = 0;
                                viewer.Latency         = 0;
                            }
                            else
                            {
                                await casterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);

                                viewer.Latency += 300;
                                // Shave some off so it doesn't get deadlocked by dropped frames.
                                viewer.WebSocketBuffer += (int)(encodedImageBytes.Length * .9);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Write(ex);
                }
                finally
                {
                    GC.Collect();
                }
            }

            Logger.Write($"Ended screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}.");
            viewers.TryRemove(viewerID, out _);
            var shouldExit = viewers.Count == 0 && mode == Enums.AppMode.Unattended;

            try
            {
                viewer.Dispose();

                if (shouldExit)
                {
                    capturer.Dispose();

                    await casterSocket.Disconnect();
                }
            }
            catch (Exception ex)
            {
                Logger.Write(ex);
            }
            finally
            {
                // Close if no one is viewing.
                if (shouldExit)
                {
                    Logger.Debug($"Exiting process ID {Process.GetCurrentProcess().Id}.");
                    Environment.Exit(0);
                }
            }
        }
Exemple #3
0
        public static async void BeginScreenCasting(string viewerID,
                                                    string requesterName,
                                                    ICapturer capturer,
                                                    Conductor conductor)
        {
            Viewer viewer;

            byte[] encodedImageBytes;
            var    success = false;


            Logger.Write($"Starting screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}.  App Mode: {conductor.Mode}  Desktop: {conductor.CurrentDesktopName}");

            viewer = new Viewer()
            {
                Capturer            = capturer,
                DisconnectRequested = false,
                Name = requesterName,
                ViewerConnectionID = viewerID,
                HasControl         = true
            };

            while (!success)
            {
                success = conductor.Viewers.TryAdd(viewerID, viewer);
            }

            if (conductor.Mode == Enums.AppMode.Normal)
            {
                conductor.InvokeViewerAdded(viewer);
            }

            await conductor.OutgoingMessages.SendScreenCount(
                capturer.SelectedScreen,
                capturer.GetScreenCount(),
                viewerID);

            await conductor.OutgoingMessages.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);

            capturer.ScreenChanged += async(sender, bounds) =>
            {
                await conductor.OutgoingMessages.SendScreenSize(bounds.Width, bounds.Height, viewerID);
            };

            // TODO: SetThradDesktop causes issues with input after switching.
            //var desktopName = Win32Interop.GetCurrentDesktop();
            while (!viewer.DisconnectRequested)
            {
                try
                {
                    // TODO: SetThradDesktop causes issues with input after switching.
                    //var currentDesktopName = Win32Interop.GetCurrentDesktop();
                    //if (desktopName.ToLower() != currentDesktopName.ToLower())
                    //{
                    //    desktopName = currentDesktopName;
                    //    Logger.Write($"Switching to desktop {desktopName} in ScreenCaster.");
                    //    var inputDesktop = Win32Interop.OpenInputDesktop();
                    //    User32.SetThreadDesktop(inputDesktop);
                    //    User32.CloseDesktop(inputDesktop);
                    //    continue;
                    //}

                    while (viewer.PendingFrames > 10)
                    {
                        await Task.Delay(1);
                    }

                    capturer.Capture();

                    var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);

                    if (diffArea.IsEmpty)
                    {
                        continue;
                    }

                    using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
                    {
                        if (capturer.CaptureFullscreen)
                        {
                            capturer.CaptureFullscreen = false;
                        }

                        //long newQuality;
                        //if (viewer.PendingFrames < 8)
                        //{
                        //    newQuality = Math.Min(1, viewer.ImageQuality + 1);
                        //}
                        //else
                        //{
                        //    newQuality = Math.Max(0, viewer.ImageQuality - 1);
                        //}

                        //if (newQuality != viewer.ImageQuality)
                        //{
                        //    Logger.Write($"New quality: {newQuality}");
                        //    viewer.ImageQuality = newQuality;
                        //    viewer.FullScreenRefreshNeeded = true;
                        //}
                        //else if (viewer.FullScreenRefreshNeeded)
                        //{
                        //    Logger.Write($"Quality stabilized.");
                        //    capturer.CaptureFullscreen = true;
                        //    viewer.FullScreenRefreshNeeded = false;
                        //}

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

                        if (encodedImageBytes?.Length > 0)
                        {
                            await conductor.OutgoingMessages.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);

                            viewer.PendingFrames++;
                        }
                        // TODO: Even after disposing of the bitmap, GC doesn't collect in time.  Memory usage soars quickly.
                        // Need to revisit this later.
                        GC.Collect();
                    }
                }
                catch (Exception ex)
                {
                    Logger.Write(ex);
                }
            }
            Logger.Write($"Ended screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}.");
            success = false;
            while (!success)
            {
                success = conductor.Viewers.TryRemove(viewerID, out _);
            }

            capturer.Dispose();

            // Close if no one is viewing.
            if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended)
            {
                Environment.Exit(0);
            }
        }
Exemple #4
0
        public async Task BeginScreenCasting(string viewerID,
                                             string requesterName,
                                             ICapturer capturer)
        {
            var conductor = Conductor.Current;

            Logger.Write($"Starting screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}.  App Mode: {conductor.Mode}");

            byte[] encodedImageBytes;
            var    fpsQueue = new Queue <DateTime>();

            var viewer = new Viewer()
            {
                Capturer            = capturer,
                DisconnectRequested = false,
                Name = requesterName,
                ViewerConnectionID = viewerID,
                HasControl         = true
            };


            conductor.Viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer);

            if (conductor.Mode == Enums.AppMode.Normal)
            {
                conductor.InvokeViewerAdded(viewer);
            }

            await conductor.CasterSocket.SendMachineName(Environment.MachineName, viewerID);

            await conductor.CasterSocket.SendScreenCount(
                capturer.SelectedScreen,
                capturer.GetScreenCount(),
                viewerID);

            await conductor.CasterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);

            capturer.ScreenChanged += async(sender, bounds) =>
            {
                await conductor.CasterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID);
            };

            while (!viewer.DisconnectRequested)
            {
                try
                {
                    if (viewer.Latency > 30000)
                    {
                        // Viewer isn't responding.  Abort sending.
                        break;
                    }

                    if (Conductor.Current.IsDebug)
                    {
                        while (fpsQueue.Any() && DateTime.Now - fpsQueue.Peek() > TimeSpan.FromSeconds(1))
                        {
                            fpsQueue.Dequeue();
                        }
                        fpsQueue.Enqueue(DateTime.Now);
                        Debug.WriteLine($"Capture FPS: {fpsQueue.Count}");
                    }

                    if (viewer.OutputBuffer > 150_000)
                    {
                        Debug.WriteLine($"Waiting for buffer to clear.  Size: {viewer.OutputBuffer}");
                        await Task.Delay(50);

                        continue;
                    }

                    capturer.GetNextFrame();

                    var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);

                    if (diffArea.IsEmpty)
                    {
                        continue;
                    }

                    using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
                    {
                        if (capturer.CaptureFullscreen)
                        {
                            capturer.CaptureFullscreen = false;
                        }

                        if (viewer.AutoAdjustQuality && viewer.Latency > 1000)
                        {
                            var quality = (int)(viewer.ImageQuality * 1000 / viewer.Latency);
                            Debug.WriteLine($"Auto-adjusting image quality. Latency: {viewer.Latency}. Quality: {quality}");
                            encodedImageBytes = ImageUtils.EncodeBitmap(newImage, new EncoderParameters()
                            {
                                Param = new[]
                                {
                                    new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality)
                                }
                            });
                        }
                        else
                        {
                            encodedImageBytes = ImageUtils.EncodeBitmap(newImage, viewer.EncoderParams);
                        }

                        if (encodedImageBytes?.Length > 0)
                        {
                            await conductor.CasterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);

                            viewer.Latency      += 300;
                            viewer.OutputBuffer += encodedImageBytes.Length;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Write(ex);
                }
                finally
                {
                    GC.Collect();
                }
            }


            Logger.Write($"Ended screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}.");
            conductor.Viewers.TryRemove(viewerID, out _);

            capturer.Dispose();

            // Close if no one is viewing.
            if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended)
            {
                await conductor.CasterSocket.Disconnect();

                Environment.Exit(0);
            }
        }
        public static async void BeginScreenCasting(string viewerID,
                                                    string requesterName,
                                                    ICapturer capturer,
                                                    Conductor conductor)
        {
            Viewer viewer;

            byte[] encodedImageBytes;


            Logger.Write($"Starting screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}.  App Mode: {conductor.Mode}  Desktop: {conductor.CurrentDesktopName}");

            viewer = new Viewer()
            {
                Capturer            = capturer,
                DisconnectRequested = false,
                Name = requesterName,
                ViewerConnectionID = viewerID,
                HasControl         = true
            };

            conductor.Viewers.AddOrUpdate(viewerID, viewer, (id, v) => viewer);

            if (conductor.Mode == Enums.AppMode.Normal)
            {
                conductor.InvokeViewerAdded(viewer);
            }

            await conductor.CasterSocket.SendMachineName(Environment.MachineName, viewerID);

            await conductor.CasterSocket.SendScreenCount(
                capturer.SelectedScreen,
                capturer.GetScreenCount(),
                viewerID);

            await conductor.CasterSocket.SendScreenSize(capturer.CurrentScreenBounds.Width, capturer.CurrentScreenBounds.Height, viewerID);

            capturer.ScreenChanged += async(sender, bounds) =>
            {
                await conductor.CasterSocket.SendScreenSize(bounds.Width, bounds.Height, viewerID);
            };

            var desktopName = string.Empty;

            if (OSUtils.IsWindows)
            {
                desktopName = Win32Interop.GetCurrentDesktop();
            }

            while (!viewer.DisconnectRequested)
            {
                try
                {
                    var currentDesktopName = Win32Interop.GetCurrentDesktop();
                    if (desktopName.ToLower() != currentDesktopName.ToLower())
                    {
                        desktopName = currentDesktopName;
                        Logger.Write($"Switching to desktop {desktopName} in ScreenCaster.");
                        Win32Interop.SwitchToInputDesktop();
                        continue;
                    }

                    while (viewer.PendingFrames > 10)
                    {
                        await Task.Delay(1);
                    }

                    capturer.Capture();

                    var diffArea = ImageUtils.GetDiffArea(capturer.CurrentFrame, capturer.PreviousFrame, capturer.CaptureFullscreen);

                    if (diffArea.IsEmpty)
                    {
                        continue;
                    }

                    using (var newImage = capturer.CurrentFrame.Clone(diffArea, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
                    {
                        if (capturer.CaptureFullscreen)
                        {
                            capturer.CaptureFullscreen = false;
                        }

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

                        if (encodedImageBytes?.Length > 0)
                        {
                            await conductor.CasterSocket.SendScreenCapture(encodedImageBytes, viewerID, diffArea.Left, diffArea.Top, diffArea.Width, diffArea.Height, DateTime.UtcNow);

                            viewer.PendingFrames++;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Write(ex);
                }
                finally
                {
                    // TODO: Even after disposing of the bitmap, GC doesn't collect in time.  Memory usage soars quickly.
                    // Need to revisit this later.
                    GC.Collect();
                }
            }
            Logger.Write($"Ended screen cast.  Requester: {requesterName}. Viewer ID: {viewerID}.");
            conductor.Viewers.TryRemove(viewerID, out _);

            capturer.Dispose();

            // Close if no one is viewing.
            if (conductor.Viewers.Count == 0 && conductor.Mode == Enums.AppMode.Unattended)
            {
                Environment.Exit(0);
            }
        }