From 2b706343de6f79839f46d12008ec3c8062bb94bc Mon Sep 17 00:00:00 2001 From: zstein Date: Thu, 24 Aug 2017 14:52:17 -0700 Subject: [PATCH] Add audio_level member to RtpSource and set it from RtpReceiverImpl::IncomingRtpPacket. BUG=webrtc:7987 Review-Url: https://codereview.webrtc.org/3000713002 Cr-Commit-Position: refs/heads/master@{#19503} --- webrtc/api/rtpreceiverinterface.h | 19 ++++- .../rtp_rtcp/source/rtp_receiver_impl.cc | 11 ++- .../rtp_rtcp/source/rtp_receiver_impl.h | 2 +- .../rtp_rtcp/source/rtp_receiver_unittest.cc | 84 +++++++++++++++++++ 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/webrtc/api/rtpreceiverinterface.h b/webrtc/api/rtpreceiverinterface.h index ce4abeb511..3119fb781d 100644 --- a/webrtc/api/rtpreceiverinterface.h +++ b/webrtc/api/rtpreceiverinterface.h @@ -39,6 +39,15 @@ class RtpSource { 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 @@ class RtpSource { // 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 audio_level() const { return rtc::Optional(); } + rtc::Optional audio_level() const { return audio_level_; } + void set_audio_level(const rtc::Optional& 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 audio_level_; }; class RtpReceiverObserverInterface { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc index 20f57460a6..ed0383f0d6 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc @@ -163,7 +163,11 @@ bool RtpReceiverImpl::IncomingRtpPacket( webrtc_rtp_header.header = rtp_header; CheckCSRC(webrtc_rtp_header); - UpdateSources(); + auto audio_level = + rtp_header.extension.hasAudioLevel + ? rtc::Optional(rtp_header.extension.audioLevel) + : rtc::Optional(); + UpdateSources(audio_level); size_t payload_data_length = payload_length - rtp_header.paddingLength; @@ -500,7 +504,8 @@ void RtpReceiverImpl::CheckCSRC(const WebRtcRTPHeader& rtp_header) { } } -void RtpReceiverImpl::UpdateSources() { +void RtpReceiverImpl::UpdateSources( + const rtc::Optional& ssrc_audio_level) { rtc::CritScope lock(&critical_section_rtp_receiver_); int64_t now_ms = clock_->TimeInMilliseconds(); @@ -527,6 +532,8 @@ void RtpReceiverImpl::UpdateSources() { ssrc_sources_.rbegin()->update_timestamp_ms(now_ms); } + ssrc_sources_.back().set_audio_level(ssrc_audio_level); + RemoveOutdatedSources(now_ms); } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h index b64683a17c..6d38cf7e4d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h @@ -79,7 +79,7 @@ class RtpReceiverImpl : public RtpReceiver { bool* is_red, PayloadUnion* payload); - void UpdateSources(); + void UpdateSources(const rtc::Optional& ssrc_audio_level); void RemoveOutdatedSources(int64_t now_ms); Clock* clock_; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc index b0531c3c51..e20d2d52a9 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_unittest.cc @@ -255,4 +255,88 @@ TEST_F(RtpReceiverTest, GetSourcesRemoveOutdatedSource) { 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