Fix unscaled timestamps passed to nack_tracker
If timestamp_scaler_ is used, then rtp_header.timestamp, passed to UpdateLastDecodedPacket, will advance at a different rate than the scaled timestamp packet->timestamp, passed to UpdateLastDecodedPacket. NackTracker::EstimateTimestamp uses timestamp_last_received_rtp_, and NackTracker::TimeToPlay uses timestamp_last_decoded_rtp_. This difference causes TimeToPlay to continuously increase to huge values, so that every missing packet will be returned from GetNackList, even if RTT > real time to play. Change-Id: Ie6ca347972edea98a202c9cdd26c6ab3f45a73c4 Bug: None Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/222841 Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org> Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34361}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
9233af3e22
commit
f2ed401679
@ -628,8 +628,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
|
|||||||
if (update_sample_rate_and_channels) {
|
if (update_sample_rate_and_channels) {
|
||||||
nack_->Reset();
|
nack_->Reset();
|
||||||
}
|
}
|
||||||
nack_->UpdateLastReceivedPacket(rtp_header.sequenceNumber,
|
nack_->UpdateLastReceivedPacket(main_sequence_number, main_timestamp);
|
||||||
rtp_header.timestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for RED payload type, and separate payloads into several packets.
|
// Check for RED payload type, and separate payloads into several packets.
|
||||||
|
@ -736,6 +736,15 @@ class NetEqImplTestSampleRateParameter
|
|||||||
const int initial_sample_rate_hz_;
|
const int initial_sample_rate_hz_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NetEqImplTestSdpFormatParameter
|
||||||
|
: public NetEqImplTest,
|
||||||
|
public testing::WithParamInterface<SdpAudioFormat> {
|
||||||
|
protected:
|
||||||
|
NetEqImplTestSdpFormatParameter()
|
||||||
|
: NetEqImplTest(), sdp_format_(GetParam()) {}
|
||||||
|
const SdpAudioFormat sdp_format_;
|
||||||
|
};
|
||||||
|
|
||||||
// This test does the following:
|
// This test does the following:
|
||||||
// 0. Set up NetEq with initial sample rate given by test parameter, and a codec
|
// 0. Set up NetEq with initial sample rate given by test parameter, and a codec
|
||||||
// sample rate of 16000.
|
// sample rate of 16000.
|
||||||
@ -919,6 +928,67 @@ INSTANTIATE_TEST_SUITE_P(SampleRates,
|
|||||||
NetEqImplTestSampleRateParameter,
|
NetEqImplTestSampleRateParameter,
|
||||||
testing::Values(8000, 16000, 32000, 48000));
|
testing::Values(8000, 16000, 32000, 48000));
|
||||||
|
|
||||||
|
TEST_P(NetEqImplTestSdpFormatParameter, GetNackListScaledTimestamp) {
|
||||||
|
UseNoMocks();
|
||||||
|
CreateInstance();
|
||||||
|
|
||||||
|
neteq_->EnableNack(128);
|
||||||
|
|
||||||
|
const uint8_t kPayloadType = 17; // Just an arbitrary number.
|
||||||
|
const int kPayloadSampleRateHz = sdp_format_.clockrate_hz;
|
||||||
|
const size_t kPayloadLengthSamples =
|
||||||
|
static_cast<size_t>(10 * kPayloadSampleRateHz / 1000); // 10 ms.
|
||||||
|
const size_t kPayloadLengthBytes = kPayloadLengthSamples * 2;
|
||||||
|
std::vector<uint8_t> payload(kPayloadLengthBytes, 0);
|
||||||
|
RTPHeader rtp_header;
|
||||||
|
rtp_header.payloadType = kPayloadType;
|
||||||
|
rtp_header.sequenceNumber = 0x1234;
|
||||||
|
rtp_header.timestamp = 0x12345678;
|
||||||
|
rtp_header.ssrc = 0x87654321;
|
||||||
|
|
||||||
|
EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, sdp_format_));
|
||||||
|
|
||||||
|
auto insert_packet = [&](bool lost = false) {
|
||||||
|
rtp_header.sequenceNumber++;
|
||||||
|
rtp_header.timestamp += kPayloadLengthSamples;
|
||||||
|
if (!lost)
|
||||||
|
EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert and decode 10 packets.
|
||||||
|
for (size_t i = 0; i < 10; ++i) {
|
||||||
|
insert_packet();
|
||||||
|
}
|
||||||
|
AudioFrame output;
|
||||||
|
size_t count_loops = 0;
|
||||||
|
do {
|
||||||
|
bool muted;
|
||||||
|
// Make sure we don't hang the test if we never go to PLC.
|
||||||
|
ASSERT_LT(++count_loops, 100u);
|
||||||
|
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||||
|
} while (output.speech_type_ == AudioFrame::kNormalSpeech);
|
||||||
|
|
||||||
|
insert_packet();
|
||||||
|
|
||||||
|
insert_packet(/*lost=*/true);
|
||||||
|
|
||||||
|
// Ensure packet gets marked as missing.
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
insert_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Missing packet recoverable with 5ms RTT.
|
||||||
|
EXPECT_THAT(neteq_->GetNackList(5), Not(IsEmpty()));
|
||||||
|
|
||||||
|
// No packets should have TimeToPlay > 500ms.
|
||||||
|
EXPECT_THAT(neteq_->GetNackList(500), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(GetNackList,
|
||||||
|
NetEqImplTestSdpFormatParameter,
|
||||||
|
testing::Values(SdpAudioFormat("g722", 8000, 1),
|
||||||
|
SdpAudioFormat("opus", 48000, 2)));
|
||||||
|
|
||||||
// This test verifies that NetEq can handle comfort noise and enters/quits codec
|
// This test verifies that NetEq can handle comfort noise and enters/quits codec
|
||||||
// internal CNG mode properly.
|
// internal CNG mode properly.
|
||||||
TEST_F(NetEqImplTest, CodecInternalCng) {
|
TEST_F(NetEqImplTest, CodecInternalCng) {
|
||||||
|
Reference in New Issue
Block a user