代码改变世界

WebRTC笔记(零)WebRTC基础

2021-01-30 20:33  jiayayao  阅读(883)  评论(0编辑  收藏  举报

一、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,双端协商好使用的多媒体数据格式和网络传输地址等;