Verbara.Sdk.VoiceAi.OpenAiRealtime
2.8.0
dotnet add package Verbara.Sdk.VoiceAi.OpenAiRealtime --version 2.8.0
NuGet\Install-Package Verbara.Sdk.VoiceAi.OpenAiRealtime -Version 2.8.0
<PackageReference Include="Verbara.Sdk.VoiceAi.OpenAiRealtime" Version="2.8.0" />
<PackageVersion Include="Verbara.Sdk.VoiceAi.OpenAiRealtime" Version="2.8.0" />
<PackageReference Include="Verbara.Sdk.VoiceAi.OpenAiRealtime" />
paket add Verbara.Sdk.VoiceAi.OpenAiRealtime --version 2.8.0
#r "nuget: Verbara.Sdk.VoiceAi.OpenAiRealtime, 2.8.0"
#:package Verbara.Sdk.VoiceAi.OpenAiRealtime@2.8.0
#addin nuget:?package=Verbara.Sdk.VoiceAi.OpenAiRealtime&version=2.8.0
#tool nuget:?package=Verbara.Sdk.VoiceAi.OpenAiRealtime&version=2.8.0
Verbara.Sdk.VoiceAi.OpenAiRealtime
OpenAI Realtime API bridge for Verbara.Sdk.VoiceAi — persistent WebSocket session with function calling, transcript events, and dual-loop audio streaming.
Installation
dotnet add package Verbara.Sdk.VoiceAi.OpenAiRealtime
Quick Start
// Prerequisite: register AudioSocket transport
services.AddAudioSocketServer(opts => opts.Port = 9092);
// Register the bridge (replaces the STT→LLM→TTS chain)
services.AddOpenAiRealtimeBridge(opts =>
{
opts.ApiKey = configuration["OpenAI:ApiKey"]!;
opts.Model = "gpt-realtime";
opts.Voice = "alloy";
opts.Instructions = "You are a helpful call center assistant.";
opts.VadMode = VadMode.ServerSide;
})
.AddFunction<GetAccountBalanceFunction>(); // optional tool functions
// Subscribe to bridge events
var bridge = app.Services.GetRequiredService<OpenAiRealtimeBridge>();
bridge.Events.Subscribe(evt =>
{
if (evt is RealtimeTranscriptEvent t && t.IsFinal)
Console.WriteLine($"[{t.ChannelId}] {t.Text}");
});
Features
OpenAiRealtimeBridge—ISessionHandlerthat opens a WebSocket to OpenAI Realtime API per call- Dual audio loops: inbound PCM16 → base64 → OpenAI, OpenAI audio delta → PCM16 → Asterisk
- Automatic resampling between Asterisk 8 kHz and OpenAI 24 kHz via
ResamplerFactory - Function calling: register
IRealtimeFunctionHandlerimplementations withAddFunction<T>(), each call bounded byFunctionCallTimeout(default 30 s; writtenhh:mm:ssin configuration): a function that outlasts it is answered{"error":"timeout"}, logged at Warning, counted inopenai_realtime.function_calls.timed_outand no longer awaited (migration guide) - Observable
Eventsstream (RealtimeTranscriptEvent,RealtimeFunctionCalledEvent,RealtimeResponseStartedEvent, etc.) AddOpenAiRealtimeBridge()andAddFunction<T>()DI extension methods- Native AOT compatible (AOT-safe JSON via
System.Text.Jsonsource generation)
When the conversation ends
The bridge runs one Realtime conversation per AudioSocket session, and the session broker that
AddOpenAiRealtimeBridge registers ends the line as soon as the bridge returns:
- The vendor closes the conversation. The bridge returns and the broker hangs the line up with
one hangup frame. On the
AudioSocket()route of Asterisk 20 and later the caller goes on in the dialplan at once (measured 2026-10-02 on 20.20.1, 22.9.0 and 23.4.1: 60 of 60 calls, within 2 ms of the bridge returning); on an ARIexternalMediaroute the channel leaves Stasis with the caller still in your bridge (60 of 60). Put what the caller should hear next in the dialplan or your ARI application. On Asterisk 18 the application fails and the call is hung up. - The caller hangs up. The bridge closes the vendor session and returns; nothing more is sent to the caller.
- The host stops. A graceful stop hangs up every live call with a frame and waits for each conversation to return, within the host's shutdown budget. A conversation the host cancels returns once both of its audio loops have ended, without waiting for a function still running, and an event a session raises after the bridge was disposed is dropped and logged at Debug rather than thrown inside the session.
Register AddAudioSocketServer before AddOpenAiRealtimeBridge (the prerequisite above), so the
broker stops before the server and every call ends with a hangup frame.
Documentation
See the main README for full documentation. Upgrading from 2.6.1: voice-session-ending-migration.md and voice-bounds-migration.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 10.0.12)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
- System.Reactive (>= 7.0.0)
- Verbara.Sdk.Audio (>= 2.8.0)
- Verbara.Sdk.VoiceAi (>= 2.8.0)
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 |
|---|---|---|
| 2.8.0 | 137 | 10/9/2026 |
| 2.7.0 | 549 | 10/3/2026 |
| 2.6.1 | 460 | 9/30/2026 |
| 2.6.0 | 705 | 9/24/2026 |
| 2.5.3 | 600 | 9/13/2026 |
| 2.5.2 | 250 | 9/13/2026 |
| 2.5.1 | 278 | 9/12/2026 |
| 2.5.0 | 334 | 8/25/2026 |
| 2.4.0 | 200 | 7/27/2026 |
| 2.3.2 | 138 | 7/20/2026 |
| 2.3.1 | 127 | 7/14/2026 |
| 2.3.0 | 141 | 7/6/2026 |
| 2.2.1 | 140 | 5/23/2026 |
| 2.2.0 | 124 | 5/20/2026 |
| 2.1.2 | 138 | 5/8/2026 |
| 2.1.1 | 131 | 5/7/2026 |
| 2.1.0 | 3,380 | 5/7/2026 |
| 2.0.0 | 131 | 5/6/2026 |