Implement RTCOutboundRtpStreamStats.targetBitrate for audio.
Spec: https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-targetbitrate
Bug: webrtc:13377
Change-Id: I98dd263e0b9d6e2ca94969d2a91857b14cd65f70
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/237402
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35337}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 7742538..3795d79 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -529,7 +529,7 @@
RTCStatsMember<uint64_t> bytes_sent;
RTCStatsMember<uint64_t> header_bytes_sent;
RTCStatsMember<uint64_t> retransmitted_bytes_sent;
- // TODO(hbos): Collect and populate this value. https://bugs.webrtc.org/7066
+ // TODO(https://crbug.com/webrtc/13394): Also collect this metric for video.
RTCStatsMember<double> target_bitrate;
RTCStatsMember<uint32_t> frames_encoded;
RTCStatsMember<uint32_t> key_frames_encoded;
diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc
index 7d70592..08bb4e6 100644
--- a/audio/audio_send_stream.cc
+++ b/audio/audio_send_stream.cc
@@ -427,7 +427,7 @@
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
webrtc::AudioSendStream::Stats stats;
stats.local_ssrc = config_.rtp.ssrc;
- stats.target_bitrate_bps = channel_send_->GetBitrate();
+ stats.target_bitrate_bps = channel_send_->GetTargetBitrate();
webrtc::CallSendStatistics call_stats = channel_send_->GetRTCPStatistics();
stats.payload_bytes_sent = call_stats.payload_bytes_sent;
diff --git a/audio/audio_send_stream_unittest.cc b/audio/audio_send_stream_unittest.cc
index 3c5b142..9228611 100644
--- a/audio/audio_send_stream_unittest.cc
+++ b/audio/audio_send_stream_unittest.cc
@@ -300,7 +300,7 @@
.WillRepeatedly(Return(report_blocks));
EXPECT_CALL(*channel_send_, GetANAStatistics())
.WillRepeatedly(Return(ANAStats()));
- EXPECT_CALL(*channel_send_, GetBitrate()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*channel_send_, GetTargetBitrate()).WillRepeatedly(Return(0));
audio_processing_stats_.echo_return_loss = kEchoReturnLoss;
audio_processing_stats_.echo_return_loss_enhancement =
diff --git a/audio/channel_send.cc b/audio/channel_send.cc
index 6a65655..2ad031e 100644
--- a/audio/channel_send.cc
+++ b/audio/channel_send.cc
@@ -96,7 +96,7 @@
// Codecs
void OnBitrateAllocation(BitrateAllocationUpdate update) override;
- int GetBitrate() const override;
+ int GetTargetBitrate() const override;
// Network
void ReceivedRTCPPacket(const uint8_t* data, size_t length) override;
@@ -238,9 +238,6 @@
rtc::scoped_refptr<ChannelSendFrameTransformerDelegate>
frame_transformer_delegate_ RTC_GUARDED_BY(encoder_queue_);
- mutable Mutex bitrate_mutex_;
- int configured_bitrate_bps_ RTC_GUARDED_BY(bitrate_mutex_) = 0;
-
// Defined last to ensure that there are no running tasks when the other
// members are destroyed.
rtc::TaskQueue encoder_queue_;
@@ -616,18 +613,14 @@
// rules.
// RTC_DCHECK(worker_thread_checker_.IsCurrent() ||
// module_process_thread_checker_.IsCurrent());
- MutexLock lock(&bitrate_mutex_);
-
CallEncoder([&](AudioEncoder* encoder) {
encoder->OnReceivedUplinkAllocation(update);
});
retransmission_rate_limiter_->SetMaxRate(update.target_bitrate.bps());
- configured_bitrate_bps_ = update.target_bitrate.bps();
}
-int ChannelSend::GetBitrate() const {
- MutexLock lock(&bitrate_mutex_);
- return configured_bitrate_bps_;
+int ChannelSend::GetTargetBitrate() const {
+ return audio_coding_->GetTargetBitrate();
}
void ChannelSend::OnUplinkPacketLossRate(float packet_loss_rate) {
diff --git a/audio/channel_send.h b/audio/channel_send.h
index 663b947..e100725 100644
--- a/audio/channel_send.h
+++ b/audio/channel_send.h
@@ -91,7 +91,7 @@
int payload_frequency) = 0;
virtual bool SendTelephoneEventOutband(int event, int duration_ms) = 0;
virtual void OnBitrateAllocation(BitrateAllocationUpdate update) = 0;
- virtual int GetBitrate() const = 0;
+ virtual int GetTargetBitrate() const = 0;
virtual void SetInputMute(bool muted) = 0;
virtual void ProcessAndEncodeAudio(
diff --git a/audio/mock_voe_channel_proxy.h b/audio/mock_voe_channel_proxy.h
index d445b51..a02bee3 100644
--- a/audio/mock_voe_channel_proxy.h
+++ b/audio/mock_voe_channel_proxy.h
@@ -166,7 +166,7 @@
(std::unique_ptr<AudioFrame>),
(override));
MOCK_METHOD(RtpRtcpInterface*, GetRtpRtcp, (), (const, override));
- MOCK_METHOD(int, GetBitrate, (), (const, override));
+ MOCK_METHOD(int, GetTargetBitrate, (), (const, override));
MOCK_METHOD(int64_t, GetRTT, (), (const, override));
MOCK_METHOD(void, StartSend, (), (override));
MOCK_METHOD(void, StopSend, (), (override));
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index 2607a7a..519ca5d 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -375,6 +375,8 @@
uint64_t retransmitted_packets_sent = 0;
// https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-nackcount
uint32_t nacks_rcvd = 0;
+ // https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-targetbitrate
+ double target_bitrate = 0.0;
int packets_lost = 0;
float fraction_lost = 0.0f;
int64_t rtt_ms = 0;
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index 5d4455c..6934a0c 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -2369,6 +2369,7 @@
sinfo.packets_lost = stats.packets_lost;
sinfo.fraction_lost = stats.fraction_lost;
sinfo.nacks_rcvd = stats.nacks_rcvd;
+ sinfo.target_bitrate = stats.target_bitrate_bps;
sinfo.codec_name = stats.codec_name;
sinfo.codec_payload_type = stats.codec_payload_type;
sinfo.jitter_ms = stats.jitter_ms;
diff --git a/modules/audio_coding/acm2/audio_coding_module.cc b/modules/audio_coding/acm2/audio_coding_module.cc
index 8ba1b9f..b742a82 100644
--- a/modules/audio_coding/acm2/audio_coding_module.cc
+++ b/modules/audio_coding/acm2/audio_coding_module.cc
@@ -92,6 +92,8 @@
ANAStats GetANAStats() const override;
+ int GetTargetBitrate() const override;
+
private:
struct InputData {
InputData() : buffer(kInitialInputDataBufferSize) {}
@@ -603,6 +605,14 @@
return ANAStats();
}
+int AudioCodingModuleImpl::GetTargetBitrate() const {
+ MutexLock lock(&acm_mutex_);
+ if (!encoder_stack_) {
+ return -1;
+ }
+ return encoder_stack_->GetTargetBitrate();
+}
+
} // namespace
AudioCodingModule::Config::Config(
diff --git a/modules/audio_coding/include/audio_coding_module.h b/modules/audio_coding/include/audio_coding_module.h
index 7551814..9b1dce8 100644
--- a/modules/audio_coding/include/audio_coding_module.h
+++ b/modules/audio_coding/include/audio_coding_module.h
@@ -237,6 +237,8 @@
NetworkStatistics* network_statistics) = 0;
virtual ANAStats GetANAStats() const = 0;
+
+ virtual int GetTargetBitrate() const = 0;
};
} // namespace webrtc
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 7637c07..23e24dc 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -536,6 +536,9 @@
outbound_audio);
outbound_audio->media_type = "audio";
outbound_audio->kind = "audio";
+ if (voice_sender_info.target_bitrate > 0) {
+ outbound_audio->target_bitrate = voice_sender_info.target_bitrate;
+ }
if (voice_sender_info.codec_payload_type) {
outbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
mid, /*inbound=*/false, *voice_sender_info.codec_payload_type);
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index b8c3213..8c3c42f 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -2180,6 +2180,7 @@
voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
voice_media_info.senders[0].retransmitted_bytes_sent = 30;
voice_media_info.senders[0].nacks_rcvd = 31;
+ voice_media_info.senders[0].target_bitrate = 32000;
voice_media_info.senders[0].codec_payload_type = 42;
RtpCodecParameters codec_parameters;
@@ -2214,6 +2215,7 @@
expected_audio.header_bytes_sent = 12;
expected_audio.retransmitted_bytes_sent = 30;
expected_audio.nack_count = 31;
+ expected_audio.target_bitrate = 32000;
ASSERT_TRUE(report->Get(expected_audio.id()));
EXPECT_EQ(
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index 81ead00..32c567e 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -964,7 +964,6 @@
outbound_stream.header_bytes_sent);
verifier.TestMemberIsNonNegative<uint64_t>(
outbound_stream.retransmitted_bytes_sent);
- verifier.TestMemberIsUndefined(outbound_stream.target_bitrate);
if (outbound_stream.media_type.is_defined() &&
*outbound_stream.media_type == "video") {
verifier.TestMemberIsDefined(outbound_stream.frames_encoded);
@@ -1000,6 +999,7 @@
verifier.TestMemberIsNonNegative<uint32_t>(outbound_stream.frames_sent);
verifier.TestMemberIsNonNegative<uint32_t>(
outbound_stream.huge_frames_sent);
+ verifier.TestMemberIsUndefined(outbound_stream.target_bitrate);
verifier.MarkMemberTested(outbound_stream.rid, true);
} else {
verifier.TestMemberIsUndefined(outbound_stream.frames_encoded);
@@ -1023,6 +1023,7 @@
verifier.TestMemberIsUndefined(outbound_stream.frame_width);
verifier.TestMemberIsUndefined(outbound_stream.frames_sent);
verifier.TestMemberIsUndefined(outbound_stream.huge_frames_sent);
+ verifier.TestMemberIsNonNegative<double>(outbound_stream.target_bitrate);
}
return verifier.ExpectAllMembersSuccessfullyTested();
}