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}
diff --git a/api/rtp_receiver_interface.cc b/api/rtp_receiver_interface.cc
index 52f72df..efa7f1b 100644
--- a/api/rtp_receiver_interface.cc
+++ b/api/rtp_receiver_interface.cc
@@ -14,10 +14,22 @@
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 @@
: 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;
diff --git a/api/rtp_receiver_interface.h b/api/rtp_receiver_interface.h
index 3934215c..f79bf8f 100644
--- a/api/rtp_receiver_interface.h
+++ b/api/rtp_receiver_interface.h
@@ -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 @@
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 @@
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 @@
uint32_t source_id_;
RtpSourceType source_type_;
absl::optional<uint8_t> audio_level_;
+ uint32_t rtp_timestamp_;
};
class RtpReceiverObserverInterface {
diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc
index 85a029d..5f59275 100644
--- a/audio/channel_receive.cc
+++ b/audio/channel_receive.cc
@@ -564,9 +564,10 @@
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 @@
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
diff --git a/modules/rtp_rtcp/source/contributing_sources.cc b/modules/rtp_rtcp/source/contributing_sources.cc
index 64dc443..88274ff 100644
--- a/modules/rtp_rtcp/source/contributing_sources.cc
+++ b/modules/rtp_rtcp/source/contributing_sources.cc
@@ -26,8 +26,9 @@
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> 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 @@
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
diff --git a/modules/rtp_rtcp/source/contributing_sources.h b/modules/rtp_rtcp/source/contributing_sources.h
index 81bf725..67e8967 100644
--- a/modules/rtp_rtcp/source/contributing_sources.h
+++ b/modules/rtp_rtcp/source/contributing_sources.h
@@ -32,8 +32,10 @@
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 @@
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);
diff --git a/modules/rtp_rtcp/source/contributing_sources_unittest.cc b/modules/rtp_rtcp/source/contributing_sources_unittest.cc
index 38d25ce..acf8a90 100644
--- a/modules/rtp_rtcp/source/contributing_sources_unittest.cc
+++ b/modules/rtp_rtcp/source/contributing_sources_unittest.cc
@@ -23,6 +23,9 @@
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 @@
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 @@
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 @@
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 @@
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
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index 305b8bd..edced5d 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -326,7 +326,8 @@
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 @@
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;