Add RTP timestamp to contributing sources
RTP timestamp was recently added to contributing sources in the WebRTC specification. This CL implements that change in WebRTC. Bug: webrtc:10650 Change-Id: Ic0ccfbea7049a5b66063fa6cf60d01d5bd713132 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/137515 Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Johannes Kron <kron@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28020}
This commit is contained in:
parent
afb8d5cdae
commit
b5d918324c
@ -12,12 +12,24 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
RtpSource::RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
RtpSourceType source_type,
|
||||
absl::optional<uint8_t> audio_level,
|
||||
uint32_t rtp_timestamp)
|
||||
: timestamp_ms_(timestamp_ms),
|
||||
source_id_(source_id),
|
||||
source_type_(source_type),
|
||||
audio_level_(audio_level),
|
||||
rtp_timestamp_(rtp_timestamp) {}
|
||||
|
||||
RtpSource::RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
RtpSourceType source_type)
|
||||
: timestamp_ms_(timestamp_ms),
|
||||
source_id_(source_id),
|
||||
source_type_(source_type) {}
|
||||
source_type_(source_type),
|
||||
rtp_timestamp_(0) {}
|
||||
|
||||
RtpSource::RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
@ -26,7 +38,8 @@ RtpSource::RtpSource(int64_t timestamp_ms,
|
||||
: timestamp_ms_(timestamp_ms),
|
||||
source_id_(source_id),
|
||||
source_type_(source_type),
|
||||
audio_level_(audio_level) {}
|
||||
audio_level_(audio_level),
|
||||
rtp_timestamp_(0) {}
|
||||
|
||||
RtpSource::RtpSource(const RtpSource&) = default;
|
||||
RtpSource& RtpSource::operator=(const RtpSource&) = default;
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "api/proxy.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "rtc_base/deprecation.h"
|
||||
#include "rtc_base/ref_count.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -36,13 +37,23 @@ enum class RtpSourceType {
|
||||
class RtpSource {
|
||||
public:
|
||||
RtpSource() = delete;
|
||||
RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
RtpSourceType source_type);
|
||||
|
||||
RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
RtpSourceType source_type,
|
||||
uint8_t audio_level);
|
||||
absl::optional<uint8_t> audio_level,
|
||||
uint32_t rtp_timestamp);
|
||||
|
||||
// DEPRECATED: Will be removed after 2019-07-31.
|
||||
RTC_DEPRECATED RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
RtpSourceType source_type);
|
||||
// DEPRECATED: Will be removed after 2019-07-31.
|
||||
RTC_DEPRECATED RtpSource(int64_t timestamp_ms,
|
||||
uint32_t source_id,
|
||||
RtpSourceType source_type,
|
||||
uint8_t audio_level);
|
||||
|
||||
RtpSource(const RtpSource&);
|
||||
RtpSource& operator=(const RtpSource&);
|
||||
~RtpSource();
|
||||
@ -64,9 +75,12 @@ class RtpSource {
|
||||
audio_level_ = level;
|
||||
}
|
||||
|
||||
uint32_t rtp_timestamp() const { return rtp_timestamp_; }
|
||||
|
||||
bool operator==(const RtpSource& o) const {
|
||||
return timestamp_ms_ == o.timestamp_ms() && source_id_ == o.source_id() &&
|
||||
source_type_ == o.source_type() && audio_level_ == o.audio_level_;
|
||||
source_type_ == o.source_type() && audio_level_ == o.audio_level_ &&
|
||||
rtp_timestamp_ == o.rtp_timestamp();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -74,6 +88,7 @@ class RtpSource {
|
||||
uint32_t source_id_;
|
||||
RtpSourceType source_type_;
|
||||
absl::optional<uint8_t> audio_level_;
|
||||
uint32_t rtp_timestamp_;
|
||||
};
|
||||
|
||||
class RtpReceiverObserverInterface {
|
||||
|
||||
@ -564,9 +564,10 @@ std::vector<webrtc::RtpSource> ChannelReceive::GetSources() const {
|
||||
sources = contributing_sources_.GetSources(now_ms);
|
||||
if (last_received_rtp_system_time_ms_ >=
|
||||
now_ms - ContributingSources::kHistoryMs) {
|
||||
RTC_DCHECK(last_received_rtp_timestamp_.has_value());
|
||||
sources.emplace_back(*last_received_rtp_system_time_ms_, remote_ssrc_,
|
||||
RtpSourceType::SSRC);
|
||||
sources.back().set_audio_level(last_received_rtp_audio_level_);
|
||||
RtpSourceType::SSRC, last_received_rtp_audio_level_,
|
||||
*last_received_rtp_timestamp_);
|
||||
}
|
||||
}
|
||||
return sources;
|
||||
@ -599,7 +600,8 @@ void ChannelReceive::OnRtpPacket(const RtpPacketReceived& packet) {
|
||||
std::vector<uint32_t> csrcs = packet.Csrcs();
|
||||
contributing_sources_.Update(
|
||||
now_ms, csrcs,
|
||||
has_audio_level ? absl::optional<uint8_t>(audio_level) : absl::nullopt);
|
||||
has_audio_level ? absl::optional<uint8_t>(audio_level) : absl::nullopt,
|
||||
packet.Timestamp());
|
||||
}
|
||||
|
||||
// Store playout timestamp for the received RTP packet
|
||||
|
||||
@ -26,8 +26,9 @@ ContributingSources::~ContributingSources() = default;
|
||||
|
||||
void ContributingSources::Update(int64_t now_ms,
|
||||
rtc::ArrayView<const uint32_t> csrcs,
|
||||
absl::optional<uint8_t> audio_level) {
|
||||
Entry entry = { now_ms, audio_level };
|
||||
absl::optional<uint8_t> audio_level,
|
||||
uint32_t rtp_timestamp) {
|
||||
Entry entry = {now_ms, audio_level, rtp_timestamp};
|
||||
for (uint32_t csrc : csrcs) {
|
||||
active_csrcs_[csrc] = entry;
|
||||
}
|
||||
@ -47,14 +48,9 @@ std::vector<RtpSource> ContributingSources::GetSources(int64_t now_ms) const {
|
||||
std::vector<RtpSource> sources;
|
||||
for (auto& record : active_csrcs_) {
|
||||
if (record.second.last_seen_ms >= now_ms - kHistoryMs) {
|
||||
if (record.second.audio_level.has_value()) {
|
||||
sources.emplace_back(record.second.last_seen_ms, record.first,
|
||||
RtpSourceType::CSRC,
|
||||
*record.second.audio_level);
|
||||
} else {
|
||||
sources.emplace_back(record.second.last_seen_ms, record.first,
|
||||
RtpSourceType::CSRC);
|
||||
}
|
||||
sources.emplace_back(record.second.last_seen_ms, record.first,
|
||||
RtpSourceType::CSRC, record.second.audio_level,
|
||||
record.second.rtp_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +72,10 @@ void ContributingSources::DeleteOldEntries(int64_t now_ms) {
|
||||
|
||||
ContributingSources::Entry::Entry() = default;
|
||||
ContributingSources::Entry::Entry(int64_t timestamp_ms,
|
||||
absl::optional<uint8_t> audio_level_arg)
|
||||
: last_seen_ms(timestamp_ms), audio_level(audio_level_arg) {}
|
||||
absl::optional<uint8_t> audio_level_arg,
|
||||
uint32_t rtp_timestamp)
|
||||
: last_seen_ms(timestamp_ms),
|
||||
audio_level(audio_level_arg),
|
||||
rtp_timestamp(rtp_timestamp) {}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -32,8 +32,10 @@ class ContributingSources {
|
||||
ContributingSources();
|
||||
~ContributingSources();
|
||||
|
||||
void Update(int64_t now_ms, rtc::ArrayView<const uint32_t> csrcs,
|
||||
absl::optional<uint8_t> audio_level);
|
||||
void Update(int64_t now_ms,
|
||||
rtc::ArrayView<const uint32_t> csrcs,
|
||||
absl::optional<uint8_t> audio_level,
|
||||
uint32_t rtp_timestamp);
|
||||
|
||||
// Returns contributing sources seen the last 10 s.
|
||||
std::vector<RtpSource> GetSources(int64_t now_ms) const;
|
||||
@ -41,10 +43,13 @@ class ContributingSources {
|
||||
private:
|
||||
struct Entry {
|
||||
Entry();
|
||||
Entry(int64_t timestamp_ms, absl::optional<uint8_t> audio_level);
|
||||
Entry(int64_t timestamp_ms,
|
||||
absl::optional<uint8_t> audio_level,
|
||||
uint32_t rtp_timestamp);
|
||||
|
||||
int64_t last_seen_ms;
|
||||
absl::optional<uint8_t> audio_level;
|
||||
uint32_t rtp_timestamp;
|
||||
};
|
||||
|
||||
void DeleteOldEntries(int64_t now_ms);
|
||||
|
||||
@ -23,6 +23,9 @@ using ::testing::UnorderedElementsAre;
|
||||
constexpr uint32_t kCsrc1 = 111;
|
||||
constexpr uint32_t kCsrc2 = 222;
|
||||
constexpr uint32_t kCsrc3 = 333;
|
||||
constexpr uint32_t kRtpTimestamp1 = 314;
|
||||
constexpr uint32_t kRtpTimestamp2 = 315;
|
||||
constexpr uint32_t kRtpTimestamp3 = 316;
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -30,11 +33,13 @@ TEST(ContributingSourcesTest, RecordSources) {
|
||||
ContributingSources csrcs;
|
||||
constexpr uint32_t kCsrcs[] = {kCsrc1, kCsrc2};
|
||||
constexpr int64_t kTime1 = 10;
|
||||
csrcs.Update(kTime1, kCsrcs, absl::nullopt);
|
||||
csrcs.Update(kTime1, kCsrcs, absl::nullopt, kRtpTimestamp1);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime1),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1)));
|
||||
}
|
||||
|
||||
TEST(ContributingSourcesTest, UpdateSources) {
|
||||
@ -45,17 +50,22 @@ TEST(ContributingSourcesTest, UpdateSources) {
|
||||
constexpr uint32_t kCsrcs2[] = {kCsrc2, kCsrc3};
|
||||
constexpr int64_t kTime1 = 10;
|
||||
constexpr int64_t kTime2 = kTime1 + 5 * rtc::kNumMillisecsPerSec;
|
||||
csrcs.Update(kTime1, kCsrcs1, absl::nullopt);
|
||||
csrcs.Update(kTime1, kCsrcs1, absl::nullopt, kRtpTimestamp1);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime1),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
|
||||
csrcs.Update(kTime2, kCsrcs2, absl::nullopt);
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1)));
|
||||
csrcs.Update(kTime2, kCsrcs2, absl::nullopt, kRtpTimestamp2);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime2),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC),
|
||||
RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC)));
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1),
|
||||
RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp2),
|
||||
RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp2)));
|
||||
}
|
||||
|
||||
TEST(ContributingSourcesTest, ReturnRecentOnly) {
|
||||
@ -65,16 +75,20 @@ TEST(ContributingSourcesTest, ReturnRecentOnly) {
|
||||
constexpr int64_t kTime1 = 10;
|
||||
constexpr int64_t kTime2 = kTime1 + 5 * rtc::kNumMillisecsPerSec;
|
||||
constexpr int64_t kTime3 = kTime1 + 12 * rtc::kNumMillisecsPerSec;
|
||||
csrcs.Update(kTime1, kCsrcs1, absl::nullopt);
|
||||
csrcs.Update(kTime1, kCsrcs1, absl::nullopt, kRtpTimestamp1);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime1),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
|
||||
csrcs.Update(kTime2, kCsrcs2, absl::nullopt);
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1)));
|
||||
csrcs.Update(kTime2, kCsrcs2, absl::nullopt, kRtpTimestamp2);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime3),
|
||||
UnorderedElementsAre(RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC),
|
||||
RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC)));
|
||||
UnorderedElementsAre(RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp2),
|
||||
RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp2)));
|
||||
}
|
||||
|
||||
TEST(ContributingSourcesTest, PurgeOldSources) {
|
||||
@ -84,46 +98,58 @@ TEST(ContributingSourcesTest, PurgeOldSources) {
|
||||
constexpr int64_t kTime1 = 10;
|
||||
constexpr int64_t kTime2 = kTime1 + 10 * rtc::kNumMillisecsPerSec;
|
||||
constexpr int64_t kTime3 = kTime1 + 20 * rtc::kNumMillisecsPerSec;
|
||||
csrcs.Update(kTime1, kCsrcs1, absl::nullopt);
|
||||
csrcs.Update(kTime1, kCsrcs1, absl::nullopt, kRtpTimestamp1);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime2),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
|
||||
csrcs.Update(kTime2, kCsrcs2, absl::nullopt);
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1)));
|
||||
csrcs.Update(kTime2, kCsrcs2, absl::nullopt, kRtpTimestamp2);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime2),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC),
|
||||
RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC)));
|
||||
csrcs.Update(kTime3, kCsrcs2, absl::nullopt);
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp1),
|
||||
RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp2),
|
||||
RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp2)));
|
||||
csrcs.Update(kTime3, kCsrcs2, absl::nullopt, kRtpTimestamp3);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime3),
|
||||
UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC),
|
||||
RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC)));
|
||||
UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp3),
|
||||
RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp3)));
|
||||
// Query at an earlier time; check that old sources really have been purged
|
||||
// and don't reappear.
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime2),
|
||||
UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC),
|
||||
RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC)));
|
||||
UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp3),
|
||||
RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC,
|
||||
absl::nullopt, kRtpTimestamp3)));
|
||||
}
|
||||
|
||||
TEST(ContributingSourcesTest, AudioLevel) {
|
||||
ContributingSources csrcs;
|
||||
constexpr uint32_t kCsrcs[] = {kCsrc1, kCsrc2};
|
||||
constexpr int64_t kTime1 = 10;
|
||||
csrcs.Update(kTime1, kCsrcs, 47);
|
||||
csrcs.Update(kTime1, kCsrcs, 47, kRtpTimestamp1);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime1),
|
||||
UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC, 47),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47)));
|
||||
UnorderedElementsAre(
|
||||
RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC, 47, kRtpTimestamp1),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47, kRtpTimestamp1)));
|
||||
|
||||
constexpr uint32_t kCsrcsSubset[] = {kCsrc1};
|
||||
csrcs.Update(kTime1 + 1, kCsrcsSubset, absl::nullopt);
|
||||
csrcs.Update(kTime1 + 1, kCsrcsSubset, absl::nullopt, kRtpTimestamp2);
|
||||
EXPECT_THAT(
|
||||
csrcs.GetSources(kTime1 + 1),
|
||||
UnorderedElementsAre(RtpSource(kTime1 + 1, kCsrc1, RtpSourceType::CSRC),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47)));
|
||||
UnorderedElementsAre(
|
||||
RtpSource(kTime1 + 1, kCsrc1, RtpSourceType::CSRC, absl::nullopt,
|
||||
kRtpTimestamp2),
|
||||
RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47, kRtpTimestamp1)));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -326,7 +326,8 @@ void RtpVideoStreamReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
|
||||
|
||||
std::vector<uint32_t> csrcs = packet.Csrcs();
|
||||
contributing_sources_.Update(now_ms, csrcs,
|
||||
/* audio level */ absl::nullopt);
|
||||
/* audio level */ absl::nullopt,
|
||||
packet.Timestamp());
|
||||
}
|
||||
// Periodically log the RTP header of incoming packets.
|
||||
if (now_ms - last_packet_log_ms_ > kPacketLogIntervalMs) {
|
||||
@ -781,8 +782,11 @@ std::vector<webrtc::RtpSource> RtpVideoStreamReceiver::GetSources() const {
|
||||
sources = contributing_sources_.GetSources(now_ms);
|
||||
if (last_received_rtp_system_time_ms_ >=
|
||||
now_ms - ContributingSources::kHistoryMs) {
|
||||
RTC_DCHECK(last_received_rtp_timestamp_.has_value());
|
||||
sources.emplace_back(*last_received_rtp_system_time_ms_,
|
||||
config_.rtp.remote_ssrc, RtpSourceType::SSRC);
|
||||
config_.rtp.remote_ssrc, RtpSourceType::SSRC,
|
||||
/* audio_level */ absl::nullopt,
|
||||
*last_received_rtp_timestamp_);
|
||||
}
|
||||
}
|
||||
return sources;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user