Add audio_level member to RtpSource and set it from RtpReceiverImpl::IncomingRtpPacket.
BUG=webrtc:7987
Review-Url: https://codereview.webrtc.org/3000713002
Cr-Original-Commit-Position: refs/heads/master@{#19503}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 2b706343de6f79839f46d12008ec3c8062bb94bc
diff --git a/api/rtpreceiverinterface.h b/api/rtpreceiverinterface.h
index ce4abeb..3119fb7 100644
--- a/api/rtpreceiverinterface.h
+++ b/api/rtpreceiverinterface.h
@@ -39,6 +39,15 @@
source_id_(source_id),
source_type_(source_type) {}
+ RtpSource(int64_t timestamp_ms,
+ uint32_t source_id,
+ RtpSourceType source_type,
+ uint8_t audio_level)
+ : timestamp_ms_(timestamp_ms),
+ source_id_(source_id),
+ source_type_(source_type),
+ audio_level_(audio_level) {}
+
int64_t timestamp_ms() const { return timestamp_ms_; }
void update_timestamp_ms(int64_t timestamp_ms) {
RTC_DCHECK_LE(timestamp_ms_, timestamp_ms);
@@ -51,19 +60,21 @@
// The source can be either a contributing source or a synchronization source.
RtpSourceType source_type() const { return source_type_; }
- // This isn't implemented yet and will always return an empty Optional.
- // TODO(zhihuang): Implement this to return real audio level.
- rtc::Optional<int8_t> audio_level() const { return rtc::Optional<int8_t>(); }
+ rtc::Optional<uint8_t> audio_level() const { return audio_level_; }
+ void set_audio_level(const rtc::Optional<uint8_t>& level) {
+ audio_level_ = level;
+ }
bool operator==(const RtpSource& o) const {
return timestamp_ms_ == o.timestamp_ms() && source_id_ == o.source_id() &&
- source_type_ == o.source_type();
+ source_type_ == o.source_type() && audio_level_ == o.audio_level_;
}
private:
int64_t timestamp_ms_;
uint32_t source_id_;
RtpSourceType source_type_;
+ rtc::Optional<uint8_t> audio_level_;
};
class RtpReceiverObserverInterface {
diff --git a/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/modules/rtp_rtcp/source/rtp_receiver_impl.cc
index 20f5746..ed0383f 100644
--- a/modules/rtp_rtcp/source/rtp_receiver_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_receiver_impl.cc
@@ -163,7 +163,11 @@
webrtc_rtp_header.header = rtp_header;
CheckCSRC(webrtc_rtp_header);
- UpdateSources();
+ auto audio_level =
+ rtp_header.extension.hasAudioLevel
+ ? rtc::Optional<uint8_t>(rtp_header.extension.audioLevel)
+ : rtc::Optional<uint8_t>();
+ UpdateSources(audio_level);
size_t payload_data_length = payload_length - rtp_header.paddingLength;
@@ -500,7 +504,8 @@
}
}
-void RtpReceiverImpl::UpdateSources() {
+void RtpReceiverImpl::UpdateSources(
+ const rtc::Optional<uint8_t>& ssrc_audio_level) {
rtc::CritScope lock(&critical_section_rtp_receiver_);
int64_t now_ms = clock_->TimeInMilliseconds();
@@ -527,6 +532,8 @@
ssrc_sources_.rbegin()->update_timestamp_ms(now_ms);
}
+ ssrc_sources_.back().set_audio_level(ssrc_audio_level);
+
RemoveOutdatedSources(now_ms);
}
diff --git a/modules/rtp_rtcp/source/rtp_receiver_impl.h b/modules/rtp_rtcp/source/rtp_receiver_impl.h
index b64683a..6d38cf7 100644
--- a/modules/rtp_rtcp/source/rtp_receiver_impl.h
+++ b/modules/rtp_rtcp/source/rtp_receiver_impl.h
@@ -79,7 +79,7 @@
bool* is_red,
PayloadUnion* payload);
- void UpdateSources();
+ void UpdateSources(const rtc::Optional<uint8_t>& ssrc_audio_level);
void RemoveOutdatedSources(int64_t now_ms);
Clock* clock_;
diff --git a/modules/rtp_rtcp/source/rtp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtp_receiver_unittest.cc
index b0531c3..e20d2d5 100644
--- a/modules/rtp_rtcp/source/rtp_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_receiver_unittest.cc
@@ -255,4 +255,88 @@
csrc_sources.begin()->timestamp_ms());
}
+// The audio level from the RTPHeader extension should be stored in the
+// RtpSource with the matching SSRC.
+TEST_F(RtpReceiverTest, GetSourcesContainsAudioLevelExtension) {
+ RTPHeader header;
+ int64_t time1_ms = fake_clock_.TimeInMilliseconds();
+ header.payloadType = kPcmuPayloadType;
+ header.ssrc = kSsrc1;
+ header.timestamp = rtp_timestamp(time1_ms);
+ header.extension.hasAudioLevel = true;
+ header.extension.audioLevel = 10;
+ PayloadUnion payload_specific = {AudioPayload()};
+
+ EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+ header, kTestPayload, sizeof(kTestPayload), payload_specific, !kInOrder));
+ auto sources = rtp_receiver_->GetSources();
+ EXPECT_THAT(sources, UnorderedElementsAre(RtpSource(
+ time1_ms, kSsrc1, RtpSourceType::SSRC, 10)));
+
+ // Receive a packet from a different SSRC with a different level and check
+ // that they are both remembered.
+ fake_clock_.AdvanceTimeMilliseconds(1);
+ int64_t time2_ms = fake_clock_.TimeInMilliseconds();
+ header.ssrc = kSsrc2;
+ header.timestamp = rtp_timestamp(time2_ms);
+ header.extension.hasAudioLevel = true;
+ header.extension.audioLevel = 20;
+
+ EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+ header, kTestPayload, sizeof(kTestPayload), payload_specific, !kInOrder));
+ sources = rtp_receiver_->GetSources();
+ EXPECT_THAT(sources,
+ UnorderedElementsAre(
+ RtpSource(time1_ms, kSsrc1, RtpSourceType::SSRC, 10),
+ RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20)));
+
+ // Receive a packet from the first SSRC again and check that the level is
+ // updated.
+ fake_clock_.AdvanceTimeMilliseconds(1);
+ int64_t time3_ms = fake_clock_.TimeInMilliseconds();
+ header.ssrc = kSsrc1;
+ header.timestamp = rtp_timestamp(time3_ms);
+ header.extension.hasAudioLevel = true;
+ header.extension.audioLevel = 30;
+
+ EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+ header, kTestPayload, sizeof(kTestPayload), payload_specific, !kInOrder));
+ sources = rtp_receiver_->GetSources();
+ EXPECT_THAT(sources,
+ UnorderedElementsAre(
+ RtpSource(time3_ms, kSsrc1, RtpSourceType::SSRC, 30),
+ RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20)));
+}
+
+TEST_F(RtpReceiverTest,
+ MissingAudioLevelHeaderExtensionClearsRtpSourceAudioLevel) {
+ RTPHeader header;
+ int64_t time1_ms = fake_clock_.TimeInMilliseconds();
+ header.payloadType = kPcmuPayloadType;
+ header.ssrc = kSsrc1;
+ header.timestamp = rtp_timestamp(time1_ms);
+ header.extension.hasAudioLevel = true;
+ header.extension.audioLevel = 10;
+ PayloadUnion payload_specific = {AudioPayload()};
+
+ EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+ header, kTestPayload, sizeof(kTestPayload), payload_specific, !kInOrder));
+ auto sources = rtp_receiver_->GetSources();
+ EXPECT_THAT(sources, UnorderedElementsAre(RtpSource(
+ time1_ms, kSsrc1, RtpSourceType::SSRC, 10)));
+
+ // Receive a second packet without the audio level header extension and check
+ // that the audio level is cleared.
+ fake_clock_.AdvanceTimeMilliseconds(1);
+ int64_t time2_ms = fake_clock_.TimeInMilliseconds();
+ header.timestamp = rtp_timestamp(time2_ms);
+ header.extension.hasAudioLevel = false;
+
+ EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
+ header, kTestPayload, sizeof(kTestPayload), payload_specific, !kInOrder));
+ sources = rtp_receiver_->GetSources();
+ EXPECT_THAT(sources, UnorderedElementsAre(
+ RtpSource(time2_ms, kSsrc1, RtpSourceType::SSRC)));
+}
+
} // namespace webrtc