mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
修复rtcp rr/sr时间戳转换相关问题,计算rtt
This commit is contained in:
parent
bf8642d62f
commit
4c296488f1
@ -263,11 +263,25 @@ string RtcpSR::getNtpStamp() const{
|
|||||||
return LogChannel::printTime(tv);
|
return LogChannel::printTime(tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t RtcpSR::getNtpUnixStampMS() const {
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = ntpmsw - 0x83AA7E80;
|
||||||
|
tv.tv_usec = (decltype(tv.tv_usec)) (ntplsw / ((double) (((uint64_t) 1) << 32) * 1.0e-6));
|
||||||
|
return 1000 * tv.tv_sec + tv.tv_usec / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
void RtcpSR::setNtpStamp(struct timeval tv) {
|
void RtcpSR::setNtpStamp(struct timeval tv) {
|
||||||
ntpmsw = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
|
ntpmsw = htonl(tv.tv_sec + 0x83AA7E80); /* 0x83AA7E80 is the number of seconds from 1900 to 1970 */
|
||||||
ntplsw = htonl((uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6));
|
ntplsw = htonl((uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RtcpSR::setNtpStamp(uint64_t unix_stamp_ms) {
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = unix_stamp_ms / 1000;
|
||||||
|
tv.tv_usec = (unix_stamp_ms % 1000) * 1000;
|
||||||
|
setNtpStamp(tv);
|
||||||
|
}
|
||||||
|
|
||||||
string RtcpSR::dumpString() const{
|
string RtcpSR::dumpString() const{
|
||||||
_StrPrinter printer;
|
_StrPrinter printer;
|
||||||
printer << RtcpHeader::dumpHeader();
|
printer << RtcpHeader::dumpHeader();
|
||||||
|
@ -347,12 +347,14 @@ public:
|
|||||||
* @param tv 时间
|
* @param tv 时间
|
||||||
*/
|
*/
|
||||||
void setNtpStamp(struct timeval tv);
|
void setNtpStamp(struct timeval tv);
|
||||||
|
void setNtpStamp(uint64_t unix_stamp_ms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回ntp时间的字符串
|
* 返回ntp时间的字符串
|
||||||
* 使用net2Host转换成主机字节序后才可使用此函数
|
* 使用net2Host转换成主机字节序后才可使用此函数
|
||||||
*/
|
*/
|
||||||
string getNtpStamp() const;
|
string getNtpStamp() const;
|
||||||
|
uint64_t getNtpUnixStampMS() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取ReportItem对象指针列表
|
* 获取ReportItem对象指针列表
|
||||||
|
@ -22,14 +22,14 @@ RtcpContext::RtcpContext(bool is_receiver) {
|
|||||||
_is_receiver = is_receiver;
|
_is_receiver = is_receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpContext::onRtp(uint16_t seq, uint32_t stamp, size_t bytes) {
|
void RtcpContext::onRtp(uint16_t seq, uint32_t stamp, uint32_t sample_rate, size_t bytes) {
|
||||||
if (_is_receiver) {
|
if (_is_receiver) {
|
||||||
//接收者才做复杂的统计运算
|
//接收者才做复杂的统计运算
|
||||||
auto sys_stamp = getCurrentMillisecond();
|
auto sys_stamp = getCurrentMillisecond();
|
||||||
if (_last_rtp_sys_stamp) {
|
if (_last_rtp_sys_stamp) {
|
||||||
//计算时间戳抖动值
|
//计算时间戳抖动值
|
||||||
double diff = double(
|
double diff = double((int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp)) * (sample_rate / double(1000.0))
|
||||||
int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp) - int64_t(stamp) + int64_t(_last_rtp_stamp));
|
- (int64_t(stamp) - int64_t(_last_rtp_stamp)));
|
||||||
if (diff < 0) {
|
if (diff < 0) {
|
||||||
diff = -diff;
|
diff = -diff;
|
||||||
}
|
}
|
||||||
@ -68,23 +68,49 @@ void RtcpContext::onRtp(uint16_t seq, uint32_t stamp, size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtcpContext::onRtcp(RtcpHeader *rtcp) {
|
void RtcpContext::onRtcp(RtcpHeader *rtcp) {
|
||||||
if ((RtcpType) rtcp->pt != RtcpType::RTCP_SR) {
|
switch ((RtcpType) rtcp->pt) {
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
|
case RtcpType::RTCP_RR: {
|
||||||
|
auto rtcp_rr = (RtcpRR *) rtcp;
|
||||||
|
for (auto item : rtcp_rr->getItemList()) {
|
||||||
|
if (!item->last_sr_stamp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//rtp接收端收到sr包后,回复rr包的延时,已转换为毫秒
|
||||||
|
auto delay_ms = (uint64_t) item->delay_since_last_sr * 1000 / 65536;
|
||||||
|
//这个rr包对应sr包的ntpmsw和ntplsw
|
||||||
|
auto ntpmsw = item->last_sr_stamp >> 16;
|
||||||
|
auto ntplsw = (item->last_sr_stamp & 0xFFFF) << 16;
|
||||||
|
RtcpSR sr;
|
||||||
|
//获取当前时间戳
|
||||||
|
sr.setNtpStamp(getCurrentMillisecond(true));
|
||||||
|
|
||||||
|
//当前时间戳与上次发送的sr包直接的ntp时间差
|
||||||
|
int64_t ntpmsw_inc = (int64_t)(ntohl(sr.ntpmsw) & 0xFFFF) - (int64_t)ntpmsw;
|
||||||
|
int64_t ntplsw_inc = (int64_t)(ntohl(sr.ntplsw)) - (int64_t)ntplsw;
|
||||||
|
|
||||||
|
//转换为毫秒
|
||||||
|
auto ms_inc = ntpmsw_inc * 1000 + (ntplsw_inc / ((double) (((uint64_t) 1) << 32) * 1.0e-3));
|
||||||
|
auto rtt = (int) ((ms_inc - delay_ms) / 2);
|
||||||
|
_rtt[item->ssrc] = rtt;
|
||||||
|
//InfoL << "ssrc:" << item->ssrc << ",rtt:" << rtt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
if (!_is_receiver) {
|
|
||||||
WarnL << "rtp发送者收到sr包";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RtcpContext::getExpectedPackets() const {
|
size_t RtcpContext::getExpectedPackets() const {
|
||||||
@ -120,14 +146,9 @@ Buffer::Ptr RtcpContext::createRtcpSR(uint32_t rtcp_ssrc) {
|
|||||||
throw std::runtime_error("rtp接收者尝试发送sr包");
|
throw std::runtime_error("rtp接收者尝试发送sr包");
|
||||||
}
|
}
|
||||||
auto rtcp = RtcpSR::create(0);
|
auto rtcp = RtcpSR::create(0);
|
||||||
rtcp->ssrc = htonl(rtcp_ssrc);
|
rtcp->setNtpStamp(getCurrentMillisecond(true));
|
||||||
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
rtcp->setNtpStamp(tv);
|
|
||||||
|
|
||||||
//转换成rtp时间戳
|
|
||||||
rtcp->rtpts = htonl(_last_rtp_stamp);
|
rtcp->rtpts = htonl(_last_rtp_stamp);
|
||||||
|
rtcp->ssrc = htonl(rtcp_ssrc);
|
||||||
rtcp->packet_count = htonl((uint32_t) _packets);
|
rtcp->packet_count = htonl((uint32_t) _packets);
|
||||||
rtcp->octet_count = htonl((uint32_t) _bytes);
|
rtcp->octet_count = htonl((uint32_t) _bytes);
|
||||||
return RtcpHeader::toBuffer(std::move(rtcp));
|
return RtcpHeader::toBuffer(std::move(rtcp));
|
||||||
|
@ -30,9 +30,10 @@ public:
|
|||||||
* 输出或输入rtp时调用
|
* 输出或输入rtp时调用
|
||||||
* @param seq rtp的seq
|
* @param seq rtp的seq
|
||||||
* @param stamp rtp的时间戳,单位采样数(非毫秒)
|
* @param stamp rtp的时间戳,单位采样数(非毫秒)
|
||||||
|
* @param rtp rtp时间戳采样率,视频一般为90000,音频一般为采样率
|
||||||
* @param bytes rtp数据长度
|
* @param bytes rtp数据长度
|
||||||
*/
|
*/
|
||||||
void onRtp(uint16_t seq, uint32_t stamp, size_t bytes);
|
void onRtp(uint16_t seq, uint32_t stamp, uint32_t sample_rate, size_t bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入sr rtcp包
|
* 输入sr rtcp包
|
||||||
@ -112,6 +113,7 @@ private:
|
|||||||
uint32_t _last_sr_lsr = 0;
|
uint32_t _last_sr_lsr = 0;
|
||||||
//上次收到sr时的系统时间戳,单位毫秒
|
//上次收到sr时的系统时间戳,单位毫秒
|
||||||
uint64_t _last_sr_ntp_sys = 0;
|
uint64_t _last_sr_ntp_sys = 0;
|
||||||
|
unordered_map<uint32_t/*ssrc*/, uint32_t/*rtt*/> _rtt;
|
||||||
};
|
};
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -35,7 +35,7 @@ public:
|
|||||||
void onRecvRtp(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len){
|
void onRecvRtp(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len){
|
||||||
//统计rtp接受情况,用于发送rr包
|
//统计rtp接受情况,用于发送rr包
|
||||||
auto header = (RtpHeader *) buf->data();
|
auto header = (RtpHeader *) buf->data();
|
||||||
onRtp(ntohs(header->seq), ntohl(header->stamp), buf->size());
|
onRtp(ntohs(header->seq), ntohl(header->stamp), _sample_rate, buf->size());
|
||||||
sendRtcp(ntohl(header->ssrc), addr, addr_len);
|
sendRtcp(ntohl(header->ssrc), addr, addr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ void RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrC
|
|||||||
|
|
||||||
void RtspPlayer::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_idx){
|
void RtspPlayer::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_idx){
|
||||||
auto &rtcp_ctx = _rtcp_context[track_idx];
|
auto &rtcp_ctx = _rtcp_context[track_idx];
|
||||||
rtcp_ctx->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
rtcp_ctx->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->sample_rate, rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
||||||
|
|
||||||
auto &ticker = _rtcp_send_ticker[track_idx];
|
auto &ticker = _rtcp_send_ticker[track_idx];
|
||||||
if (ticker.elapsedTime() < 3 * 1000) {
|
if (ticker.elapsedTime() < 3 * 1000) {
|
||||||
|
@ -360,7 +360,7 @@ void RtspPusher::updateRtcpContext(const RtpPacket::Ptr &rtp){
|
|||||||
int track_index = getTrackIndexByTrackType(rtp->type);
|
int track_index = getTrackIndexByTrackType(rtp->type);
|
||||||
auto &ticker = _rtcp_send_ticker[track_index];
|
auto &ticker = _rtcp_send_ticker[track_index];
|
||||||
auto &rtcp_ctx = _rtcp_context[track_index];
|
auto &rtcp_ctx = _rtcp_context[track_index];
|
||||||
rtcp_ctx->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
rtcp_ctx->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->sample_rate, rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
||||||
|
|
||||||
//send rtcp every 5 second
|
//send rtcp every 5 second
|
||||||
if (ticker.elapsedTime() > 5 * 1000) {
|
if (ticker.elapsedTime() > 5 * 1000) {
|
||||||
|
@ -1126,7 +1126,7 @@ void RtspSession::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index){
|
|||||||
void RtspSession::updateRtcpContext(const RtpPacket::Ptr &rtp){
|
void RtspSession::updateRtcpContext(const RtpPacket::Ptr &rtp){
|
||||||
int track_index = getTrackIndexByTrackType(rtp->type);
|
int track_index = getTrackIndexByTrackType(rtp->type);
|
||||||
auto &rtcp_ctx = _rtcp_context[track_index];
|
auto &rtcp_ctx = _rtcp_context[track_index];
|
||||||
rtcp_ctx->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
rtcp_ctx->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->sample_rate, rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
||||||
|
|
||||||
auto &ticker = _rtcp_send_tickers[track_index];
|
auto &ticker = _rtcp_send_tickers[track_index];
|
||||||
//send rtcp every 5 second
|
//send rtcp every 5 second
|
||||||
|
@ -586,7 +586,7 @@ public:
|
|||||||
//统计rtp接受情况,便于生成nack rtcp包
|
//统计rtp接受情况,便于生成nack rtcp包
|
||||||
_nack_ctx.received(seq);
|
_nack_ctx.received(seq);
|
||||||
//统计rtp收到的情况,好做rr汇报
|
//统计rtp收到的情况,好做rr汇报
|
||||||
_rtcp_context.onRtp(seq, ntohl(rtp->stamp), len);
|
_rtcp_context.onRtp(seq, ntohl(rtp->stamp), sample_rate, len);
|
||||||
}
|
}
|
||||||
return RtpTrack::inputRtp(type, sample_rate, ptr, len);
|
return RtpTrack::inputRtp(type, sample_rate, ptr, len);
|
||||||
}
|
}
|
||||||
@ -825,7 +825,7 @@ void WebRtcTransportImp::onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool r
|
|||||||
}
|
}
|
||||||
if (!rtx) {
|
if (!rtx) {
|
||||||
//统计rtp发送情况,好做sr汇报
|
//统计rtp发送情况,好做sr汇报
|
||||||
track->rtcp_context_send->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
track->rtcp_context_send->onRtp(rtp->getSeq(), ntohl(rtp->getHeader()->stamp), rtp->sample_rate, rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
||||||
track->nack_list.push_back(rtp);
|
track->nack_list.push_back(rtp);
|
||||||
#if 0
|
#if 0
|
||||||
//此处模拟发送丢包
|
//此处模拟发送丢包
|
||||||
|
Loading…
Reference in New Issue
Block a user