WebRTC RTP/RTCP 源碼分析(二):RTP 的接收

基于 Chromium M69版本

當(dāng) RTP 包完成拆分后镊掖,BaseChannel 把包到達(dá)時(shí)間抓換成微秒夹攒,然后通知 MediaChannel 處理收到的包仅颇。

// src/pc/channel.cc
void BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet) {
  // 重構(gòu)了 parsed_packet 里的 PacketTime
  OnPacketReceived(/*rtcp=*/false, parsed_packet.Buffer(), packet_time);
}
void BaseChannel::OnPacketReceived(bool rtcp,
                                   const rtc::CopyOnWriteBuffer& packet,
                                   const rtc::PacketTime& packet_time) {
  // 如果是第一個(gè) RTP 包則進(jìn)行額外處理
  invoker_.AsyncInvoke<void>(
      RTC_FROM_HERE, worker_thread_,
      Bind(&BaseChannel::ProcessPacket, this, rtcp, packet, packet_time));
}
void BaseChannel::ProcessPacket(bool rtcp,
                                const rtc::CopyOnWriteBuffer& packet,
                                const rtc::PacketTime& packet_time) {
  media_channel_->OnPacketReceived(&data, packet_time);
}

MediaChannel 是個(gè)父類受神,由 VoiceMediaChannel,VideoMediaChannel和DataMediaChannel實(shí)現(xiàn)魏颓,一下主要講視頻方面岭辣。WebRtcVideoChannel 繼承了 VideoMediaChannel,實(shí)現(xiàn)了 OnPacketReceived甸饱,響應(yīng) BaseChannel 的調(diào)用沦童。

WebRtcVideoChannel 通知 Call 遞交 RTP 包。如果遞交結(jié)果為DELIVERY_OK則說明包被正常遞交柜候,DELIVERY_PACKET_ERROR說明包無法正常解析搞动,DELIVERY_UNKNOWN_SSRC說明沒找到該包的 ssrc,最后返回渣刷。

// src/media/engine/webrtcvideoengine.cc
void WebRtcVideoChannel::OnPacketReceived(rtc::CopyOnWriteBuffer* packet,
                                          const rtc::PacketTime& packet_time) {
  const webrtc::PacketReceiver::DeliveryStatus delivery_result =
      call_->Receiver()->DeliverPacket(webrtc::MediaType::VIDEO, *packet,
                                       webrtc_packet_time);
}

Call 判斷包是否能正常解析,是否能找到對(duì)應(yīng) ssrc矗烛,計(jì)算包到達(dá)時(shí)間辅柴,計(jì)算方式為 (timestamp_us + 500) / 1000,調(diào)用 RemoteEstimatorProxy 記錄每個(gè)包序列號(hào)對(duì)應(yīng)的到達(dá)時(shí)間用于 send-side congestion control瞭吃,然后把視頻包傳遞給 RtpStreamReceiverController 進(jìn)一步處理碌嘀。之后統(tǒng)計(jì)每秒收到的數(shù)據(jù)總大小和每秒收到的視頻數(shù)據(jù)總大小。

// src/call/call.cc
PacketReceiver::DeliveryStatus Call::DeliverPacket(
    MediaType media_type,
    rtc::CopyOnWriteBuffer packet,
    const PacketTime& packet_time) {
  // 如果是 RTCP 包則調(diào)用 DeliverRtcp 處理
  return DeliverRtp(media_type, std::move(packet), packet_time);
}
PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type,
                                                rtc::CopyOnWriteBuffer packet,
                                                const PacketTime& packet_time) {

  NotifyBweOfReceivedPacket(parsed_packet, media_type);
  video_receiver_controller_.OnRtpPacket(parsed_packet);
}

RtpStreamReceiverController 沒有其他操作直接傳給 RtpDemuxer 處理包歪架。

// src/call/rtp_stream_receiver_controller.cc
bool RtpStreamReceiverController::OnRtpPacket(const RtpPacketReceived& packet) {
  rtc::CritScope cs(&lock_);
  return demuxer_.OnRtpPacket(packet);
}

RtpDemuxer 根據(jù) MID股冗、RSID 或者 payload 類型獲取對(duì)應(yīng)的 RtpPacketSinkInterface。
視頻包由 RtpVideoStreamReceiver 繼續(xù)處理和蚪,其余還有 RtxReceiveStream止状、FlexfecReceiveStream、ChannelProxy攒霹。

// src/call/rtp_demuxer.cc
bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) {
  RtpPacketSinkInterface* sink = ResolveSink(packet);
  if (sink != nullptr) {
    sink->OnRtpPacket(packet);
    return true;
  }
  return false;
}

RtpVideoStreamReceiver 負(fù)責(zé)處理常規(guī) RTP 包和由 FlexFEC 恢復(fù)的包怯疤。首先獲取包的 Header 信息,然后通知 RtpReceiver 正式接收 RTP 包催束,記錄非重傳包的接收數(shù)據(jù)集峦。最后調(diào)用二級(jí)sink繼續(xù)處理。

// src/video/rtp_video_stream_receiver.cc
void RtpVideoStreamReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
  packet.GetHeader(&header);
  ReceivePacket(packet.data(), packet.size(), header);
  rtp_receive_statistics_->IncomingPacket(header, packet.size(),
                                          IsPacketRetransmitted(header));
  secondary_sink->OnRtpPacket(packet);
}
void RtpVideoStreamReceiver::ReceivePacket(const uint8_t* packet,
                                           size_t packet_length,
                                           const RTPHeader& header) {
  if (header.payloadType == config_.rtp.red_payload_type) {
    ParseAndHandleEncapsulatingHeader(packet, packet_length, header);
    return;
  }
  const uint8_t* payload = packet + header.headerLength;
  assert(packet_length >= header.headerLength);
  size_t payload_length = packet_length - header.headerLength;
  const auto pl =
      rtp_payload_registry_.PayloadTypeToPayload(header.payloadType);
  if (pl) {
    rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
                                     pl->typeSpecific);
  }
}

RtpReceiver 類由 RtpReceiverImpl 進(jìn)行實(shí)現(xiàn),響應(yīng)上面對(duì) IncomingRtpPacket 的調(diào)用塔淤。RtpReceiver 負(fù)責(zé)處理 audio_level 信息摘昌,通知 RTPReceiverStrategy 解析 RTP 包,并區(qū)別遲到和重傳的包高蜂。

bool RtpReceiverImpl::IncomingRtpPacket(const RTPHeader& rtp_header,
                                        const uint8_t* payload,
                                        size_t payload_length,
                                        PayloadUnion payload_specific) {
  int32_t ret_val = rtp_media_receiver_->ParseRtpPacket(
      &webrtc_rtp_header, payload_specific, payload, payload_length,
      clock_->TimeInMilliseconds());
}

RTPReceiverStrategy 類由 RTPReceiverVideo 和 RTPReceiverAudio 進(jìn)行實(shí)現(xiàn)聪黎,視頻 RTP 包由 RTPReceiverVideo 負(fù)責(zé)具體解析 rtp_header 和 rtp_payload。

int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
                                         const PayloadUnion& specific_payload,
                                         const uint8_t* payload,
                                         size_t payload_length,
                                         int64_t timestamp_ms) {}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妨马,一起剝皮案震驚了整個(gè)濱河市挺举,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烘跺,老刑警劉巖湘纵,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滤淳,居然都是意外死亡梧喷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門脖咐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铺敌,“玉大人,你說我怎么就攤上這事屁擅〕テ荆” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵派歌,是天一觀的道長弯囊。 經(jīng)常有香客問我,道長胶果,這世上最難降的妖魔是什么匾嘱? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮早抠,結(jié)果婚禮上霎烙,老公的妹妹穿的比我還像新娘。我一直安慰自己蕊连,他們只是感情好悬垃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著咪奖,像睡著了一般盗忱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上羊赵,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天趟佃,我揣著相機(jī)與錄音扇谣,去河邊找鬼。 笑死闲昭,一個(gè)胖子當(dāng)著我的面吹牛罐寨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播序矩,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼鸯绿,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了簸淀?” 一聲冷哼從身側(cè)響起瓶蝴,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎租幕,沒想到半個(gè)月后舷手,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡劲绪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年男窟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贾富。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歉眷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出颤枪,到底是詐尸還是另有隱情汗捡,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布畏纲,位于F島的核電站凉唐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏霍骄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一淡溯、第九天 我趴在偏房一處隱蔽的房頂上張望读整。 院中可真熱鬧,春花似錦咱娶、人聲如沸米间。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屈糊。三九已至,卻和暖如春琼了,著一層夾襖步出監(jiān)牢的瞬間逻锐,已是汗流浹背夫晌。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昧诱,地道東北人晓淀。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像盏档,于是被迫代替她去往敵國和親凶掰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353