RemoteViewer.SessionKit
0.9.0
dotnet add package RemoteViewer.SessionKit --version 0.9.0
NuGet\Install-Package RemoteViewer.SessionKit -Version 0.9.0
<PackageReference Include="RemoteViewer.SessionKit" Version="0.9.0" />
<PackageVersion Include="RemoteViewer.SessionKit" Version="0.9.0" />
<PackageReference Include="RemoteViewer.SessionKit" />
paket add RemoteViewer.SessionKit --version 0.9.0
#r "nuget: RemoteViewer.SessionKit, 0.9.0"
#:package RemoteViewer.SessionKit@0.9.0
#addin nuget:?package=RemoteViewer.SessionKit&version=0.9.0
#tool nuget:?package=RemoteViewer.SessionKit&version=0.9.0
SessionKit
Remote desktop as a library — for .NET. Drop cross-platform screen sharing and remote control into your own application, riding whatever secure channel you already have.
RemoteViewer.SessionKit is the session layer of a remote-desktop stack: it captures a screen, encodes it,
streams it, and injects the operator's mouse/keyboard back — plus clipboard, file transfer, and audio — all
multiplexed over a single transport-agnostic byte channel (ISessionChannel) that you provide. It does not
open sockets, traverse NATs, or run a relay: you bring the pipe (a WebSocket, a raw socket with framing, an SSH
tunnel, or ConnectKit for an encrypted NAT-traversing one), and SessionKit
is what flows over it.
your app ──▶ SessionHost(channel, screenSource, inputSink) // device: capture → encode → send, apply input
your app ──▶ ViewerSession(channel) // operator: OnFrame(bgra) + SendMouse/SendKey/…
If you're building remote support, an RMM/kiosk/POS tool, an industrial-HMI console, or any .NET app that needs "see and control that machine" — SessionKit is the embeddable core, without bundling a third-party product.
Why SessionKit
- .NET-native. A single NuGet package (net8.0 / net9.0), one dependency (SkiaSharp). No native SDK to vendor,
no C++ interop for you to maintain — it's
using RemoteViewer.SessionKit;and go. - Transport-agnostic. SessionKit never assumes a network. Anything that can carry a byte message — preserving message boundaries — is a valid channel, so it slots into apps that already have a connection.
- Cross-platform, both ends. Windows, Linux, and macOS can each be the host (the controlled device) and the viewer (the operator). Capture, input, and codecs are chosen per OS behind stable seams.
- Hardware H.264, license-clean. Video is JPEG-tile deltas by default, or hardware H.264 via each OS's native codec — Media Foundation (Windows), VideoToolbox (macOS), VA-API (Linux). Using the OS codec means the OS covers the H.264 patent licensing. The codec is negotiated automatically.
- Composable. Screen source, input sink, clipboard, and channel are all interfaces — swap in your own, or use the built-ins. Pairs with ConnectKit for a batteries-included-but-not-monolithic stack.
Install
dotnet add package RemoteViewer.SessionKit
Requires the .NET 8 or .NET 9 SDK. Sole dependency: SkiaSharp.
30-second example
Host — capture this machine and apply the operator's input:
using RemoteViewer.SessionKit;
using RemoteViewer.SessionKit.Capture;
using RemoteViewer.SessionKit.Input;
var host = new SessionHost(
channel, // your ISessionChannel
WindowsScreenCapture.CreateBest(out _), // DXGI→GDI on Windows; see below for Linux/macOS
new WindowsInputSink(), // applies the viewer's mouse/keyboard
new HostOptions { MaxWidth = 1920, MaxFps = 15, Quality = 70 });
host.Start(); // capture/send loop runs until Dispose()
Viewer — show frames and drive the host:
using RemoteViewer.SessionKit;
using RemoteViewer.SessionKit.Input;
var viewer = new ViewerSession(channel);
viewer.OnFrame += frame =>
{
// frame.Bgra is tight BGRA8888 (Width*Height*4). Wrap it in your UI's bitmap and blit.
};
viewer.Start();
viewer.SendMouseMove(0.5f, 0.5f); // coordinates are normalized 0..1 across the frame
viewer.SendMouseButton(MouseButton.Left, down: true);
viewer.SendMouseButton(MouseButton.Left, down: false);
viewer.SendText("hello");
Full walkthrough (including a runnable offline selftest): GETTING-STARTED.md.
What's in the box
| Capability | Windows | Linux | macOS |
|---|---|---|---|
| Screen capture | DXGI (→ GDI fallback) | X11 (XGetImage) |
CoreGraphics¹ |
| Input inject | SendInput | XTest (mouse + Unicode text) | CGEvent (mouse + Unicode text) |
| H.264 encode | Media Foundation | VA-API (Intel/AMD) | VideoToolbox |
| H.264 decode | Media Foundation | VA-API | VideoToolbox |
| Clipboard | Win32 (text + image) | X11 via xclip (text + img) |
(in-memory)² |
| File transfer | ✓ (chunked, hashed) | ✓ | ✓ |
| Audio | WASAPI loopback → playback | — | — |
¹ Needs Screen Recording permission; SessionKit ships preflight/request helpers. ² Native mac clipboard is a planned backend behind the same interface. Everything is multiplexed on one channel by a 1-byte tag.
Video is JPEG-tile deltas (only changed 16×16 tiles, JPEG-compressed) by default — no codec, works everywhere.
Supply an IVideoEncoder/IVideoDecoder to opt into H.264 instead; JPEG remains the automatic fallback.
Bring your own channel
public interface ISessionChannel
{
void Send(ReadOnlySpan<byte> data); // send one whole message
event Action<byte[]>? OnData; // one message received (boundaries preserved)
event Action? OnClosed;
}
The one rule: one Send must arrive as exactly one OnData. Datagram-like transports (ConnectKit,
WebSocket messages) satisfy this directly; over a raw TCP stream, add length-prefix framing in your adapter.
Codec negotiation
Supplying an encoder is always safe. The host doesn't assume the viewer can decode H.264 — on connect the viewer advertises the codecs it can decode, and the host switches to H.264 only when it can also encode it, else it stays on the JPEG-tile baseline every viewer understands. A viewer that can't do H.264 simply keeps getting JPEG.
Interoperable, verified
The H.264 wire format is platform-independent Annex-B. The full 3×3 encode/decode matrix — Media Foundation, VideoToolbox, VA-API — cross-decodes in every direction, verified on real Windows, macOS, and Linux hardware (including colorspace handling and multi-slice pictures). A Linux box captured over X11, encoded on its Intel iGPU, and streamed over TCP to a decoding viewer end-to-end.
Status — 0.9.0
Pre-1.0 but broadly exercised: 50 unit tests, an offline selftest, live two-process sessions on all three
OSes, and the cross-OS codec matrix above. The public API (SessionHost / ViewerSession / ISessionChannel
and the capture/input/codec seams) is settling toward 1.0; remaining work (native Wayland capture, macOS
ScreenCaptureKit) is additive behind the existing interfaces and won't break your code.
Build & test from source
dotnet build SessionKit.slnx -c Release
dotnet test SessionKit.slnx
dotnet run --project samples/SessionKit.Sample -- selftest # offline host→loopback→viewer
License
Commercial / proprietary — see LICENSE.txt. Installation requires accepting the license terms. For evaluation, pricing, or licensing questions, see the project site.
Part of the RemoteViewer family
Connection = ConnectKit · Session = SessionKit. ConnectKit (RemoteViewer.ConnectKit) gives you the
encrypted, NAT-traversing pipe (IConnectChannel); SessionKit is what rides it. They combine through a thin
adapter (IConnectChannel → ISessionChannel) shown in the sample — SessionKit itself takes no ConnectKit
dependency, so you can pair it with any transport you like.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.9.0 | 0 | 8/31/2026 |