Add integration test for NACK functionality
This adds a test that sets the required feedback mechanisms to get NACK configured for video, connects, and then sets packet loss to 100%. The expected result is that the receiver sends NACK; this will cause the test to set packet loss to 0%, so the next NACK sent should get to the sender and cause retransmission. This is explicating a problematic case in splitting media channel. Bug: webrtc:13931 Change-Id: I0c23c4a89953976454d84b0211f0a7545bbb717a Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/293720 Commit-Queue: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39412}
This commit is contained in:
parent
437bf78ed9
commit
5b4c651d67
@ -69,9 +69,11 @@
|
||||
#include "p2p/base/test_turn_server.h"
|
||||
#include "p2p/base/transport_description.h"
|
||||
#include "p2p/base/transport_info.h"
|
||||
#include "pc/channel.h"
|
||||
#include "pc/media_session.h"
|
||||
#include "pc/peer_connection.h"
|
||||
#include "pc/peer_connection_factory.h"
|
||||
#include "pc/rtp_transceiver.h"
|
||||
#include "pc/session_description.h"
|
||||
#include "pc/test/fake_periodic_video_source.h"
|
||||
#include "pc/test/integration_test_helpers.h"
|
||||
@ -3813,6 +3815,133 @@ TEST_P(PeerConnectionIntegrationTest, EndToEndRtpSenderVideoEncoderSelector) {
|
||||
EXPECT_TRUE(ExpectNewFrames(media_expectations));
|
||||
}
|
||||
|
||||
int NacksReceivedCount(PeerConnectionIntegrationWrapper& pc) {
|
||||
rtc::scoped_refptr<const webrtc::RTCStatsReport> report = pc.NewGetStats();
|
||||
auto sender_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
|
||||
if (sender_stats.size() != 1) {
|
||||
ADD_FAILURE();
|
||||
return 0;
|
||||
}
|
||||
if (!sender_stats[0]->nack_count.is_defined()) {
|
||||
return 0;
|
||||
}
|
||||
return *sender_stats[0]->nack_count;
|
||||
}
|
||||
|
||||
int NacksSentCount(PeerConnectionIntegrationWrapper& pc) {
|
||||
rtc::scoped_refptr<const webrtc::RTCStatsReport> report = pc.NewGetStats();
|
||||
auto receiver_stats = report->GetStatsOfType<RTCInboundRTPStreamStats>();
|
||||
if (receiver_stats.size() != 1) {
|
||||
ADD_FAILURE();
|
||||
return 0;
|
||||
}
|
||||
if (!receiver_stats[0]->nack_count.is_defined()) {
|
||||
return 0;
|
||||
}
|
||||
return *receiver_stats[0]->nack_count;
|
||||
}
|
||||
|
||||
// Test disabled because it is flaky.
|
||||
TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
DISABLED_AudioPacketLossCausesNack) {
|
||||
RTCConfiguration config;
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
|
||||
ConnectFakeSignaling();
|
||||
auto audio_transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalAudioTrack());
|
||||
ASSERT_TRUE(audio_transceiver_or_error.ok());
|
||||
auto send_transceiver = audio_transceiver_or_error.MoveValue();
|
||||
// Munge the SDP to include NACK and RRTR on Opus, and remove all other
|
||||
// codecs.
|
||||
caller()->SetGeneratedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
cricket::AudioContentDescription* media =
|
||||
content.media_description()->as_audio();
|
||||
std::vector<cricket::AudioCodec> codecs = media->codecs();
|
||||
std::vector<cricket::AudioCodec> codecs_out;
|
||||
for (cricket::AudioCodec codec : codecs) {
|
||||
if (codec.name == "opus") {
|
||||
codec.AddFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty));
|
||||
codec.AddFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamRrtr, cricket::kParamValueEmpty));
|
||||
codecs_out.push_back(codec);
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(codecs_out.empty());
|
||||
media->set_codecs(codecs_out);
|
||||
}
|
||||
});
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
// Check for failure in helpers
|
||||
ASSERT_FALSE(HasFailure());
|
||||
MediaExpectations media_expectations;
|
||||
media_expectations.CalleeExpectsSomeAudio(1);
|
||||
ExpectNewFrames(media_expectations);
|
||||
ASSERT_FALSE(HasFailure());
|
||||
|
||||
virtual_socket_server()->set_drop_probability(0.2);
|
||||
|
||||
// Wait until callee has sent at least one NACK.
|
||||
// Note that due to stats caching, this might only be visible 50 ms
|
||||
// after the nack was in fact sent.
|
||||
EXPECT_TRUE_WAIT(NacksSentCount(*callee()) > 0, kDefaultTimeout);
|
||||
ASSERT_FALSE(HasFailure());
|
||||
|
||||
virtual_socket_server()->set_drop_probability(0.0);
|
||||
// Wait until caller has received at least one NACK
|
||||
EXPECT_TRUE_WAIT(NacksReceivedCount(*caller()) > 0, kDefaultTimeout);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionIntegrationTestUnifiedPlan, VideoPacketLossCausesNack) {
|
||||
RTCConfiguration config;
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
|
||||
ConnectFakeSignaling();
|
||||
auto video_transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack());
|
||||
ASSERT_TRUE(video_transceiver_or_error.ok());
|
||||
auto send_transceiver = video_transceiver_or_error.MoveValue();
|
||||
// Munge the SDP to include NACK and RRTR on VP8, and remove all other
|
||||
// codecs.
|
||||
caller()->SetGeneratedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
cricket::VideoContentDescription* media =
|
||||
content.media_description()->as_video();
|
||||
std::vector<cricket::VideoCodec> codecs = media->codecs();
|
||||
std::vector<cricket::VideoCodec> codecs_out;
|
||||
for (cricket::VideoCodec codec : codecs) {
|
||||
if (codec.name == "VP8") {
|
||||
ASSERT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
||||
codecs_out.push_back(codec);
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(codecs_out.empty());
|
||||
media->set_codecs(codecs_out);
|
||||
}
|
||||
});
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
// Check for failure in helpers
|
||||
ASSERT_FALSE(HasFailure());
|
||||
MediaExpectations media_expectations;
|
||||
media_expectations.CalleeExpectsSomeVideo(1);
|
||||
ExpectNewFrames(media_expectations);
|
||||
ASSERT_FALSE(HasFailure());
|
||||
|
||||
virtual_socket_server()->set_drop_probability(0.2);
|
||||
|
||||
// Wait until callee has sent at least one NACK.
|
||||
// Note that due to stats caching, this might only be visible 50 ms
|
||||
// after the nack was in fact sent.
|
||||
EXPECT_TRUE_WAIT(NacksSentCount(*callee()) > 0, kDefaultTimeout);
|
||||
ASSERT_FALSE(HasFailure());
|
||||
|
||||
// Wait until caller has received at least one NACK
|
||||
EXPECT_TRUE_WAIT(NacksReceivedCount(*caller()) > 0, kDefaultTimeout);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user