Add RequestKeyFrame with Pli to RtcpTransceiver
Add support for reduced size mode. Bug: webrtc:8239 Change-Id: I1d646f0d7848af6632c9204ce5b96ae24cfc0ad3 Reviewed-on: https://webrtc-review.googlesource.com/23681 Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20812}
This commit is contained in:

committed by
Commit Bot

parent
de939432dc
commit
a7e418cd5f
@ -90,4 +90,18 @@ void RtcpTransceiver::UnsetRemb() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RtcpTransceiver::RequestKeyFrame(std::vector<uint32_t> ssrcs) {
|
||||||
|
// TODO(danilchap): Replace with lambda with move capture when available.
|
||||||
|
struct RequestKeyFrameClosure {
|
||||||
|
void operator()() {
|
||||||
|
if (ptr)
|
||||||
|
ptr->RequestKeyFrame(ssrcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::WeakPtr<RtcpTransceiverImpl> ptr;
|
||||||
|
std::vector<uint32_t> ssrcs;
|
||||||
|
};
|
||||||
|
task_queue_->PostTask(RequestKeyFrameClosure{ptr_, std::move(ssrcs)});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -44,6 +44,8 @@ class RtcpTransceiver {
|
|||||||
// Stops sending REMB in following compound packets.
|
// Stops sending REMB in following compound packets.
|
||||||
void UnsetRemb();
|
void UnsetRemb();
|
||||||
|
|
||||||
|
void RequestKeyFrame(std::vector<uint32_t> ssrcs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rtc::TaskQueue* const task_queue_;
|
rtc::TaskQueue* const task_queue_;
|
||||||
std::unique_ptr<RtcpTransceiverImpl> rtcp_transceiver_;
|
std::unique_ptr<RtcpTransceiverImpl> rtcp_transceiver_;
|
||||||
|
@ -48,6 +48,11 @@ bool RtcpTransceiverConfig::Validate() const {
|
|||||||
RTC_LOG(LS_ERROR) << debug_id << "outgoing transport must be set";
|
RTC_LOG(LS_ERROR) << debug_id << "outgoing transport must be set";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (initial_report_delay_ms < 0) {
|
||||||
|
RTC_LOG(LS_ERROR) << debug_id << "delay " << initial_report_delay_ms
|
||||||
|
<< "ms before first report shouldn't be negative.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (report_period_ms <= 0) {
|
if (report_period_ms <= 0) {
|
||||||
RTC_LOG(LS_ERROR) << debug_id << "period " << report_period_ms
|
RTC_LOG(LS_ERROR) << debug_id << "period " << report_period_ms
|
||||||
<< "ms between reports should be positive.";
|
<< "ms between reports should be positive.";
|
||||||
@ -58,6 +63,10 @@ bool RtcpTransceiverConfig::Validate() const {
|
|||||||
<< "missing task queue for periodic compound packets";
|
<< "missing task queue for periodic compound packets";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (rtcp_mode != RtcpMode::kCompound && rtcp_mode != RtcpMode::kReducedSize) {
|
||||||
|
RTC_LOG(LS_ERROR) << debug_id << "unsupported rtcp mode";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// TODO(danilchap): Remove or update the warning when RtcpTransceiver supports
|
// TODO(danilchap): Remove or update the warning when RtcpTransceiver supports
|
||||||
// send-only sessions.
|
// send-only sessions.
|
||||||
if (receive_statistics == nullptr)
|
if (receive_statistics == nullptr)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||||
#include "rtc_base/task_queue.h"
|
#include "rtc_base/task_queue.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -51,6 +52,11 @@ struct RtcpTransceiverConfig {
|
|||||||
// Rtcp report block generator for outgoing receiver reports.
|
// Rtcp report block generator for outgoing receiver reports.
|
||||||
ReceiveStatisticsProvider* receive_statistics = nullptr;
|
ReceiveStatisticsProvider* receive_statistics = nullptr;
|
||||||
|
|
||||||
|
// Configures if sending should
|
||||||
|
// enforce compound packets: https://tools.ietf.org/html/rfc4585#section-3.1
|
||||||
|
// or allow reduced size packets: https://tools.ietf.org/html/rfc5506
|
||||||
|
// Receiving accepts both compound and reduced-size packets.
|
||||||
|
RtcpMode rtcp_mode = RtcpMode::kCompound;
|
||||||
//
|
//
|
||||||
// Tuning parameters.
|
// Tuning parameters.
|
||||||
//
|
//
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet.h"
|
#include "modules/rtp_rtcp/source/rtcp_packet.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
|
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
|
||||||
|
#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
|
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
|
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
|
#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
|
||||||
@ -28,11 +29,13 @@
|
|||||||
#include "rtc_base/timeutils.h"
|
#include "rtc_base/timeutils.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Helper to put several RTCP packets into lower layer datagram composing
|
// Helper to put several RTCP packets into lower layer datagram composing
|
||||||
// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
|
// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
|
||||||
class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
|
// TODO(danilchap): When in compound mode and packets are so many that several
|
||||||
|
// compound RTCP packets need to be generated, ensure each packet is compound.
|
||||||
|
class RtcpTransceiverImpl::PacketSender
|
||||||
|
: public rtcp::RtcpPacket::PacketReadyCallback {
|
||||||
public:
|
public:
|
||||||
PacketSender(Transport* transport, size_t max_packet_size)
|
PacketSender(Transport* transport, size_t max_packet_size)
|
||||||
: transport_(transport), max_packet_size_(max_packet_size) {
|
: transport_(transport), max_packet_size_(max_packet_size) {
|
||||||
@ -56,6 +59,8 @@ class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const { return index_ == 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Implements RtcpPacket::PacketReadyCallback
|
// Implements RtcpPacket::PacketReadyCallback
|
||||||
void OnPacketReady(uint8_t* data, size_t length) override {
|
void OnPacketReady(uint8_t* data, size_t length) override {
|
||||||
@ -68,8 +73,6 @@ class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
|
|||||||
uint8_t buffer_[IP_PACKET_SIZE];
|
uint8_t buffer_[IP_PACKET_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
|
RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
|
||||||
: config_(config), ptr_factory_(this) {
|
: config_(config), ptr_factory_(this) {
|
||||||
RTC_CHECK(config_.Validate());
|
RTC_CHECK(config_.Validate());
|
||||||
@ -94,12 +97,8 @@ void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtcpTransceiverImpl::SendCompoundPacket() {
|
void RtcpTransceiverImpl::SendCompoundPacket() {
|
||||||
SendPacket();
|
SendPeriodicCompoundPacket();
|
||||||
if (config_.schedule_periodic_compound_packets) {
|
ReschedulePeriodicCompoundPackets();
|
||||||
// Stop existent send task.
|
|
||||||
ptr_factory_.InvalidateWeakPtrs();
|
|
||||||
SchedulePeriodicCompoundPackets(config_.report_period_ms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
|
void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
|
||||||
@ -117,6 +116,27 @@ void RtcpTransceiverImpl::UnsetRemb() {
|
|||||||
remb_.reset();
|
remb_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RtcpTransceiverImpl::RequestKeyFrame(
|
||||||
|
rtc::ArrayView<const uint32_t> ssrcs) {
|
||||||
|
RTC_DCHECK(!ssrcs.empty());
|
||||||
|
const uint32_t sender_ssrc = config_.feedback_ssrc;
|
||||||
|
PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
|
||||||
|
if (config_.rtcp_mode == RtcpMode::kCompound)
|
||||||
|
CreateCompoundPacket(&sender);
|
||||||
|
|
||||||
|
for (uint32_t media_ssrc : ssrcs) {
|
||||||
|
rtcp::Pli pli;
|
||||||
|
pli.SetSenderSsrc(sender_ssrc);
|
||||||
|
pli.SetMediaSsrc(media_ssrc);
|
||||||
|
sender.AppendPacket(pli);
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.Send();
|
||||||
|
|
||||||
|
if (config_.rtcp_mode == RtcpMode::kCompound)
|
||||||
|
ReschedulePeriodicCompoundPackets();
|
||||||
|
}
|
||||||
|
|
||||||
void RtcpTransceiverImpl::HandleReceivedPacket(
|
void RtcpTransceiverImpl::HandleReceivedPacket(
|
||||||
const rtcp::CommonHeader& rtcp_packet_header,
|
const rtcp::CommonHeader& rtcp_packet_header,
|
||||||
int64_t now_us) {
|
int64_t now_us) {
|
||||||
@ -134,17 +154,25 @@ void RtcpTransceiverImpl::HandleReceivedPacket(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
|
||||||
|
if (!config_.schedule_periodic_compound_packets)
|
||||||
|
return;
|
||||||
|
// Stop existent send task.
|
||||||
|
ptr_factory_.InvalidateWeakPtrs();
|
||||||
|
SchedulePeriodicCompoundPackets(config_.report_period_ms);
|
||||||
|
}
|
||||||
|
|
||||||
void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
|
void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
|
||||||
class SendPeriodicCompoundPacket : public rtc::QueuedTask {
|
class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
|
||||||
public:
|
public:
|
||||||
SendPeriodicCompoundPacket(rtc::TaskQueue* task_queue,
|
SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
|
||||||
rtc::WeakPtr<RtcpTransceiverImpl> ptr)
|
rtc::WeakPtr<RtcpTransceiverImpl> ptr)
|
||||||
: task_queue_(task_queue), ptr_(std::move(ptr)) {}
|
: task_queue_(task_queue), ptr_(std::move(ptr)) {}
|
||||||
bool Run() override {
|
bool Run() override {
|
||||||
RTC_DCHECK(task_queue_->IsCurrent());
|
RTC_DCHECK(task_queue_->IsCurrent());
|
||||||
if (!ptr_)
|
if (!ptr_)
|
||||||
return true;
|
return true;
|
||||||
ptr_->SendPacket();
|
ptr_->SendPeriodicCompoundPacket();
|
||||||
task_queue_->PostDelayedTask(rtc::WrapUnique(this),
|
task_queue_->PostDelayedTask(rtc::WrapUnique(this),
|
||||||
ptr_->config_.report_period_ms);
|
ptr_->config_.report_period_ms);
|
||||||
return false;
|
return false;
|
||||||
@ -157,7 +185,7 @@ void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
|
|||||||
|
|
||||||
RTC_DCHECK(config_.schedule_periodic_compound_packets);
|
RTC_DCHECK(config_.schedule_periodic_compound_packets);
|
||||||
|
|
||||||
auto task = rtc::MakeUnique<SendPeriodicCompoundPacket>(
|
auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
|
||||||
config_.task_queue, ptr_factory_.GetWeakPtr());
|
config_.task_queue, ptr_factory_.GetWeakPtr());
|
||||||
if (delay_ms > 0)
|
if (delay_ms > 0)
|
||||||
config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
|
config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
|
||||||
@ -165,27 +193,30 @@ void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
|
|||||||
config_.task_queue->PostTask(std::move(task));
|
config_.task_queue->PostTask(std::move(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtcpTransceiverImpl::SendPacket() {
|
void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
|
||||||
PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
|
RTC_DCHECK(sender->IsEmpty());
|
||||||
const uint32_t sender_ssrc = config_.feedback_ssrc;
|
const uint32_t sender_ssrc = config_.feedback_ssrc;
|
||||||
|
|
||||||
rtcp::ReceiverReport receiver_report;
|
rtcp::ReceiverReport receiver_report;
|
||||||
receiver_report.SetSenderSsrc(sender_ssrc);
|
receiver_report.SetSenderSsrc(sender_ssrc);
|
||||||
receiver_report.SetReportBlocks(CreateReportBlocks());
|
receiver_report.SetReportBlocks(CreateReportBlocks());
|
||||||
sender.AppendPacket(receiver_report);
|
sender->AppendPacket(receiver_report);
|
||||||
|
|
||||||
if (!config_.cname.empty()) {
|
if (!config_.cname.empty()) {
|
||||||
rtcp::Sdes sdes;
|
rtcp::Sdes sdes;
|
||||||
bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
|
bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
|
||||||
RTC_DCHECK(added) << "Failed to add cname " << config_.cname
|
RTC_DCHECK(added) << "Failed to add cname " << config_.cname
|
||||||
<< " to rtcp sdes packet.";
|
<< " to rtcp sdes packet.";
|
||||||
sender.AppendPacket(sdes);
|
sender->AppendPacket(sdes);
|
||||||
}
|
}
|
||||||
if (remb_) {
|
if (remb_) {
|
||||||
remb_->SetSenderSsrc(sender_ssrc);
|
remb_->SetSenderSsrc(sender_ssrc);
|
||||||
sender.AppendPacket(*remb_);
|
sender->AppendPacket(*remb_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
|
||||||
|
PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
|
||||||
|
CreateCompoundPacket(&sender);
|
||||||
sender.Send();
|
sender.Send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,10 @@ class RtcpTransceiverImpl {
|
|||||||
// Stops sending REMB in following compound packets.
|
// Stops sending REMB in following compound packets.
|
||||||
void UnsetRemb();
|
void UnsetRemb();
|
||||||
|
|
||||||
|
void RequestKeyFrame(rtc::ArrayView<const uint32_t> ssrcs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class PacketSender;
|
||||||
struct SenderReportTimes {
|
struct SenderReportTimes {
|
||||||
int64_t local_received_time_us;
|
int64_t local_received_time_us;
|
||||||
NtpTime remote_sent_time;
|
NtpTime remote_sent_time;
|
||||||
@ -57,9 +60,13 @@ class RtcpTransceiverImpl {
|
|||||||
void HandleReceivedPacket(const rtcp::CommonHeader& rtcp_packet_header,
|
void HandleReceivedPacket(const rtcp::CommonHeader& rtcp_packet_header,
|
||||||
int64_t now_us);
|
int64_t now_us);
|
||||||
|
|
||||||
|
void ReschedulePeriodicCompoundPackets();
|
||||||
void SchedulePeriodicCompoundPackets(int64_t delay_ms);
|
void SchedulePeriodicCompoundPackets(int64_t delay_ms);
|
||||||
|
// Creates compound RTCP packet, as defined in
|
||||||
|
// https://tools.ietf.org/html/rfc5506#section-2
|
||||||
|
void CreateCompoundPacket(PacketSender* sender);
|
||||||
// Sends RTCP packets.
|
// Sends RTCP packets.
|
||||||
void SendPacket();
|
void SendPeriodicCompoundPacket();
|
||||||
// Generate Report Blocks to be send in Sender or Receiver Report.
|
// Generate Report Blocks to be send in Sender or Receiver Report.
|
||||||
std::vector<rtcp::ReportBlock> CreateReportBlocks();
|
std::vector<rtcp::ReportBlock> CreateReportBlocks();
|
||||||
|
|
||||||
|
@ -447,4 +447,69 @@ TEST(RtcpTransceiverImplTest,
|
|||||||
EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100);
|
EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RtcpTransceiverImplTest, RequestKeyFrameWithPictureLossIndication) {
|
||||||
|
const uint32_t kSenderSsrc = 1234;
|
||||||
|
const uint32_t kRemoteSsrcs[] = {4321, 5321};
|
||||||
|
MockTransport outgoing_transport;
|
||||||
|
RtcpTransceiverConfig config;
|
||||||
|
config.feedback_ssrc = kSenderSsrc;
|
||||||
|
config.schedule_periodic_compound_packets = false;
|
||||||
|
config.outgoing_transport = &outgoing_transport;
|
||||||
|
RtcpTransceiverImpl rtcp_transceiver(config);
|
||||||
|
RtcpPacketParser rtcp_parser;
|
||||||
|
EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
|
||||||
|
.WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
|
||||||
|
|
||||||
|
rtcp_transceiver.RequestKeyFrame(kRemoteSsrcs);
|
||||||
|
|
||||||
|
// Expect a pli packet per ssrc in the sent single compound packet.
|
||||||
|
EXPECT_EQ(rtcp_parser.pli()->num_packets(), 2);
|
||||||
|
EXPECT_EQ(rtcp_parser.pli()->sender_ssrc(), kSenderSsrc);
|
||||||
|
// test::RtcpPacketParser overwrites first pli packet with second one.
|
||||||
|
EXPECT_EQ(rtcp_parser.pli()->media_ssrc(), kRemoteSsrcs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesCompoundPacket) {
|
||||||
|
const uint32_t kRemoteSsrcs[] = {4321};
|
||||||
|
MockTransport outgoing_transport;
|
||||||
|
RtcpTransceiverConfig config;
|
||||||
|
// Turn periodic off to ensure sent rtcp packet is explicitly requested.
|
||||||
|
config.schedule_periodic_compound_packets = false;
|
||||||
|
config.outgoing_transport = &outgoing_transport;
|
||||||
|
|
||||||
|
config.rtcp_mode = webrtc::RtcpMode::kCompound;
|
||||||
|
|
||||||
|
RtcpTransceiverImpl rtcp_transceiver(config);
|
||||||
|
RtcpPacketParser rtcp_parser;
|
||||||
|
EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
|
||||||
|
.WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
|
||||||
|
|
||||||
|
rtcp_transceiver.RequestKeyFrame(kRemoteSsrcs);
|
||||||
|
|
||||||
|
// Test sent packet is compound by expecting presense of receiver report.
|
||||||
|
EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesReducedSizePacket) {
|
||||||
|
const uint32_t kRemoteSsrcs[] = {4321};
|
||||||
|
MockTransport outgoing_transport;
|
||||||
|
RtcpTransceiverConfig config;
|
||||||
|
// Turn periodic off to ensure sent rtcp packet is explicitly requested.
|
||||||
|
config.schedule_periodic_compound_packets = false;
|
||||||
|
config.outgoing_transport = &outgoing_transport;
|
||||||
|
|
||||||
|
config.rtcp_mode = webrtc::RtcpMode::kReducedSize;
|
||||||
|
|
||||||
|
RtcpTransceiverImpl rtcp_transceiver(config);
|
||||||
|
RtcpPacketParser rtcp_parser;
|
||||||
|
// Expect some rtcp packet is triggered by the RequestKeyFrame.
|
||||||
|
EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
|
||||||
|
.WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
|
||||||
|
|
||||||
|
rtcp_transceiver.RequestKeyFrame(kRemoteSsrcs);
|
||||||
|
|
||||||
|
// Test sent packet is reduced size by expecting absense of receiver report.
|
||||||
|
EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
Reference in New Issue
Block a user