Commit 4c296488 by ziyue

修复rtcp rr/sr时间戳转换相关问题,计算rtt

parent bf8642d6
......@@ -263,11 +263,25 @@ string RtcpSR::getNtpStamp() const{
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) {
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));
}
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{
_StrPrinter printer;
printer << RtcpHeader::dumpHeader();
......
......@@ -347,12 +347,14 @@ public:
* @param tv 时间
*/
void setNtpStamp(struct timeval tv);
void setNtpStamp(uint64_t unix_stamp_ms);
/**
* 返回ntp时间的字符串
* 使用net2Host转换成主机字节序后才可使用此函数
*/
string getNtpStamp() const;
uint64_t getNtpUnixStampMS() const;
/**
* 获取ReportItem对象指针列表
......
......@@ -22,14 +22,14 @@ RtcpContext::RtcpContext(bool 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) {
//接收者才做复杂的统计运算
auto sys_stamp = getCurrentMillisecond();
if (_last_rtp_sys_stamp) {
//计算时间戳抖动值
double diff = double(
int64_t(sys_stamp) - int64_t(_last_rtp_sys_stamp) - int64_t(stamp) + int64_t(_last_rtp_stamp));
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;
}
......@@ -68,14 +68,9 @@ void RtcpContext::onRtp(uint16_t seq, uint32_t stamp, size_t bytes) {
}
void RtcpContext::onRtcp(RtcpHeader *rtcp) {
if ((RtcpType) rtcp->pt != RtcpType::RTCP_SR) {
return;
}
if (!_is_receiver) {
WarnL << "rtp发送者收到sr包";
return;
}
auto rtcp_sr = (RtcpSR *) (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
......@@ -85,6 +80,37 @@ void RtcpContext::onRtcp(RtcpHeader *rtcp) {
*/
_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;
}
}
size_t RtcpContext::getExpectedPackets() const {
......@@ -120,14 +146,9 @@ Buffer::Ptr RtcpContext::createRtcpSR(uint32_t rtcp_ssrc) {
throw std::runtime_error("rtp接收者尝试发送sr包");
}
auto rtcp = RtcpSR::create(0);
rtcp->ssrc = htonl(rtcp_ssrc);
struct timeval tv;
gettimeofday(&tv, NULL);
rtcp->setNtpStamp(tv);
//转换成rtp时间戳
rtcp->setNtpStamp(getCurrentMillisecond(true));
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);
return RtcpHeader::toBuffer(std::move(rtcp));
......
......@@ -30,9 +30,10 @@ public:
* 输出或输入rtp时调用
* @param seq rtp的seq
* @param stamp rtp的时间戳,单位采样数(非毫秒)
* @param rtp rtp时间戳采样率,视频一般为90000,音频一般为采样率
* @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包
......@@ -112,6 +113,7 @@ private:
uint32_t _last_sr_lsr = 0;
//上次收到sr时的系统时间戳,单位毫秒
uint64_t _last_sr_ntp_sys = 0;
unordered_map<uint32_t/*ssrc*/, uint32_t/*rtt*/> _rtt;
};
}//namespace mediakit
......
......@@ -35,7 +35,7 @@ public:
void onRecvRtp(const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len){
//统计rtp接受情况,用于发送rr包
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);
}
......
......@@ -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){
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];
if (ticker.elapsedTime() < 3 * 1000) {
......
......@@ -360,7 +360,7 @@ void RtspPusher::updateRtcpContext(const RtpPacket::Ptr &rtp){
int track_index = getTrackIndexByTrackType(rtp->type);
auto &ticker = _rtcp_send_ticker[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
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){
int track_index = getTrackIndexByTrackType(rtp->type);
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];
//send rtcp every 5 second
......
......@@ -586,7 +586,7 @@ public:
//统计rtp接受情况,便于生成nack rtcp包
_nack_ctx.received(seq);
//统计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);
}
......@@ -825,7 +825,7 @@ void WebRtcTransportImp::onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool r
}
if (!rtx) {
//统计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);
#if 0
//此处模拟发送丢包
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论