C#(.NET) 快速开始与功能指南
C#(.NET):前置条件、安装、Token、加入频道、发布订阅、事件、错误处理与排障;接口名与签名在构建时取自公开 SDK 接口定义。
C#(.NET)端是 RtcEngine + IRtcEngineEventHandler 形状,与 Unity 端同构但面向桌面 .NET(WPF / WinForms / 控制台服务)。
前置条件
- .NET 8 SDK(
net8.0),Windows 10 1809+(当前声明对齐基准来自 Windows 端 C# 封装)。 - 系统摄像头/麦克风权限。
- 已拿到
appId与 Token 服务(见 控制台开通服务与获取凭证)。
安装
<!-- 包坐标以发布版本为准 -->
<PackageReference Include="Nimeet.Rtc" Version="0.1.0" />获取 Token
Token 由你的服务端签发(POST /v1/tokens);桌面客户端只接收字符串,不要把 appCustomerSecret 写进配置文件。
var response = await httpClient.GetFromJsonAsync<TokenResponse>("/api/rtc-token?channel=weekly-sync&uid=10001");
engine.JoinChannel(response.RtcToken, "weekly-sync", 10001, options);加入频道
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}");
}发布与订阅
engine.MuteLocalAudioStream(true);
engine.MuteLocalVideoStream(true);
engine.EnableLocalVideo(false);
engine.UpdateChannelMediaOptions(options);屏幕共享:GetScreenCaptureSources → StartScreenCaptureByWindowId / StartScreenCaptureByScreenRect; WPF 里通常把远端画面画到 Image/D3DImage,用插件提供的渲染回调。
事件
IRtcEngineEventHandler:OnJoinChannelSuccess、OnUserJoined、OnUserOffline、OnFirstRemoteVideoDecoded、 OnTokenPrivilegeWillExpire、OnError、OnConnectionStateChanged。
错误处理
- 同步方法返回
int,0成功,负值为声网错误号; - 异步错误走
OnError; - 未实现能力返回
-4(ERR_NOT_SUPPORTED)。
排障
| 现象 | 原因 | 处理 |
|---|---|---|
DllNotFoundException | 原生库未随包复制 | 把 runtimes/win-x64/native 加进输出 |
| 回调里更新 UI 抛异常 | 跨线程访问 | 用 Dispatcher.Invoke |
| 采集失败 | 系统隐私设置 | 设置里允许桌面应用访问摄像头/麦克风 |
| 64 位进程加载 32 位库 | 平台目标不匹配 | 统一 x64 |
| Token 过期后无提示 | 未处理 OnTokenPrivilegeWillExpire | 续期并 RenewToken |
下一步
平台信息
| 项 | 值 |
|---|---|
| 平台 | C#(.NET) |
| 语言 | C# |
| SDK 包 | Nimeet.Rtc |
| 接口版本 | unknown |
| 兼容参考 | 声网 csharp 端 API |
本端公开接口与声网 csharp 端 API 对齐;安装与运行要求见上面前置条件。
可用性
该端 SDK:正式可用。本页代码片段使用公开 API;运行时的能力边界以实际发布的 SDK 包为准。
加入频道链路
下列方法名、参数类型与返回值与同端 API 参考一致。一个平台若有多个重载,这里展示最常用的那一个;完整重载见同端 API 参考页。
| 步骤 | 接口 | 方法 | 重载数 |
|---|---|---|---|
| 加入频道 | __unattributed__ | JoinChannel | 1 |
| 离开频道 | __unattributed__ | LeaveChannel | 1 |
| 订阅远端媒体 | __unattributed__ | MuteRemoteAudioStream | 1 |
| 切换角色 | __unattributed__ | SetClientRole | 1 |
| 绑定本地画面 | __unattributed__ | SetupLocalVideo | 1 |
| 开启视频与本地预览 | __unattributed__ | StartPreview | 1 |
| 创建实例 / 初始化 | ILocalSpatialAudioEngine | Initialize | 1 |
| 续期 Token | IRtcEngine | RenewToken | 1 |
| 频道场景 | 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): int事件与回调
| 接口 | 事件名 | 监听器参数 |
|---|---|---|
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){ } |
错误码
| 常量 | 值 |
|---|---|
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 |
平台 REST 层用 REST 错误码;SDK 层把连接/鉴权失败映射成声网错误号,映射表见 各端 SDK 错误标识。