webrtc源码走读(二)应用层如何使用WebRTC API实现功能

webrtc源码走读(二)应用层如何使用WebRTC API实现功能

1、WebRTC 层级定位与核心功能

WebRTC为应用层提供了四个核心API,这些API是构建实时通信应用的基础:

API功能关键作用浏览器兼容性
getUserMedia获取本地音视频流访问摄像头、麦克风等硬件设备Chrome, Firefox, Edge, Safari
RTCPeerConnection建立点对点连接管理连接、交换媒体数据、处理ICE候选Chrome, Firefox, Edge, Safari
RTCDataChannel传输任意数据实现文本、文件等非媒体数据传输Chrome, Firefox, Edge
getDisplayMedia获取屏幕共享流实现屏幕共享功能Chrome, Firefox

1.1 WebRTC API的层级定位

WebRTC API位于API层,是应用层与核心引擎层之间的桥梁。应用层通过调用这些API,无需了解底层实现细节,即可实现复杂的实时通信功能。

1.2 WebRTC API的工作原理

WebRTC API本质上是JavaScript接口,它封装了底层WebRTC核心引擎的功能。当应用层调用这些API时,WebRTC引擎会执行以下操作:

  1. 通过系统接口层访问硬件设备
  2. 与核心引擎层交互,处理媒体流和网络连接
  3. 通过信令机制与其他端点交换连接信息

1.3. API层的核心功能与作用

核心功能定位

功能说明重要性
标准化接口提供统一的WebRTC API,使开发者无需关心底层实现⭐⭐⭐⭐⭐
复杂性封装将ICE候选收集、SDP协商、媒体处理等复杂逻辑封装⭐⭐⭐⭐
生命周期管理管理RTCPeerConnection等对象的创建、使用和销毁⭐⭐⭐⭐
跨平台支持确保不同浏览器提供一致的API体验⭐⭐⭐
错误处理提供标准化的错误处理机制⭐⭐⭐

2、API层关键源码应用层开发的基本流程

WebRTC应用开发的完整流程可以概括为"获取媒体→建立连接→交换信令→处理媒体→数据传输"五个核心步骤:

应用层 │ ├── 1. 获取本地媒体流 (getUserMedia) │ ├── 2. 创建RTCPeerConnection实例 (RTCPeerConnection) │ ├── 3. 信令交换 (SDP与ICE候选) │ ├── 3.1 创建Offer │ ├── 3.2 发送Offer给对方 │ ├── 3.3 接收Answer │ └── 3.4 交换ICE候选 │ ├── 4. 处理媒体流 (ontrack事件) │ └── 5. 数据传输 (RTCDataChannel) 

2.1 源码结构与目录组织

WebRTC源码中API层主要位于api/目录下:

api/ ├── peerconnectioninterface.h ├── peerconnectionfactoryinterface.h ├── mediastreaminterface.h ├── datachannelinterface.h ├── sdp.h ├── ... pc/ ├── peerconnectioninterface.cc ├── peerconnectionfactory.cc ├── ... 

2.2 关键源码文件解析

2.2.1 peerconnectioninterface.h - 核心接口
// api/peerconnectioninterface.h// RTCPeerConnection的核心接口定义classRTCPeerConnectionInterface{public:// 创建offervirtualvoidCreateOffer( CreateSessionDescriptionObserver* observer,const RTCOfferOptions* options)=0;// 创建answervirtualvoidCreateAnswer( CreateSessionDescriptionObserver* observer,const RTCOfferOptions* options)=0;// 设置远程描述virtualvoidSetRemoteDescription( SetSessionDescriptionObserver* observer,const SessionDescriptionInterface* desc)=0;// 设置本地描述virtualvoidSetLocalDescription( SetSessionDescriptionObserver* observer,const SessionDescriptionInterface* desc)=0;// 添加媒体轨道virtualvoidAddTrack(const rtc::scoped_refptr<MediaStreamTrackInterface>& track,const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams)=0;// 添加ICE候选virtualvoidAddIceCandidate(const IceCandidateInterface* candidate)=0;// 监听事件virtualvoidOnTrack(const rtc::scoped_refptr<TrackEvent>& event)=0;// 获取连接状态virtual std::string iceConnectionState()const=0;virtual std::string connectionState()const=0;// ... 其他方法};
  • 该接口定义了WebRTC的核心功能,是API层的"心脏"
  • 使用纯虚函数定义,由实现类具体实现
  • CreateSessionDescriptionObserver等接口用于处理异步操作
  • 所有方法都设计为异步,避免阻塞UI线程
2.2.2 peerconnectionfactoryinterface.h - 工厂接口
// api/peerconnectionfactoryinterface.h// PeerConnectionFactory的接口定义classPeerConnectionFactoryInterface{public:// 创建PeerConnection对象virtual rtc::scoped_refptr<RTCPeerConnectionInterface>CreatePeerConnection(const PeerConnectionInterface::Options& options,const PeerConnectionInterface::RTCConfiguration& config,const std::vector<rtc::scoped_refptr<PeerConnectionInterface::IceServer>>& ice_servers)=0;// 创建DataChannelvirtual rtc::scoped_refptr<RTCDataChannelInterface>CreateDataChannel(const std::string& label,const DataChannelInterface::Init& config)=0;// 创建MediaStreamvirtual rtc::scoped_refptr<MediaStreamInterface>CreateLocalMediaStream(const std::string& label)=0;// 创建MediaStreamTrackvirtual rtc::scoped_refptr<MediaStreamTrackInterface>CreateVideoTrack(const std::string& id, VideoTrackSourceInterface* source)=0;// ... 其他方法};
  • 工厂接口负责创建WebRTC核心对象
  • CreatePeerConnection是创建RTCPeerConnection的入口
  • 使用scoped_refptr管理对象生命周期,避免内存泄漏
  • RTCConfiguration用于配置ICE服务器等连接参数
2.2.3 mediastreaminterface.h - 媒体流接口
// api/mediastreaminterface.h// MediaStream API的核心接口classMediaStreamInterface{public:// 获取媒体流IDvirtual std::string id()const=0;// 获取媒体轨道列表virtualconst std::vector<rtc::scoped_refptr<MediaStreamTrackInterface>>&GetAudioTracks()const=0;virtualconst std::vector<rtc::scoped_refptr<MediaStreamTrackInterface>>&GetVideoTracks()const=0;// 添加媒体轨道virtualvoidAddTrack(const rtc::scoped_refptr<MediaStreamTrackInterface>& track)=0;// 移除媒体轨道virtualvoidRemoveTrack(const rtc::scoped_refptr<MediaStreamTrackInterface>& track)=0;};// MediaStreamTrack的核心接口classMediaStreamTrackInterface{public:// 获取轨道IDvirtual std::string id()const=0;// 获取轨道类型virtual std::string kind()const=0;// 获取轨道状态virtual std::string state()const=0;// 获取轨道的媒体源virtual MediaStreamSourceInterface*GetSource()const=0;};
  • 提供了媒体流和媒体轨道的标准接口
  • getUserMedia() API最终会调用这些接口
  • MediaStreamTrack是媒体流的基本单元,可以是音频或视频
2.2.4 sdp.h - SDP处理接口
// api/sdp.h// SDP处理核心接口classSessionDescriptionInterface{public:// 获取SDP类型virtual SdpType type()const=0;// 获取SDP内容virtual std::string ToString()const=0;// 获取SDP的媒体描述virtualconst std::vector<MediaDescriptionInterface*>&GetMediaDescriptions()const=0;};// SDP解析器接口classSdpParseError{public:// 错误类型enumType{ kNoError, kInvalidFormat, kInvalidMLine, kInvalidAttribute,// ... 其他错误类型};};// SDP解析器classSdpParse{public:// 解析SDP字符串static rtc::scoped_refptr<SessionDescriptionInterface>ParseSdp(const std::string& sdp, SdpParseError* error);// 生成SDP字符串static std::string GenerateSdp(const SessionDescriptionInterface* desc);};
  • SDP(Session Description Protocol)是WebRTC信令交换的核心
  • SdpParse类负责SDP的解析和生成
  • SessionDescriptionInterface是SDP的抽象表示
2.2.5 peerconnectioninterface.cc - 实现层
// pc/peerconnectioninterface.cc// RTCPeerConnection的实现classPeerConnection:publicRTCPeerConnectionInterface{public:PeerConnection(const PeerConnectionInterface::Options& options,const PeerConnectionInterface::RTCConfiguration& config,const std::vector<rtc::scoped_refptr<IceServer>>& ice_servers){// 初始化内部状态Initialize(options, config, ice_servers);}// 创建offervoidCreateOffer( CreateSessionDescriptionObserver* observer,const RTCOfferOptions* options)override{// 1. 创建SDP Offer SessionDescriptionInterface* offer =CreateOfferInternal(options);// 2. 设置本地描述if(offer){SetLocalDescriptionInternal(offer);}// 3. 通过Observer返回结果if(observer){ observer->OnSuccess(offer);}}// 设置本地描述voidSetLocalDescription( SetSessionDescriptionObserver* observer,const SessionDescriptionInterface* desc)override{// 1. 更新本地描述状态 local_desc_ = desc;// 2. 生成ICE候选GenerateIceCandidates();// 3. 通知核心引擎 core_engine_->SetLocalDescription(desc);// 4. 通过Observer通知应用层if(observer){ observer->OnSuccess();}}// 添加ICE候选voidAddIceCandidate(const IceCandidateInterface* candidate)override{// 1. 添加候选到内部列表 ice_candidates_.push_back(candidate);// 2. 通知核心引擎 core_engine_->AddIceCandidate(candidate);}// ... 其他方法实现private:// 内部状态 SessionDescriptionInterface* local_desc_ =nullptr; SessionDescriptionInterface* remote_desc_ =nullptr; std::vector<rtc::scoped_refptr<IceCandidateInterface>> ice_candidates_;// 核心引擎实例 std::unique_ptr<CoreEngine> core_engine_;// 初始化内部状态voidInitialize(const PeerConnectionInterface::Options& options,const PeerConnectionInterface::RTCConfiguration& config,const std::vector<rtc::scoped_refptr<IceServer>>& ice_servers){// 1. 创建核心引擎 core_engine_ = std::make_unique<CoreEngine>(config, ice_servers);// 2. 设置内部状态// ...}};
  • PeerConnection类实现了RTCPeerConnectionInterface接口
  • 所有API方法都调用内部core_engine_进行实际操作
  • 使用scoped_refptr管理对象生命周期
  • 通过Observer模式处理异步操作
2.2.6 peerconnectionfactory.cc - 工厂实现
// pc/peerconnectionfactory.cc// PeerConnectionFactory的实现classPeerConnectionFactory:publicPeerConnectionFactoryInterface{public:// 创建PeerConnection rtc::scoped_refptr<RTCPeerConnectionInterface>CreatePeerConnection(const PeerConnectionInterface::Options& options,const PeerConnectionInterface::RTCConfiguration& config,const std::vector<rtc::scoped_refptr<PeerConnectionInterface::IceServer>>& ice_servers)override{// 1. 创建PeerConnection对象 PeerConnection* pc =newPeerConnection(options, config, ice_servers);// 2. 初始化内部状态 pc->Initialize();// 3. 返回封装对象return rtc::scoped_refptr<RTCPeerConnectionInterface>(pc);}// 创建DataChannel rtc::scoped_refptr<RTCDataChannelInterface>CreateDataChannel(const std::string& label,const DataChannelInterface::Init& config)override{// 实现DataChannel创建逻辑// ...}// ... 其他方法实现};
  • 工厂方法负责创建和初始化PeerConnection对象
  • 使用scoped_refptr确保对象生命周期安全
  • 实现了PeerConnectionFactoryInterface接口

3. API层工作流程详解

3.1 API层交互流程

核心引擎层 (C++)API层 (WebRTC API)应用层 (JavaScript)核心引擎层 (C++)API层 (WebRTC API)应用层 (JavaScript)1. new RTCPeerConnection()2. 调用PeerConnectionFactory::CreatePeerConnection()3. 创建PeerConnection对象4. 返回PeerConnection实例5. 返回RTCPeerConnection实例6. getUserMedia()7. 调用MediaStreamInterface实现8. 获取媒体设备9. 返回媒体流10. 返回MediaStream对象11. createOffer()12. 调用PeerConnection::CreateOffer()13. 生成SDP Offer14. 返回SDP Offer15. 返回Offer SDP16. setLocalDescription()17. 调用PeerConnection::SetLocalDescription()18. 更新连接状态19. 确认设置20. 确认设置21. addTrack()22. 调用PeerConnection::AddTrack()23. 添加媒体轨道24. 确认添加25. 确认添加26. onicecandidate事件处理27. 监听ICE候选28. 收集ICE候选29. 触发onicecandidate事件

3.2 详细工作流程

3.2.1 创建RTCPeerConnection

JavaScript应用层代码

const pc =newRTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});

API层工作流程

  1. 应用层调用new RTCPeerConnection()
  2. API层调用PeerConnectionFactory::CreatePeerConnection()
  3. 工厂创建PeerConnection对象
  4. 初始化内部状态(包括ICE服务器配置)
  5. 返回封装的RTCPeerConnectionInterface对象

CoreAPIApplicationCoreAPIApplicationnew RTCPeerConnection()创建PeerConnectionFactoryCreatePeerConnection()初始化PeerConnection对象返回PeerConnection对象返回RTCPeerConnection实例

关键源码

// pc/peerconnectionfactory.cc rtc::scoped_refptr<RTCPeerConnectionInterface>PeerConnectionFactory::CreatePeerConnection(const PeerConnectionInterface::Options& options,const PeerConnectionInterface::RTCConfiguration& config,const std::vector<rtc::scoped_refptr<PeerConnectionInterface::IceServer>>& ice_servers){// 创建PeerConnection对象 PeerConnection* pc =newPeerConnection(options, config, ice_servers);// 初始化内部状态 pc->Initialize();// 返回封装对象return rtc::scoped_refptr<RTCPeerConnectionInterface>(pc);}
3.2.2 获取媒体流

JavaScript应用层代码

const stream =await navigator.mediaDevices.getUserMedia({video:true,audio:true});

API层工作流程

  1. 应用层调用getUserMedia()
  2. API层调用MediaStreamInterface实现
  3. 调用底层C++ API获取媒体设备
  4. 返回媒体流对象

关键源码

// api/mediastreaminterface.hclassMediaStreamInterface{public:static rtc::scoped_refptr<MediaStreamInterface>CreateLocalMediaStream(const std::string& label);};// 实现部分 rtc::scoped_refptr<MediaStreamInterface>MediaStreamInterface::CreateLocalMediaStream(const std::string& label){// 调用底层API创建媒体流returnCreateLocalMediaStreamInternal(label);}
3.2.3 SDP协商过程

JavaScript应用层代码

const offer =await pc.createOffer();await pc.setLocalDescription(offer);// 通过信令服务器发送offer signalingServer.send({type:"offer",sdp: offer.sdp});

API层工作流程

  1. 应用层调用createOffer()
  2. API层调用PeerConnection::CreateOffer()
  3. 内部调用CreateOfferInternal()生成SDP Offer
  4. 调用SetLocalDescriptionInternal()设置本地描述
  5. 通过Observer返回结果

CoreAPIApplicationCoreAPIApplicationcreateOffer()CreateOffer()生成SDP Offer返回SDP Offer返回OffersetLocalDescription()SetLocalDescription()更新连接状态确认设置确认设置

关键源码

// pc/peerconnectioninterface.ccvoidPeerConnection::CreateOffer( CreateSessionDescriptionObserver* observer,const RTCOfferOptions* options){// 1. 创建SDP Offer SessionDescriptionInterface* offer =CreateOfferInternal(options);// 2. 设置本地描述if(offer){SetLocalDescriptionInternal(offer);}// 3. 通过Observer返回结果if(observer){ observer->OnSuccess(offer);}} SessionDescriptionInterface*PeerConnection::CreateOfferInternal(const RTCOfferOptions* options){// 实际SDP生成逻辑// 1. 获取当前媒体配置// 2. 生成SDP Offer// 3. 返回SessionDescriptionInterfacereturnnewSessionDescription(offer_sdp);}voidPeerConnection::SetLocalDescriptionInternal( SessionDescriptionInterface* desc){// 1. 更新本地描述状态 local_desc_ = desc;// 2. 生成ICE候选GenerateIceCandidates();// 3. 通知核心引擎 core_engine_->SetLocalDescription(desc);}
3.2.4 ICE候选交换

JavaScript应用层代码

pc.onicecandidate=event=>{if(event.candidate){ signalingServer.send({type:"candidate",candidate: event.candidate});}};

API层工作流程

  1. 应用层监听onicecandidate事件
  2. API层在内部收集ICE候选
  3. 通过onicecandidate事件通知应用层
  4. 应用层将候选发送到信令服务器

CoreAPIApplicationCoreAPIApplicationonicecandidate事件监听监听ICE候选收集ICE候选触发onicecandidate事件触发onicecandidate事件发送ICE候选通过信令服务器发送候选接收ICE候选AddIceCandidate()添加候选

关键源码

// pc/peerconnectioninterface.ccvoidPeerConnection::GenerateIceCandidates(){// 1. 通过核心引擎收集候选 std::vector<IceCandidateInterface*> candidates; core_engine_->GetIceCandidates(&candidates);// 2. 通知应用层for(auto& candidate : candidates){OnIceCandidate(candidate);}}voidPeerConnection::OnIceCandidate(const IceCandidateInterface* candidate){// 触发onicecandidate事件if(ice_candidate_observer_){ ice_candidate_observer_->OnIceCandidate(candidate);}}

4、信令机制

4.1、信令机制的核心作用与原理

 信令模块是WebRTC核心引擎层的关键组成部分,负责处理WebRTC会话的建立、协商和管理。信令模块的主要作用是交换SDP(Session Description Protocol)描述和ICE候选地址,以建立P2P连接。 

​ WebRTC本身不提供信令机制,需要开发者实现自己的信令服务器。 虽然WebRTC核心源码本身不包含完整的信令服务器实现,但这是设计层面的刻意选择,而非功能缺失:

  • 核心原因:WebRTC 标准只定义了「实时媒体传输」的核心逻辑(如 ICE/NAT 穿透、DTLS/SRTP 加密、媒体编解码),但信令协议是完全开放的(可以用 WebSocket/HTTP/GRPC 等任意协议),因此 Google 没有在核心库中固化某一种信令实现。
  • 源码中的相关部分:WebRTC 源码提供了信令交互所需的「数据结构和接口」(如 SDP 解析、ICE 候选者交换的结构体),但不会实现信令的收发、转发逻辑。 - 官方的示例代码(如src/examples/下的peerconnection_server)包含一个极简的 C++ 信令服务器 demo(基于 HTTP+WebSocket),仅用于演示,并非生产级实现。

实际开发:信令服务器需要开发者自行实现(或使用开源方案如 Janus/Mediasoup/OpenVidu),核心职责是转发 SDP、ICE 候选者、房间控制指令等。

信令服务器用于交换以下关键信息:

  1. SDP (Session Description Protocol):会话描述信息,包含媒体格式、编解码器等
  2. ICE Candidates:网络地址信息,用于建立P2P连接 #### 3.3.2 信令服务器实现

信令机制的核心原理

WebRTC的信令机制是"桥梁",连接两个对等端。它不负责媒体传输,只负责交换建立连接所需的信息。信令机制包括以下关键步骤:

  1. 初始化:双方建立连接
  2. Offer/Answer:协商媒体能力
  3. ICE候选交换:确定网络路径
  4. 连接建立:P2P连接成功

信令模块的作用

  1. 会话协商:通过SDP交换,协商双方支持的媒体类型、编解码器、分辨率等参数
  2. 网络信息交换:交换ICE候选地址,用于NAT穿透和建立P2P连接
  3. 连接管理:管理连接状态,处理连接断开和重连
  4. 媒体流控制:控制媒体流的添加、删除和修改
  5. 错误处理:处理连接过程中的错误和异常情况

信令过程是建立RTCPeerConnection网络连接的关键部分,其主要目的是协调两个端点的通信参数并建立连接。

4.2. 关键源码文件及作用

信令模块的核心代码位于webrtc/pcwebrtc/api目录下,以下是关键文件及其作用:

4.2.1 peer_connection.hpeer_connection_impl.h
// webrtc/pc/peer_connection.h// RTCPeerConnection的接口类classRTCPeerConnection{public:// 创建RTCPeerConnection实例static std::unique_ptr<RTCPeerConnection>Create(const PeerConnectionInterface::Options& options);// 创建offervirtualvoidCreateOffer( CreateSessionDescriptionObserver* observer,const RTCOfferAnswerOptions* options =nullptr)=0;// 创建answervirtualvoidCreateAnswer( CreateSessionDescriptionObserver* observer,const RTCOfferAnswerOptions* options =nullptr)=0;// 设置本地描述virtualvoidSetLocalDescription( SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc)=0;// 设置远程描述virtualvoidSetRemoteDescription( SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc)=0;// 添加ICE候选virtualvoidAddIceCandidate(const IceCandidateInterface* candidate)=0;// 获取ICE候选virtualvoidGetIceCandidates( std::vector<IceCandidateInterface*>* candidates)=0;// 监听ICE连接状态变化virtualvoidOnIceConnectionStateChange( IceConnectionState state)=0;};

作用:定义RTCPeerConnection接口,实现信令交互的核心功能,包括创建offer/answer、设置本地/远程描述、添加ICE候选等。

4.2.2 session_description.hsession_description_impl.h
// webrtc/pc/session_description.h// SDP会话描述的接口类classSessionDescriptionInterface{public:// 获取会话描述类型virtual SessionDescriptionType type()const=0;// 获取会话描述内容virtualconst std::string&ToString()const=0;// 获取会话描述的媒体信息virtualconst std::vector<MediaContentDescriptionInterface*>&contents()const=0;};

作用:定义SDP会话描述的接口,用于表示offer和answer的媒体信息,包括编解码器、分辨率、带宽等参数。

4.2.3 ice_candidate.hice_candidate_impl.h
// webrtc/pc/ice_candidate.h// ICE候选的接口类classIceCandidateInterface{public:// 获取候选地址virtualconst std::string&candidate()const=0;// 获取候选的sdpMidvirtualconst std::string&sdp_mid()const=0;// 获取候选的sdpMLineIndexvirtualintsdp_mline_index()const=0;};

作用:定义ICE候选的接口,用于表示NAT穿透过程中收集的候选地址,包括Host候选、Server Reflexive候选和Relay候选。

4.2.4 signaling_channel.hsignaling_channel_impl.h
// webrtc/pc/signaling_channel.h// 信令通道的接口类classSignalingChannel{public:virtual~SignalingChannel(){}// 发送SDP offervirtualvoidSendOffer(const SessionDescriptionInterface* offer)=0;// 发送SDP answervirtualvoidSendAnswer(const SessionDescriptionInterface* answer)=0;// 发送本地描述virtualvoidSendLocalDescription(const SessionDescriptionInterface* desc)=0;// 发送ICE候选virtualvoidSendIceCandidate(const IceCandidateInterface* candidate)=0;// 设置信令消息处理回调virtualvoidSetMessageHandler( std::function<void(const SignalingMessage&)> handler)=0;};

作用:定义信令通道的接口,用于实现具体的信令传输方式(如WebSocket、MQTT等),将SDP和ICE候选通过信令服务器发送给对端。

4.3. 与其他模块的交互

4.3.1 与传输模块的交互

核心引擎层传输模块信令模块核心引擎层传输模块信令模块创建RTCPeerConnection初始化传输模块创建RTP/RTCP实例初始化ICE返回ICE候选收集ICE候选交换ICE候选设置ICE候选建立P2P连接连接建立成功返回连接状态

交互细节

  • 信令模块创建RTCPeerConnection实例
  • 传输模块初始化RTP/RTCP和ICE
  • 传输模块收集ICE候选并返回给信令模块
  • 信令模块将ICE候选通过信令服务器交换给对方
  • 信令模块设置对方的ICE候选给传输模块
  • 传输模块建立P2P连接
4.3.2 与媒体引擎的交互

核心引擎层媒体引擎信令模块核心引擎层媒体引擎信令模块创建RTCPeerConnection初始化媒体引擎采集媒体流返回媒体流返回媒体流生成SDP offer通过信令服务器交换SDP设置远程描述通过远程描述配置媒体引擎接收并处理媒体流

交互细节

  • 信令模块创建RTCPeerConnection实例
  • 媒体引擎初始化并采集媒体流
  • 信令模块生成SDP offer并交换
  • 信令模块设置远程描述
  • 媒体引擎根据远程描述配置媒体处理

4.4. 源码示例

4.4.1 RTCPeerConnection实现
// webrtc/pc/peer_connection_impl.cc// RTCPeerConnection实现类classRTCPeerConnectionImpl:publicRTCPeerConnection{public:RTCPeerConnectionImpl(const PeerConnectionInterface::Options& options):options_(options),signaling_thread_(nullptr),transport_(nullptr),media_engine_(nullptr){// 1. 初始化信令线程 signaling_thread_ =new rtc::Thread("SignalingThread"); signaling_thread_->Start();// 2. 初始化传输模块 transport_ =newTransport(); transport_->Init();// 3. 初始化媒体引擎 media_engine_ =newMediaEngine(); media_engine_->Init();}voidCreateOffer(CreateSessionDescriptionObserver* observer,const RTCOfferAnswerOptions* options)override{// 1. 生成SDP offer SessionDescriptionInterface* offer = media_engine_->CreateOffer(options);// 2. 保存offer local_description_ = offer;// 3. 通过信令通道发送offerif(signaling_channel_){ signaling_channel_->SendOffer(offer);}// 4. 通知观察者 observer->OnSuccess(offer);}voidCreateAnswer(CreateSessionDescriptionObserver* observer,const RTCOfferAnswerOptions* options)override{// 1. 生成SDP answer SessionDescriptionInterface* answer = media_engine_->CreateAnswer(options);// 2. 保存answer local_description_ = answer;// 3. 通过信令通道发送answerif(signaling_channel_){ signaling_channel_->SendAnswer(answer);}// 4. 通知观察者 observer->OnSuccess(answer);}voidSetLocalDescription(SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc)override{// 1. 设置本地描述 local_description_ = desc;// 2. 通过信令通道发送本地描述if(signaling_channel_){ signaling_channel_->SendLocalDescription(desc);}// 3. 通知观察者 observer->OnSuccess();}voidSetRemoteDescription(SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc)override{// 1. 设置远程描述 remote_description_ = desc;// 2. 通过媒体引擎配置媒体 media_engine_->SetRemoteDescription(desc);// 3. 通过传输模块配置ICE transport_->SetRemoteDescription(desc);// 4. 通知观察者 observer->OnSuccess();}voidAddIceCandidate(const IceCandidateInterface* candidate)override{// 1. 添加ICE候选 ice_candidates_.push_back(candidate);// 2. 通过信令通道发送ICE候选if(signaling_channel_){ signaling_channel_->SendIceCandidate(candidate);}}voidOnIceConnectionStateChange(IceConnectionState state)override{// 1. 处理ICE连接状态变化 ice_connection_state_ = state;// 2. 通知观察者if(ice_connection_state_observer_){ ice_connection_state_observer_->OnIceConnectionStateChange(state);}}private: PeerConnectionInterface::Options options_; rtc::Thread* signaling_thread_; Transport* transport_; MediaEngine* media_engine_; SessionDescriptionInterface* local_description_; SessionDescriptionInterface* remote_description_; std::vector<IceCandidateInterface*> ice_candidates_; IceConnectionState ice_connection_state_; IceConnectionStateObserver* ice_connection_state_observer_; SignalingChannel* signaling_channel_;};
  • RTCPeerConnectionImpl 是RTCPeerConnection的实现类
  • 通过组合模式管理传输模块、媒体引擎和信令通道
  • CreateOffer()CreateAnswer() 生成SDP描述
  • SetLocalDescription()SetRemoteDescription() 设置本地和远程描述
  • AddIceCandidate() 添加ICE候选
  • OnIceConnectionStateChange() 处理ICE连接状态变化
4.4.2 信令通道实现
// webrtc/pc/signaling_channel_impl.h// WebSocket信令通道实现classWebSocketSignalingChannel:publicSignalingChannel{public:WebSocketSignalingChannel(const std::string& url):url_(url),socket_(nullptr){// 初始化WebSocket连接Connect();}voidSendOffer(const SessionDescriptionInterface* offer)override{// 1. 创建SDP offer消息 SignalingMessage message; message.type ="sdp_offer"; message.data = offer->ToString();// 2. 通过WebSocket发送消息Send(message);}voidSendAnswer(const SessionDescriptionInterface* answer)override{// 1. 创建SDP answer消息 SignalingMessage message; message.type ="sdp_answer"; message.data = answer->ToString();// 2. 通过WebSocket发送消息Send(message);}voidSendLocalDescription(const SessionDescriptionInterface* desc)override{// 1. 创建本地描述消息 SignalingMessage message; message.type ="sdp_local"; message.data = desc->ToString();// 2. 通过WebSocket发送消息Send(message);}voidSendIceCandidate(const IceCandidateInterface* candidate)override{// 1. 创建ICE候选消息 SignalingMessage message; message.type ="ice_candidate"; message.data = candidate->candidate(); message.sdp_mid = candidate->sdp_mid(); message.sdp_mline_index = candidate->sdp_mline_index();// 2. 通过WebSocket发送消息Send(message);}voidSetMessageHandler( std::function<void(const SignalingMessage&)> handler)override{ message_handler_ = handler;}private:voidConnect(){// 1. 创建WebSocket连接 socket_ =newWebSocket(url_);// 2. 设置消息处理 socket_->SetMessageHandler([this](const std::string& message){ SignalingMessage msg;// 解析JSON消息ParseMessage(message,&msg);// 调用消息处理回调if(message_handler_){message_handler_(msg);}});}voidSend(const SignalingMessage& message){// 1. 序列化消息 std::string json =SerializeMessage(message);// 2. 通过WebSocket发送消息 socket_->Send(json);} std::string url_; WebSocket* socket_; std::function<void(const SignalingMessage&)> message_handler_;};
  • SignalingChannel 是信令通道的接口类
  • WebSocketSignalingChannel 是WebSocket信令通道的实现类
  • SendOffer()SendAnswer() 发送SDP offer和answer
  • SendIceCandidate() 发送ICE候选
  • SetMessageHandler() 设置消息处理回调
  • 信令通道负责将SDP和ICE候选通过WebSocket发送给对端

4.5. 信令模块工作时序

媒体引擎传输模块信令模块信令服务器参与者B参与者A媒体引擎传输模块信令模块信令服务器参与者B参与者A创建RTCPeerConnection采集媒体流CreateOffer生成SDP offer发送SDP offer转发SDP offer创建RTCPeerConnection采集媒体流CreateAnswer生成SDP answer发送SDP answer转发SDP answerSetRemoteDescription配置媒体引擎AddIceCandidate收集ICE候选通过STUN获取公网IP返回ICE候选发送ICE候选转发ICE候选AddIceCandidate设置ICE候选尝试建立P2P连接连接成功通知连接状态通知连接状态接收媒体流接收媒体流

4.6. 信令模块核心流程

参与者A

创建RTCPeerConnection

采集媒体流

生成SDP offer

通过信令服务器发送offer

参与者B接收offer

生成SDP answer

通过信令服务器发送answer

参与者A接收answer

设置远程描述

配置媒体引擎

收集ICE候选

通过STUN获取公网IP

发送ICE候选

参与者B接收ICE候选

设置ICE候选

尝试建立P2P连接

连接成功

传输媒体流

4.7. 信令模块的关键技术

4.7.1 SDP(Session Description Protocol)

SDP是WebRTC信令的核心,用于描述媒体会话的参数,包括:

  • 会话名称
  • 会话时间
  • 媒体类型(音频、视频)
  • 编解码器
  • 分辨率
  • 带宽
  • ICE候选地址

SDP格式示例:

v=0 o=- 123456 1 IN IP4 127.0.0.1 s=- t=0 0 m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 c=IN IP4 192.168.1.100 a=rtcp:9 IN IP4 192.168.1.100 a=rtpmap:111 opus/48000/2 a=fmtp:111 minptime=10;useinbandfec=1 a=sendrecv 
4.7.2 ICE候选交换

ICE候选是NAT穿透的关键,包括:

  • Host Candidate:本地网络地址
  • Server Reflexive Candidate:NAT反射地址
  • Relay Candidate:TURN中继地址

ICE候选格式示例:

candidate:1 1 udp 2130706431 192.168.1.100 54321 typ host candidate:2 1 udp 1686052607 203.0.113.1 54321 typ srflx raddr 192.168.1.100 rport 54321 candidate:3 1 udp 1500000000 198.51.100.1 54321 typ relay raddr 192.168.1.100 rport 54321 
4.7.3 信令协议

WebRTC没有定义具体的信令协议,开发者可以使用各种方式,如:

  • WebSocket
  • XMPP
  • SIP
  • HTTP
  • MQTT

信令消息格式示例:

{"type":"sdp_offer","data":"v=0\r\no=- 123456 1 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104\r\nc=IN IP4 192.168.1.100\r\na=rtcp:9 IN IP4 192.168.1.100\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=sendrecv\r\n"}

4.8. 信令模块的异常处理

4.8.1 连接失败处理
// 信令模块异常处理示例 pc->oniceconnectionstatechange =[this](){if(pc->iceconnectionstate()=="disconnected"){// 1. 重新发起ICE协商restartIce();}};voidrestartIce(){// 2. 创建新的offerauto offer = pc->createoffer(); pc->setlocaldescription(offer);// 3. 通过信令服务器发送新offer signaling_channel_->sendoffer(offer);}

关键点

  • 监听ICE连接状态变化
  • 当连接断开时,重新发起ICE协商
  • 创建新的offer并发送给对端
4.8.2 媒体流中断处理
// 信令模块媒体流中断处理 pc->addeventlistener("negotiationneeded",[this](){// 1. 获取传输通道auto transceiver = pc->gettransceivers()[0];// 2. 优先使用VP9编解码器 transceiver->setcodecpreferences(filtercodecs("vp9"));});

关键点

  • 监听negotiationneeded事件
  • 当媒体流中断时,切换编解码器
  • 优先使用高效的编解码器如VP9

4.9. 信令模块的未来发展方向

更高效的信令协议

WebRTC信令模块将采用更高效的信令协议:

  • MQTT:轻量级消息传输协议,适合低带宽环境
  • QUIC:基于UDP的多路复用传输协议,减少连接建立时间
  • WebTransport:基于Web标准的传输协议,支持更丰富的信令功能

AI增强的信令处理

WebRTC信令模块将集成AI技术,实现更智能的信令处理:

  • AI信令优化:使用AI算法优化信令消息的发送和处理
  • AI连接预测:使用AI算法预测连接状态,提前进行优化
  • AI异常检测:使用AI算法检测连接异常,自动进行处理

信令与边缘计算结合

WebRTC信令模块将与边缘计算结合,实现更高效的信令处理:

  • 边缘信令服务器:在边缘节点部署信令服务器,减少延迟
  • 本地信令处理:在设备端进行部分信令处理,减少对中心服务器的依赖
  • 分布式信令网络:构建分布式信令网络,提高信令处理的可靠性和效率

Read more

【Web APIs】JavaScript touch 触摸事件 ① ( touchstart 触摸开始事件 | touchmove 触摸移动事件 | touchend 触摸结束事件 )

【Web APIs】JavaScript touch 触摸事件 ① ( touchstart 触摸开始事件 | touchmove 触摸移动事件 | touchend 触摸结束事件 )

文章目录 * 一、JavaScript touch 触摸事件 * 1、 touchstart 触摸开始事件 * 2、touchmove 触摸移动事件 * 3、touchend 触摸结束事件 * 二、代码示例 - touch 触摸事件 * 1、代码示例 * 2、执行结果 一、JavaScript touch 触摸事件 touchstart、touchmove、touchend 事件是 JavaScript 专为支持 触摸操作 的 移动设备( 手机、平板等 ) 设计的核心触摸事件, 用于 监听用户的触摸行为 , 构成了 完整的 触摸生命周期 ; 1、 touchstart 触摸开始事件 touchstart 触摸开始事件 : * 核心定义

Qwen3-VL-WEBUI移动端集成:App调用API部署教程

Qwen3-VL-WEBUI移动端集成:App调用API部署教程 1. 引言 1.1 业务场景描述 随着多模态大模型在移动端应用的不断拓展,如何将强大的视觉-语言模型(VLM)能力无缝集成到移动 App 中,成为智能客服、图像理解、自动化操作等场景的关键技术挑战。传统方案往往依赖云端纯文本推理,难以满足对图像、视频内容实时理解与交互的需求。 Qwen3-VL-WEBUI 的出现为这一问题提供了高效解决方案。它不仅集成了阿里最新开源的 Qwen3-VL-4B-Instruct 模型,还内置了完整的 Web API 接口服务,支持通过 HTTP 调用实现图文输入、结构化输出,非常适合移动端 App 快速接入。 1.2 痛点分析 目前移动端集成 VLM 面临三大核心痛点: * 部署复杂:多数模型需自行搭建推理环境,配置 CUDA、PyTorch、Transformers 等组件,门槛高。 * 接口缺失:

AI Agent Skill Day 12:Web Search技能:互联网搜索与信息聚合

【AI Agent Skill Day 12】Web Search技能:互联网搜索与信息聚合 在“AI Agent Skill技能开发实战”系列的第12天,我们聚焦于Web Search技能——这一使Agent具备实时获取互联网公开信息能力的核心模块。随着大模型知识存在时效性限制(如训练数据截止至2023年或2024年),仅依赖内部知识库难以应对动态世界中的最新事件、股价、新闻、产品发布等需求。Web Search技能通过集成搜索引擎API(如SerpAPI、Google Programmable Search Engine、DuckDuckGo等),实现对网络信息的精准检索、结果聚合与语义提炼,是构建“活Agent”的关键一环。本技能广泛应用于智能客服、市场情报分析、科研辅助、金融舆情监控等场景,显著提升Agent的信息鲜度与决策质量。 技能概述 Web Search技能是指AI Agent在接收到用户查询后,自动调用外部搜索引擎接口,获取相关网页摘要、链接及结构化信息,并将结果进行清洗、去重、排序和语义压缩后返回给大模型,

实战:手写一个通用Web层鉴权注解,解决水平权限漏洞

实战:手写一个通用Web层鉴权注解,解决水平权限漏洞

实战:手写一个通用Web层鉴权注解,解决水平权限漏洞 * 一、背景:一次渗透测试引发的改造 * 二、需求分析:如何高效修复 * 三、业务模型:用户-公司授权关系 * 四、整体架构设计 * 五、代码实现:一步一步来 * 5.1 注解定义 * 5.2 权限管理服务 * 5.3 AOP切面:核心逻辑 * 六、使用示例 * 6.1 场景1:最简单的用法 * 6.2 场景2:对象属性 * 6.3 场景3:批量操作 * 6.4 场景4:嵌套属性 * 6.5 场景5:类级别默认配置 * 七、