Add accounting of actual audio bit usage
Part of a set of CL to allow video to borrow underused audio bitrate. Bug: webrtc:35055527 Change-Id: Idb504cbbc5794c06b28bdc21b3d860c9da9df175 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358202 Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org> Commit-Queue: Dan Tan <dwtan@google.com> Cr-Commit-Position: refs/heads/main@{#42733}
This commit is contained in:
parent
075349f039
commit
2406aaf475
@ -492,8 +492,7 @@ uint32_t AudioSendStream::OnBitrateUpdated(BitrateAllocationUpdate update) {
|
||||
}
|
||||
|
||||
absl::optional<DataRate> AudioSendStream::GetUsedRate() const {
|
||||
// TODO(bugs.webrtc.org/35055527): Implement
|
||||
return absl::nullopt;
|
||||
return channel_send_->GetUsedRate();
|
||||
}
|
||||
|
||||
void AudioSendStream::SetTransportOverhead(
|
||||
@ -518,6 +517,7 @@ void AudioSendStream::UpdateOverheadPerPacket() {
|
||||
if (registered_with_allocator_) {
|
||||
ConfigureBitrateObserver();
|
||||
}
|
||||
channel_send_->RegisterPacketOverhead(overhead_per_packet_bytes);
|
||||
}
|
||||
|
||||
size_t AudioSendStream::TestOnlyGetPerPacketOverheadBytes() const {
|
||||
|
||||
@ -560,6 +560,7 @@ TEST(AudioSendStreamTest, AudioNetworkAdaptorReceivesOverhead) {
|
||||
}));
|
||||
EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
|
||||
.WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead);
|
||||
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
|
||||
@ -672,6 +673,7 @@ TEST(AudioSendStreamTest, SSBweWithOverhead) {
|
||||
"WebRTC-Audio-LegacyOverhead/Disabled/");
|
||||
EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
|
||||
.WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead);
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
const DataRate bitrate =
|
||||
DataRate::BitsPerSec(helper.config().max_bitrate_bps) +
|
||||
@ -694,6 +696,7 @@ TEST(AudioSendStreamTest, SSBweWithOverheadMinRespected) {
|
||||
"WebRTC-Audio-Allocation/min:6kbps,max:64kbps/");
|
||||
EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
|
||||
.WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead);
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
const DataRate bitrate = DataRate::KilobitsPerSec(6) + kMinOverheadRate;
|
||||
EXPECT_CALL(*helper.channel_send(),
|
||||
@ -714,6 +717,7 @@ TEST(AudioSendStreamTest, SSBweWithOverheadMaxRespected) {
|
||||
"WebRTC-Audio-Allocation/min:6kbps,max:64kbps/");
|
||||
EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
|
||||
.WillRepeatedly(Return(kOverheadPerPacket.bytes<size_t>()));
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead);
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
const DataRate bitrate = DataRate::KilobitsPerSec(64) + kMaxOverheadRate;
|
||||
EXPECT_CALL(*helper.channel_send(),
|
||||
@ -796,6 +800,7 @@ TEST(AudioSendStreamTest, OnTransportOverheadChanged) {
|
||||
|
||||
// CallEncoder will be called on overhead change.
|
||||
EXPECT_CALL(*helper.channel_send(), CallEncoder);
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead);
|
||||
|
||||
const size_t transport_overhead_per_packet_bytes = 333;
|
||||
send_stream->SetTransportOverhead(transport_overhead_per_packet_bytes);
|
||||
@ -811,6 +816,8 @@ TEST(AudioSendStreamTest, DoesntCallEncoderWhenOverheadUnchanged) {
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
auto new_config = helper.config();
|
||||
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead).Times(2);
|
||||
|
||||
// CallEncoder will be called on overhead change.
|
||||
EXPECT_CALL(*helper.channel_send(), CallEncoder);
|
||||
const size_t transport_overhead_per_packet_bytes = 333;
|
||||
@ -832,6 +839,7 @@ TEST(AudioSendStreamTest, AudioOverheadChanged) {
|
||||
const size_t audio_overhead_per_packet_bytes = 555;
|
||||
EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
|
||||
.WillRepeatedly(Return(audio_overhead_per_packet_bytes));
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead).Times(2);
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
|
||||
BitrateAllocationUpdate update;
|
||||
@ -862,6 +870,7 @@ TEST(AudioSendStreamTest, OnAudioAndTransportOverheadChanged) {
|
||||
const size_t audio_overhead_per_packet_bytes = 555;
|
||||
EXPECT_CALL(*helper.rtp_rtcp(), ExpectedPerPacketOverhead)
|
||||
.WillRepeatedly(Return(audio_overhead_per_packet_bytes));
|
||||
EXPECT_CALL(*helper.channel_send(), RegisterPacketOverhead).Times(2);
|
||||
auto send_stream = helper.CreateAudioSendStream();
|
||||
auto new_config = helper.config();
|
||||
|
||||
|
||||
@ -57,6 +57,47 @@ constexpr int64_t kMinRetransmissionWindowMs = 30;
|
||||
class RtpPacketSenderProxy;
|
||||
class TransportSequenceNumberProxy;
|
||||
|
||||
class AudioBitrateAccountant {
|
||||
public:
|
||||
void RegisterPacketOverhead(int packet_byte_overhead) {
|
||||
packet_overhead_ = DataSize::Bytes(packet_byte_overhead);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
rate_last_frame_ = DataRate::BitsPerSec(0);
|
||||
next_frame_duration_ = TimeDelta::Millis(0);
|
||||
report_rate_ = absl::nullopt;
|
||||
}
|
||||
|
||||
// A new frame is formed when bytesize is nonzero.
|
||||
void UpdateBpsEstimate(DataSize payload_size, TimeDelta frame_duration) {
|
||||
next_frame_duration_ += frame_duration;
|
||||
// Do not have a full frame yet.
|
||||
if (payload_size.bytes() == 0)
|
||||
return;
|
||||
|
||||
// We report the larger of the rates computed using the last frame, and
|
||||
// second last frame. Under DTX, frame sizes sometimes alternate, it is
|
||||
// preferable to report the upper envelop.
|
||||
DataRate rate_cur_frame =
|
||||
(payload_size + packet_overhead_) / next_frame_duration_;
|
||||
|
||||
report_rate_ =
|
||||
(rate_cur_frame > rate_last_frame_) ? rate_cur_frame : rate_last_frame_;
|
||||
|
||||
rate_last_frame_ = rate_cur_frame;
|
||||
next_frame_duration_ = TimeDelta::Millis(0);
|
||||
}
|
||||
|
||||
absl::optional<DataRate> GetUsedRate() const { return report_rate_; }
|
||||
|
||||
private:
|
||||
TimeDelta next_frame_duration_ = TimeDelta::Millis(0);
|
||||
DataSize packet_overhead_ = DataSize::Bytes(72);
|
||||
DataRate rate_last_frame_ = DataRate::BitsPerSec(0);
|
||||
absl::optional<DataRate> report_rate_;
|
||||
};
|
||||
|
||||
class ChannelSend : public ChannelSendInterface,
|
||||
public AudioPacketizationCallback, // receive encoded
|
||||
// packets from the ACM
|
||||
@ -152,6 +193,17 @@ class ChannelSend : public ChannelSendInterface,
|
||||
// ReportBlockDataObserver.
|
||||
void OnReportBlockDataUpdated(ReportBlockData report_block) override;
|
||||
|
||||
// Reports actual bitrate used (vs allocated).
|
||||
absl::optional<DataRate> GetUsedRate() const override {
|
||||
MutexLock lock(&bitrate_accountant_mutex_);
|
||||
return bitrate_accountant_.GetUsedRate();
|
||||
}
|
||||
|
||||
void RegisterPacketOverhead(int packet_byte_overhead) override {
|
||||
MutexLock lock(&bitrate_accountant_mutex_);
|
||||
bitrate_accountant_.RegisterPacketOverhead(packet_byte_overhead);
|
||||
}
|
||||
|
||||
private:
|
||||
// From AudioPacketizationCallback in the ACM
|
||||
int32_t SendData(AudioFrameType frameType,
|
||||
@ -240,6 +292,10 @@ class ChannelSend : public ChannelSendInterface,
|
||||
RTC_NO_UNIQUE_ADDRESS SequenceChecker encoder_queue_checker_;
|
||||
|
||||
SdpAudioFormat encoder_format_;
|
||||
|
||||
mutable Mutex bitrate_accountant_mutex_;
|
||||
AudioBitrateAccountant bitrate_accountant_
|
||||
RTC_GUARDED_BY(bitrate_accountant_mutex_);
|
||||
};
|
||||
|
||||
const int kTelephoneEventAttenuationdB = 10;
|
||||
@ -800,10 +856,15 @@ void ChannelSend::ProcessAndEncodeAudio(
|
||||
// encoding is done and payload is ready for packetization and
|
||||
// transmission. Otherwise, it will return without invoking the
|
||||
// callback.
|
||||
if (audio_coding_->Add10MsData(*audio_frame) < 0) {
|
||||
int32_t encoded_bytes = audio_coding_->Add10MsData(*audio_frame);
|
||||
MutexLock lock(&bitrate_accountant_mutex_);
|
||||
if (encoded_bytes < 0) {
|
||||
RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed.";
|
||||
bitrate_accountant_.Reset();
|
||||
return;
|
||||
}
|
||||
bitrate_accountant_.UpdateBpsEstimate(DataSize::Bytes(encoded_bytes),
|
||||
TimeDelta::Millis(10));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -110,6 +110,12 @@ class ChannelSendInterface {
|
||||
virtual void SetEncoderToPacketizerFrameTransformer(
|
||||
rtc::scoped_refptr<webrtc::FrameTransformerInterface>
|
||||
frame_transformer) = 0;
|
||||
|
||||
// Returns payload bitrate actually used.
|
||||
virtual absl::optional<DataRate> GetUsedRate() const = 0;
|
||||
|
||||
// Registers per packet byte overhead.
|
||||
virtual void RegisterPacketOverhead(int packet_byte_overhead) = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<ChannelSendInterface> CreateChannelSend(
|
||||
|
||||
@ -306,6 +306,62 @@ TEST_F(ChannelSendTest, AudioLevelsAttachedToInsertedTransformedFrame) {
|
||||
EXPECT_TRUE_WAIT(sent_audio_level, 1000);
|
||||
EXPECT_EQ(*sent_audio_level, audio_level);
|
||||
}
|
||||
|
||||
// Ensure that GetUsedRate returns null if no frames are coded.
|
||||
TEST_F(ChannelSendTest, NoUsedRateInitially) {
|
||||
channel_->StartSend();
|
||||
auto used_rate = channel_->GetUsedRate();
|
||||
EXPECT_EQ(used_rate, absl::nullopt);
|
||||
}
|
||||
|
||||
// Ensure that GetUsedRate returns value with one coded frame.
|
||||
TEST_F(ChannelSendTest, ValidUsedRateWithOneCodedFrame) {
|
||||
channel_->StartSend();
|
||||
EXPECT_CALL(transport_, SendRtp).Times(1);
|
||||
ProcessNextFrame();
|
||||
ProcessNextFrame();
|
||||
auto used_rate = channel_->GetUsedRate();
|
||||
EXPECT_GT(used_rate.value().bps(), 0);
|
||||
}
|
||||
|
||||
// Ensure that GetUsedRate returns value with one coded frame.
|
||||
TEST_F(ChannelSendTest, UsedRateIsLargerofLastTwoFrames) {
|
||||
channel_->StartSend();
|
||||
channel_->CallEncoder(
|
||||
[&](AudioEncoder* encoder) { encoder->OnReceivedOverhead(72); });
|
||||
DataRate lowrate = DataRate::BitsPerSec(40000);
|
||||
DataRate highrate = DataRate::BitsPerSec(80000);
|
||||
BitrateAllocationUpdate update;
|
||||
update.bwe_period = TimeDelta::Millis(100);
|
||||
|
||||
update.target_bitrate = lowrate;
|
||||
channel_->OnBitrateAllocation(update);
|
||||
EXPECT_CALL(transport_, SendRtp).Times(1);
|
||||
ProcessNextFrame();
|
||||
ProcessNextFrame();
|
||||
// Last two frames have rates [32kbps, -], yielding 32kbps.
|
||||
auto used_rate_1 = channel_->GetUsedRate();
|
||||
|
||||
update.target_bitrate = highrate;
|
||||
channel_->OnBitrateAllocation(update);
|
||||
EXPECT_CALL(transport_, SendRtp).Times(1);
|
||||
ProcessNextFrame();
|
||||
ProcessNextFrame();
|
||||
// Last two frames have rates [54kbps, 32kbps], yielding 54kbps
|
||||
auto used_rate_2 = channel_->GetUsedRate();
|
||||
|
||||
update.target_bitrate = lowrate;
|
||||
channel_->OnBitrateAllocation(update);
|
||||
EXPECT_CALL(transport_, SendRtp).Times(1);
|
||||
ProcessNextFrame();
|
||||
ProcessNextFrame();
|
||||
// Last two frames have rates [32kbps 54kbps], yielding 54kbps
|
||||
auto used_rate_3 = channel_->GetUsedRate();
|
||||
|
||||
EXPECT_GT(used_rate_2, used_rate_1);
|
||||
EXPECT_EQ(used_rate_3, used_rate_2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace voe
|
||||
} // namespace webrtc
|
||||
|
||||
@ -182,6 +182,11 @@ class MockChannelSend : public voe::ChannelSendInterface {
|
||||
SetEncoderToPacketizerFrameTransformer,
|
||||
(rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer),
|
||||
(override));
|
||||
MOCK_METHOD(absl::optional<DataRate>, GetUsedRate, (), (const, override));
|
||||
MOCK_METHOD(void,
|
||||
RegisterPacketOverhead,
|
||||
(int packet_byte_overhead),
|
||||
(override));
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user