diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.cc b/modules/rtp_rtcp/source/receive_statistics_impl.cc index e8b99ced10..deae14e8c5 100644 --- a/modules/rtp_rtcp/source/receive_statistics_impl.cc +++ b/modules/rtp_rtcp/source/receive_statistics_impl.cc @@ -142,7 +142,6 @@ void StreamStatisticianImpl::UpdateCounters(const RtpPacketReceived& packet) { } last_received_timestamp_ = packet.Timestamp(); last_receive_time_ms_ = now_ms; - last_payload_type_frequency_ = packet.payload_type_frequency(); } void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet, @@ -156,6 +155,8 @@ void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet, time_diff_samples = std::abs(time_diff_samples); + ReviseFrequencyAndJitter(packet.payload_type_frequency()); + // lib_jingle sometimes deliver crazy jumps in TS for the same stream. // If this happens, don't update jitter value. Use 5 secs video frequency // as the threshold. @@ -166,6 +167,38 @@ void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet, } } +void StreamStatisticianImpl::ReviseFrequencyAndJitter( + int payload_type_frequency) { + if (payload_type_frequency == last_payload_type_frequency_) { + return; + } + + if (payload_type_frequency != 0) { + if (last_payload_type_frequency_ != 0) { + // Value in "jitter_q4_" variable is a number of samples. + // I.e. jitter = timestamp (ms) * frequency (kHz). + // Since the frequency has changed we have to update the number of samples + // accordingly. The new value should rely on a new frequency. + + // If we don't do such procedure we end up with the number of samples that + // cannot be converted into milliseconds correctly + // (i.e. jitter_ms = jitter_q4_ >> 4 / (payload_type_frequency / 1000)). + // In such case, the number of samples has a "mix". + + // Doing so we pretend that everything prior and including the current + // packet were computed on packet's frequency. + jitter_q4_ = static_cast(static_cast(jitter_q4_) * + payload_type_frequency / + last_payload_type_frequency_); + } + // If last_payload_type_frequency_ is not present, the jitter_q4_ + // variable has its initial value. + + // Keep last_payload_type_frequency_ up to date and non-zero (set). + last_payload_type_frequency_ = payload_type_frequency; + } +} + void StreamStatisticianImpl::SetMaxReorderingThreshold( int max_reordering_threshold) { max_reordering_threshold_ = max_reordering_threshold; diff --git a/modules/rtp_rtcp/source/receive_statistics_impl.h b/modules/rtp_rtcp/source/receive_statistics_impl.h index c6f2d8468e..4aac20a74b 100644 --- a/modules/rtp_rtcp/source/receive_statistics_impl.h +++ b/modules/rtp_rtcp/source/receive_statistics_impl.h @@ -65,6 +65,7 @@ class StreamStatisticianImpl : public StreamStatisticianImplInterface { bool IsRetransmitOfOldPacket(const RtpPacketReceived& packet, int64_t now_ms) const; void UpdateJitter(const RtpPacketReceived& packet, int64_t receive_time_ms); + void ReviseFrequencyAndJitter(int payload_type_frequency); // Updates StreamStatistician for out of order packets. // Returns true if packet considered to be out of order. bool UpdateOutOfOrder(const RtpPacketReceived& packet, diff --git a/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/modules/rtp_rtcp/source/receive_statistics_unittest.cc index d8f2df1fdf..92c8f34196 100644 --- a/modules/rtp_rtcp/source/receive_statistics_unittest.cc +++ b/modules/rtp_rtcp/source/receive_statistics_unittest.cc @@ -55,6 +55,25 @@ RtpPacketReceived CreateRtpPacket(uint32_t ssrc, return packet; } +RtpPacketReceived MakeRtpPacket(int payload_type_frequency, + uint32_t timestamp) { + RtpPacketReceived packet = + CreateRtpPacket(kSsrc1, + /*header_size=*/12, kPacketSize1 - 12, + /*padding_size=*/0); + packet.SetTimestamp(timestamp); + packet.set_payload_type_frequency(payload_type_frequency); + return packet; +} + +RtpPacketReceived MakeNextRtpPacket(const RtpPacketReceived& previous_packet, + int payload_type_frequency, + uint32_t timestamp) { + RtpPacketReceived packet = MakeRtpPacket(payload_type_frequency, timestamp); + packet.SetSequenceNumber(previous_packet.SequenceNumber() + 1); + return packet; +} + RtpPacketReceived CreateRtpPacket(uint32_t ssrc, size_t packet_size) { return CreateRtpPacket(ssrc, 12, packet_size - 12, 0); } @@ -67,6 +86,10 @@ void IncrementSequenceNumber(RtpPacketReceived* packet) { IncrementSequenceNumber(packet, 1); } +uint32_t GetJitter(const ReceiveStatistics& stats) { + return stats.GetStatistician(kSsrc1)->GetStats().jitter; +} + class ReceiveStatisticsTest : public ::testing::TestWithParam { public: ReceiveStatisticsTest() @@ -607,5 +630,272 @@ TEST_P(ReceiveStatisticsTest, SimpleJitterComputation) { statistician->GetStats().interarrival_jitter); } +TEST(ReviseJitterTest, AllPacketsHaveSamePayloadTypeFrequency) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/8'000, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 160); + + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 2 * 160); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 240 + // packet3: jitter = 240[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 240[jitter] + 8) + // / 16 = 465 + // final jitter: 465 / 16 = 29 + EXPECT_EQ(GetJitter(*statistics), 29U); +} + +TEST(ReviseJitterTest, AllPacketsHaveDifferentPayloadTypeFrequency) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/8'000, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 160); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/48'000, /*timestamp=*/1 + 160 + 960); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 240 + // packet3: revised jitter: 240 * 48[frequency KHz] / 8[frequency KHz] = 1'440 + // jitter = 1'440[jitter] + (abs(50[receive time ms] * + // 48[frequency KHz] - 960[timestamp diff]) * 16 - 1'440[jitter] + 8) + // / 16 = 2'790 + // final jitter: 2'790 / 16 = 174 + EXPECT_EQ(GetJitter(*statistics), 174U); +} + +TEST(ReviseJitterTest, + FirstPacketPayloadTypeFrequencyIsZeroAndFrequencyChanged) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/0, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 160); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/48'000, /*timestamp=*/1 + 160 + 960); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 240 + // packet3: revised jitter: 240 * 48[frequency KHz] / 8[frequency KHz] = 1'440 + // jitter = 1'440[jitter] + (abs(50[receive time ms] * + // 48[frequency KHz] - 960[timestamp diff]) * 16 - 1'440[jitter] + 8) + // / 16 = 2'790 + // final jitter: 2'790 / 16 = 174 + EXPECT_EQ(GetJitter(*statistics), 174U); +} + +TEST(ReviseJitterTest, + FirstPacketPayloadTypeFrequencyIsZeroAndFrequencyNotChanged) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/0, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 160); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 160 + 160); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 240 + // packet3: jitter = 240[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 240[jitter] + 8) + // / 16 = 465 + // final jitter: 465 / 16 = 29 + EXPECT_EQ(GetJitter(*statistics), 29U); +} + +TEST(ReviseJitterTest, + TwoFirstPacketPayloadTypeFrequencyIsZeroAndFrequencyChanged) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/0, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/0, /*timestamp=*/1 + 160); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/48'000, /*timestamp=*/1 + 160 + 960); + RtpPacketReceived packet4 = + MakeNextRtpPacket(packet3, /*payload_type_frequency=*/8'000, + /*timestamp=*/1 + 160 + 960 + 160); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet4); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 0[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 160 + // packet3: jitter = 160[jitter] + (abs(50[receive time ms] * + // 48[frequency KHz] - 960[timestamp diff]) * 16 - 160[jitter] + 8) + // / 16 = 1'590 + // packet4: revised jitter: 1'590 * 8[frequency KHz] / 48[frequency KHz] = 265 + // packet4: jitter = 265[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 265[jitter] + 8) + // / 16 = 488 + // final jitter: 488 / 16 = 30 + EXPECT_EQ(GetJitter(*statistics), 30U); +} + +TEST(ReviseJitterTest, + TwoFirstPacketPayloadTypeFrequencyIsZeroAndFrequencyNotChanged) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/0, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/0, /*timestamp=*/1 + 160); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/8'000, /*timestamp=*/1 + 160 + 160); + RtpPacketReceived packet4 = + MakeNextRtpPacket(packet3, /*payload_type_frequency=*/8'000, + /*timestamp=*/1 + 160 + 160 + 160); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet4); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 0[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 160 + // packet3: jitter = 160[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 160[jitter] + 8) + // / 16 = 390 + // packet4: jitter = 390[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 390[jitter] + 8) + // / 16 = 606 + // final jitter: 606 / 16 = 37 + EXPECT_EQ(GetJitter(*statistics), 37U); +} + +TEST(ReviseJitterTest, + MiddlePacketPayloadTypeFrequencyIsZeroAndFrequencyChanged) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/48'000, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/48'000, /*timestamp=*/1 + 960); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/0, /*timestamp=*/1 + 960 + 55); + RtpPacketReceived packet4 = + MakeNextRtpPacket(packet3, /*payload_type_frequency=*/8'000, + /*timestamp=*/1 + 960 + 55 + 160); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet4); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 48[frequency KHz] - 960[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 1'440 + // packet3: jitter = 1'440[jitter] + (abs(50[receive time ms] * + // 0[frequency KHz] - 55[timestamp diff]) * 16 - 1'440[jitter] + 8) + // / 16 = 1'405 + // packet4: revised jitter: 1'405 * 8[frequency KHz] / 48[frequency KHz] = 234 + // jitter = 234[jitter] + (abs(50[receive time ms] * + // 8[frequency KHz] - 160[timestamp diff]) * 16 - 234[jitter] + 8) + // / 16 = 459 + // final jitter: 459 / 16 = 28 + EXPECT_EQ(GetJitter(*statistics), 28U); +} + +TEST(ReviseJitterTest, + MiddlePacketPayloadTypeFrequencyIsZeroAndFrequencyNotChanged) { + SimulatedClock clock(0); + std::unique_ptr statistics = + ReceiveStatistics::Create(&clock); + RtpPacketReceived packet1 = MakeRtpPacket(/*payload_type_frequency=*/48'000, + /*timestamp=*/1); + RtpPacketReceived packet2 = MakeNextRtpPacket( + packet1, /*payload_type_frequency=*/48'000, /*timestamp=*/1 + 960); + RtpPacketReceived packet3 = MakeNextRtpPacket( + packet2, /*payload_type_frequency=*/0, /*timestamp=*/1 + 960 + 55); + RtpPacketReceived packet4 = + MakeNextRtpPacket(packet3, /*payload_type_frequency=*/48'000, + /*timestamp=*/1 + 960 + 55 + 960); + + statistics->OnRtpPacket(packet1); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet2); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet3); + clock.AdvanceTimeMilliseconds(50); + statistics->OnRtpPacket(packet4); + + // packet1: no jitter calculation + // packet2: jitter = 0[jitter] + (abs(50[receive time ms] * + // 48[frequency KHz] - 960[timestamp diff]) * 16 - 0[jitter] + 8) + // / 16 = 1'440 + // packet3: jitter = 1'440[jitter] + (abs(50[receive time ms] * + // 0[frequency KHz] - 55[timestamp diff]) * 16 - 1'440[jitter] + 8) + // / 16 = 1'405 + // packet4: jitter = 1'405[jitter] + (abs(50[receive time ms] * + // 48[frequency KHz] - 960[timestamp diff]) * 16 - 1'405[jitter] + 8) + // / 16 = 2'757 + // final jitter: 2'757 / 16 = 172 + EXPECT_EQ(GetJitter(*statistics), 172U); +} + } // namespace } // namespace webrtc