Implement recieving FIR in RtcpTranceiver
Bug: webrtc:8239 Change-Id: I2075af1598faf62b4eb3ab85e80590ff41cd2f49 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/256811 Reviewed-by: Emil Lundmark <lndmrk@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36341}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
3d6c6556b4
commit
56a04c3430
@ -100,6 +100,7 @@ class RtpStreamRtcpHandler {
|
||||
|
||||
virtual void OnNack(uint32_t sender_ssrc,
|
||||
rtc::ArrayView<const uint16_t> sequence_numbers) {}
|
||||
virtual void OnFir(uint32_t sender_ssrc) {}
|
||||
virtual void OnPli(uint32_t sender_ssrc) {}
|
||||
};
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
|
||||
#include "modules/rtp_rtcp/source/time_util.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/containers/flat_map.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/numerics/divide_round.h"
|
||||
#include "rtc_base/task_utils/repeating_task.h"
|
||||
@ -57,6 +58,8 @@ struct RtcpTransceiverImpl::RemoteSenderState {
|
||||
struct RtcpTransceiverImpl::LocalSenderState {
|
||||
uint32_t ssrc;
|
||||
size_t last_num_sent_bytes = 0;
|
||||
// Sequence number of the last FIR message per sender SSRC.
|
||||
flat_map<uint32_t, uint8_t> last_fir;
|
||||
RtpStreamRtcpHandler* handler = nullptr;
|
||||
};
|
||||
|
||||
@ -337,6 +340,9 @@ void RtcpTransceiverImpl::HandlePayloadSpecificFeedback(
|
||||
const rtcp::CommonHeader& rtcp_packet_header,
|
||||
Timestamp now) {
|
||||
switch (rtcp_packet_header.fmt()) {
|
||||
case rtcp::Fir::kFeedbackMessageType:
|
||||
HandleFir(rtcp_packet_header);
|
||||
break;
|
||||
case rtcp::Pli::kFeedbackMessageType:
|
||||
HandlePli(rtcp_packet_header);
|
||||
break;
|
||||
@ -346,6 +352,26 @@ void RtcpTransceiverImpl::HandlePayloadSpecificFeedback(
|
||||
}
|
||||
}
|
||||
|
||||
void RtcpTransceiverImpl::HandleFir(
|
||||
const rtcp::CommonHeader& rtcp_packet_header) {
|
||||
rtcp::Fir fir;
|
||||
if (local_senders_.empty() || !fir.Parse(rtcp_packet_header)) {
|
||||
return;
|
||||
}
|
||||
for (const rtcp::Fir::Request& r : fir.requests()) {
|
||||
auto it = local_senders_by_ssrc_.find(r.ssrc);
|
||||
if (it == local_senders_by_ssrc_.end()) {
|
||||
continue;
|
||||
}
|
||||
auto [fir_it, is_new] =
|
||||
it->second->last_fir.emplace(fir.sender_ssrc(), r.seq_nr);
|
||||
if (is_new || fir_it->second != r.seq_nr) {
|
||||
it->second->handler->OnFir(fir.sender_ssrc());
|
||||
fir_it->second = r.seq_nr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RtcpTransceiverImpl::HandlePli(
|
||||
const rtcp::CommonHeader& rtcp_packet_header) {
|
||||
rtcp::Pli pli;
|
||||
|
@ -105,6 +105,7 @@ class RtcpTransceiverImpl {
|
||||
Timestamp now);
|
||||
void HandleRtpFeedback(const rtcp::CommonHeader& rtcp_packet_header,
|
||||
Timestamp now);
|
||||
void HandleFir(const rtcp::CommonHeader& rtcp_packet_header);
|
||||
void HandlePli(const rtcp::CommonHeader& rtcp_packet_header);
|
||||
void HandleRemb(const rtcp::CommonHeader& rtcp_packet_header, Timestamp now);
|
||||
void HandleNack(const rtcp::CommonHeader& rtcp_packet_header);
|
||||
|
@ -87,6 +87,7 @@ class MockRtpStreamRtcpHandler : public RtpStreamRtcpHandler {
|
||||
OnNack,
|
||||
(uint32_t, rtc::ArrayView<const uint16_t>),
|
||||
(override));
|
||||
MOCK_METHOD(void, OnFir, (uint32_t), (override));
|
||||
MOCK_METHOD(void, OnPli, (uint32_t), (override));
|
||||
|
||||
private:
|
||||
@ -1204,6 +1205,83 @@ TEST(RtcpTransceiverImplTest, SendFirDoesNotIncreaseSeqNoIfOldRequest) {
|
||||
EXPECT_EQ(rtcp_parser.fir()->requests()[1].seq_nr, fir_sequence_number1);
|
||||
}
|
||||
|
||||
TEST(RtcpTransceiverImplTest, ReceivesFir) {
|
||||
static constexpr uint32_t kRemoteSsrc = 4321;
|
||||
static constexpr uint32_t kMediaSsrc1 = 1234;
|
||||
static constexpr uint32_t kMediaSsrc2 = 1235;
|
||||
RtcpTransceiverConfig config = DefaultTestConfig();
|
||||
RtcpTransceiverImpl rtcp_transceiver(config);
|
||||
|
||||
MockRtpStreamRtcpHandler local_stream1;
|
||||
MockRtpStreamRtcpHandler local_stream2;
|
||||
EXPECT_CALL(local_stream1, OnFir(kRemoteSsrc));
|
||||
EXPECT_CALL(local_stream2, OnFir).Times(0);
|
||||
|
||||
EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc1, &local_stream1));
|
||||
EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc2, &local_stream2));
|
||||
|
||||
rtcp::Fir fir;
|
||||
fir.SetSenderSsrc(kRemoteSsrc);
|
||||
fir.AddRequestTo(kMediaSsrc1, /*seq_num=*/13);
|
||||
|
||||
rtcp_transceiver.ReceivePacket(fir.Build(), config.clock->CurrentTime());
|
||||
}
|
||||
|
||||
TEST(RtcpTransceiverImplTest, IgnoresReceivedFirWithRepeatedSequenceNumber) {
|
||||
static constexpr uint32_t kRemoteSsrc = 4321;
|
||||
static constexpr uint32_t kMediaSsrc1 = 1234;
|
||||
static constexpr uint32_t kMediaSsrc2 = 1235;
|
||||
RtcpTransceiverConfig config = DefaultTestConfig();
|
||||
RtcpTransceiverImpl rtcp_transceiver(config);
|
||||
|
||||
MockRtpStreamRtcpHandler local_stream1;
|
||||
MockRtpStreamRtcpHandler local_stream2;
|
||||
EXPECT_CALL(local_stream1, OnFir(kRemoteSsrc)).Times(1);
|
||||
EXPECT_CALL(local_stream2, OnFir(kRemoteSsrc)).Times(2);
|
||||
|
||||
EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc1, &local_stream1));
|
||||
EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc2, &local_stream2));
|
||||
|
||||
rtcp::Fir fir1;
|
||||
fir1.SetSenderSsrc(kRemoteSsrc);
|
||||
fir1.AddRequestTo(kMediaSsrc1, /*seq_num=*/132);
|
||||
fir1.AddRequestTo(kMediaSsrc2, /*seq_num=*/10);
|
||||
rtcp_transceiver.ReceivePacket(fir1.Build(), config.clock->CurrentTime());
|
||||
|
||||
// Repeat request for MediaSsrc1 - expect it to be ignored,
|
||||
// Change FIR sequence number for MediaSsrc2 - expect a 2nd callback.
|
||||
rtcp::Fir fir2;
|
||||
fir2.SetSenderSsrc(kRemoteSsrc);
|
||||
fir2.AddRequestTo(kMediaSsrc1, /*seq_num=*/132);
|
||||
fir2.AddRequestTo(kMediaSsrc2, /*seq_num=*/13);
|
||||
rtcp_transceiver.ReceivePacket(fir2.Build(), config.clock->CurrentTime());
|
||||
}
|
||||
|
||||
TEST(RtcpTransceiverImplTest, ReceivedFirTracksSequenceNumberPerRemoteSsrc) {
|
||||
static constexpr uint32_t kRemoteSsrc1 = 4321;
|
||||
static constexpr uint32_t kRemoteSsrc2 = 4323;
|
||||
static constexpr uint32_t kMediaSsrc = 1234;
|
||||
RtcpTransceiverConfig config = DefaultTestConfig();
|
||||
RtcpTransceiverImpl rtcp_transceiver(config);
|
||||
|
||||
MockRtpStreamRtcpHandler local_stream;
|
||||
EXPECT_CALL(local_stream, OnFir(kRemoteSsrc1));
|
||||
EXPECT_CALL(local_stream, OnFir(kRemoteSsrc2));
|
||||
|
||||
EXPECT_TRUE(rtcp_transceiver.AddMediaSender(kMediaSsrc, &local_stream));
|
||||
|
||||
rtcp::Fir fir1;
|
||||
fir1.SetSenderSsrc(kRemoteSsrc1);
|
||||
fir1.AddRequestTo(kMediaSsrc, /*seq_num=*/13);
|
||||
rtcp_transceiver.ReceivePacket(fir1.Build(), config.clock->CurrentTime());
|
||||
|
||||
// Use the same FIR sequence number, but different sender SSRC.
|
||||
rtcp::Fir fir2;
|
||||
fir2.SetSenderSsrc(kRemoteSsrc2);
|
||||
fir2.AddRequestTo(kMediaSsrc, /*seq_num=*/13);
|
||||
rtcp_transceiver.ReceivePacket(fir2.Build(), config.clock->CurrentTime());
|
||||
}
|
||||
|
||||
TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesCompoundPacket) {
|
||||
const uint32_t kRemoteSsrcs[] = {4321};
|
||||
SimulatedClock clock(0);
|
||||
|
Reference in New Issue
Block a user