mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00

This is in preparation of using the state that SourceTracker manages for more things than only getContributingSources. Audio levels reported via getStats(), aren't consistent with levels reported via getCS. Since more operations will be derived from the ST owned data, moving the management of it away from the audio thread, reduces the potential of contention. Bug: webrtc:14029, webrtc:7517, webrtc:15119 Change-Id: I553f7e473316a1c61eeb43ded905a18242a04424 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/302280 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org> Cr-Commit-Position: refs/heads/main@{#39943}
544 lines
21 KiB
C++
544 lines
21 KiB
C++
/*
|
|
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/rtp_rtcp/source/source_tracker.h"
|
|
|
|
#include <algorithm>
|
|
#include <list>
|
|
#include <random>
|
|
#include <set>
|
|
#include <tuple>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "absl/types/optional.h"
|
|
#include "api/rtp_headers.h"
|
|
#include "api/rtp_packet_info.h"
|
|
#include "api/rtp_packet_infos.h"
|
|
#include "system_wrappers/include/ntp_time.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
#include "test/time_controller/simulated_time_controller.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
using ::testing::Combine;
|
|
using ::testing::ElementsAre;
|
|
using ::testing::ElementsAreArray;
|
|
using ::testing::IsEmpty;
|
|
using ::testing::TestWithParam;
|
|
using ::testing::Values;
|
|
|
|
constexpr size_t kPacketInfosCountMax = 5;
|
|
|
|
// Simple "guaranteed to be correct" re-implementation of `SourceTracker` for
|
|
// dual-implementation testing purposes.
|
|
class ExpectedSourceTracker {
|
|
public:
|
|
explicit ExpectedSourceTracker(Clock* clock) : clock_(clock) {}
|
|
|
|
void OnFrameDelivered(const RtpPacketInfos& packet_infos) {
|
|
const int64_t now_ms = clock_->TimeInMilliseconds();
|
|
|
|
for (const auto& packet_info : packet_infos) {
|
|
RtpSource::Extensions extensions = {
|
|
packet_info.audio_level(), packet_info.absolute_capture_time(),
|
|
packet_info.local_capture_clock_offset()};
|
|
|
|
for (const auto& csrc : packet_info.csrcs()) {
|
|
entries_.emplace_front(now_ms, csrc, RtpSourceType::CSRC,
|
|
packet_info.rtp_timestamp(), extensions);
|
|
}
|
|
|
|
entries_.emplace_front(now_ms, packet_info.ssrc(), RtpSourceType::SSRC,
|
|
packet_info.rtp_timestamp(), extensions);
|
|
}
|
|
|
|
PruneEntries(now_ms);
|
|
}
|
|
|
|
std::vector<RtpSource> GetSources() const {
|
|
PruneEntries(clock_->TimeInMilliseconds());
|
|
|
|
return std::vector<RtpSource>(entries_.begin(), entries_.end());
|
|
}
|
|
|
|
private:
|
|
void PruneEntries(int64_t now_ms) const {
|
|
const int64_t prune_ms = now_ms - 10000; // 10 seconds
|
|
|
|
std::set<std::pair<RtpSourceType, uint32_t>> seen;
|
|
|
|
auto it = entries_.begin();
|
|
auto end = entries_.end();
|
|
while (it != end) {
|
|
auto next = it;
|
|
++next;
|
|
|
|
auto key = std::make_pair(it->source_type(), it->source_id());
|
|
if (!seen.insert(key).second || it->timestamp_ms() < prune_ms) {
|
|
entries_.erase(it);
|
|
}
|
|
|
|
it = next;
|
|
}
|
|
}
|
|
|
|
Clock* const clock_;
|
|
|
|
mutable std::list<RtpSource> entries_;
|
|
};
|
|
|
|
class SourceTrackerRandomTest
|
|
: public TestWithParam<std::tuple<uint32_t, uint32_t>> {
|
|
protected:
|
|
SourceTrackerRandomTest()
|
|
: ssrcs_count_(std::get<0>(GetParam())),
|
|
csrcs_count_(std::get<1>(GetParam())),
|
|
generator_(42) {}
|
|
|
|
RtpPacketInfos GeneratePacketInfos() {
|
|
size_t count = std::uniform_int_distribution<size_t>(
|
|
1, kPacketInfosCountMax)(generator_);
|
|
|
|
RtpPacketInfos::vector_type packet_infos;
|
|
for (size_t i = 0; i < count; ++i) {
|
|
packet_infos
|
|
.emplace_back(GenerateSsrc(), GenerateCsrcs(), GenerateRtpTimestamp(),
|
|
GenerateReceiveTime())
|
|
.set_audio_level(GenerateAudioLevel())
|
|
.set_absolute_capture_time(GenerateAbsoluteCaptureTime())
|
|
.set_local_capture_clock_offset(GenerateLocalCaptureClockOffset());
|
|
}
|
|
|
|
return RtpPacketInfos(std::move(packet_infos));
|
|
}
|
|
|
|
TimeDelta GenerateClockAdvanceTime() {
|
|
double roll = std::uniform_real_distribution<double>(0.0, 1.0)(generator_);
|
|
|
|
if (roll < 0.05) {
|
|
return TimeDelta::Zero();
|
|
}
|
|
|
|
if (roll < 0.08) {
|
|
return SourceTracker::kTimeout - TimeDelta::Millis(1);
|
|
}
|
|
|
|
if (roll < 0.11) {
|
|
return SourceTracker::kTimeout;
|
|
}
|
|
|
|
if (roll < 0.19) {
|
|
return TimeDelta::Millis(std::uniform_int_distribution<int64_t>(
|
|
SourceTracker::kTimeout.ms(),
|
|
SourceTracker::kTimeout.ms() * 1000)(generator_));
|
|
}
|
|
|
|
return TimeDelta::Millis(std::uniform_int_distribution<int64_t>(
|
|
1, SourceTracker::kTimeout.ms() - 1)(generator_));
|
|
}
|
|
|
|
private:
|
|
uint32_t GenerateSsrc() {
|
|
return std::uniform_int_distribution<uint32_t>(1, ssrcs_count_)(generator_);
|
|
}
|
|
|
|
std::vector<uint32_t> GenerateCsrcs() {
|
|
std::vector<uint32_t> csrcs;
|
|
for (size_t i = 1; i <= csrcs_count_ && csrcs.size() < kRtpCsrcSize; ++i) {
|
|
if (std::bernoulli_distribution(0.5)(generator_)) {
|
|
csrcs.push_back(i);
|
|
}
|
|
}
|
|
|
|
return csrcs;
|
|
}
|
|
|
|
uint32_t GenerateRtpTimestamp() {
|
|
return std::uniform_int_distribution<uint32_t>()(generator_);
|
|
}
|
|
|
|
absl::optional<uint8_t> GenerateAudioLevel() {
|
|
if (std::bernoulli_distribution(0.25)(generator_)) {
|
|
return absl::nullopt;
|
|
}
|
|
|
|
// Workaround for std::uniform_int_distribution<uint8_t> not being allowed.
|
|
return static_cast<uint8_t>(
|
|
std::uniform_int_distribution<uint16_t>()(generator_));
|
|
}
|
|
|
|
absl::optional<AbsoluteCaptureTime> GenerateAbsoluteCaptureTime() {
|
|
if (std::bernoulli_distribution(0.25)(generator_)) {
|
|
return absl::nullopt;
|
|
}
|
|
|
|
AbsoluteCaptureTime value;
|
|
|
|
value.absolute_capture_timestamp =
|
|
std::uniform_int_distribution<uint64_t>()(generator_);
|
|
|
|
if (std::bernoulli_distribution(0.5)(generator_)) {
|
|
value.estimated_capture_clock_offset = absl::nullopt;
|
|
} else {
|
|
value.estimated_capture_clock_offset =
|
|
std::uniform_int_distribution<int64_t>()(generator_);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
absl::optional<TimeDelta> GenerateLocalCaptureClockOffset() {
|
|
if (std::bernoulli_distribution(0.5)(generator_)) {
|
|
return absl::nullopt;
|
|
}
|
|
return TimeDelta::Millis(
|
|
UQ32x32ToInt64Ms(std::uniform_int_distribution<int64_t>()(generator_)));
|
|
}
|
|
|
|
Timestamp GenerateReceiveTime() {
|
|
return Timestamp::Micros(
|
|
std::uniform_int_distribution<int64_t>()(generator_));
|
|
}
|
|
|
|
protected:
|
|
GlobalSimulatedTimeController time_controller_{Timestamp::Seconds(1000)};
|
|
|
|
private:
|
|
const uint32_t ssrcs_count_;
|
|
const uint32_t csrcs_count_;
|
|
|
|
std::mt19937 generator_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_P(SourceTrackerRandomTest, RandomOperations) {
|
|
constexpr size_t kIterationsCount = 200;
|
|
|
|
SourceTracker actual_tracker(time_controller_.GetClock());
|
|
ExpectedSourceTracker expected_tracker(time_controller_.GetClock());
|
|
|
|
ASSERT_THAT(actual_tracker.GetSources(), IsEmpty());
|
|
ASSERT_THAT(expected_tracker.GetSources(), IsEmpty());
|
|
|
|
for (size_t i = 0; i < kIterationsCount; ++i) {
|
|
RtpPacketInfos packet_infos = GeneratePacketInfos();
|
|
|
|
actual_tracker.OnFrameDelivered(packet_infos);
|
|
expected_tracker.OnFrameDelivered(packet_infos);
|
|
|
|
time_controller_.AdvanceTime(GenerateClockAdvanceTime());
|
|
ASSERT_THAT(actual_tracker.GetSources(),
|
|
ElementsAreArray(expected_tracker.GetSources()));
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(All,
|
|
SourceTrackerRandomTest,
|
|
Combine(/*ssrcs_count_=*/Values(1, 2, 4),
|
|
/*csrcs_count_=*/Values(0, 1, 3, 7)));
|
|
|
|
TEST(SourceTrackerTest, StartEmpty) {
|
|
GlobalSimulatedTimeController time_controller(Timestamp::Seconds(1000));
|
|
SourceTracker tracker(time_controller.GetClock());
|
|
|
|
EXPECT_THAT(tracker.GetSources(), IsEmpty());
|
|
}
|
|
|
|
TEST(SourceTrackerTest, OnFrameDeliveredRecordsSourcesDistinctSsrcs) {
|
|
constexpr uint32_t kSsrc1 = 10;
|
|
constexpr uint32_t kSsrc2 = 11;
|
|
constexpr uint32_t kCsrcs0 = 20;
|
|
constexpr uint32_t kCsrcs1 = 21;
|
|
constexpr uint32_t kCsrcs2 = 22;
|
|
constexpr uint32_t kRtpTimestamp0 = 40;
|
|
constexpr uint32_t kRtpTimestamp1 = 50;
|
|
constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
|
|
constexpr absl::optional<uint8_t> kAudioLevel1 = 20;
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime =
|
|
AbsoluteCaptureTime{/*absolute_capture_timestamp=*/12,
|
|
/*estimated_capture_clock_offset=*/absl::nullopt};
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset = absl::nullopt;
|
|
constexpr Timestamp kReceiveTime0 = Timestamp::Millis(60);
|
|
constexpr Timestamp kReceiveTime1 = Timestamp::Millis(70);
|
|
|
|
GlobalSimulatedTimeController time_controller(Timestamp::Seconds(1000));
|
|
SourceTracker tracker(time_controller.GetClock());
|
|
|
|
tracker.OnFrameDelivered(RtpPacketInfos(
|
|
{RtpPacketInfo(kSsrc1, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kReceiveTime0)
|
|
.set_audio_level(kAudioLevel0)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset),
|
|
RtpPacketInfo(kSsrc2, {kCsrcs2}, kRtpTimestamp1, kReceiveTime1)
|
|
.set_audio_level(kAudioLevel1)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset)}));
|
|
|
|
Timestamp timestamp = time_controller.GetClock()->CurrentTime();
|
|
constexpr RtpSource::Extensions extensions0 = {
|
|
.audio_level = kAudioLevel0,
|
|
.absolute_capture_time = kAbsoluteCaptureTime,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset};
|
|
constexpr RtpSource::Extensions extensions1 = {
|
|
.audio_level = kAudioLevel1,
|
|
.absolute_capture_time = kAbsoluteCaptureTime,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset};
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
|
|
|
EXPECT_THAT(
|
|
tracker.GetSources(),
|
|
ElementsAre(RtpSource(timestamp.ms(), kSsrc2, RtpSourceType::SSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp.ms(), kCsrcs2, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp.ms(), kSsrc1, RtpSourceType::SSRC,
|
|
kRtpTimestamp0, extensions0),
|
|
RtpSource(timestamp.ms(), kCsrcs1, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0),
|
|
RtpSource(timestamp.ms(), kCsrcs0, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0)));
|
|
}
|
|
|
|
TEST(SourceTrackerTest, OnFrameDeliveredRecordsSourcesSameSsrc) {
|
|
constexpr uint32_t kSsrc = 10;
|
|
constexpr uint32_t kCsrcs0 = 20;
|
|
constexpr uint32_t kCsrcs1 = 21;
|
|
constexpr uint32_t kCsrcs2 = 22;
|
|
constexpr uint32_t kRtpTimestamp0 = 40;
|
|
constexpr uint32_t kRtpTimestamp1 = 45;
|
|
constexpr uint32_t kRtpTimestamp2 = 50;
|
|
constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
|
|
constexpr absl::optional<uint8_t> kAudioLevel1 = 20;
|
|
constexpr absl::optional<uint8_t> kAudioLevel2 = 10;
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime =
|
|
AbsoluteCaptureTime{/*absolute_capture_timestamp=*/12,
|
|
/*estimated_capture_clock_offset=*/absl::nullopt};
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset = absl::nullopt;
|
|
constexpr Timestamp kReceiveTime0 = Timestamp::Millis(60);
|
|
constexpr Timestamp kReceiveTime1 = Timestamp::Millis(70);
|
|
constexpr Timestamp kReceiveTime2 = Timestamp::Millis(80);
|
|
|
|
GlobalSimulatedTimeController time_controller(Timestamp::Seconds(1000));
|
|
SourceTracker tracker(time_controller.GetClock());
|
|
|
|
tracker.OnFrameDelivered(RtpPacketInfos({
|
|
RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kReceiveTime0)
|
|
.set_audio_level(kAudioLevel0)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset),
|
|
RtpPacketInfo(kSsrc, {kCsrcs2}, kRtpTimestamp1, kReceiveTime1)
|
|
.set_audio_level(kAudioLevel1)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset),
|
|
RtpPacketInfo(kSsrc, {kCsrcs0}, kRtpTimestamp2, kReceiveTime2)
|
|
.set_audio_level(kAudioLevel2)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset),
|
|
}));
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
|
Timestamp timestamp = time_controller.GetClock()->CurrentTime();
|
|
constexpr RtpSource::Extensions extensions0 = {
|
|
.audio_level = kAudioLevel0,
|
|
.absolute_capture_time = kAbsoluteCaptureTime,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset};
|
|
constexpr RtpSource::Extensions extensions1 = {
|
|
.audio_level = kAudioLevel1,
|
|
.absolute_capture_time = kAbsoluteCaptureTime,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset};
|
|
constexpr RtpSource::Extensions extensions2 = {
|
|
.audio_level = kAudioLevel2,
|
|
.absolute_capture_time = kAbsoluteCaptureTime,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset};
|
|
|
|
EXPECT_THAT(
|
|
tracker.GetSources(),
|
|
ElementsAre(RtpSource(timestamp.ms(), kSsrc, RtpSourceType::SSRC,
|
|
kRtpTimestamp2, extensions2),
|
|
RtpSource(timestamp.ms(), kCsrcs0, RtpSourceType::CSRC,
|
|
kRtpTimestamp2, extensions2),
|
|
RtpSource(timestamp.ms(), kCsrcs2, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp.ms(), kCsrcs1, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0)));
|
|
}
|
|
|
|
TEST(SourceTrackerTest, OnFrameDeliveredUpdatesSources) {
|
|
constexpr uint32_t kSsrc1 = 10;
|
|
constexpr uint32_t kSsrc2 = 11;
|
|
constexpr uint32_t kCsrcs0 = 20;
|
|
constexpr uint32_t kCsrcs1 = 21;
|
|
constexpr uint32_t kCsrcs2 = 22;
|
|
constexpr uint32_t kRtpTimestamp0 = 40;
|
|
constexpr uint32_t kRtpTimestamp1 = 41;
|
|
constexpr uint32_t kRtpTimestamp2 = 42;
|
|
constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
|
|
constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
|
|
constexpr absl::optional<uint8_t> kAudioLevel2 = 10;
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime0 =
|
|
AbsoluteCaptureTime{12, 34};
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime1 =
|
|
AbsoluteCaptureTime{56, 78};
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime2 =
|
|
AbsoluteCaptureTime{89, 90};
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset0 =
|
|
TimeDelta::Millis(123);
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset1 =
|
|
TimeDelta::Millis(456);
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset2 =
|
|
TimeDelta::Millis(789);
|
|
constexpr Timestamp kReceiveTime0 = Timestamp::Millis(60);
|
|
constexpr Timestamp kReceiveTime1 = Timestamp::Millis(61);
|
|
constexpr Timestamp kReceiveTime2 = Timestamp::Millis(62);
|
|
|
|
constexpr RtpSource::Extensions extensions0 = {
|
|
.audio_level = kAudioLevel0,
|
|
.absolute_capture_time = kAbsoluteCaptureTime0,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset0};
|
|
constexpr RtpSource::Extensions extensions1 = {
|
|
.audio_level = kAudioLevel1,
|
|
.absolute_capture_time = kAbsoluteCaptureTime1,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset1};
|
|
constexpr RtpSource::Extensions extensions2 = {
|
|
.audio_level = kAudioLevel2,
|
|
.absolute_capture_time = kAbsoluteCaptureTime2,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset2};
|
|
|
|
GlobalSimulatedTimeController time_controller(Timestamp::Seconds(1000));
|
|
SourceTracker tracker(time_controller.GetClock());
|
|
|
|
tracker.OnFrameDelivered(RtpPacketInfos(
|
|
{RtpPacketInfo(kSsrc1, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kReceiveTime0)
|
|
.set_audio_level(kAudioLevel0)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime0)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset0)}));
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
|
Timestamp timestamp_0 = time_controller.GetClock()->CurrentTime();
|
|
EXPECT_THAT(
|
|
tracker.GetSources(),
|
|
ElementsAre(RtpSource(timestamp_0.ms(), kSsrc1, RtpSourceType::SSRC,
|
|
kRtpTimestamp0, extensions0),
|
|
RtpSource(timestamp_0.ms(), kCsrcs1, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0),
|
|
RtpSource(timestamp_0.ms(), kCsrcs0, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0)));
|
|
|
|
// Deliver packets with updated sources.
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Millis(17));
|
|
tracker.OnFrameDelivered(RtpPacketInfos(
|
|
{RtpPacketInfo(kSsrc1, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kReceiveTime1)
|
|
.set_audio_level(kAudioLevel1)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime1)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset1)}));
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
|
Timestamp timestamp_1 = time_controller.GetClock()->CurrentTime();
|
|
|
|
EXPECT_THAT(
|
|
tracker.GetSources(),
|
|
ElementsAre(RtpSource(timestamp_1.ms(), kSsrc1, RtpSourceType::SSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_1.ms(), kCsrcs2, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_1.ms(), kCsrcs0, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_0.ms(), kCsrcs1, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0)));
|
|
|
|
// Deliver more packets with update csrcs and a new ssrc.
|
|
time_controller.AdvanceTime(TimeDelta::Millis(17));
|
|
|
|
tracker.OnFrameDelivered(RtpPacketInfos(
|
|
{RtpPacketInfo(kSsrc2, {kCsrcs0}, kRtpTimestamp2, kReceiveTime2)
|
|
.set_audio_level(kAudioLevel2)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime2)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset2)}));
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
|
Timestamp timestamp_2 = time_controller.GetClock()->CurrentTime();
|
|
|
|
EXPECT_THAT(
|
|
tracker.GetSources(),
|
|
ElementsAre(RtpSource(timestamp_2.ms(), kSsrc2, RtpSourceType::SSRC,
|
|
kRtpTimestamp2, extensions2),
|
|
RtpSource(timestamp_2.ms(), kCsrcs0, RtpSourceType::CSRC,
|
|
kRtpTimestamp2, extensions2),
|
|
RtpSource(timestamp_1.ms(), kSsrc1, RtpSourceType::SSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_1.ms(), kCsrcs2, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_0.ms(), kCsrcs1, RtpSourceType::CSRC,
|
|
kRtpTimestamp0, extensions0)));
|
|
}
|
|
|
|
TEST(SourceTrackerTest, TimedOutSourcesAreRemoved) {
|
|
constexpr uint32_t kSsrc = 10;
|
|
constexpr uint32_t kCsrcs0 = 20;
|
|
constexpr uint32_t kCsrcs1 = 21;
|
|
constexpr uint32_t kCsrcs2 = 22;
|
|
constexpr uint32_t kRtpTimestamp0 = 40;
|
|
constexpr uint32_t kRtpTimestamp1 = 41;
|
|
constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
|
|
constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime0 =
|
|
AbsoluteCaptureTime{12, 34};
|
|
constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime1 =
|
|
AbsoluteCaptureTime{56, 78};
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset0 =
|
|
TimeDelta::Millis(123);
|
|
constexpr absl::optional<TimeDelta> kLocalCaptureClockOffset1 =
|
|
TimeDelta::Millis(456);
|
|
constexpr Timestamp kReceiveTime0 = Timestamp::Millis(60);
|
|
constexpr Timestamp kReceiveTime1 = Timestamp::Millis(61);
|
|
|
|
GlobalSimulatedTimeController time_controller(Timestamp::Seconds(1000));
|
|
SourceTracker tracker(time_controller.GetClock());
|
|
|
|
tracker.OnFrameDelivered(RtpPacketInfos(
|
|
{RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kReceiveTime0)
|
|
.set_audio_level(kAudioLevel0)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime0)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset0)}));
|
|
|
|
time_controller.AdvanceTime(TimeDelta::Millis(17));
|
|
|
|
tracker.OnFrameDelivered(RtpPacketInfos(
|
|
{RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kReceiveTime1)
|
|
.set_audio_level(kAudioLevel1)
|
|
.set_absolute_capture_time(kAbsoluteCaptureTime1)
|
|
.set_local_capture_clock_offset(kLocalCaptureClockOffset1)}));
|
|
|
|
Timestamp timestamp_1 = time_controller.GetClock()->CurrentTime();
|
|
|
|
time_controller.AdvanceTime(SourceTracker::kTimeout);
|
|
|
|
constexpr RtpSource::Extensions extensions1 = {
|
|
.audio_level = kAudioLevel1,
|
|
.absolute_capture_time = kAbsoluteCaptureTime1,
|
|
.local_capture_clock_offset = kLocalCaptureClockOffset1};
|
|
|
|
EXPECT_THAT(
|
|
tracker.GetSources(),
|
|
ElementsAre(RtpSource(timestamp_1.ms(), kSsrc, RtpSourceType::SSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_1.ms(), kCsrcs2, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1),
|
|
RtpSource(timestamp_1.ms(), kCsrcs0, RtpSourceType::CSRC,
|
|
kRtpTimestamp1, extensions1)));
|
|
}
|
|
|
|
} // namespace webrtc
|