284 lines
10 KiB
C++
284 lines
10 KiB
C++
/*
|
||
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
|
||
*
|
||
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
|
||
*
|
||
* Use of this source code is governed by MIT-like license that can be found in the
|
||
* LICENSE file in the root of the source tree. All contributing project authors
|
||
* may be found in the AUTHORS file in the root of the source tree.
|
||
*/
|
||
|
||
#include "RtcpContext.h"
|
||
#include "Util/logger.h"
|
||
using namespace toolkit;
|
||
|
||
namespace mediakit {
|
||
|
||
void RtcpContext::onRtp(
|
||
uint16_t /*seq*/, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t /*sample_rate*/, size_t bytes) {
|
||
++_packets;
|
||
_bytes += bytes;
|
||
_last_rtp_stamp = stamp;
|
||
_last_ntp_stamp_ms = ntp_stamp_ms;
|
||
}
|
||
|
||
size_t RtcpContext::getExpectedPackets() const {
|
||
throw std::runtime_error("没有实现, rtp发送者无法统计应收包数");
|
||
}
|
||
|
||
size_t RtcpContext::getExpectedPacketsInterval() {
|
||
throw std::runtime_error("没有实现, rtp发送者无法统计应收包数");
|
||
}
|
||
|
||
size_t RtcpContext::getLost() {
|
||
throw std::runtime_error("没有实现, rtp发送者无法统计丢包率");
|
||
}
|
||
|
||
size_t RtcpContext::getLostInterval() {
|
||
throw std::runtime_error("没有实现, rtp发送者无法统计丢包率");
|
||
}
|
||
|
||
Buffer::Ptr RtcpContext::createRtcpSR(uint32_t rtcp_ssrc) {
|
||
throw std::runtime_error("没有实现, rtp接收者尝试发送sr包");
|
||
}
|
||
|
||
Buffer::Ptr RtcpContext::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
||
throw std::runtime_error("没有实现, rtp发送者尝试发送rr包");
|
||
}
|
||
|
||
Buffer::Ptr RtcpContext::createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
||
throw std::runtime_error("没有实现, rtp发送者尝试发送xr dlrr包");
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void RtcpContextForSend::onRtcp(RtcpHeader *rtcp) {
|
||
switch ((RtcpType)rtcp->pt) {
|
||
case RtcpType::RTCP_RR: {
|
||
auto rtcp_rr = (RtcpRR *)rtcp;
|
||
for (auto item : rtcp_rr->getItemList()) {
|
||
if (!item->last_sr_stamp) {
|
||
continue;
|
||
}
|
||
auto it = _sender_report_ntp.find(item->last_sr_stamp);
|
||
if (it == _sender_report_ntp.end()) {
|
||
continue;
|
||
}
|
||
// 发送sr到收到rr之间的时间戳增量 [AUTO-TRANSLATED:da014bf1]
|
||
// Timestamp increment between sending sr and receiving rr
|
||
auto ms_inc = getCurrentMillisecond() - it->second;
|
||
// rtp接收端收到sr包后,回复rr包的延时,已转换为毫秒 [AUTO-TRANSLATED:bfab8622]
|
||
// Delay of the rtp receiver replying to the rr packet after receiving the sr packet, converted to milliseconds
|
||
auto delay_ms = (uint64_t)item->delay_since_last_sr * 1000 / 65536;
|
||
auto rtt = (int)(ms_inc - delay_ms);
|
||
if (rtt >= 0) {
|
||
// rtt不可能小于0 [AUTO-TRANSLATED:34914014]
|
||
// RTT cannot be less than 0
|
||
_rtt[item->ssrc] = rtt;
|
||
// InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case RtcpType::RTCP_XR: {
|
||
auto rtcp_xr = (RtcpXRRRTR *)rtcp;
|
||
if (rtcp_xr->bt == 4) {
|
||
_xr_xrrtr_recv_last_rr[rtcp_xr->ssrc]
|
||
= ((rtcp_xr->ntpmsw & 0xFFFF) << 16) | ((rtcp_xr->ntplsw >> 16) & 0xFFFF);
|
||
_xr_rrtr_recv_sys_stamp[rtcp_xr->ssrc] = getCurrentMillisecond();
|
||
} else if (rtcp_xr->bt == 5) {
|
||
TraceL << "for sender not recive dlrr";
|
||
} else {
|
||
TraceL << "not support xr bt " << rtcp_xr->bt;
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
uint32_t RtcpContextForSend::getRtt(uint32_t ssrc) const {
|
||
auto it = _rtt.find(ssrc);
|
||
if (it == _rtt.end()) {
|
||
return 0;
|
||
}
|
||
return it->second;
|
||
}
|
||
|
||
Buffer::Ptr RtcpContextForSend::createRtcpSR(uint32_t rtcp_ssrc) {
|
||
auto rtcp = RtcpSR::create(0);
|
||
rtcp->setNtpStamp(_last_ntp_stamp_ms);
|
||
rtcp->rtpts = htonl(_last_rtp_stamp);
|
||
rtcp->ssrc = htonl(rtcp_ssrc);
|
||
rtcp->packet_count = htonl((uint32_t)_packets);
|
||
rtcp->octet_count = htonl((uint32_t)_bytes);
|
||
|
||
// 记录上次发送的sender report信息,用于后续统计rtt [AUTO-TRANSLATED:1d22d2c8]
|
||
// Record the last sent sender report information for subsequent RTT statistics
|
||
auto last_sr_lsr = ((ntohl(rtcp->ntpmsw) & 0xFFFF) << 16) | ((ntohl(rtcp->ntplsw) >> 16) & 0xFFFF);
|
||
_sender_report_ntp[last_sr_lsr] = getCurrentMillisecond();
|
||
if (_sender_report_ntp.size() >= 5) {
|
||
// 删除最早的sr rtcp [AUTO-TRANSLATED:2457e08d]
|
||
// Delete the earliest sr rtcp
|
||
_sender_report_ntp.erase(_sender_report_ntp.begin());
|
||
}
|
||
|
||
return RtcpHeader::toBuffer(std::move(rtcp));
|
||
}
|
||
|
||
toolkit::Buffer::Ptr RtcpContextForSend::createRtcpXRDLRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
||
auto rtcp = RtcpXRDLRR::create(1);
|
||
rtcp->bt = 5;
|
||
rtcp->reserved = 0;
|
||
rtcp->block_length = htons(3);
|
||
rtcp->ssrc = htonl(rtcp_ssrc);
|
||
rtcp->items.ssrc = htonl(rtp_ssrc);
|
||
|
||
if (_xr_xrrtr_recv_last_rr.find(rtp_ssrc) == _xr_xrrtr_recv_last_rr.end()) {
|
||
rtcp->items.lrr = 0;
|
||
WarnL;
|
||
} else {
|
||
rtcp->items.lrr = htonl(_xr_xrrtr_recv_last_rr[rtp_ssrc]);
|
||
}
|
||
|
||
if (_xr_rrtr_recv_sys_stamp.find(rtp_ssrc) == _xr_rrtr_recv_sys_stamp.end()) {
|
||
rtcp->items.dlrr = 0;
|
||
WarnL;
|
||
} else {
|
||
// now - Last SR time,单位毫秒 [AUTO-TRANSLATED:cc449199]
|
||
// now - Last SR time, in milliseconds
|
||
auto delay = getCurrentMillisecond() - _xr_rrtr_recv_sys_stamp[rtp_ssrc];
|
||
// in units of 1/65536 seconds
|
||
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
|
||
rtcp->items.dlrr = htonl(dlsr);
|
||
}
|
||
return RtcpHeader::toBuffer(std::move(rtcp));
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void RtcpContextForRecv::onRtp(
|
||
uint16_t seq, uint32_t stamp, uint64_t ntp_stamp_ms, uint32_t sample_rate, size_t bytes) {
|
||
{
|
||
// 接收者才做复杂的统计运算 [AUTO-TRANSLATED:853c68e0]
|
||
// The receiver performs complex statistical calculations
|
||
auto sys_stamp = getCurrentMillisecond();
|
||
if (_last_rtp_sys_stamp) {
|
||
// 计算时间戳抖动值 [AUTO-TRANSLATED:cd3571b4]
|
||
// Calculate the timestamp jitter value
|
||
double diff = double(
|
||
(int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp)) * (sample_rate / double(1000.0))
|
||
- (int64_t(stamp) - int64_t(_last_rtp_stamp)));
|
||
if (diff < 0) {
|
||
diff = -diff;
|
||
}
|
||
// 抖动单位为采样次数 [AUTO-TRANSLATED:b713633a]
|
||
// Jitter unit is the number of samples
|
||
_jitter += (diff - _jitter) / 16.0;
|
||
} else {
|
||
_jitter = 0;
|
||
}
|
||
|
||
if (_last_rtp_seq > 0xFF00 && seq < 0xFF && (!_seq_cycles || _packets - _last_cycle_packets > 0x1FFF)) {
|
||
// 上次seq大于0xFF00且本次seq小于0xFF, [AUTO-TRANSLATED:82dd69fa]
|
||
// Last seq is greater than 0xFF00 and this seq is less than 0xFF,
|
||
// 且未发生回环或者距离上次回环间隔超过0x1FFF个包,则认为回环 [AUTO-TRANSLATED:2907b595]
|
||
// and no loopback occurs or the interval between the last loopback is greater than 0x1FFF packets, then it is considered a loopback
|
||
++_seq_cycles;
|
||
_last_cycle_packets = _packets;
|
||
_seq_max = seq;
|
||
} else if (seq > _seq_max) {
|
||
// 本次回环前最大seq [AUTO-TRANSLATED:c02f6a87]
|
||
// Maximum seq before this loopback
|
||
_seq_max = seq;
|
||
}
|
||
|
||
if (!_seq_base) {
|
||
// 记录第一个rtp的seq [AUTO-TRANSLATED:ce2bb7d7]
|
||
// Record the seq of the first rtp
|
||
_seq_base = seq;
|
||
} else if (!_seq_cycles && seq < _seq_base) {
|
||
// 未发生回环,那么取最新的seq为基准seq [AUTO-TRANSLATED:721b37fc]
|
||
// If no loopback occurs, then take the latest seq as the base seq
|
||
_seq_base = seq;
|
||
}
|
||
|
||
_last_rtp_seq = seq;
|
||
_last_rtp_sys_stamp = sys_stamp;
|
||
}
|
||
RtcpContext::onRtp(seq, stamp, ntp_stamp_ms, sample_rate, bytes);
|
||
}
|
||
|
||
void RtcpContextForRecv::onRtcp(RtcpHeader *rtcp) {
|
||
switch ((RtcpType)rtcp->pt) {
|
||
case RtcpType::RTCP_SR: {
|
||
auto rtcp_sr = (RtcpSR *)rtcp;
|
||
/**
|
||
last SR timestamp (LSR): 32 bits
|
||
The middle 32 bits out of 64 in the NTP timestamp (as explained in
|
||
Section 4) received as part of the most recent RTCP sender report
|
||
(SR) packet from source SSRC_n. If no SR has been received yet,
|
||
the field is set to zero.
|
||
*/
|
||
_last_sr_lsr = ((rtcp_sr->ntpmsw & 0xFFFF) << 16) | ((rtcp_sr->ntplsw >> 16) & 0xFFFF);
|
||
_last_sr_ntp_sys = getCurrentMillisecond();
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
size_t RtcpContextForRecv::getExpectedPackets() const {
|
||
return (_seq_cycles << 16) + _seq_max - _seq_base + 1;
|
||
}
|
||
|
||
size_t RtcpContextForRecv::getExpectedPacketsInterval() {
|
||
auto expected = getExpectedPackets();
|
||
auto ret = expected - _last_expected;
|
||
_last_expected = expected;
|
||
return ret;
|
||
}
|
||
|
||
size_t RtcpContextForRecv::getLost() {
|
||
return getExpectedPackets() - _packets;
|
||
}
|
||
|
||
size_t RtcpContextForRecv::getLostInterval() {
|
||
auto lost = getLost();
|
||
auto ret = lost - _last_lost;
|
||
_last_lost = lost;
|
||
return ret;
|
||
}
|
||
|
||
Buffer::Ptr RtcpContextForRecv::createRtcpRR(uint32_t rtcp_ssrc, uint32_t rtp_ssrc) {
|
||
auto rtcp = RtcpRR::create(1);
|
||
rtcp->ssrc = htonl(rtcp_ssrc);
|
||
|
||
ReportItem *item = (ReportItem *)&rtcp->items;
|
||
item->ssrc = htonl(rtp_ssrc);
|
||
|
||
uint8_t fraction = 0;
|
||
auto expected_interval = getExpectedPacketsInterval();
|
||
if (expected_interval) {
|
||
fraction = uint8_t(getLostInterval() << 8 / expected_interval);
|
||
}
|
||
|
||
item->fraction = fraction;
|
||
item->cumulative = htonl(uint32_t(getLost())) >> 8;
|
||
item->seq_cycles = htons(_seq_cycles);
|
||
item->seq_max = htons(_seq_max);
|
||
item->jitter = htonl(uint32_t(_jitter));
|
||
item->last_sr_stamp = htonl(_last_sr_lsr);
|
||
|
||
// now - Last SR time,单位毫秒 [AUTO-TRANSLATED:cc449199]
|
||
// now - Last SR time, in milliseconds
|
||
auto delay = getCurrentMillisecond() - _last_sr_ntp_sys;
|
||
// in units of 1/65536 seconds
|
||
auto dlsr = (uint32_t)(delay / 1000.0f * 65536);
|
||
item->delay_since_last_sr = htonl(_last_sr_lsr ? dlsr : 0);
|
||
return RtcpHeader::toBuffer(rtcp);
|
||
}
|
||
|
||
} // namespace mediakit
|