mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-26 20:25:34 +08:00
[feat] update sr and rr implementation
This commit is contained in:
5
src/channel/rtcp_channel/rtcp_receiver.cpp
Normal file
5
src/channel/rtcp_channel/rtcp_receiver.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include "rtcp_receiver.h"
|
||||||
|
|
||||||
|
RtcpReceiver::RtcpReceiver() {}
|
||||||
|
|
||||||
|
RtcpReceiver::~RtcpReceiver() {}
|
||||||
19
src/channel/rtcp_channel/rtcp_receiver.h
Normal file
19
src/channel/rtcp_channel/rtcp_receiver.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-02-17
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTCP_RECEIVER_H_
|
||||||
|
#define _RTCP_RECEIVER_H_
|
||||||
|
|
||||||
|
class RtcpReceiver {
|
||||||
|
public:
|
||||||
|
RtcpReceiver();
|
||||||
|
~RtcpReceiver();
|
||||||
|
|
||||||
|
public:
|
||||||
|
private:
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
43
src/channel/rtcp_channel/rtcp_sender.cpp
Normal file
43
src/channel/rtcp_channel/rtcp_sender.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "rtcp_sender.h"
|
||||||
|
|
||||||
|
RtcpSender::RtcpSender(std::shared_ptr<webrtc::Clock> clock, uint32_t ssrc)
|
||||||
|
: clock_(clock), ssrc_(ssrc) {}
|
||||||
|
|
||||||
|
RtcpSender::~RtcpSender() {}
|
||||||
|
|
||||||
|
void RtcpSender::BuildSR(const RtcpContext& ctx, PacketSender& sender) {
|
||||||
|
// The timestamp of this RTCP packet should be estimated as the timestamp of
|
||||||
|
// the frame being captured at this moment. We are calculating that
|
||||||
|
// timestamp as the last frame's timestamp + the time since the last frame
|
||||||
|
// was captured.
|
||||||
|
int rtp_rate = rtp_clock_rates_khz_[last_payload_type_];
|
||||||
|
if (rtp_rate <= 0) {
|
||||||
|
rtp_rate =
|
||||||
|
(audio_ ? kBogusRtpRateForAudioRtcp : kVideoPayloadTypeFrequency) /
|
||||||
|
1000;
|
||||||
|
}
|
||||||
|
// Round now_us_ to the closest millisecond, because Ntp time is rounded
|
||||||
|
// when converted to milliseconds,
|
||||||
|
uint32_t rtp_timestamp =
|
||||||
|
timestamp_offset_ + last_rtp_timestamp_ +
|
||||||
|
((ctx.now_.us() + 500) / 1000 - last_frame_capture_time_->ms()) *
|
||||||
|
rtp_rate;
|
||||||
|
|
||||||
|
rtcp::SenderReport report;
|
||||||
|
report.SetSenderSsrc(ssrc_);
|
||||||
|
report.SetNtp(env_.clock().ConvertTimestampToNtpTime(ctx.now_));
|
||||||
|
report.SetRtpTimestamp(rtp_timestamp);
|
||||||
|
report.SetPacketCount(ctx.feedback_state_.packets_sent);
|
||||||
|
report.SetOctetCount(ctx.feedback_state_.media_bytes_sent);
|
||||||
|
report.SetReportBlocks(CreateReportBlocks(ctx.feedback_state_));
|
||||||
|
sender.AppendPacket(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcpSender::BuildRR(const RtcpContext& ctx, PacketSender& sender) {
|
||||||
|
rtcp::ReceiverReport report;
|
||||||
|
report.SetSenderSsrc(ssrc_);
|
||||||
|
report.SetReportBlocks(CreateReportBlocks(ctx.feedback_state_));
|
||||||
|
if (method_ == RtcpMode::kCompound || !report.report_blocks().empty()) {
|
||||||
|
sender.AppendPacket(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/channel/rtcp_channel/rtcp_sender.h
Normal file
26
src/channel/rtcp_channel/rtcp_sender.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-02-17
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTCP_SENDER_H_
|
||||||
|
#define _RTCP_SENDER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "api/clock/clock.h"
|
||||||
|
#include "rtcp/rtcp_packet/rtcp_packet.h"
|
||||||
|
|
||||||
|
class RtcpSender {
|
||||||
|
public:
|
||||||
|
RtcpSender(std::shared_ptr<webrtc::Clock> clock, uint32_t ssrc);
|
||||||
|
~RtcpSender();
|
||||||
|
|
||||||
|
public:
|
||||||
|
private:
|
||||||
|
std::shared_ptr<webrtc::Clock> clock_;
|
||||||
|
uint32_t ssrc_;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -261,7 +261,7 @@ size_t CongestionControlFeedback::BlockLength() const {
|
|||||||
return total_size;
|
return total_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CongestionControlFeedback::Parse(const rtcp::CommonHeader& packet) {
|
bool CongestionControlFeedback::Parse(const CommonHeader& packet) {
|
||||||
const uint8_t* payload = packet.payload();
|
const uint8_t* payload = packet.payload();
|
||||||
const uint8_t* payload_end = packet.payload() + packet.payload_size_bytes();
|
const uint8_t* payload_end = packet.payload() + packet.payload_size_bytes();
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
#include "byte_io.h"
|
#include "byte_io.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
namespace rtcp {
|
|
||||||
// 0 1 1 2 3
|
// 0 1 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@@ -83,5 +81,3 @@ bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace rtcp
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
namespace rtcp {
|
|
||||||
class CommonHeader {
|
class CommonHeader {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t kHeaderSizeBytes = 4;
|
static constexpr size_t kHeaderSizeBytes = 4;
|
||||||
@@ -47,6 +45,5 @@ class CommonHeader {
|
|||||||
uint32_t payload_size_ = 0;
|
uint32_t payload_size_ = 0;
|
||||||
const uint8_t* payload_ = nullptr;
|
const uint8_t* payload_ = nullptr;
|
||||||
};
|
};
|
||||||
} // namespace rtcp
|
|
||||||
} // namespace webrtc
|
|
||||||
#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_
|
#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_
|
||||||
|
|||||||
96
src/rtcp/rtcp_packet/receiver_report.cpp
Normal file
96
src/rtcp/rtcp_packet/receiver_report.cpp
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "receiver_report.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "byte_io.h"
|
||||||
|
#include "common_header.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
// RTCP receiver report (RFC 3550).
|
||||||
|
//
|
||||||
|
// 0 1 2 3
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// |V=2|P| RC | PT=RR=201 | length |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | SSRC of packet sender |
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | report block(s) |
|
||||||
|
// | .... |
|
||||||
|
|
||||||
|
ReceiverReport::ReceiverReport() = default;
|
||||||
|
|
||||||
|
ReceiverReport::ReceiverReport(const ReceiverReport& rhs) = default;
|
||||||
|
|
||||||
|
ReceiverReport::~ReceiverReport() = default;
|
||||||
|
|
||||||
|
bool ReceiverReport::Parse(const CommonHeader& packet) {
|
||||||
|
const uint8_t report_blocks_count = packet.count();
|
||||||
|
|
||||||
|
if (packet.payload_size_bytes() <
|
||||||
|
kRrBaseLength + report_blocks_count * ReportBlock::kLength) {
|
||||||
|
LOG_WARN("Packet is too small to contain all the data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSenderSsrc(ByteReader<uint32_t>::ReadBigEndian(packet.payload()));
|
||||||
|
|
||||||
|
const uint8_t* next_report_block = packet.payload() + kRrBaseLength;
|
||||||
|
|
||||||
|
report_blocks_.resize(report_blocks_count);
|
||||||
|
for (ReportBlock& block : report_blocks_) {
|
||||||
|
block.Parse(next_report_block, ReportBlock::kLength);
|
||||||
|
next_report_block += ReportBlock::kLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ReceiverReport::BlockLength() const {
|
||||||
|
return kHeaderLength + kRrBaseLength +
|
||||||
|
report_blocks_.size() * ReportBlock::kLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReceiverReport::Create(uint8_t* packet, size_t* index, size_t max_length,
|
||||||
|
PacketReadyCallback callback) const {
|
||||||
|
while (*index + BlockLength() > max_length) {
|
||||||
|
if (!OnBufferFull(packet, index, callback)) return false;
|
||||||
|
}
|
||||||
|
CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet,
|
||||||
|
index);
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc());
|
||||||
|
*index += kRrBaseLength;
|
||||||
|
for (const ReportBlock& block : report_blocks_) {
|
||||||
|
block.Create(packet + *index);
|
||||||
|
*index += ReportBlock::kLength;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReceiverReport::AddReportBlock(const ReportBlock& block) {
|
||||||
|
if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
|
||||||
|
LOG_WARN("Max report blocks reached.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
report_blocks_.push_back(block);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReceiverReport::SetReportBlocks(std::vector<ReportBlock> blocks) {
|
||||||
|
if (blocks.size() > kMaxNumberOfReportBlocks) {
|
||||||
|
LOG_WARN("Too many report blocks ({}) for receiver report.", blocks.size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
report_blocks_ = std::move(blocks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
50
src/rtcp/rtcp_packet/receiver_report.h
Normal file
50
src/rtcp/rtcp_packet/receiver_report.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-02-17
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RECEIVER_REPORT_H_
|
||||||
|
#define _RECEIVER_REPORT_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "report_block.h"
|
||||||
|
#include "rtcp_packet.h"
|
||||||
|
|
||||||
|
class CommonHeader;
|
||||||
|
|
||||||
|
class ReceiverReport : public RtcpPacket {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t kPacketType = 201;
|
||||||
|
static constexpr size_t kMaxNumberOfReportBlocks = 0x1f;
|
||||||
|
|
||||||
|
ReceiverReport();
|
||||||
|
ReceiverReport(const ReceiverReport&);
|
||||||
|
~ReceiverReport() override;
|
||||||
|
|
||||||
|
// Parse assumes header is already parsed and validated.
|
||||||
|
bool Parse(const CommonHeader& packet);
|
||||||
|
|
||||||
|
bool AddReportBlock(const ReportBlock& block);
|
||||||
|
bool SetReportBlocks(std::vector<ReportBlock> blocks);
|
||||||
|
|
||||||
|
const std::vector<ReportBlock>& report_blocks() const {
|
||||||
|
return report_blocks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t BlockLength() const override;
|
||||||
|
|
||||||
|
bool Create(uint8_t* packet, size_t* index, size_t max_length,
|
||||||
|
PacketReadyCallback callback) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t kRrBaseLength = 4;
|
||||||
|
|
||||||
|
std::vector<ReportBlock> report_blocks_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
79
src/rtcp/rtcp_packet/report_block.cpp
Normal file
79
src/rtcp/rtcp_packet/report_block.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "report_block.h"
|
||||||
|
|
||||||
|
#include "byte_io.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
|
||||||
|
//
|
||||||
|
// RTCP report block (RFC 3550).
|
||||||
|
//
|
||||||
|
// 0 1 2 3
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// 0 | SSRC_1 (SSRC of first source) |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 4 | fraction lost | cumulative number of packets lost |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 8 | extended highest sequence number received |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 12 | interarrival jitter |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 16 | last SR (LSR) |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 20 | delay since last SR (DLSR) |
|
||||||
|
// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
ReportBlock::ReportBlock()
|
||||||
|
: source_ssrc_(0),
|
||||||
|
fraction_lost_(0),
|
||||||
|
cumulative_lost_(0),
|
||||||
|
extended_high_seq_num_(0),
|
||||||
|
jitter_(0),
|
||||||
|
last_sr_(0),
|
||||||
|
delay_since_last_sr_(0) {}
|
||||||
|
|
||||||
|
bool ReportBlock::Parse(const uint8_t* buffer, size_t length) {
|
||||||
|
if (length < ReportBlock::kLength) {
|
||||||
|
LOG_ERROR("Report Block should be 24 bytes long");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]);
|
||||||
|
fraction_lost_ = buffer[4];
|
||||||
|
cumulative_lost_ = ByteReader<int32_t, 3>::ReadBigEndian(&buffer[5]);
|
||||||
|
extended_high_seq_num_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
|
||||||
|
jitter_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[12]);
|
||||||
|
last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[16]);
|
||||||
|
delay_since_last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[20]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportBlock::Create(uint8_t* buffer) const {
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&buffer[0], source_ssrc());
|
||||||
|
ByteWriter<uint8_t>::WriteBigEndian(&buffer[4], fraction_lost());
|
||||||
|
ByteWriter<int32_t, 3>::WriteBigEndian(&buffer[5], cumulative_lost());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&buffer[8], extended_high_seq_num());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&buffer[12], jitter());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&buffer[16], last_sr());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&buffer[20], delay_since_last_sr());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReportBlock::SetCumulativeLost(int32_t cumulative_lost) {
|
||||||
|
// We have only 3 bytes to store it, and it's a signed value.
|
||||||
|
if (cumulative_lost >= (1 << 23) || cumulative_lost < -(1 << 23)) {
|
||||||
|
LOG_WARN("Cumulative lost is too big to fit into Report Block");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cumulative_lost_ = cumulative_lost;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
60
src/rtcp/rtcp_packet/report_block.h
Normal file
60
src/rtcp/rtcp_packet/report_block.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-02-17
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _REPORT_BLOCK_H_
|
||||||
|
#define _REPORT_BLOCK_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// A ReportBlock represents the Sender Report packet from
|
||||||
|
// RFC 3550 section 6.4.1.
|
||||||
|
class ReportBlock {
|
||||||
|
public:
|
||||||
|
static constexpr size_t kLength = 24;
|
||||||
|
|
||||||
|
ReportBlock();
|
||||||
|
~ReportBlock() {}
|
||||||
|
|
||||||
|
bool Parse(const uint8_t* buffer, size_t length);
|
||||||
|
|
||||||
|
// Fills buffer with the ReportBlock.
|
||||||
|
// Consumes ReportBlock::kLength bytes.
|
||||||
|
void Create(uint8_t* buffer) const;
|
||||||
|
|
||||||
|
void SetMediaSsrc(uint32_t ssrc) { source_ssrc_ = ssrc; }
|
||||||
|
void SetFractionLost(uint8_t fraction_lost) {
|
||||||
|
fraction_lost_ = fraction_lost;
|
||||||
|
}
|
||||||
|
bool SetCumulativeLost(int32_t cumulative_lost);
|
||||||
|
void SetExtHighestSeqNum(uint32_t ext_highest_seq_num) {
|
||||||
|
extended_high_seq_num_ = ext_highest_seq_num;
|
||||||
|
}
|
||||||
|
void SetJitter(uint32_t jitter) { jitter_ = jitter; }
|
||||||
|
void SetLastSr(uint32_t last_sr) { last_sr_ = last_sr; }
|
||||||
|
void SetDelayLastSr(uint32_t delay_last_sr) {
|
||||||
|
delay_since_last_sr_ = delay_last_sr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t source_ssrc() const { return source_ssrc_; }
|
||||||
|
uint8_t fraction_lost() const { return fraction_lost_; }
|
||||||
|
int32_t cumulative_lost() const { return cumulative_lost_; }
|
||||||
|
uint32_t extended_high_seq_num() const { return extended_high_seq_num_; }
|
||||||
|
uint32_t jitter() const { return jitter_; }
|
||||||
|
uint32_t last_sr() const { return last_sr_; }
|
||||||
|
uint32_t delay_since_last_sr() const { return delay_since_last_sr_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t source_ssrc_; // 32 bits
|
||||||
|
uint8_t fraction_lost_; // 8 bits representing a fixed point value 0..1
|
||||||
|
int32_t cumulative_lost_; // Signed 24-bit value
|
||||||
|
uint32_t extended_high_seq_num_; // 32 bits
|
||||||
|
uint32_t jitter_; // 32 bits
|
||||||
|
uint32_t last_sr_; // 32 bits
|
||||||
|
uint32_t delay_since_last_sr_; // 32 bits, units of 1/65536 seconds
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
120
src/rtcp/rtcp_packet/sender_report.cpp
Normal file
120
src/rtcp/rtcp_packet/sender_report.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sender_report.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "byte_io.h"
|
||||||
|
#include "common_header.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
// Sender report (SR) (RFC 3550).
|
||||||
|
// 0 1 2 3
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// |V=2|P| RC | PT=SR=200 | length |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 0 | SSRC of sender |
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// 4 | NTP timestamp, most significant word |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 8 | NTP timestamp, least significant word |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 12 | RTP timestamp |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 16 | sender's packet count |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// 20 | sender's octet count |
|
||||||
|
// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
|
||||||
|
SenderReport::SenderReport()
|
||||||
|
: rtp_timestamp_(0), sender_packet_count_(0), sender_octet_count_(0) {}
|
||||||
|
|
||||||
|
SenderReport::SenderReport(const SenderReport&) = default;
|
||||||
|
SenderReport::SenderReport(SenderReport&&) = default;
|
||||||
|
SenderReport& SenderReport::operator=(const SenderReport&) = default;
|
||||||
|
SenderReport& SenderReport::operator=(SenderReport&&) = default;
|
||||||
|
SenderReport::~SenderReport() = default;
|
||||||
|
|
||||||
|
bool SenderReport::Parse(const CommonHeader& packet) {
|
||||||
|
const uint8_t report_block_count = packet.count();
|
||||||
|
if (packet.payload_size_bytes() <
|
||||||
|
kSenderBaseLength + report_block_count * ReportBlock::kLength) {
|
||||||
|
LOG_WARN("Packet is too small to contain all the data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Read SenderReport header.
|
||||||
|
const uint8_t* const payload = packet.payload();
|
||||||
|
SetSenderSsrc(ByteReader<uint32_t>::ReadBigEndian(&payload[0]));
|
||||||
|
uint32_t secs = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
|
||||||
|
uint32_t frac = ByteReader<uint32_t>::ReadBigEndian(&payload[8]);
|
||||||
|
ntp_.Set(secs, frac);
|
||||||
|
rtp_timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&payload[12]);
|
||||||
|
sender_packet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[16]);
|
||||||
|
sender_octet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[20]);
|
||||||
|
report_blocks_.resize(report_block_count);
|
||||||
|
const uint8_t* next_block = payload + kSenderBaseLength;
|
||||||
|
for (ReportBlock& block : report_blocks_) {
|
||||||
|
bool block_parsed = block.Parse(next_block, ReportBlock::kLength);
|
||||||
|
next_block += ReportBlock::kLength;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SenderReport::BlockLength() const {
|
||||||
|
return kHeaderLength + kSenderBaseLength +
|
||||||
|
report_blocks_.size() * ReportBlock::kLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SenderReport::Create(uint8_t* packet, size_t* index, size_t max_length,
|
||||||
|
PacketReadyCallback callback) const {
|
||||||
|
while (*index + BlockLength() > max_length) {
|
||||||
|
if (!OnBufferFull(packet, index, callback)) return false;
|
||||||
|
}
|
||||||
|
const size_t index_end = *index + BlockLength();
|
||||||
|
|
||||||
|
CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet,
|
||||||
|
index);
|
||||||
|
// Write SenderReport header.
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 0], sender_ssrc());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 4], ntp_.seconds());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 8], ntp_.fractions());
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 12], rtp_timestamp_);
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 16],
|
||||||
|
sender_packet_count_);
|
||||||
|
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index + 20],
|
||||||
|
sender_octet_count_);
|
||||||
|
*index += kSenderBaseLength;
|
||||||
|
// Write report blocks.
|
||||||
|
for (const ReportBlock& block : report_blocks_) {
|
||||||
|
block.Create(packet + *index);
|
||||||
|
*index += ReportBlock::kLength;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SenderReport::AddReportBlock(const ReportBlock& block) {
|
||||||
|
if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
|
||||||
|
LOG_WARN("Max report blocks reached.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
report_blocks_.push_back(block);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SenderReport::SetReportBlocks(std::vector<ReportBlock> blocks) {
|
||||||
|
if (blocks.size() > kMaxNumberOfReportBlocks) {
|
||||||
|
LOG_WARN("Too many report blocks ({}) for sender report.", blocks.size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
report_blocks_ = std::move(blocks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
71
src/rtcp/rtcp_packet/sender_report.h
Normal file
71
src/rtcp/rtcp_packet/sender_report.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-02-17
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SENDER_REPORT_H_
|
||||||
|
#define _SENDER_REPORT_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "api/ntp/ntp_time.h"
|
||||||
|
#include "report_block.h"
|
||||||
|
#include "rtcp_packet.h"
|
||||||
|
|
||||||
|
class CommonHeader;
|
||||||
|
|
||||||
|
class SenderReport : public RtcpPacket {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t kPacketType = 200;
|
||||||
|
static constexpr size_t kMaxNumberOfReportBlocks = 0x1f;
|
||||||
|
|
||||||
|
SenderReport();
|
||||||
|
SenderReport(const SenderReport&);
|
||||||
|
SenderReport(SenderReport&&);
|
||||||
|
SenderReport& operator=(const SenderReport&);
|
||||||
|
SenderReport& operator=(SenderReport&&);
|
||||||
|
~SenderReport() override;
|
||||||
|
|
||||||
|
// Parse assumes header is already parsed and validated.
|
||||||
|
bool Parse(const CommonHeader& packet);
|
||||||
|
|
||||||
|
void SetNtp(webrtc::NtpTime ntp) { ntp_ = ntp; }
|
||||||
|
void SetRtpTimestamp(uint32_t rtp_timestamp) {
|
||||||
|
rtp_timestamp_ = rtp_timestamp;
|
||||||
|
}
|
||||||
|
void SetPacketCount(uint32_t packet_count) {
|
||||||
|
sender_packet_count_ = packet_count;
|
||||||
|
}
|
||||||
|
void SetOctetCount(uint32_t octet_count) {
|
||||||
|
sender_octet_count_ = octet_count;
|
||||||
|
}
|
||||||
|
bool AddReportBlock(const ReportBlock& block);
|
||||||
|
bool SetReportBlocks(std::vector<ReportBlock> blocks);
|
||||||
|
void ClearReportBlocks() { report_blocks_.clear(); }
|
||||||
|
|
||||||
|
webrtc::NtpTime ntp() const { return ntp_; }
|
||||||
|
uint32_t rtp_timestamp() const { return rtp_timestamp_; }
|
||||||
|
uint32_t sender_packet_count() const { return sender_packet_count_; }
|
||||||
|
uint32_t sender_octet_count() const { return sender_octet_count_; }
|
||||||
|
|
||||||
|
const std::vector<ReportBlock>& report_blocks() const {
|
||||||
|
return report_blocks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t BlockLength() const override;
|
||||||
|
|
||||||
|
bool Create(uint8_t* packet, size_t* index, size_t max_length,
|
||||||
|
PacketReadyCallback callback) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t kSenderBaseLength = 24;
|
||||||
|
|
||||||
|
webrtc::NtpTime ntp_;
|
||||||
|
uint32_t rtp_timestamp_;
|
||||||
|
uint32_t sender_packet_count_;
|
||||||
|
uint32_t sender_octet_count_;
|
||||||
|
std::vector<ReportBlock> report_blocks_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -207,7 +207,7 @@ void IceTransport::OnReceiveBuffer(NiceAgent *agent, guint stream_id,
|
|||||||
|
|
||||||
bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size,
|
bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size,
|
||||||
RtcpPacketInfo *rtcp_packet_info) {
|
RtcpPacketInfo *rtcp_packet_info) {
|
||||||
webrtc::rtcp::CommonHeader rtcp_block;
|
CommonHeader rtcp_block;
|
||||||
// If a sender report is received but no DLRR, we need to reset the
|
// If a sender report is received but no DLRR, we need to reset the
|
||||||
// roundTripTime stat according to the standard, see
|
// roundTripTime stat according to the standard, see
|
||||||
// https://www.w3.org/TR/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats-roundtriptime
|
// https://www.w3.org/TR/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats-roundtriptime
|
||||||
@@ -300,8 +300,7 @@ bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IceTransport::HandleCongestionControlFeedback(
|
bool IceTransport::HandleCongestionControlFeedback(
|
||||||
const webrtc::rtcp::CommonHeader &rtcp_block,
|
const CommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info) {
|
||||||
RtcpPacketInfo *rtcp_packet_info) {
|
|
||||||
webrtc::rtcp::CongestionControlFeedback feedback;
|
webrtc::rtcp::CongestionControlFeedback feedback;
|
||||||
if (!feedback.Parse(rtcp_block) || feedback.packets().empty()) {
|
if (!feedback.Parse(rtcp_block) || feedback.packets().empty()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -318,7 +317,7 @@ bool IceTransport::HandleCongestionControlFeedback(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IceTransport::HandleNack(const webrtc::rtcp::CommonHeader &rtcp_block,
|
bool IceTransport::HandleNack(const CommonHeader &rtcp_block,
|
||||||
RtcpPacketInfo *rtcp_packet_info) {
|
RtcpPacketInfo *rtcp_packet_info) {
|
||||||
webrtc::rtcp::Nack nack;
|
webrtc::rtcp::Nack nack;
|
||||||
if (!nack.Parse(rtcp_block)) {
|
if (!nack.Parse(rtcp_block)) {
|
||||||
|
|||||||
@@ -128,11 +128,10 @@ class IceTransport {
|
|||||||
bool ParseRtcpPacket(const uint8_t *buffer, size_t size,
|
bool ParseRtcpPacket(const uint8_t *buffer, size_t size,
|
||||||
RtcpPacketInfo *rtcp_packet_info);
|
RtcpPacketInfo *rtcp_packet_info);
|
||||||
|
|
||||||
bool HandleCongestionControlFeedback(
|
bool HandleCongestionControlFeedback(const CommonHeader &rtcp_block,
|
||||||
const webrtc::rtcp::CommonHeader &rtcp_block,
|
RtcpPacketInfo *rtcp_packet_info);
|
||||||
RtcpPacketInfo *rtcp_packet_info);
|
|
||||||
|
|
||||||
bool HandleNack(const webrtc::rtcp::CommonHeader &rtcp_block,
|
bool HandleNack(const CommonHeader &rtcp_block,
|
||||||
RtcpPacketInfo *rtcp_packet_info);
|
RtcpPacketInfo *rtcp_packet_info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user