Put a real telephone in a .NET application. SIP signalling, RTP/SRTP media, WebRTC and a self-hostable STUN/TURN server — one facade, no native dependencies.
dotnet add package CalloraVoipSdk
dotnet add package CalloraVoipSdk.Audio.Linux # or .Audio.Windowsusing CalloraVoipSdk;
using CalloraVoipSdk.Core.Domain.Lines;
using var client = new VoipClient();
var connected = await client.ConnectAsync(new SipAccount
{
Username = "1001",
Password = "secret",
SipServer = "pbx.example.org",
});
var dialed = await client.DialAndWaitUntilConnectedAsync(
connected.Line!, "sip:1002@pbx.example.org");
await client.AttachDefaultAudioAsync(dialed.Call!);A registered line, a connected call, live audio on the machine's default devices. Both results carry
a status you should check rather than the ! used here for brevity — a call that nobody answered is
not an exception, it is an outcome.
Everything below is what happens when you need more than that.
It is checked against real software, not against itself. Every CI run boots an Asterisk (PJSIP) container and runs the matrix through it — registration, in- and outbound calls with live RTP, codec negotiation, SRTP-SDES, DTMF, hold, blind and attended transfer, session timers, early media, TCP/TLS — plus a two-leg bridged call whose media is verified byte-exact in both directions. The WebRTC side runs against Chromium and Firefox (headless, via Playwright) with the SDK as offerer and as answerer, and the TURN server against a real coturn.
The limits are written down. A protocol library that only advertises what works is a library you find the edges of in production. What is proven, and what is not is a section, not a footnote.
Three depths, mixable per call. Most libraries make you choose once between a black box and a raw protocol stack. Here the levels sit on top of each other, and using the easy one does not close off the others:
| Depth | What you use | For |
|---|---|---|
| Managed workflows | ConnectAsync, DialAndWaitUntilConnectedAsync, default audio, playback |
Softphones, dialers, ordinary call flows |
| Typed call control | IPhoneLine, ICall, transfer, DTMF, in-dialog SIP, negotiated media, quality and ICE state, custom headers |
Contact-centre logic, routing, diagnostics |
| Media and extension seams | IMediaReceiver, IMediaSender, MediaConnector, your own IAudioDevice, ModuleRegistry |
Voice bots, custom routing, observability, separately shipped modules |
What stays internal stays internal: SIP and RTP implementation classes, and arbitrary mutation of the wire. Controlled extensibility rather than an unstable stack with the lid off.
No native dependencies for the protocol stack. Managed C# end to end, so it runs where .NET runs. Audio devices are the exception and live in their own packages.
|
SIP
|
Media
|
|
WebRTC
|
Connectivity
|
Full API reference: bechsteindigital.github.io/callora-voip-sdk
The line between "we run this in production" and "this compiles and has tests" is where most integration time goes, so it is drawn here.
| Area | State | What that means |
|---|---|---|
| SIP + RTP core | Production-proven | Exercised end to end against a real Asterisk in every CI run, zero skipped cases in the matrix |
| SRTP (SDES) | Production-proven | Same matrix, real PBX |
| WebRTC audio + video | Browser-verified | Chromium and Firefox in CI, SDK as offerer and answerer, 1 audio + 1 video |
| UDP TURN relay | Production-proven | End to end against real coturn |
| TCP/TLS TURN relay | Unit-proven | Data path against a real server is still in the interop matrix — validate before relying on it |
| Full ICE (RFC 8445) | Opt-in | Symmetric RTP is the proven NAT path; validate ICE for your trunk before switching |
| Multi-track topologies | Transport-only | The primitives are stable; the browser matrix covers one audio and one video track |
| Data channels (SCTP) | Not implemented | No timeline; open an issue if you need them |
| G.729 | Negotiable, not decodable | The format can be negotiated and forwarded; this SDK carries no G.729 implementation |
Known gaps and interop defects are tracked in the issue tracker. Interop reports from a carrier or a device we have not seen are the single most useful contribution.
| Package | What it is |
|---|---|
CalloraVoipSdk |
The facade. Start here. |
CalloraVoipSdk.Core |
Calls, lines, media and protocol contracts |
CalloraVoipSdk.Audio.Windows |
Windows audio devices (NAudio) |
CalloraVoipSdk.Audio.Linux |
Linux audio devices (PortAudio) |
Headless services need no audio package at all — media flows through streams and taps.
Runnable projects in examples/, roughly in order of depth:
| BasicCalling | Register, dial, answer |
| Dialer | Outbound campaign over one line |
| Transfer | Blind and attended |
| Switchboard | Several calls at once, bridged |
| CustomAudio | Your own source and sink instead of a device |
| VideoCalling | SIP video with a codec you bring |
| WebRtcPeer · DI · Recording | The WebRTC facade |
| WebRtcVideoCall.Web | A browser video call, end to end |
client.Modules takes feature modules that ship as separate packages. A module implements
IVoipClientModule, attaches to the client, and is then resolvable by any interface it implements:
client.Modules.Register(new MyRecordingModule());
var recording = client.Modules.Get<IMyRecordingFeature>(); // throws when absent
if (client.Modules.TryGet<IMyRecordingFeature>(out var feature)) // or probe
feature.Start();Modules build on the per-call media tap, and its contract is two sentences worth reading twice:
IMediaReceiver.FrameReceived fires synchronously on the media path — a handler must buffer and
return immediately, never block, or it stalls the call it is listening to. The negotiated format
(payload type, clock rate, samples per packet) is on ICall.MediaParameters.
Commercial modules are in development on top of this seam, distributed through a private feed rather than nuget.org: Callora.Realtime (call audio to realtime AI APIs, with pacing, backpressure and barge-in — the basis for voice agents), Callora.WebSocket (raw call audio over a socket), and Callora.Privacy / Risk / Intelligence (redaction and consent, spam screening, transcription and sentiment). The SDK core stays open and free; the modules are licensed separately — info@bechstein.digital for early access.
net8.0, net9.0, net10.0. Windows, Linux and macOS for the protocol stack; audio devices on Windows and Linux.
Versioning is SemVer, and the public surface is a tracked file. Every
public type and member lives in PublicApi.approved.txt, and a CI gate fails the build when a change
is not reflected there — so a breaking change is a reviewable diff rather than something a consumer
discovers after upgrading.
Per-release detail lives in docs/release-notes/; the machine-readable list is
CHANGELOG.md.
git clone https://github.com/BechsteinDigital/callora-voip-sdk.git
cd callora-voip-sdk
dotnet test tests/CalloraVoipSdk.ArchitectureTests # the gates CI runs first
dotnet test # the standard setThe Asterisk and browser interop suites need a Docker daemon and self-skip without one. Maintainer
workflows, the architecture map and the invariants are in MAINTAINING.md; the
rules the tests enforce are in ENGINEERING_RULES.md.
Bug reports, interop feedback and pull requests are welcome — see
CONTRIBUTING.md and the CODE_OF_CONDUCT.md.
Found a security issue? Do not open an issue — SECURITY.md says where to send it.
Apache-2.0. Third-party components are listed in
THIRD-PARTY-NOTICES.md.