CalloraVoipSdk.Audio.Linux
3.1.2
See the version list below for details.
dotnet add package CalloraVoipSdk.Audio.Linux --version 3.1.2
NuGet\Install-Package CalloraVoipSdk.Audio.Linux -Version 3.1.2
<PackageReference Include="CalloraVoipSdk.Audio.Linux" Version="3.1.2" />
<PackageVersion Include="CalloraVoipSdk.Audio.Linux" Version="3.1.2" />
<PackageReference Include="CalloraVoipSdk.Audio.Linux" />
paket add CalloraVoipSdk.Audio.Linux --version 3.1.2
#r "nuget: CalloraVoipSdk.Audio.Linux, 3.1.2"
#:package CalloraVoipSdk.Audio.Linux@3.1.2
#addin nuget:?package=CalloraVoipSdk.Audio.Linux&version=3.1.2
#tool nuget:?package=CalloraVoipSdk.Audio.Linux&version=3.1.2
CalloraVoipSdk
Commercial-grade .NET VoIP SDK for SIP signaling, RTP media, PBX integrations and voice automation.
CalloraVoipSdk is a .NET VoIP SDK (net8.0 / net9.0 / net10.0) for building softphones, PBX integrations, contact-center workflows and voice automation systems.
It exposes a stable, developer-friendly API through VoipClient while keeping transport, media and device internals behind a clean facade — and opens up through a module registry for building products like AI voice agents on top.
Why CalloraVoipSdk
CalloraVoipSdk is built for developers who need more than a black-box telephony wrapper.
- Stable public API centered around
VoipClient - Full SIP call control for outbound and inbound scenarios
- RTP media pipeline with sender, receiver and cross-connect support
- Runtime audio device control for Linux and Windows
- DDD-oriented architecture with clear boundaries
- Extensive RFC-oriented unit and compliance tests
Typical use cases
- Softphones and operator desktops
- PBX and SIP integrations
- Contact-center and queue workflows
- Voice bots and automation systems
- Media bridging and custom audio routing
- Real-time call control in backend services
Current feature set
Available in the repository today:
- SIP basics: register, invite/dial, accept, hangup, hold/unhold
- Advanced call control: DTMF, blind transfer, attended transfer
- In-dialog operations:
INFO,OPTIONS,SUBSCRIBE,NOTIFY - Media stack: RTP sessions, sender, receiver,
MediaConnector, cross-connect - Per-call media tap: attach frame receivers/senders to any call for bots, bridging
and streaming scenarios (
client.Media.CreateReceiver()/CreateSender()) - Module registry (
client.Modules) as the extension point for separately shipped feature modules - Configurable audio codec preference (
SdkConfiguration.PreferredAudioCodecs) - RTCP quality metrics with measured values: local/remote jitter, packet loss and round-trip time from SR/RR (LSR/DLSR); RFC 3611 XR-tolerant compound decoding
- Linux audio devices via
CalloraVoipSdk.Audio.Linux - Windows audio devices via
CalloraVoipSdk.Audio.Windows - Runtime device controls:
- device hot-switch
- input/output mute
- input/output volume
- format updates
- RFC-oriented unit and compliance test coverage
Package layout
CalloraVoipSdk
Public entry point and developer-facing facadeCalloraVoipSdk.Core
Core call, line, media and protocol abstractionsCalloraVoipSdk.Audio.Windows
Windows audio integration based on NAudioCalloraVoipSdk.Audio.Linux
Linux audio integration based on PortAudio
Architecture
The solution follows a DDD-oriented structure:
src/Core/Domain
Entities, value objects, states and domain eventssrc/Core/Application
Use cases and orchestration for calls, lines and mediasrc/Core/Infrastructure
SIP, RTP, SDP and audio-specific implementationssrc/Client
Public facade, convenience APIs and dependency injection wiring
Public API boundary
For SDK consumers, VoipClient is the central entry point.
VoipClientis the supported integration surfaceInfrastructuretypes are internal implementation detailsApplicationtypes are only exposed where necessary for practical SDK usage
This keeps the external API compact and stable while allowing internal evolution.
Versioning
CalloraVoipSdk follows Semantic Versioning (MAJOR.MINOR.PATCH).
- Current public release line:
3.x(see releases) - Public API removals only happen in MAJOR releases; deprecations are introduced
through
[Obsolete(...)]before removal - Consumer-relevant changes are documented in
CHANGELOG.md
Requirements
- .NET SDK 8.0+ (packages target
net8.0,net9.0andnet10.0) - SIP account or PBX credentials
- For real audio I/O on Linux:
CalloraVoipSdk.Audio.Linux - For real audio I/O on Windows:
CalloraVoipSdk.Audio.Windows
Installation
NuGet
dotnet add package CalloraVoipSdk
dotnet add package CalloraVoipSdk.Audio.Windows # Windows
dotnet add package CalloraVoipSdk.Audio.Linux # Linux
Local development via ProjectReference
<ItemGroup>
<ProjectReference Include="..\voip\src\Client\CalloraVoipSdk.Client.csproj" />
<ProjectReference Include="..\voip\src\Core\CalloraVoipSdk.Core.csproj" />
<ProjectReference Include="..\voip\src\Audio\Linux\CalloraVoipSdk.Audio.Linux.csproj" />
<ProjectReference Include="..\voip\src\Audio\Windows\CalloraVoipSdk.Audio.Windows.csproj" />
</ItemGroup>
Build and test
dotnet restore CalloraVoipSdk.sln
dotnet build CalloraVoipSdk.sln
dotnet test CalloraVoipSdk.sln
Quickstart
1. Connect and place a call
using Microsoft.Extensions.Logging;
using CalloraVoipSdk.Core.Domain.Calls;
using CalloraVoipSdk.Core.Domain.Lines;
using CalloraVoipSdk;
using var loggerFactory = LoggerFactory.Create(b => b
.AddConsole()
.SetMinimumLevel(LogLevel.Information));
using var client = new VoipClient(new SdkConfiguration
{
LoggerFactory = loggerFactory,
UserAgent = "MySoftphone/1.0",
MaxConcurrentCallsPerLine = 4
});
var connectResult = await client.ConnectAsync(
new SipAccount
{
Username = "1001",
Password = "secret",
SipServer = "pbx.example.com",
DisplayName = "Agent 1001",
Transport = SipTransport.Tls
},
new ConnectOptions
{
Timeout = TimeSpan.FromSeconds(15),
FailFastOnRegistrationFailed = true
});
if (!connectResult.IsSuccess || connectResult.Line is null)
throw new InvalidOperationException($"Connect failed: {connectResult.Status}");
var line = connectResult.Line;
var dialResult = await client.DialAndWaitUntilConnectedAsync(
line,
"sip:1002@pbx.example.com",
new DialWaitOptions
{
ConnectTimeout = TimeSpan.FromSeconds(30),
HangupOnTimeout = true,
HangupOnCancellation = true
});
if (!dialResult.IsSuccess || dialResult.Call is null)
throw new InvalidOperationException($"Dial failed: {dialResult.Status}");
var call = dialResult.Call;
await client.AttachDefaultAudioAsync(call);
await call.SendDtmfAsync(new DtmfTone('5'));
await call.HoldAsync();
await call.UnholdAsync();
await call.HangupAsync();
2. Runtime audio device control
var inDevices = client.GetAvailableInputAudioDevices();
var outDevices = client.GetAvailableOutputAudioDevices();
if (inDevices.Count > 1)
client.SwitchAudioInputDevice(inDevices[1].Id);
if (outDevices.Count > 1)
client.SwitchAudioOutputDevice(outDevices[1].Id);
client.SetAudioInputVolume(0.8f);
client.SetAudioOutputVolume(1.1f);
client.SetAudioInputMuted(false);
client.SetAudioOutputMuted(false);
client.UpdateAudioFormat(new AudioDeviceFormat
{
SampleRate = 16000,
BitsPerSample = 16,
Channels = 1
});
3. Handle inbound calls
using var subscription = client.OnIncomingCall(async call =>
{
Console.WriteLine($"Inbound from: {call.RemoteParty}");
if (IsInLunchBreak())
{
await call.RejectAsync(486, "Busy Here");
return;
}
if (ShouldForwardToQueue(call.RemoteParty))
{
var result = await call.RedirectAsync(["sip:queue@pbx.example.com"], statusCode: 302);
Console.WriteLine($"Redirect: {result.Status}");
return;
}
await call.AcceptAsync();
await client.AttachDefaultAudioAsync(call);
});
static bool IsInLunchBreak() => false;
static bool ShouldForwardToQueue(string remoteParty) => false;
4. Advanced event-driven flow
var line = client.Lines.Register(account);
line.StateChanged += (_, e) =>
Console.WriteLine($"Line: {e.OldState} -> {e.NewState}");
var call = await line.DialAsync("sip:1002@pbx.example.com");
call.StateChanged += (_, e) =>
Console.WriteLine($"Call {e.Call.CallId}: {e.OldState} -> {e.NewState}");
5. Manual media control
using CalloraVoipSdk.Audio.Linux;
using CalloraVoipSdk.Core.Application.Ports.Audio;
using CalloraVoipSdk.Core.Domain.Calls;
using var audioDevice = new LinuxAudioDevice();
using var receiver = client.Media.CreateReceiver();
using var sender = client.Media.CreateSender();
call.StateChanged += (_, e) =>
{
if (e.NewState == CallState.Connected)
{
receiver.AttachToCall(call);
sender.AttachToCall(call);
var audioParameters = call.MediaParameters is { } mp
? AudioConnectionParameters.From(mp)
: AudioConnectionParameters.Default;
audioDevice.Connect(receiver, sender, audioParameters);
if (audioDevice is IAudioDeviceRuntimeControl runtime)
{
runtime.SetInputMuted(false);
runtime.SetOutputMuted(false);
runtime.SetInputVolume(0.9f);
runtime.SetOutputVolume(1.0f);
}
}
if (e.NewState == CallState.Terminated)
{
audioDevice.Disconnect();
receiver.Detach();
sender.Detach();
}
};
6. Bridge two active calls
using var aRx = client.Media.CreateReceiver();
using var aTx = client.Media.CreateSender();
using var bRx = client.Media.CreateReceiver();
using var bTx = client.Media.CreateSender();
aRx.AttachToCall(callA);
aTx.AttachToCall(callA);
bRx.AttachToCall(callB);
bTx.AttachToCall(callB);
using var bridge = client.Media.CreateConnector().CrossConnect(aRx, aTx, bRx, bTx);
7. Pin the audio codec
using var client = new VoipClient(new SdkConfiguration
{
UserAgent = "MyVoiceBot/1.0",
// Order = preference. Offers/answers only include the listed codecs (plus DTMF
// telephone-event), and RTP sessions pick their primary codec accordingly.
// Useful for passthrough scenarios, e.g. G.711 µ-law towards a realtime AI API.
PreferredAudioCodecs = ["PCMU"]
});
Extending the SDK — module registry
client.Modules is the extension point for feature modules that ship as separate
packages. A module implements IVoipClientModule, gets attached to the client and is
then resolvable by any interface it implements:
// Register (or inject via DI as IVoipClientModule before AddCallora):
client.Modules.Register(new MyRecordingModule());
// Resolve anywhere:
var recording = client.Modules.Get<IMyRecordingFeature>(); // throws if unavailable
if (client.Modules.TryGet<IMyRecordingFeature>(out var feature)) // or probe
feature.Start();
Modules build on the public per-call media tap. Its contract in two sentences:
IMediaReceiver.FrameReceived fires synchronously on the media path — handlers must
buffer and return immediately, never block. Negotiated format details (payload type,
clock rate, samples per packet) are available via ICall.MediaParameters.
Commercial plugins (private, paid — in development)
On top of this extension point we are building a set of commercial plugins, distributed through a private feed (not on nuget.org):
- Callora.Realtime — bridge call audio to realtime AI APIs (e.g. OpenAI Realtime) with pacing, backpressure and barge-in support; powers AI voice agents
- Callora.WebSocket — raw call-audio streaming over WebSocket
- Callora.Privacy / Callora.Risk / Callora.Intelligence — redaction & consent, spam/scam screening, AMD/transcription/sentiment
The SDK core stays open and free; plugins are licensed separately. Contact info@bechstein.digital for early access.
Production guidance
- Dispose and unregister
VoipClient,IPhoneLineandICallcleanly - Execute call actions only in valid states such as
Connected,RingingorOnHold - Keep event handlers short and non-blocking under load
- Choose audio providers explicitly via platform-specific packages
- Treat infrastructure details as non-public integration surface
Roadmap
- ICE state machine completion for full NAT traversal (STUN/TURN transport is in place)
- Commercial plugin line-up (private feed, licensed): Callora.Realtime, WebSocket streaming, Privacy/Risk/Intelligence — in development
- CI/CD hardening: soak, interop and chaos gates
- More end-to-end examples and interoperability validation
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Contributing
Contributions, issues and discussions are welcome.
If you plan to contribute larger changes, open an issue first so architecture and API impact can be discussed before implementation.
| 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 is compatible. 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. |
-
net10.0
- CalloraVoipSdk.Audio.Abstractions (>= 3.1.2)
- CalloraVoipSdk.Core (>= 3.1.2)
- NAudio.Core (>= 2.3.0)
- PortAudioSharp2 (>= 1.0.6)
-
net8.0
- CalloraVoipSdk.Audio.Abstractions (>= 3.1.2)
- CalloraVoipSdk.Core (>= 3.1.2)
- NAudio.Core (>= 2.3.0)
- PortAudioSharp2 (>= 1.0.6)
-
net9.0
- CalloraVoipSdk.Audio.Abstractions (>= 3.1.2)
- CalloraVoipSdk.Core (>= 3.1.2)
- NAudio.Core (>= 2.3.0)
- PortAudioSharp2 (>= 1.0.6)
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 |
|---|---|---|
| 4.6.0-preview.2 | 0 | 7/22/2026 |
| 4.6.0-preview.1 | 41 | 7/18/2026 |
| 4.5.0 | 87 | 7/15/2026 |
| 4.4.1 | 98 | 7/11/2026 |
| 4.4.0 | 91 | 7/11/2026 |
| 4.3.5 | 93 | 7/11/2026 |
| 4.3.4 | 95 | 7/11/2026 |
| 4.3.3 | 94 | 7/10/2026 |
| 4.3.2 | 99 | 7/9/2026 |
| 4.3.1 | 97 | 7/9/2026 |
| 4.3.0 | 95 | 7/9/2026 |
| 4.2.0 | 98 | 7/9/2026 |
| 4.1.0 | 92 | 7/9/2026 |
| 4.0.0 | 93 | 7/9/2026 |
| 3.2.0 | 90 | 7/8/2026 |
| 3.1.2 | 97 | 7/8/2026 |
| 3.1.1 | 96 | 7/8/2026 |
| 3.1.0 | 101 | 7/8/2026 |
| 3.0.0 | 105 | 7/7/2026 |
| 2.0.0 | 97 | 7/7/2026 |