C# (.NET) SDK Reference
Windows .NET SDK public interface, installation and capability notes.
The C# (.NET) SDK has the RtcEngine + IRtcEngineEventHandler shape; it is isomorphic to the Unity SDK but targets desktop .NET (WPF / WinForms / console services).
Prerequisites
- .NET 8 SDK (
net8.0), Windows 10 1809+ (the current declaration reference version comes from the Windows C# wrapper). - System camera/microphone permissions.
- An
appIdand a token service (see Enable Services and Get Credentials).
Installation
<!-- planned coordinates, not published to NuGet yet -->
<PackageReference Include="Nimeet.Rtc" Version="0.1.0" />Get a token
Your server issues the token (POST /v1/tokens); the desktop client only receives the string. Never put appCustomerSecret into a configuration file.
var response = await httpClient.GetFromJsonAsync<TokenResponse>("/api/rtc-token?channel=weekly-sync&uid=10001");
engine.JoinChannel(response.RtcToken, "weekly-sync", 10001, options);Join a channel
using Nimeet.Rtc;
public sealed class MeetingController : IRtcEngineEventHandler
{
private readonly IRtcEngine engine;
public MeetingController(string appId)
{
engine = RtcEngine.CreateAgoraRtcEngine();
engine.Initialize(new RtcEngineContext { AppId = appId, EventHandler = this });
engine.SetChannelProfile(ChannelProfileType.ChannelProfileLiveBroadcasting);
engine.EnableVideo();
engine.StartPreview();
}
public void Join(string token, uint uid)
{
var options = new ChannelMediaOptions
{
ClientRoleType = ClientRoleType.ClientRoleBroadcaster,
AutoSubscribeAudio = true,
AutoSubscribeVideo = true,
};
var code = engine.JoinChannel(token, "weekly-sync", uid, options);
if (code < 0) throw new RtcException(code);
}
public void OnJoinChannelSuccess(RtcConnection connection, int elapsed) { }
public void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed) { }
public void OnUserOffline(RtcConnection connection, uint remoteUid, UserOfflineReasonType reason) { }
public void OnTokenPrivilegeWillExpire(string token) => engine.RenewToken(FetchFreshToken());
public void OnError(int err, string msg) => Console.Error.WriteLine($"rtc {err}: {msg}");
}Publishing and subscribing
engine.MuteLocalAudioStream(true);
engine.MuteLocalVideoStream(true);
engine.EnableLocalVideo(false);
engine.UpdateChannelMediaOptions(options);Screen sharing: GetScreenCaptureSources → StartScreenCaptureByWindowId / StartScreenCaptureByScreenRect; in WPF the remote picture is usually drawn into an Image/D3DImage through the render callback the plugin provides.
Events
IRtcEngineEventHandler: OnJoinChannelSuccess, OnUserJoined, OnUserOffline, OnFirstRemoteVideoDecoded, OnTokenPrivilegeWillExpire, OnError, OnConnectionStateChanged.
Error handling
- Synchronous methods return
int;0means success and a negative value is an Agora error number; - Asynchronous errors arrive through
OnError; - Unimplemented capabilities return
-4(ERR_NOT_SUPPORTED).
Troubleshooting
| Symptom | Cause | Handling |
|---|---|---|
DllNotFoundException | The native library was not copied with the package | Add runtimes/win-x64/native to the output |
| Updating the UI inside a callback throws | Cross-thread access | Use Dispatcher.Invoke |
| Capture fails | System privacy settings | Allow desktop apps to use the camera/microphone in Settings |
| A 64-bit process loads a 32-bit library | Platform target mismatch | Use x64 everywhere |
| Token expiry goes unnoticed | OnTokenPrivilegeWillExpire is not handled | Renew the token and call RenewToken |
Next steps
- Full interfaces and overloads: API reference for this platform
- Error codes and troubleshooting: Error code table, FAQ
- Issue tokens on your server: Token authentication
Platform information
| Item | value |
|---|---|
| Platform | C#(.NET) |
| Language | C# |
| SDK package | Nimeet.Rtc |
| Interface version | unknown |
| Compatible Agora API | Agora csharp API |
The public interfaces are aligned with the Agora csharp API; installation and runtime requirements are listed under Prerequisites above.
Availability
This platform's SDK: Generally available. The examples use the public API; runtime capability follows the published SDK package.
join-channel flow
The method names, parameter types and return values match the API reference for the same platform. Where a method has several overloads, the most common one is shown here; see the API reference for all overloads.
| Step | Interface | Method | Overload count |
|---|---|---|---|
| Join a channel | __unattributed__ | JoinChannel | 1 |
| Leave a channel | __unattributed__ | LeaveChannel | 1 |
| subscribe to remote media | __unattributed__ | MuteRemoteAudioStream | 1 |
| switch roles | __unattributed__ | SetClientRole | 1 |
| bind the local video | __unattributed__ | SetupLocalVideo | 1 |
| enable video and local preview | __unattributed__ | StartPreview | 1 |
| Create instance / initialize | ILocalSpatialAudioEngine | Initialize | 1 |
| Renew the Token | IRtcEngine | RenewToken | 1 |
| Channel scenarios | IRtcEngine | SetChannelProfile | 1 |
JoinChannel(token: string, channelId: string, info?: string, uid?: uint): int
LeaveChannel(): int
MuteRemoteAudioStream(uid: uint, mute: bool): int
SetClientRole(role: CLIENT_ROLE_TYPE): int
SetupLocalVideo(canvas: VideoCanvas): int
StartPreview(): int
Initialize(): int
RenewToken(token: string): int
SetChannelProfile(profile: CHANNEL_PROFILE_TYPE): intEvents and callbacks
| Interface | event name | listener parameters |
|---|---|---|
IMediaPlayerSourceObserver | OnPlayerCacheStats | public virtual void OnPlayerCacheStats(CacheStatistics stats) { } |
IMediaPlayerSourceObserver | OnPlayerPlaybackStats | public virtual void OnPlayerPlaybackStats(PlayerPlaybackStats stats) { } |
IRtcEngineEventHandler | OnExtensionErrorWithContext | public virtual void OnExtensionErrorWithContext(ExtensionContext context, int error, string message){} |
IRtcEngineEventHandler | OnExtensionEventWithContext | public virtual void OnExtensionEventWithContext(ExtensionContext context, string key, string value){} |
IRtcEngineEventHandler | OnExtensionStartedWithContext | public virtual void OnExtensionEventWithContext(ExtensionContext context, string key, string value){ } |
IRtcEngineEventHandler | OnExtensionStoppedWithContext | public virtual void OnExtensionStoppedWithContext(ExtensionContext context){ } |
Error codes
| Constant | value |
|---|---|
ERR_ABORTED | 20 |
ERR_ADM_GENERAL_ERROR | 1005 |
ERR_ADM_INIT_PLAYOUT | 1008 |
ERR_ADM_INIT_RECORDING | 1011 |
ERR_ADM_START_PLAYOUT | 1009 |
ERR_ADM_START_RECORDING | 1012 |
ERR_ADM_STOP_PLAYOUT | 1010 |
ERR_ADM_STOP_RECORDING | 1013 |
ERR_ALREADY_IN_USE | 19 |
ERR_BITRATE_LIMIT | 115 |
ERR_BUFFER_TOO_SMALL | 6 |
ERR_CLIENT_IS_BANNED_BY_SERVER | 123 |
ERR_CONNECTION_INTERRUPTED | 111 |
ERR_CONNECTION_LOST | 112 |
ERR_DATASTREAM_DECRYPTION_FAILED | 122 |
ERR_DECRYPTION_FAILED | 120 |
ERR_ENCRYPTED_STREAM_NOT_ALLOWED_PUBLISH | 130 |
ERR_FAILED | 1 |
ERR_INIT_NET_ENGINE | 21 |
ERR_INVALID_APP_ID | 101 |
ERR_INVALID_ARGUMENT | 2 |
ERR_INVALID_CHANNEL_NAME | 102 |
ERR_INVALID_STATE | 8 |
ERR_INVALID_TOKEN | 110 |
ERR_INVALID_USER_ACCOUNT | 134 |
ERR_INVALID_USER_ID | 121 |
ERR_JOIN_CHANNEL_REJECTED | 17 |
ERR_LEAVE_CHANNEL_REJECTED | 18 |
ERR_LOAD_MEDIA_ENGINE | 1001 |
ERR_NOT_INITIALIZED | 7 |
ERR_NOT_IN_CHANNEL | 113 |
ERR_NOT_READY | 3 |
ERR_NOT_SUPPORTED | 4 |
ERR_NO_PERMISSION | 9 |
ERR_NO_SERVER_RESOURCES | 103 |
ERR_OK | 0 |
ERR_REFUSED | 5 |
ERR_RESOURCE_LIMITED | 22 |
ERR_SET_CLIENT_ROLE_NOT_AUTHORIZED | 119 |
ERR_SIZE_TOO_LARGE | 114 |
ERR_STREAM_MESSAGE_TIMEOUT | 117 |
ERR_TIMEDOUT | 10 |
ERR_TOKEN_EXPIRED | 109 |
ERR_TOO_MANY_DATA_STREAMS | 116 |
ERR_VDM_CAMERA_NOT_AUTHORIZED | 1501 |
IRtcEngine | null |
the platform REST layer uses REST error codes;the SDK layer maps connection/authentication failures to Agora error numbers, for the mapping table see SDK error identifiers per platform。