一、Ninja与GN
一般编译源码使用的是g++或clang++,这俩是编译器;
make是调用g++实现编译的构建系统(build system),Makefile是告诉make如何构建;
Ninja和make类似,也是一个构建系统;
GN是google用来生成Ninja配置文件的工具,WebRTC使用GN来生成Ninja配置文件;GN的配置文件使用的是Python语法(位于根目录下的BUILD.gn);
二、 WebRTC运行模式
WebRTC有三种运行模式:
1. p2p,客户端之间直接建立媒体数据连接,避免使用服务器转发媒体数据;
优缺点:优点是可以减少租用服务器和网络带宽的成本;但缺点是客户端之间的网络连接质量难以得到保证,音视频通话的效果往往会差一些;
2. sfu,selective forwarding unit,服务端接收数据后直接转发,优点是不需要编解码,对CPU消耗小;直接转发极大的降低了延迟,提高了实时性;
缺点是不同的人看到的不同的画面,回放也有限制;
3. mcu, multi-point control unit, 服务端作为音视频网关,通过解码再编码可以屏蔽不同设备的差异化;多路流合成一路,所有人看到的都是同一个画面,提升了用户体验;
缺点是编解码加混流需要大量的CPU计算,同时带来了延迟;
调试时必须有信令服务器,Android/iOS/macOS是AppRTC Server,客户端是AppRTCMobile;Windows/Linux则是另一套,信令服务器是PeerConnection Server,客户端叫做PeerConnection Client;本文所示的是在windows平台下断点下来的堆栈。
三、SDP协议
SDP(Session Description Protocol)会话描述协议,描述多媒体数据传输格式和网络传输地址。之所以需要SDP协议,是因为参与会话的各成员能力不对等。这就涉及一个协商的过程,会话发起者先提出一些Offer,其他参与者再根据Offer提出自己的Answer。
四、一次PeerConnection P2P视频通信过程
-
发起端创建本地PeerConnection对象,并创建Offer;
class PeerConnection { std::map<std::string, rtc::scoped_refptr<DataChannel>> rtp_data_channels_; std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_; std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels_to_free_; bool remote_peer_supports_msid_ = false; std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>> senders_; std::vector< rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>> receivers_; std::unique_ptr<WebRtcSession> session_; // WebRtc数据通信 std::unique_ptr<StatsCollector> stats_; rtc::scoped_refptr<RTCStatsCollector> stats_collector_; };
PeerConnection::CreateOffer->
WebRtcSessionDescriptionFactory::CreateOffer
-
发送端通过Signaling Server把Offer送到应答端;
-
应答端创建本地PeerConnection对象,并把发起端的Offer设置给本地PeerConnection然后获得Answer;
-
应答端通过Signaling Server把Answer发送给发起端;
-
发起端把应答端的Answer设置给自己的PeerConnection对象;
// 处理Signaling Server传递的消息,json格式,json中有一个字段会标识当前是Offer还是Answer
void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) {
// 将获取到的Answer(SDP信息)设置给PeerConnection对象;
peer_connection_->SetRemoteDescription();
}
发送端获取到的SDP信息:
v=0 o=- 3191439438210652066 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE audio video a=msid-semantic: WMS stream_label m=audio 9 UDP/TLS/RTP/SAVPF 103 104 0 8 106 105 13 112 113 126 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:YXLe a=ice-pwd:12xORpVbT8qdIeDgwrOdgPbA a=fingerprint:sha-256 33:BD:49:9D:D8:9A:EF:4C:E8:BB:FE:E6:7E:D2:35:26:F6:1B:86:97:7E:47:FE:AA:79:E9:21:B0:48:37:7C:36 a=setup:active a=mid:audio a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=sendrecv a=rtcp-mux a=rtpmap:103 ISAC/16000 a=rtpmap:104 ISAC/32000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:106 CN/32000 a=rtpmap:105 CN/16000 a=rtpmap:13 CN/8000 a=rtpmap:112 telephone-event/32000 a=rtpmap:113 telephone-event/16000 a=rtpmap:126 telephone-event/8000 a=ssrc:1030752977 cname:djnC/REx5tbxVb/6 a=ssrc:1030752977 msid:stream_label audio_label a=ssrc:1030752977 mslabel:stream_label a=ssrc:1030752977 label:audio_label m=video 9 UDP/TLS/RTP/SAVPF 96 98 100 102 127 97 99 101 125 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:YXLe a=ice-pwd:12xORpVbT8qdIeDgwrOdgPbA a=fingerprint:sha-256 33:BD:49:9D:D8:9A:EF:4C:E8:BB:FE:E6:7E:D2:35:26:F6:1B:86:97:7E:47:FE:AA:79:E9:21:B0:48:37:7C:36 a=setup:active a=mid:video a=extmap:2 urn:ietf:params:rtp-hdrext:toffset a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:4 urn:3gpp:video-orientation a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay a=sendrecv a=rtcp-mux a=rtcp-rsize a=rtpmap:96 VP8/90000 a=rtcp-fb:96 ccm fir a=rtcp-fb:96 nack a=rtcp-fb:96 nack pli a=rtcp-fb:96 goog-remb a=rtcp-fb:96 transport-cc a=rtpmap:98 VP9/90000 a=rtcp-fb:98 ccm fir a=rtcp-fb:98 nack a=rtcp-fb:98 nack pli a=rtcp-fb:98 goog-remb a=rtcp-fb:98 transport-cc a=rtpmap:100 H264/90000 a=rtcp-fb:100 ccm fir a=rtcp-fb:100 nack a=rtcp-fb:100 nack pli a=rtcp-fb:100 goog-remb a=rtcp-fb:100 transport-cc a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f a=rtpmap:102 red/90000 a=rtpmap:127 ulpfec/90000 a=rtpmap:97 rtx/90000 a=fmtp:97 apt=96 a=rtpmap:99 rtx/90000 a=fmtp:99 apt=98 a=rtpmap:101 rtx/90000 a=fmtp:101 apt=100 a=rtpmap:125 rtx/90000 a=fmtp:125 apt=102 a=ssrc-group:FID 3701325982 3818105161 a=ssrc:3701325982 cname:djnC/REx5tbxVb/6 a=ssrc:3701325982 msid:stream_label video_label a=ssrc:3701325982 mslabel:stream_label a=ssrc:3701325982 label:video_label a=ssrc:3818105161 cname:djnC/REx5tbxVb/6 a=ssrc:3818105161 msid:stream_label video_label a=ssrc:3818105161 mslabel:stream_label a=ssrc:3818105161 label:video_label
-
双端都收集本地PeerConnection的ICE Candidate(包括访问TURN Server),通过Signaling Server发送给对端,对端把ICE Candidate设备给本地的PeerConnection;
收到的Candidate信息: { "candidate" : "candidate:1221703924 1 udp 2122260223 192.168.0.105 60608 typ host generation 0 ufrag RIxM network-id 3 network-cost 50", "sdpMLineIndex" : 0, "sdpMid" : "audio" }
-
端开始建立P2P的Socket,并收发音视频数据;
Offer和Answer都属于SDP,双端协商好使用的多媒体数据格式和网络传输地址等;