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}
This commit is contained in:
zstein 2017-08-24 14:52:17 -07:00 committed by Commit Bot
parent 0cab085157
commit 2b706343de
4 changed files with 109 additions and 7 deletions

View File

@ -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<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 {

View File

@ -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<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::CheckCSRC(const WebRtcRTPHeader& rtp_header) {
}
}
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 @@ void RtpReceiverImpl::UpdateSources() {
ssrc_sources_.rbegin()->update_timestamp_ms(now_ms);
}
ssrc_sources_.back().set_audio_level(ssrc_audio_level);
RemoveOutdatedSources(now_ms);
}

View File

@ -79,7 +79,7 @@ class RtpReceiverImpl : public RtpReceiver {
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_;

View File

@ -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