在官方库函数中,进入handle_signaling_message后开始解析msg消息结构体中的type,解析后会有三种type == "request",type == "answer",type == "candidate"
当对端发送 request
本端会先做四件事,这边会建立PeerConnection,创建本端DataChannel(createDataChannel(label))、添加视频轨(make_video_track(pc)),把其他的回调注册(onGatheringStateChange,onStateChange,nLocalCandidate)
后面执行c->setLocalDescription();
1. 本端 SDP
- 库根据当前
PeerConnection状态(已addTrack的视频轨、createDataChannel的 SCTP 等)生成本地 SDP,并设为 local description。 - 信令状态会从例如 stable → have-local-offer 一类变化(具体以
libdatachannel为准)。
2. ICE 收集与 candidate
- ICE gathering 会进入
InProgress,向 STUN 等发绑定请求、枚举 host / srflx 等候选。 - 每拿到一个候选,会调注册的
onLocalCandidate→emit_signaling_json,日志输出为``type=candidate的 TX。 - 收集结束状态改变
GatheringState::Complete,触发onGatheringStateChange→ 取localDescription()→emit_signaling_json日志输出type=offer+ 整段sdp
3. 连接状态
onStateChange被调用,例如进入Connecting(PC state=1对应这里)- 等对端
answer且本端setRemoteDescription成功后,才会继续到Connected(state=2)。
4. 建立连接时刻
setLocalDescription()本身不会完成对端的setRemoteDescription,也不会立刻刻Connected;answer 要等信令从对端来。- DataChannel
onOpen、videotrack->onOpen一般在 SDP/ICE/DTLS 更往后才触发。
5. 代码的对应关系
setLocalDescription() ------> 告诉库「按当前视频轨 && DC 配置 开始出本端 SDP 并跑 ICE」;
之后由库回调 onLocalCandidate / onGatheringStateChange 去 emit_signaling_json,把 candidate 和 offer 发到信令通道。
/创建本端 DataChannel,代码写法分析
std::shared_ptr<rtc::DataChannel> local_dc; //创建本端 DataChannel
if (cfg.enable_datachannel) {
const std::string label = cfg.data_channel_label.empty() ? std::string("app") : cfg.data_channel_label;
local_dc = pc->createDataChannel(label);
attach_dc_handlers(local_dc, "local");
}
-
pc->createDataChannel(label)调用
PeerConnection的成员函数,返回类型是std::shared_ptr<rtc::DataChannel>(库里声明好的) -
local_dc事先声明成 同一种类型 的变量:
std::shared_ptr<rtc::DataChannel> local_dc;一开始是空指针(不指向任何
DataChannel)。 -
local_dc = ...这是
shared_ptr的赋值:把函数返回的那个shared_ptr拷给local_dc,local_dc和返回值指向同一条DataChannel对象,引用计数按shared_ptr规则增加。
createDataChannel 返回 shared_ptr<DataChannel>,你用赋值运算符把它保存到 local_dc 里,后面就用 local_dc 操作这条通道。
onGatheringStateChange指针写法分析:
pc->onGatheringStateChange([wpc = std::weak_ptr<rtc::PeerConnection>(pc), peer_id](rtc::PeerConnection::GatheringState st) {
if (st != rtc::PeerConnection::GatheringState::Complete) {
return;
}
auto locked = wpc.lock();
if (!locked) {
return;
}
auto desc = locked->localDescription();
if (!desc) {
return;
}
json out = {{"id", peer_id}, {"type", desc->typeString()}, {"sdp", std::string(*desc)}};
emit_signaling_json(out);
log_info("[webrtc_ldc] sent local SDP type={}", desc->typeString());
});
pc:当前这次request里新建的PeerConnection的shared_ptr,指向真实对象。std::weak_ptr<rtc::PeerConnection>(pc):用pc拷贝构造一个weak_ptr,让wpc和pc指向同一块PeerConnection,但wpc不计入引用计数。- 必须传
pc:没有shared_ptr,weak_ptr就不知道要弱引用谁;不能凭空weak_ptr<T>()就绑到正确对象上。
之后回调里 wpc.lock(),等价于:"当初注册时关心的那个 PeerConnection,现在还有没有活着的shared_ptr管着它?" 有就临时拿一个shared_ptr用一下,没有就说明已经关了。