Skip to content

Repository files navigation

StreamTransport

NuGet CI License: MIT

Local-first, peer-to-peer real-time media for .NET. Move hardware-encoded H.265 video and Opus audio between machines over WebRTC, on a first-party WebRTC stack (ICE / STUN / DTLS-SRTP / RTP / RTCP / SDP) built on the BCL, no SIP stack, NativeAOT-friendly.

capture (camera / Spout / Syphon / PipeWire) -> HW H.265 -> WebRTC P2P -> HW H.265 -> publish

⚠️ Alpha, early and rough

This is an early 0.1.2-alpha. The core works and is exercised by tests, but it is largely untested in the real world, unpolished in places, and has lots of room to improve. Expect breaking changes and sharp edges. Please try it and file issues, just don't ship it to production yet.

What you get

  • A complete, dependency-light WebRTC stack: ICE, STUN, DTLS-SRTP (GCM), RTP/RTCP, SDP/JSEP, and a PeerConnection, BCL crypto, with one BouncyCastle dependency for the DTLS handshake.
  • Hardware H.265 encode/decode through FFmpeg (NVENC, AMF, QSV, VAAPI, VideoToolbox) with a software fallback, plus pure-managed Opus audio on the same connection, kept in lip-sync.
  • Resilience for real links: SCReAM congestion control (RFC 8298 / 8888), sequence-aware H.265 reassembly, NACK/RTX and FlexFEC loss recovery, and ICE-restart / hot-standby mobility, selected by one media profile (InteractiveP2P, ScreenShare, IrlContribution).
  • Transparency through an opaque codec: side-by-side alpha packing carries a BGRA frame's alpha channel as full-resolution luma in a 2W x H frame, so it survives 4:2:0 encode crisply and needs no codec-level alpha support. GPU implementations ship for all three platforms (D3D11 / Metal / Vulkan compute) with a CPU reference that is byte-compatible with them, so a frame packed on one platform unpacks correctly on another.
  • Per-link telemetry: MediaPublisher.PeerMetrics gives a per-subscriber snapshot of loss, RTT, target and pacing bitrate; MediaSubscriber.CurrentHealth / CurrentLossStats give the receive side.
  • NativeAOT-friendly: self-contained, trimmed binaries on Windows, Linux, and macOS.

Two seams the host fills in

  • Capture, IVideoFrameSource / IVideoFrameSink / IAudioFrameSource. The transport never knows where frames come from, so the GPU-interop libraries below live in the consumer. What the transport does ship is the GPU surface transforms those consumers need — NV12 to BGRA and the side-by-side alpha pack/unpack, in D3D11, Metal, and Vulkan compute. They used to live in the agent sample; keeping them here means every consumer gets the same pixel-exact result instead of reimplementing the colour matrix.
  • Signaling, ISignalingChannel. The transport never knows how SDP/ICE are delivered (a WebSocket, a SignalR hub, a tunnel); the host owns reachability.

Capture companions

Zero-copy GPU sharing libraries that feed the capture seam, published separately:

Library Platform Mechanism
Spout2.NET Windows Spout (DirectX 11 shared texture)
Syphon.NET macOS Syphon (IOSurface / Metal)
PipeWire.NET Linux PipeWire (DMA-BUF)

Packages

Package What it is
Agash.StreamTransport The transport: WebRTC + FFmpeg hardware codecs + room client + GPU surface transforms.
Agash.StreamTransport.Abstractions Capture + signaling contracts. BCL only.
Agash.StreamTransport.WebRtc The WebRTC core: ICE, STUN, SRTP, RTP/RTCP, SDP, PeerConnection.
Agash.StreamTransport.WebRtc.Abstractions Seams for the WebRTC stack.
Agash.StreamTransport.WebRtc.Dtls DTLS-SRTP handshake (the one BouncyCastle dependency).
Agash.StreamTransport.WebRtc.CongestionControl SCReAM controller + pacing.
Agash.StreamTransport.WebRtc.DependencyInjection AddStreamTransportWebRtc() wiring.
Agash.StreamTransport.Signaling Room router + a WebSocket signaling transport.
Agash.StreamTransport.Stun STUN binding server + ICE server providers.

Build

Needs the .NET 11 preview SDK. FFmpeg 8.1 natives are fetched per platform first:

./eng/fetch-ffmpeg.ps1 -Rids win-x64        # or linux-x64 / linux-arm64 / osx-arm64
dotnet build StreamTransport.slnx -c Release
dotnet test  StreamTransport.slnx -c Release --filter "TestCategory!=Integration"

Try it

A self-hostable signaling relay and a sender/receiver agent live in samples/:

dotnet run --project samples/StreamTransport.Relay                                       # WS :8080/ws + STUN :3478
dotnet run --project samples/StreamTransport.Agent -- send    --relay ws://localhost:8080/ws --room demo
dotnet run --project samples/StreamTransport.Agent -- receive --relay ws://localhost:8080/ws --room demo

The agent is a thin consumer now: the GPU alpha and colour-conversion compute it used to carry lives in Agash.StreamTransport (Codecs/), so the sample shows wiring rather than reimplementation.

See samples/StreamTransport.Agent for capture setup (Spout / Syphon / PipeWire), device selection, and publishing into OBS.

License

MIT. See LICENSE.

About

Local-first P2P WebRTC media transport for .NET - hardware H.265, Opus, congestion control, FlexFEC, ICE mobility on a first-party NativeAOT-ready stack

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages