Net.Agora.Video
4.6.2.5
dotnet add package Net.Agora.Video --version 4.6.2.5
NuGet\Install-Package Net.Agora.Video -Version 4.6.2.5
<PackageReference Include="Net.Agora.Video" Version="4.6.2.5" />
<PackageVersion Include="Net.Agora.Video" Version="4.6.2.5" />
<PackageReference Include="Net.Agora.Video" />
paket add Net.Agora.Video --version 4.6.2.5
#r "nuget: Net.Agora.Video, 4.6.2.5"
#:package Net.Agora.Video@4.6.2.5
#addin nuget:?package=Net.Agora.Video&version=4.6.2.5
#tool nuget:?package=Net.Agora.Video&version=4.6.2.5
Net.Agora
.NET bindings for Agora's native SDKs, with one API across Android, iOS and macOS. Join RTC channels, publish and subscribe audio and video, from C# — in .NET MAUI or plain .NET for Android / .NET for iOS.
Built on Net.Agora.iOS and Net.Agora.Android, which bind the native SDKs. This repository binds nothing itself — see How this repository works.
dotnet add package Net.Agora.Video.Maui # MAUI video apps: adds the video view
dotnet add package Net.Agora.Video # video, everything else
dotnet add package Net.Agora.Voice.Maui # MAUI voice-only apps
dotnet add package Net.Agora.Voice # voice-only, everything else
dotnet add package Net.Agora.Signaling # realtime messaging (RTM) — MAUI or plain, same package
dotnet add package Net.Agora.Signaling.Maui # optional: CreateClient() symmetry with the others
dotnet add package Net.Agora.Chat.Maui # MAUI chat (IM) apps
dotnet add package Net.Agora.Chat # chat (IM), everything else
dotnet add package Net.Agora.Whiteboard.Maui # MAUI whiteboard apps: adds the board view
dotnet add package Net.Agora.Whiteboard # whiteboard, everything else
dotnet add package Net.Agora.Fastboard.Maui # MAUI whiteboard apps, toolbar included
dotnet add package Net.Agora.Fastboard # same, everything else
var client = new AgoraVideoOptions { AppId = "your-app-id" }.CreateClient();
client.SetLocalView(LocalView); // a <agora:AgoraVideoView /> from your XAML
client.UserJoined += (_, e) => client.SetRemoteView(e.Uid, RemoteView);
await client.JoinAsync("my-channel"); // completes when the server confirms
Both clients carry the call essentials — speakerphone routing, who-is-speaking reports, remote mute state, connection lifecycle events, token renewal — and the video client adds the camera half (preview, flip, remote video mute). Voice-only apps get all of it over native artifacts that carry no video codecs at all:
var client = new AgoraVoiceOptions { AppId = "your-app-id", DefaultToSpeakerphone = true }.CreateClient();
client.VolumeIndication += (_, e) => ShowSpeakers(e.Speakers); // uid 0 is you
client.EnableVolumeIndication(TimeSpan.FromMilliseconds(200));
await client.JoinAsync("my-room");
client.SetSpeakerphone(false); // switch the live route mid-call
Signaling is the third product — login, channel subscribe, publish/receive — with the same awaitable shape; it has no MAUI companion because it needs no platform glue at all:
var signaling = new AgoraSignalingClient(new AgoraSignalingOptions
{
AppId = "your-app-id",
UserId = "alice",
});
signaling.MessageReceived += (_, e) => Show($"{e.Publisher}: {e.Text}");
await signaling.LoginAsync();
await signaling.SubscribeAsync("lobby");
await signaling.PublishAsync("lobby", "hi all");
Chat is the fourth — a persistent IM service, where Signaling is ephemeral pub/sub. It signs in, sends and receives messages, and keeps a local conversation history:
var chat = new AgoraChatOptions
{
AppId = "your-app-id",
UserId = "alice",
Token = "chat-token-from-your-server", // required — Chat has no App ID-only mode
}.CreateClient();
chat.MessageReceived += (_, e) => Show($"{e.Message.From}: {e.Message.Text}");
await chat.LoginAsync();
await chat.SendTextMessageAsync("bob", "hi");
foreach (var conversation in chat.GetConversations()) // local, most recent first
{
Show($"{conversation.ConversationId}: {conversation.UnreadCount} unread");
}
The Interactive Whiteboard is the fifth. It is a shared drawing surface rather than a stream, and on both platforms the board is a web view — so, like the video client, it comes with a MAUI view:
// <agora:AgoraWhiteboardView x:Name="Board" /> in your XAML
var board = Board.CreateClient(new AgoraWhiteboardOptions
{
AppIdentifier = "your-whiteboard-app-identifier", // not an RTC App ID
RoomUuid = uuid, // both from your own server's call
RoomToken = token, // to the whiteboard REST API
Uid = "alice",
});
await board.JoinAsync();
board.SetTool(AgoraWhiteboardTool.Pencil, color: 0xE81123, strokeWidth: 4);
Fastboard is the same board with netless's toolbar already drawn and wired — tools, colours, undo/redo, page navigation — for an app that wants a working whiteboard rather than a canvas to build a UI around. Same identifiers, one fewer thing to write:
// <agora:AgoraFastboardView x:Name="Board" /> in your XAML
var board = Board.CreateClient(new AgoraFastboardOptions { /* the same four identifiers */ });
await board.JoinAsync(); // the toolbar comes up with it
Pick one RTC product per app: Video already carries the full audio surface, and the two RTC
products' native artifacts collide (same Java classes on Android, same AgoraRtcKit framework on
iOS). Signaling, Chat and Whiteboard coexist with either, and with each other.
Status
This repository covers Agora's Video, Voice, Signaling, Chat, Interactive Whiteboard and Fastboard SDKs, wired end to end: the raw Android/iOS bindings (in the two sibling repositories above), the cross-platform clients, the MAUI packages, package tests, sample apps, CI. See docs/BUILD.md for the exact state.
| Product | Android | iOS | Cross-platform client | MAUI |
|---|---|---|---|---|
| Video | ✅ Net.Agora.Android | ✅ Net.Agora.iOS | ✅ | ✅ view + glue |
| Voice | ✅ Net.Agora.Android | ✅ Net.Agora.iOS | ✅ | ✅ glue (no view — voice renders nothing) |
| Signaling | ✅ Net.Agora.Android | ✅ Net.Agora.iOS | ✅ | ✅ CreateClient() for symmetry (no glue needed — the plain package works in MAUI too) |
| Chat | ✅ Net.Agora.Android | ✅ Net.Agora.iOS | ✅ | ✅ glue (no view — chat renders nothing) |
| Whiteboard | ✅ Net.Agora.Android | ✅ Net.Agora.iOS | ✅ | ✅ board view + glue |
| Fastboard | ✅ Net.Agora.Android | ✅ Net.Agora.iOS | ✅ | ✅ board view + glue |
How this repository works
Three repositories, each independently versioned and released:
Net.Agora.Android— the raw Android bindings (Agora.Rtc.*, generated fromio.agora.rtc:full-rtc-basic/voice-rtc-basic).Net.Agora.iOS— the raw iOS bindings (Net.Agora.Video.iOS.*/Net.Agora.Voice.iOS.*, hand-written againstAgoraRtcEngineKit).Net.Agora(this repository) — the façades. Each façade package depends on its two platform packages at an exact pinned version (NetAgora<Product><Platform>VersioninDirectory.Build.props) the same way any consumer would, restored from nuget.org. It contains noApiDefinition.cs, no native artifact, noAndroidLibrary/NativeReference— see docs/BUILD.md.
Without MAUI
Net.Agora.Video.Maui only adds the video view and the platform glue. A plain .NET for Android or
.NET for iOS app needs none of that — reference Net.Agora.Video and use the same
AgoraVideoClient, with the platform's own view type instead of AgoraVideoView:
dotnet add package Net.Agora.Video
Android — the SDK renders into a plain Android.Views.SurfaceView, and the client needs the
Context:
using Net.Agora.Video;
using Android.App;
using Android.OS;
using Android.Views;
[Activity(Label = "Publisher", MainLauncher = true)]
public class MainActivity : Activity
{
private AgoraVideoClient? _client;
private SurfaceView? _preview;
protected override async void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
_preview = new SurfaceView(this);
SetContentView(_preview);
var options = new AgoraVideoOptions { AppId = "your-app-id" };
// The Context is the one thing the Android SDK cannot work out for itself.
// Net.Agora.Video.Maui is what supplies it in a MAUI app.
_client = new AgoraVideoClient(options, this);
_client.SetLocalView(_preview);
_client.EnableVideo();
_client.UserJoined += (_, e) => Log.Info("app", $"remote user joined: {e.Uid}");
_client.Error += (_, e) => Log.Error("app", e.Message);
await _client.JoinAsync("my-channel");
}
protected override void OnDestroy()
{
// Releases the camera and the engine; managed collection alone does not.
_client?.Dispose();
base.OnDestroy();
}
}
iOS — a plain UIView, and the client takes no platform handle at all:
using System;
using Net.Agora.Video;
using UIKit;
public class ChannelViewController : UIViewController
{
private AgoraVideoClient? _client;
public override async void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
var options = new AgoraVideoOptions { AppId = "your-app-id" };
_client = new AgoraVideoClient(options);
// Any UIView will do — the SDK adds its own renderer as a subview.
_client.SetLocalView(View!);
_client.EnableVideo();
_client.UserJoined += (_, e) => Console.WriteLine($"remote user joined: {e.Uid}");
_client.Error += (_, e) => Console.WriteLine($"error: {e.Message}");
await _client.JoinAsync("my-channel");
}
public override void ViewDidDisappear(bool animated)
{
_client?.Dispose();
_client = null;
base.ViewDidDisappear(animated);
}
}
Both snippets create the client once the view exists rather than in a constructor — on Android the
Context route (Platform.CurrentActivity) is not reliably usable before OnCreate, and on Apple
the view has no window before ViewDidAppear.
Capture permissions are the app's own responsibility either way: CAMERA and RECORD_AUDIO in
AndroidManifest.xml, NSCameraUsageDescription and NSMicrophoneUsageDescription in
Info.plist.
Packages
| Package | What it is | Target frameworks | Published from |
|---|---|---|---|
Net.Agora.Video.Maui |
MAUI video view and handlers | net8.0, net9.0, net10.0 (android + ios) | this repo |
Net.Agora.Video |
The cross-platform client: IAgoraVideoClient, options, events, async |
net8.0, net9.0, net10.0 (android + ios + macos) | this repo |
Net.Agora.Video.Android |
The raw binding to Agora's Video Android SDK | net8.0-android34.0, net9.0-android35.0, net10.0-android36.0 |
Net.Agora.Android |
Net.Agora.Video.iOS |
The raw binding to Agora's Video iOS SDK | net8.0-ios18.0, net9.0-ios18.0, net10.0-ios26.0 |
Net.Agora.iOS |
Net.Agora.Video.Mac |
The raw binding to Agora's Video macOS (AppKit) SDK | net8.0-macos, net9.0-macos, net10.0-macos |
Net.Agora.Mac |
Each package pulls in the one below it, so a single reference is enough. Drop to a platform
binding directly for anything the cross-platform API does not expose — the full bound surface is
under Agora.Rtc.* (Android), Net.Agora.Video.iOS.* and Net.Agora.Video.Mac.* (hand-written
subsets — see each repository's own README).
Native macOS, but not Mac Catalyst. The cross-platform Net.Agora.Video / Net.Agora.Voice /
Net.Agora.Signaling clients gain a net*-macos (AppKit) leg over the .Mac bindings, so a native
.NET for macOS app gets the same API as Android and iOS. There is no MAUI-on-Mac path: MAUI's only
desktop-Mac target is Mac Catalyst, and Agora ships no maccatalyst slice — so the .Maui packages
stay Android + iOS, and macOS support is native-AppKit only. Chat, Whiteboard and Fastboard have no
macOS leg (Agora ships no native macOS SDK for them).
Why there is a cross-platform layer
Android's RtcEngine is a Java abstract class overridden with a 100+ method event-handler class;
iOS's AgoraRtcEngineKit takes an Objective-C delegate. Written against the bindings directly, an
app targeting both needs a real per-platform adapter before it can join a channel.
Net.Agora.Video is that adapter, so you do not write it.
The sample is the evidence: samples/Net.Agora.Sample joins a channel and renders
local/remote video with no per-platform code at all.
Building
See docs/BUILD.md. In short, the platform packages are built in their own repositories:
# In sbokatuk/Net.Agora.Android:
./build/BuildNugets.sh
# In sbokatuk/Net.Agora.iOS:
./build/fetch-video.sh
./build/BuildNugets.sh
Then, in this repository, pointing NuGet.config's local-artifacts source at wherever those two
were packed (or once both are published, straight from nuget.org):
./build/BuildNugets.sh video
Licence
MIT — see LICENSE. The bundled Agora SDKs are Agora's own, distributed under their own terms via Maven Central and CocoaPods respectively.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-android34.0 is compatible. net8.0-browser was computed. net8.0-ios was computed. net8.0-ios18.0 is compatible. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-macos15.0 is compatible. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-android35.0 is compatible. net9.0-browser was computed. net9.0-ios was computed. net9.0-ios18.0 is compatible. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-macos15.0 is compatible. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-macos26.0 is compatible. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net10.0-android36.0
- Net.Agora.Video.Android (= 4.6.3.5)
-
net10.0-ios26.0
- Net.Agora.Video.iOS (= 4.6.2.5)
-
net10.0-macos26.0
- Net.Agora.Video.Mac (= 4.6.2.2)
-
net8.0
- No dependencies.
-
net8.0-android34.0
- Net.Agora.Video.Android (= 4.6.3.5)
-
net8.0-ios18.0
- Net.Agora.Video.iOS (= 4.6.2.5)
-
net8.0-macos15.0
- Net.Agora.Video.Mac (= 4.6.2.2)
-
net9.0
- No dependencies.
-
net9.0-android35.0
- Net.Agora.Video.Android (= 4.6.3.5)
-
net9.0-ios18.0
- Net.Agora.Video.iOS (= 4.6.2.5)
-
net9.0-macos15.0
- Net.Agora.Video.Mac (= 4.6.2.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Net.Agora.Video:
| Package | Downloads |
|---|---|
|
Net.Agora.Video.Maui
Adds an AgoraVideoView control and the platform glue a .NET MAUI app needs to use Net.Agora.Video: rendering into a native surface on Android and iOS, and supplying the Android Activity RtcEngineConfig requires. Add Net.Agora.Video on its own if you are not using MAUI. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.6.2.5 | 99 | 7/27/2026 |
| 4.6.2.5-beta.13.26 | 46 | 7/31/2026 |
| 4.6.2.5-beta.12.24 | 46 | 7/30/2026 |
| 4.6.2.5-beta.10.23 | 49 | 7/30/2026 |
| 4.6.2.5-beta.9.21 | 45 | 7/29/2026 |
| 4.6.2.5-beta.8.20 | 46 | 7/28/2026 |
| 4.6.2.5-beta.7.19 | 52 | 7/27/2026 |
| 4.6.2.4 | 95 | 7/24/2026 |
| 4.6.2.4-beta.6.17 | 50 | 7/26/2026 |
| 4.6.2.4-beta.5.16 | 47 | 7/25/2026 |
| 4.6.2.4-beta.4.11 | 53 | 7/24/2026 |
| 4.6.2.3 | 102 | 7/24/2026 |
| 4.6.2.3-beta.3.10 | 50 | 7/24/2026 |
| 4.6.2.2 | 94 | 7/24/2026 |
| 4.6.2.2-beta.2.6 | 46 | 7/24/2026 |
| 4.6.2.1 | 98 | 7/23/2026 |
| 4.6.2.1-beta.1.2 | 43 | 7/23/2026 |
| 4.2.6.1-beta1 | 181 | 2/9/2024 |