You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何收发RTCSessionDescription实现Unity WebRTC信令

Unity C# 实现WebRTC RTCSessionDescription 收发方案

以下流程基于Unity官方com.unity.webrtc稳定版实现,信令传输层不做限制,你可以用WebSocket、TCP、HTTP轮询任意方式传SDP内容,核心协商逻辑和传输通道无关。


前置准备

先通过Package Manager导入官方WebRTC包,不要用第三方维护的分叉版本,避免API不兼容问题。

Offer 发起方 SDP 生成与发送流程

  • 初始化Peer连接,配置ICE服务器参数
// STUN服务器可自行替换,示例用公共STUN
RTCConfiguration config = default;
config.iceServers = new RTCIceServer[] {
    new RTCIceServer { urls = new string[] { "stun:stun.l.google.com:19302" } }
};
RTCPeerConnection peer = new RTCPeerConnection(ref config);
// 提前绑定ICE候选收集、媒体轨道、连接状态变更等回调
  • 添加本地要传输的媒体轨道(音视频、数据通道都算),未添加任何轨道时生成的SDP不包含媒体协商信息,无法建立媒体连接
// 示例:添加本地摄像头视频轨道
WebCamTexture cam = new WebCamTexture();
cam.Play();
VideoStreamTrack videoTrack = new VideoStreamTrack("main_cam", cam);
peer.AddTrack(videoTrack);
  • 生成Offer类型SDP,设置为本地描述
// 注意所有WebRTC异步操作要等执行完成再走下一步
RTCSessionDescriptionAsyncOperation createOfferOp = peer.CreateOffer();
yield return createOfferOp;
if (createOfferOp.IsError) {
    Debug.LogError($"Offer生成失败:{createOfferOp.Error.message}");
    yield break;
}
RTCSessionDescription offerSdp = createOfferOp.Desc;
RTCSetSessionDescriptionAsyncOperation setLocalOp = peer.SetLocalDescription(ref offerSdp);
yield return setLocalOp;
if (setLocalOp.IsError) {
    Debug.LogError($"本地SDP设置失败:{setLocalOp.Error.message}");
    yield break;
}
  • 序列化SDP通过信令通道发送给对端
    注意:必须等SetLocalDescription执行完成再发送SDP,此时ICE候选信息才会写入SDP内容,提前发送会导致连接失败
// 序列化时只需要传SDP类型和SDP内容字符串即可
SdpPayload payload = new SdpPayload {
    type = offerSdp.type.ToString().ToLower(),
    sdp = offerSdp.sdp
};
string sendStr = JsonUtility.ToJson(payload);
// 替换为你自己的信令发送逻辑
SendSignalingMessage(sendStr);

Answer 接收方 SDP 接收与回发流程

  • 同Offer方,先初始化RTCPeerConnection,配置相同的ICE参数,添加本地需要的媒体轨道
  • 监听信令通道消息,收到Offer类型SDP后反序列化,设置为远端描述
// 信令消息接收回调
void OnSignalingReceive(string rawMsg) {
    SdpPayload payload = JsonUtility.FromJson<SdpPayload>(rawMsg);
    if (payload.type == "offer") {
        RTCSessionDescription remoteOffer = new RTCSessionDescription {
            type = RTCSdpType.Offer,
            sdp = payload.sdp
        };
        RTCSetSessionDescriptionAsyncOperation setRemoteOp = peer.SetRemoteDescription(ref remoteOffer);
        StartCoroutine(HandleRemoteOffer(setRemoteOp));
    }
}

// SDP序列化/反序列化用结构体
[Serializable]
public struct SdpPayload {
    public string type;
    public string sdp;
}
  • 等远端Offer设置完成后,生成Answer类型SDP,设置为本地描述后发回Offer方
IEnumerator HandleRemoteOffer(RTCSetSessionDescriptionAsyncOperation op) {
    yield return op;
    if (op.IsError) {
        Debug.LogError($"远端Offer设置失败:{op.Error.message}");
        yield break;
    }
    // 生成Answer SDP
    RTCSessionDescriptionAsyncOperation createAnswerOp = peer.CreateAnswer();
    yield return createAnswerOp;
    if (createAnswerOp.IsError) {
        Debug.LogError($"Answer生成失败:{createAnswerOp.Error.message}");
        yield break;
    }
    RTCSessionDescription answerSdp = createAnswerOp.Desc;
    RTCSetSessionDescriptionAsyncOperation setLocalOp = peer.SetLocalDescription(ref answerSdp);
    yield return setLocalOp;
    if (setLocalOp.IsError) {
        Debug.LogError($"本地Answer设置失败:{setLocalOp.Error.message}");
        yield break;
    }
    // 序列化Answer发回给Offer方
    SdpPayload answerPayload = new SdpPayload {
        type = answerSdp.type.ToString().ToLower(),
        sdp = answerSdp.sdp
    };
    SendSignalingMessage(JsonUtility.ToJson(answerPayload));
}
  • Offer方收到Answer类型的SDP消息后,反序列化设置为自己的远端描述,SDP协商流程即完成
// Offer方的信令消息判断逻辑
if (payload.type == "answer") {
    RTCSessionDescription remoteAnswer = new RTCSessionDescription {
        type = RTCSdpType.Answer,
        sdp = payload.sdp
    };
    RTCSetSessionDescriptionAsyncOperation setRemoteOp = peer.SetRemoteDescription(ref remoteAnswer);
    yield return setRemoteOp;
    // 后续等待ICE候选交换完成、连接状态变更为Connected即可
}

常见踩坑

  • 所有RTCPeerConnection相关API必须在Unity主线程调用,如果信令层(比如WebSocket)在子线程收消息,要先把消息投递到主线程再处理,否则会出现内存报错、状态异常
  • SDP字符串自带换行符,序列化/反序列化时不要做特殊字符过滤、错误转义,否则会导致SDP解析失败
  • 所有CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription都是异步非阻塞操作,必须等返回的AsyncOperation执行完成再走后续逻辑,不要直接同步取结果
  • WebRTC包版本尽量用2.4.0以上的正式版,2.0以下版本存在大量SDP协商、ICE收集的已知bug

内容的提问来源于stack exchange,提问作者user19404661

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:33:08