Hi, the idea seems good, but doesn't work just like that. Having given all these info, you could also explain the parameters too in the code, for eg. where you got this from : .withUrl("https://localhost:5001/ScreenCastHub") If the project was attached here it would have been better. Also, it doesn't speak of how to share the screen in a pure browser environment (Like Hangouts) rather than using electron.
Sir can you please upload a Project Solution code zip file.
Introduction
In this article, we will see how to create a simple screen-sharing app using signalR streaming. SignalR supports both server-to-client and client-to-server streaming. In my previous article, I have done server to client streaming with ChannelReader and ChannelWriter for streaming support. This may look very complex to implement asynchronous streaming just like writing the asynchronous method without async and await keyword. IAsyncEnumerable is the latest addition to .Net Core 3.0 and C# 8 feature for asynchronous streaming. It is now super easy to implement asynchronous streaming with a few lines of clean code. In this example, we will use the client to server streaming to stream the desktop content to all the connected remote client viewers using signalR stream with the support of IAsyncEnumerable API.
Disclaimer
The sample code for this article is just an experimental project for testing signalR streaming with IAsyncEnumerable. In Real-world scenarios, You may consider using peer to peer connection using WebRTC or other socket libraries for building effective screen sharing tool.
Architecture
How it works
ScreencastR Agent
Steps
ScreencastR agent is an Electron-based desktop application. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It allows you to create desktop applications with pure JavaScript by providing a runtime with rich native (operating system) APIs. In our example, I have used desktopCapturer API to capture the desktop content. If you are new to electron, you can follow this official doc to create your first electron application.
A simple electron application will have the following files which are similar to the node.js application.
your-app/
├── package.json
├── main.js
└── index.html
The starting point is the package.json which will have entry point javascript (main.js) and main.js will create a basic electron shell with default menu option and load the main HTML page. (index.html). In this package.json, I have added the dependency of latest SignalR client.
When we run the npm build, it will bring all the dependencies under node_modules folder including signalR client. Copy the signalr.js file from node_modules\@microsoft\signalr\dist\browserfolder into the root folder.
In the renderer.js javascript, initializeSignalR method would initialize the signalR connection when the application gets loaded and listens to NewViewer and NoViewer hub methods. The NewViewer method gets called whenever the new remote viewer joining to view the stream. The agent will not stream the content until atleast one viewer exists. When NoViewer method is called, it will stop the stream.
CaptureScreen method will use the desktopCapturer API to get the list of available screen and window sources and filter to get the “Entire screen“ source only. After the source is identified, screen thumbnail data can be generated from the source based on the thumbnail size that is defined. CaptureScreen method is based on the promised API and will return the image data in a string as part of the resolve method. We will call the CaptureScreen method in the timer (setInterval method) based on the frame per second defined and the output will be streamed via signalR subject class.
ScreenCastR Remote Viewer
ScreenCastR Remote Viewer is a server-side blazor app with signalR hub hosted in it. This app also has the interface for signalR client to receive the streaming data from the hub. Whenever the New Agent joined, it will show the details of the agent in the dashboard page with the name of agent and View and Stop Cast button. When the user clicks on the View Cast button, it will start receiving the streaming from the hub and render the output on the screen. In the above video, the left side is the agent streaming data to the signalR hub and the right side is the viewer rendering the streaming data from the signalR hub.
ScreenCastHub class is the streaming hub with all methods to communicate between agent and remote viewer.
StreamCastData is the main streaming method which will take IAsyncEnumerable Items and stream the chunk of data that it receives to all the connected remote viewers.
AddScreenCastAgent method will send the notification to all the connected remote viewers whenever the new agent joins the hub.
RemoveScreenCastAgent method will send the notification to all the connected remote viewer whenever the agent disconnects from the hub.
AddScreenCastViewer method will send the notification to the agent if the new viewer joined to view the screencast.
RemoveScreenCastViewer method will send the notification to the agent if all the viewers are disconnected from viewing the screencast.
ScreenCastManager
publicclass ScreenCastManager
{
private List<Viewer> viewers = new List<Viewer>();
public Viewer(string connectionId, string agentName)
{
ConnectionId = connectionId;
AgentName = agentName;
}
}
This class will hold the number of viewers connected per agent. This class is injected to hub via dependency injection in singleton scope.
services.AddSingleton<ScreenCastManager>();
Startup.cs
In startup.cs, increase the default message size from 32KB to a bigger range based on the quality of stream output. Otherwise, the hub will fail to transmit the data.
In this component, as part of OnInitializedAsync method, initialize the signalR client connection with the hub and subscribe to the streaming method. When the stream data arrives from the hub, it updates the image source DOM element and renders the screen with the changes.
Demo (Youtube)
Summary
IAsyncEnumerable is a very nice feature added to .Net Core 3.0 and C# 8 for asynchronous streaming with cleaner and more readable code. With this new feature and SignalR streaming, we can do many cool projects like a Real Time App health monitor dashboard, Real Time multiplayer games, etc… I have uploaded the entire source code for this article in the GitHub repository.
Daniel PilaPosted Mar 13, 2023, 7:59 AM
Great article!. Would it be possible to stream one part of the screen instead of the entire screen?
faker usPosted Sep 6, 2022, 11:51 AM
Some errors? This code cannot work. PLease correct your code or delete this post.
Raviraj PatelPosted Nov 5, 2020, 1:46 AM
The code has some errors and not able to communicate between the electron and .net app
Madhu VenugopalPosted Sep 23, 2020, 4:13 AM
Hi, the idea seems good, but doesn't work just like that. Having given all these info, you could also explain the parameters too in the code, for eg. where you got this from : .withUrl("https://localhost:5001/ScreenCastHub") If the project was attached here it would have been better. Also, it doesn't speak of how to share the screen in a pure browser environment (Like Hangouts) rather than using electron.
Nitesh soniPosted Feb 21, 2020, 12:03 PM
Sir can you please upload a Project Solution code zip file.