From 573e746914f14e069d8a2dca96ed32640e5796f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=85hgren?= Date: Mon, 9 Feb 2026 14:17:39 +0100 Subject: [PATCH 001/472] Correct the switching between the coarse and refined filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL corrects the switching between the coarse and refined filters to be done smoothly for all channels, and to be decided based on the _ content of all channels. Bug: chromium:464314991 Change-Id: I5eb90848fbe135ec2c2ef9a5339920c6b7f56bbf Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/447060 Reviewed-by: Sam Zackrisson Commit-Queue: Per Åhgren Cr-Commit-Position: refs/heads/main@{#46854} --- modules/audio_processing/aec3/echo_remover.cc | 95 +++++++++++-------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 1f0773780f..c720982193 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -108,6 +108,45 @@ void WindowedPaddedFft(const Aec3Fft& fft, std::copy(v.begin(), v.end(), v_old.begin()); } +// Detects whether the output of the refined filter is more appropriate to use +// than the output of the coarse filter, returning the result as a bool. +bool UseRefinedOutput(const SubtractorOutput& subtractor_output) { + // As the output of the refined adaptive filter generally should be better + // than the coarse filter output, add a margin and threshold for when + // choosing the coarse filter output. + if (subtractor_output.e2_coarse < 0.9f * subtractor_output.e2_refined && + subtractor_output.y2 > 30.f * 30.f * kBlockSize && + (subtractor_output.s2_refined > 60.f * 60.f * kBlockSize || + subtractor_output.s2_coarse > 60.f * 60.f * kBlockSize)) { + return false; + } + + // If the refined filter is diverged, choose the filter output that has + // the lowest power. + if (subtractor_output.e2_coarse < subtractor_output.e2_refined && + subtractor_output.y2 < subtractor_output.e2_refined) { + return false; + } + return true; +} + +// Forms the linear filter output by smoothly transition between the refined and +// coarse filter outputs according to which of the filters is to be used. +void FormLinearFilterOutput(bool refined_filter_output_last_selected, + bool use_refined_output, + const SubtractorOutput& subtractor_output, + ArrayView output) { + RTC_DCHECK_EQ(subtractor_output.e_refined.size(), output.size()); + RTC_DCHECK_EQ(subtractor_output.e_coarse.size(), output.size()); + + SignalTransition(refined_filter_output_last_selected + ? subtractor_output.e_refined + : subtractor_output.e_coarse, + use_refined_output ? subtractor_output.e_refined + : subtractor_output.e_coarse, + output); +} + // Class for removing the echo from the capture signal. class EchoRemoverImpl final : public EchoRemover { public: @@ -144,12 +183,6 @@ class EchoRemoverImpl final : public EchoRemover { } private: - // Selects which of the coarse and refined linear filter outputs that is most - // appropriate to pass to the suppressor and forms the linear filter output by - // smoothly transition between those. - void FormLinearFilterOutput(const SubtractorOutput& subtractor_output, - ArrayView output); - static std::atomic instance_count_; const EchoCanceller3Config config_; const Aec3Fft fft_; @@ -385,14 +418,28 @@ void EchoRemoverImpl::ProcessCapture( subtractor_output); // Compute spectra. + bool use_refined_output; + if (use_coarse_filter_output_) { + use_refined_output = false; + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + if (UseRefinedOutput(subtractor_output[ch])) { + use_refined_output = true; + break; + } + } + } else { + use_refined_output = true; + } for (size_t ch = 0; ch < num_capture_channels_; ++ch) { - FormLinearFilterOutput(subtractor_output[ch], e[ch]); + FormLinearFilterOutput(refined_filter_output_last_selected_, + use_refined_output, subtractor_output[ch], e[ch]); WindowedPaddedFft(fft_, y->View(/*band=*/0, ch), y_old_[ch], &Y[ch]); WindowedPaddedFft(fft_, e[ch], e_old_[ch], &E[ch]); LinearEchoPower(E[ch], Y[ch], &S2_linear[ch]); Y[ch].Spectrum(optimization_, Y2[ch]); E[ch].Spectrum(optimization_, E2[ch]); } + refined_filter_output_last_selected_ = use_refined_output; const auto& nearend_spectrum = aec_state_.UsableLinearEstimate() ? E2 : Y2; // `y_old_` and `e_old_` now point to the current block. Though their channel // layout is already suitable for residual echo estimation, an alias is @@ -494,40 +541,6 @@ void EchoRemoverImpl::ProcessCapture( aec_state_.SaturatedCapture() ? 1 : 0); } -void EchoRemoverImpl::FormLinearFilterOutput( - const SubtractorOutput& subtractor_output, - ArrayView output) { - RTC_DCHECK_EQ(subtractor_output.e_refined.size(), output.size()); - RTC_DCHECK_EQ(subtractor_output.e_coarse.size(), output.size()); - bool use_refined_output = true; - if (use_coarse_filter_output_) { - // As the output of the refined adaptive filter generally should be better - // than the coarse filter output, add a margin and threshold for when - // choosing the coarse filter output. - if (subtractor_output.e2_coarse < 0.9f * subtractor_output.e2_refined && - subtractor_output.y2 > 30.f * 30.f * kBlockSize && - (subtractor_output.s2_refined > 60.f * 60.f * kBlockSize || - subtractor_output.s2_coarse > 60.f * 60.f * kBlockSize)) { - use_refined_output = false; - } else { - // If the refined filter is diverged, choose the filter output that has - // the lowest power. - if (subtractor_output.e2_coarse < subtractor_output.e2_refined && - subtractor_output.y2 < subtractor_output.e2_refined) { - use_refined_output = false; - } - } - } - - SignalTransition(refined_filter_output_last_selected_ - ? subtractor_output.e_refined - : subtractor_output.e_coarse, - use_refined_output ? subtractor_output.e_refined - : subtractor_output.e_coarse, - output); - refined_filter_output_last_selected_ = use_refined_output; -} - } // namespace std::unique_ptr EchoRemover::Create( From ffe79876ecad93bdf0c14d69ef9e7bd087a8fc09 Mon Sep 17 00:00:00 2001 From: webrtc-version-updater Date: Mon, 9 Feb 2026 20:08:39 -0800 Subject: [PATCH 002/472] Update WebRTC code version (2026-02-10T04:08:07). Bug: None Change-Id: I202f8ab3448cea9478227b187446ec670382d2b6 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/447940 Commit-Queue: webrtc-version-updater@webrtc-ci.iam.gserviceaccount.com Bot-Commit: webrtc-version-updater@webrtc-ci.iam.gserviceaccount.com Cr-Commit-Position: refs/heads/main@{#46855} --- call/version.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/call/version.cc b/call/version.cc index 0776b93707..2d297f3f41 100644 --- a/call/version.cc +++ b/call/version.cc @@ -13,7 +13,7 @@ namespace webrtc { // The timestamp is always in UTC. -const char* const kSourceTimestamp = "WebRTC source stamp 2026-02-09T04:06:40"; +const char* const kSourceTimestamp = "WebRTC source stamp 2026-02-10T04:08:07"; void LoadWebRTCVersionInRegister() { // Using volatile to instruct the compiler to not optimize `p` away even From 7c388cbabb1ba422c626addc37e40765de200169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=85hgren?= Date: Tue, 10 Feb 2026 10:33:22 +0100 Subject: [PATCH 003/472] Changing default values of multi channel processing to be true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL changes the default values of multi channel processing to be true. The CL will be followed by another CL that removes these parameters once their use in Chromium has been removed. The reason for their removal is that their initial purpose, which was allowing a fallback to single-channel processing until the multi-channel processing functionality was verified is no longer needed. The CL also includes an update of the unittests where the tests was including an expectation on a code-independent test threshold value. That change is needed as the threshold took effect as part of this code-change. A follow-up CL will be made to refactor that test. Bug: chromium:464314991 Change-Id: Ie4141cd5b13c6b748f1ff1552b526c15155ac279 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/429343 Reviewed-by: Sam Zackrisson Commit-Queue: Per Åhgren Cr-Commit-Position: refs/heads/main@{#46856} --- api/audio/audio_processing.h | 6 +++--- resources/audio_processing/output_data_float.pb.sha1 | 2 +- resources/audio_processing/output_data_float_avx2.pb.sha1 | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/audio/audio_processing.h b/api/audio/audio_processing.h index a83078ae9b..1e0ea0beee 100644 --- a/api/audio/audio_processing.h +++ b/api/audio/audio_processing.h @@ -147,10 +147,10 @@ class RTC_EXPORT AudioProcessing : public RefCountInterface { // 32000 or 48000 and any differing values will be treated as 48000. int maximum_internal_processing_rate = 32000; // Allow multi-channel processing of render audio. - bool multi_channel_render = false; + bool multi_channel_render = true; // Allow multi-channel processing of capture audio when AEC3 is active - // or a custom AEC is injected.. - bool multi_channel_capture = false; + // or a custom AEC is injected. + bool multi_channel_capture = true; // Indicates how to downmix multi-channel capture audio to mono (when // needed). DownmixMethod capture_downmix_method = DownmixMethod::kAverageChannels; diff --git a/resources/audio_processing/output_data_float.pb.sha1 b/resources/audio_processing/output_data_float.pb.sha1 index 7dd76325f3..7035368d68 100644 --- a/resources/audio_processing/output_data_float.pb.sha1 +++ b/resources/audio_processing/output_data_float.pb.sha1 @@ -1 +1 @@ -d80019464496fec3a149fd36809769e84a9ea5ce \ No newline at end of file +c5f9b0b9c75f89e34e8f58cfb6e37e8a46271072 \ No newline at end of file diff --git a/resources/audio_processing/output_data_float_avx2.pb.sha1 b/resources/audio_processing/output_data_float_avx2.pb.sha1 index ddca9839e7..6859932988 100644 --- a/resources/audio_processing/output_data_float_avx2.pb.sha1 +++ b/resources/audio_processing/output_data_float_avx2.pb.sha1 @@ -1 +1 @@ -8751057d01ad4d58c98781cd7236a65ece699706 \ No newline at end of file +1623a92acd619a7ad2e599d7859463227179c1d4 \ No newline at end of file From d01ecdaa05f48ed6095ed80d07142c7c76303055 Mon Sep 17 00:00:00 2001 From: Danil Chapovalov Date: Mon, 9 Feb 2026 15:59:55 +0100 Subject: [PATCH 004/472] Replace ArrayView::subview with subspan in logging/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix ExtendLoggedBatch function to produce expected resolut when `!output.empty()`. In particular avoid calling subspan function and discard result as that would be a compilation error with std::span. Bug: webrtc:439801349 Change-Id: I4a8e372417c974c796ec4eb5e1d406b13b59fa4b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/447061 Reviewed-by: Björn Terelius Commit-Queue: Danil Chapovalov Cr-Commit-Position: refs/heads/main@{#46857} --- .../rtc_event_log/dependency_descriptor_encoder_decoder.cc | 4 ++-- logging/rtc_event_log/events/rtc_event_field_encoding.cc | 2 +- .../rtc_event_log/events/rtc_event_field_encoding_parser.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/logging/rtc_event_log/dependency_descriptor_encoder_decoder.cc b/logging/rtc_event_log/dependency_descriptor_encoder_decoder.cc index eaa75331c8..ca947ddfb0 100644 --- a/logging/rtc_event_log/dependency_descriptor_encoder_decoder.cc +++ b/logging/rtc_event_log/dependency_descriptor_encoder_decoder.cc @@ -45,7 +45,7 @@ RtcEventLogDependencyDescriptorEncoderDecoder::Encode( rtclog2::DependencyDescriptorsWireInfo res; const ArrayView& base_dd = raw_dd_data[0]; auto delta_dds = - MakeArrayView(raw_dd_data.data(), raw_dd_data.size()).subview(1); + MakeArrayView(raw_dd_data.data(), raw_dd_data.size()).subspan(1); // Start and end bit. { @@ -117,7 +117,7 @@ RtcEventLogDependencyDescriptorEncoderDecoder::Encode( std::vector> values(raw_dd_data.size()); for (size_t i = 0; i < raw_dd_data.size(); ++i) { if (raw_dd_data[i].size() > 3) { - auto extended_info = raw_dd_data[i].subview(3); + auto extended_info = raw_dd_data[i].subspan(3); values[i] = {reinterpret_cast(extended_info.data()), extended_info.size()}; } diff --git a/logging/rtc_event_log/events/rtc_event_field_encoding.cc b/logging/rtc_event_log/events/rtc_event_field_encoding.cc index e5b931d7e1..e43526a411 100644 --- a/logging/rtc_event_log/events/rtc_event_field_encoding.cc +++ b/logging/rtc_event_log/events/rtc_event_field_encoding.cc @@ -214,7 +214,7 @@ void EventEncoder::EncodeField(const FieldParameters& params, // Compute delta parameters ArrayView all_values(values); uint64_t base = values[0]; - ArrayView remaining_values(all_values.subview(1)); + ArrayView remaining_values = all_values.subspan(1); FixedLengthEncodingParametersV3 delta_params = FixedLengthEncodingParametersV3::CalculateParameters( diff --git a/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h b/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h index d46c6ac5ac..2de51895a3 100644 --- a/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h +++ b/logging/rtc_event_log/events/rtc_event_field_encoding_parser.h @@ -212,9 +212,9 @@ PopulateRtcEventTimestamp(const ArrayView& values, template ArrayView ExtendLoggedBatch(std::vector& output, size_t new_elements) { size_t old_size = output.size(); - output.insert(output.end(), old_size + new_elements, E()); + output.resize(old_size + new_elements); ArrayView output_batch = output; - output_batch.subview(old_size); + output_batch = output_batch.subspan(old_size); RTC_DCHECK_EQ(output_batch.size(), new_elements); return output_batch; } From a27d608d4b063553c4c7fe9e1a7a8810a6855d6c Mon Sep 17 00:00:00 2001 From: Harald Alvestrand Date: Tue, 10 Feb 2026 08:30:02 +0000 Subject: [PATCH 005/472] Spanify rtc_base/buffer This makes it possible to compile rtc_base/buffer with the checks for unsafe buffers. Bug: webrtc:478086887 Change-Id: I53f1161164e0408f985bd8395a0fd516e47bb0cd Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/444780 Commit-Queue: Danil Chapovalov Commit-Queue: Harald Alvestrand Reviewed-by: Danil Chapovalov Auto-Submit: Harald Alvestrand Cr-Commit-Position: refs/heads/main@{#46858} --- .../source/rtp_format_vp8_test_helper.cc | 15 +- rtc_base/BUILD.gn | 1 + rtc_base/buffer.h | 40 ++++-- rtc_base/buffer_unittest.cc | 135 +++++++++--------- 4 files changed, 105 insertions(+), 86 deletions(-) diff --git a/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc index ef54c0abe4..30cc3b7c7a 100644 --- a/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc +++ b/modules/rtp_rtcp/source/rtp_format_vp8_test_helper.cc @@ -12,6 +12,7 @@ #include #include +#include #include "api/array_view.h" #include "modules/rtp_rtcp/source/rtp_format_vp8.h" @@ -70,7 +71,7 @@ void RtpFormatVp8TestHelper::GetAllPacketsAndCheck( RtpPacketizerVp8* packetizer, ArrayView expected_sizes) { EXPECT_EQ(packetizer->NumPackets(), expected_sizes.size()); - const uint8_t* data_ptr = payload_.begin(); + Buffer::const_iterator data_it = payload_.begin(); RtpPacketToSend packet(kNoExtensions); for (size_t i = 0; i < expected_sizes.size(); ++i) { EXPECT_TRUE(packetizer->NextPacket(&packet)); @@ -79,13 +80,15 @@ void RtpFormatVp8TestHelper::GetAllPacketsAndCheck( int payload_offset = CheckHeader(rtp_payload, /*first=*/i == 0); // Verify that the payload (i.e., after the headers) of the packet is - // identical to the expected (as found in data_ptr). + // identical to the expected (as found in data_it). auto vp8_payload = rtp_payload.subspan(payload_offset); - ASSERT_GE(payload_.end() - data_ptr, static_cast(vp8_payload.size())); - EXPECT_THAT(vp8_payload, ElementsAreArray(data_ptr, vp8_payload.size())); - data_ptr += vp8_payload.size(); + ASSERT_GE(std::distance(data_it, payload_.cend()), + static_cast(vp8_payload.size())); + EXPECT_THAT(vp8_payload, + ElementsAreArray(data_it, data_it + vp8_payload.size())); + data_it += vp8_payload.size(); } - EXPECT_EQ(payload_.end() - data_ptr, 0); + EXPECT_EQ(payload_.end(), data_it); } int RtpFormatVp8TestHelper::CheckHeader(ArrayView buffer, diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index 309bc31fe7..3a253296b2 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -81,6 +81,7 @@ rtc_source_set("buffer") { ":type_traits", ":zero_memory", "../api:array_view", + "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/strings:string_view", ] diff --git a/rtc_base/buffer.h b/rtc_base/buffer.h index 5d9d8caabd..322cf2536a 100644 --- a/rtc_base/buffer.h +++ b/rtc_base/buffer.h @@ -16,9 +16,11 @@ #include #include #include +#include #include #include +#include "absl/algorithm/container.h" #include "absl/base/attributes.h" #include "absl/strings/string_view.h" #include "api/array_view.h" @@ -66,7 +68,8 @@ class BufferT { public: using value_type = T; - using const_iterator = const T*; + using iterator = std::span::iterator; + using const_iterator = std::span::iterator; // An empty BufferT. BufferT() : size_(0), capacity_(0), data_(nullptr) { @@ -121,6 +124,12 @@ class BufferT { internal::BufferCompat::value>::type* = nullptr> BufferT(U (&array)[N]) : BufferT(array, N) {} + // Construct a buffer from any type with a data() and size() member. + template ::value>::type* = nullptr> + explicit BufferT(const W& w) : BufferT(w.data(), w.size()) {} + ~BufferT() { MaybeZeroCompleteBuffer(); } // Implicit conversion to absl::string_view if T is compatible with char. @@ -205,20 +214,20 @@ class BufferT { T& operator[](size_t index) { RTC_DCHECK_LT(index, size_); - return data()[index]; + return ArrayView(*this)[index]; } T operator[](size_t index) const { RTC_DCHECK_LT(index, size_); - return data()[index]; + return ArrayView(*this)[index]; } - T* begin() { return data(); } - T* end() { return data() + size(); } - const T* begin() const { return data(); } - const T* end() const { return data() + size(); } - const T* cbegin() const { return data(); } - const T* cend() const { return data() + size(); } + iterator begin() { return std::span(*this).begin(); } + iterator end() { return std::span(*this).end(); } + const_iterator begin() const { return std::span(*this).begin(); } + const_iterator end() const { return std::span(*this).end(); } + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } // The SetData functions replace the contents of the buffer. They accept the // same input types as the constructors. @@ -288,7 +297,10 @@ class BufferT { const size_t new_size = size_ + size; EnsureCapacityWithHeadroom(new_size, true); static_assert(sizeof(T) == sizeof(U), ""); - std::memcpy(data_.get() + size_, data, size * sizeof(U)); + ArrayView source(data, size); + ArrayView destination = + ArrayView(data_.get(), capacity_).subview(size_, size); + absl::c_copy(source, destination.begin()); size_ = new_size; RTC_DCHECK(IsConsistent()); } @@ -332,8 +344,8 @@ class BufferT { RTC_DCHECK(IsConsistent()); const size_t old_size = size_; SetSize(old_size + max_elements); - U* base_ptr = data() + old_size; - size_t written_elements = setter(ArrayView(base_ptr, max_elements)); + size_t written_elements = + setter(ArrayView(data(), size()).subspan(old_size)); RTC_CHECK_LE(written_elements, max_elements); size_ = old_size + written_elements; @@ -410,7 +422,7 @@ class BufferT { // It would be sufficient to only zero "size_" elements, as all other // methods already ensure that the unused capacity contains no sensitive // data---but better safe than sorry. - ExplicitZeroMemory(data_.get(), capacity_ * sizeof(T)); + ExplicitZeroMemory(ArrayView(data_.get(), capacity_)); } } @@ -418,7 +430,7 @@ class BufferT { void ZeroTrailingData(size_t count) { RTC_DCHECK(IsConsistent()); RTC_DCHECK_LE(count, capacity_ - size_); - ExplicitZeroMemory(data_.get() + size_, count * sizeof(T)); + ExplicitZeroMemory(MakeArrayView(data(), capacity_).subview(size_)); } // Precondition for all methods except Clear, operator= and the destructor. diff --git a/rtc_base/buffer_unittest.cc b/rtc_base/buffer_unittest.cc index 88ebd0dd6a..064320f96d 100644 --- a/rtc_base/buffer_unittest.cc +++ b/rtc_base/buffer_unittest.cc @@ -10,6 +10,7 @@ #include "rtc_base/buffer.h" +#include #include #include #include @@ -25,11 +26,18 @@ namespace webrtc { namespace { +using ::testing::Each; using ::testing::ElementsAre; using ::testing::ElementsAreArray; +using ::testing::Eq; -constexpr uint8_t kTestData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, - 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; +auto kTestData = + std::to_array({0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}); + +uint8_t* TestDataAtIndex(int index) { + return ArrayView(kTestData).subview(index).data(); +} void TestBuf(const Buffer& b1, size_t size, size_t capacity) { EXPECT_EQ(b1.size(), size); @@ -47,24 +55,24 @@ TEST(BufferTest, TestConstructEmpty) { // that to be considered a null pointer, which makes the call ambiguous. TestBuf(Buffer(0 + 0, 10), 0, 10); - TestBuf(Buffer(kTestData, 0), 0, 0); - TestBuf(Buffer(kTestData, 0, 20), 0, 20); + TestBuf(Buffer(kTestData.data(), 0), 0, 0); + TestBuf(Buffer(kTestData.data(), 0, 20), 0, 20); } TEST(BufferTest, TestConstructData) { - Buffer buf(kTestData, 7); + Buffer buf(kTestData.data(), 7); EXPECT_EQ(buf.size(), 7u); EXPECT_EQ(buf.capacity(), 7u); EXPECT_FALSE(buf.empty()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 7)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 7)); } TEST(BufferTest, TestConstructDataWithCapacity) { - Buffer buf(kTestData, 7, 14); + Buffer buf(kTestData.data(), 7, 14); EXPECT_EQ(buf.size(), 7u); EXPECT_EQ(buf.capacity(), 14u); EXPECT_FALSE(buf.empty()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 7)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 7)); } TEST(BufferTest, TestConstructArray) { @@ -72,33 +80,33 @@ TEST(BufferTest, TestConstructArray) { EXPECT_EQ(buf.size(), 16u); EXPECT_EQ(buf.capacity(), 16u); EXPECT_FALSE(buf.empty()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 16)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 16)); } TEST(BufferTest, TestStringViewConversion) { Buffer buf(kTestData); absl::string_view view = buf; - EXPECT_EQ(view, - absl::string_view(reinterpret_cast(kTestData), 16u)); + EXPECT_EQ(view, absl::string_view( + reinterpret_cast(kTestData.data()), 16u)); } TEST(BufferTest, TestSetData) { - Buffer buf(kTestData + 4, 7); - buf.SetData(kTestData, 9); + Buffer buf(TestDataAtIndex(4), 7); + buf.SetData(kTestData.data(), 9); EXPECT_EQ(buf.size(), 9u); EXPECT_EQ(buf.capacity(), 7u * 3 / 2); EXPECT_FALSE(buf.empty()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 9)); Buffer buf2; buf2.SetData(buf); EXPECT_EQ(buf.size(), 9u); EXPECT_EQ(buf.capacity(), 7u * 3 / 2); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 9)); } TEST(BufferTest, TestAppendData) { - Buffer buf(kTestData + 4, 3); - buf.AppendData(kTestData + 10, 2); + Buffer buf(TestDataAtIndex(4), 3); + buf.AppendData(TestDataAtIndex(10), 2); const int8_t exp[] = {0x4, 0x5, 0x6, 0xa, 0xb}; EXPECT_EQ(buf, Buffer(exp)); Buffer buf2; @@ -111,33 +119,34 @@ TEST(BufferTest, TestAppendData) { TEST(BufferTest, TestSetAndAppendWithUnknownArg) { struct TestDataContainer { size_t size() const { return 3; } - const uint8_t* data() const { return kTestData; } + const uint8_t* data() const { return kTestData.data(); } }; Buffer buf; buf.SetData(TestDataContainer()); EXPECT_EQ(3u, buf.size()); - EXPECT_EQ(Buffer(kTestData, 3), buf); + EXPECT_EQ(Buffer(kTestData.data(), 3), buf); EXPECT_THAT(buf, ElementsAre(0, 1, 2)); buf.AppendData(TestDataContainer()); EXPECT_EQ(6u, buf.size()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 3)); - EXPECT_EQ(0, memcmp(buf.data() + 3, kTestData, 3)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 3)); + EXPECT_EQ(0, memcmp(ArrayView(buf).subview(3).data(), + kTestData.data(), 3)); EXPECT_THAT(buf, ElementsAre(0, 1, 2, 0, 1, 2)); } TEST(BufferTest, TestSetSizeSmaller) { Buffer buf; - buf.SetData(kTestData, 15); + buf.SetData(kTestData.data(), 15); buf.SetSize(10); EXPECT_EQ(buf.size(), 10u); EXPECT_EQ(buf.capacity(), 15u); // Hasn't shrunk. EXPECT_FALSE(buf.empty()); - EXPECT_EQ(buf, Buffer(kTestData, 10)); + EXPECT_EQ(buf, Buffer(kTestData.data(), 10)); } TEST(BufferTest, TestSetSizeLarger) { Buffer buf; - buf.SetData(kTestData, 15); + buf.SetData(kTestData.data(), 15); EXPECT_EQ(buf.size(), 15u); EXPECT_EQ(buf.capacity(), 15u); EXPECT_FALSE(buf.empty()); @@ -145,7 +154,7 @@ TEST(BufferTest, TestSetSizeLarger) { EXPECT_EQ(buf.size(), 20u); EXPECT_EQ(buf.capacity(), 15u * 3 / 2); // Has grown. EXPECT_FALSE(buf.empty()); - EXPECT_EQ(0, memcmp(buf.data(), kTestData, 15)); + EXPECT_EQ(0, memcmp(buf.data(), kTestData.data(), 15)); } TEST(BufferTest, TestEnsureCapacitySmaller) { @@ -159,18 +168,18 @@ TEST(BufferTest, TestEnsureCapacitySmaller) { } TEST(BufferTest, TestEnsureCapacityLarger) { - Buffer buf(kTestData, 5); + Buffer buf(kTestData.data(), 5); buf.EnsureCapacity(10); const int8_t* data = buf.data(); EXPECT_EQ(buf.capacity(), 10u); - buf.AppendData(kTestData + 5, 5); + buf.AppendData(TestDataAtIndex(5), 5); EXPECT_EQ(buf.data(), data); // No reallocation. EXPECT_FALSE(buf.empty()); - EXPECT_EQ(buf, Buffer(kTestData, 10)); + EXPECT_EQ(buf, Buffer(kTestData.data(), 10)); } TEST(BufferTest, TestMoveConstruct) { - Buffer buf1(kTestData, 3, 40); + Buffer buf1(kTestData.data(), 3, 40); const uint8_t* data = buf1.data(); Buffer buf2(std::move(buf1)); EXPECT_EQ(buf2.size(), 3u); @@ -185,7 +194,7 @@ TEST(BufferTest, TestMoveConstruct) { } TEST(BufferTest, TestMoveAssign) { - Buffer buf1(kTestData, 3, 40); + Buffer buf1(kTestData.data(), 3, 40); const uint8_t* data = buf1.data(); Buffer buf2(kTestData); buf2 = std::move(buf1); @@ -206,14 +215,14 @@ TEST(BufferTest, TestMoveAssignSelf) { // state could be caught by the DCHECKs and/or by the leak checker.) We need // to be sneaky when testing this; if we're doing a too-obvious // move-assign-to-self, clang's -Wself-move triggers at compile time. - Buffer buf(kTestData, 3, 40); + Buffer buf(kTestData.data(), 3, 40); Buffer* buf_ptr = &buf; buf = std::move(*buf_ptr); } TEST(BufferTest, TestSwap) { - Buffer buf1(kTestData, 3); - Buffer buf2(kTestData, 6, 40); + Buffer buf1(kTestData.data(), 3); + Buffer buf2(kTestData.data(), 6, 40); uint8_t* data1 = buf1.data(); uint8_t* data2 = buf2.data(); using std::swap; @@ -230,7 +239,7 @@ TEST(BufferTest, TestSwap) { TEST(BufferTest, TestClear) { Buffer buf; - buf.SetData(kTestData, 15); + buf.SetData(kTestData.data(), 15); EXPECT_EQ(buf.size(), 15u); EXPECT_EQ(buf.capacity(), 15u); EXPECT_FALSE(buf.empty()); @@ -250,8 +259,8 @@ TEST(BufferTest, TestLambdaSetAppend) { }; Buffer buf1; - buf1.SetData(kTestData, 15); - buf1.AppendData(kTestData, 15); + buf1.SetData(kTestData.data(), 15); + buf1.AppendData(kTestData.data(), 15); Buffer buf2; EXPECT_EQ(buf2.SetData(15, setter), 15u); @@ -270,8 +279,8 @@ TEST(BufferTest, TestLambdaSetAppendSigned) { }; Buffer buf1; - buf1.SetData(kTestData, 15); - buf1.AppendData(kTestData, 15); + buf1.SetData(kTestData.data(), 15); + buf1.AppendData(kTestData.data(), 15); Buffer buf2; EXPECT_EQ(buf2.SetData(15, setter), 15u); @@ -290,7 +299,7 @@ TEST(BufferTest, TestLambdaAppendEmpty) { }; Buffer buf1; - buf1.SetData(kTestData, 15); + buf1.SetData(kTestData.data(), 15); Buffer buf2; EXPECT_EQ(buf2.AppendData(15, setter), 15u); @@ -336,12 +345,12 @@ TEST(BufferTest, TestMutableLambdaSetAppend) { EXPECT_FALSE(buf.empty()); for (uint8_t i = 0; i != buf.size(); ++i) { - EXPECT_EQ(buf.data()[i], magic_number + i); + EXPECT_EQ(buf[i], magic_number + i); } } TEST(BufferTest, TestBracketRead) { - Buffer buf(kTestData, 7); + Buffer buf(kTestData.data(), 7); EXPECT_EQ(buf.size(), 7u); EXPECT_EQ(buf.capacity(), 7u); EXPECT_NE(buf.data(), nullptr); @@ -353,7 +362,7 @@ TEST(BufferTest, TestBracketRead) { } TEST(BufferTest, TestBracketReadConst) { - Buffer buf(kTestData, 7); + Buffer buf(kTestData.data(), 7); EXPECT_EQ(buf.size(), 7u); EXPECT_EQ(buf.capacity(), 7u); EXPECT_NE(buf.data(), nullptr); @@ -377,20 +386,21 @@ TEST(BufferTest, TestBracketWrite) { buf[i] = kTestData[i]; } - EXPECT_THAT(buf, ElementsAreArray(kTestData, 7)); + EXPECT_THAT(buf, ElementsAreArray(kTestData.data(), 7)); } TEST(BufferTest, TestBeginEnd) { const Buffer cbuf(kTestData); Buffer buf(kTestData); - auto* b1 = cbuf.begin(); + auto b1 = cbuf.begin(); for (auto& x : buf) { EXPECT_EQ(*b1, x); + ASSERT_NE(b1, cbuf.end()); ++b1; ++x; } EXPECT_EQ(cbuf.end(), b1); - auto* b2 = buf.begin(); + auto b2 = buf.begin(); for (auto& y : cbuf) { EXPECT_EQ(*b2, y + 1); ++b2; @@ -471,12 +481,13 @@ TEST(BufferDeathTest, DieOnUseAfterMove) { } TEST(ZeroOnFreeBufferTest, TestZeroOnSetData) { - ZeroOnFreeBuffer buf(kTestData, 7); + ZeroOnFreeBuffer buf(kTestData.data(), 7); const uint8_t* old_data = buf.data(); const size_t old_capacity = buf.capacity(); - const size_t old_size = buf.size(); constexpr size_t offset = 1; - buf.SetData(kTestData + offset, 2); + // Pointer to the last five bytes of the underlying buffer. + auto to_be_zeroed = ArrayView(buf).subspan(2); + buf.SetData(TestDataAtIndex(offset), 2); // Sanity checks to make sure the underlying heap memory was not reallocated. EXPECT_EQ(old_data, buf.data()); EXPECT_EQ(old_capacity, buf.capacity()); @@ -484,9 +495,7 @@ TEST(ZeroOnFreeBufferTest, TestZeroOnSetData) { // been zeroed. EXPECT_EQ(kTestData[offset], buf[0]); EXPECT_EQ(kTestData[offset + 1], buf[1]); - for (size_t i = 2; i < old_size; i++) { - EXPECT_EQ(0, old_data[i]); - } + EXPECT_THAT(to_be_zeroed, Each(Eq(0))); } TEST(ZeroOnFreeBufferTest, TestZeroOnSetDataFromSetter) { @@ -497,10 +506,10 @@ TEST(ZeroOnFreeBufferTest, TestZeroOnSetDataFromSetter) { return 2; }; - ZeroOnFreeBuffer buf(kTestData, 7); + ZeroOnFreeBuffer buf(kTestData.data(), 7); const uint8_t* old_data = buf.data(); + auto to_be_zeroed = ArrayView(buf).subspan(2); const size_t old_capacity = buf.capacity(); - const size_t old_size = buf.size(); buf.SetData(2, setter); // Sanity checks to make sure the underlying heap memory was not reallocated. EXPECT_EQ(old_data, buf.data()); @@ -509,16 +518,14 @@ TEST(ZeroOnFreeBufferTest, TestZeroOnSetDataFromSetter) { // been zeroed. EXPECT_EQ(kTestData[offset], buf[0]); EXPECT_EQ(kTestData[offset + 1], buf[1]); - for (size_t i = 2; i < old_size; i++) { - EXPECT_EQ(0, old_data[i]); - } + EXPECT_THAT(to_be_zeroed, Each(Eq(0))); } TEST(ZeroOnFreeBufferTest, TestZeroOnSetSize) { - ZeroOnFreeBuffer buf(kTestData, 7); + ZeroOnFreeBuffer buf(kTestData.data(), 7); + auto to_be_zeroed = ArrayView(buf).subspan(2); const uint8_t* old_data = buf.data(); const size_t old_capacity = buf.capacity(); - const size_t old_size = buf.size(); buf.SetSize(2); // Sanity checks to make sure the underlying heap memory was not reallocated. EXPECT_EQ(old_data, buf.data()); @@ -527,24 +534,20 @@ TEST(ZeroOnFreeBufferTest, TestZeroOnSetSize) { // been zeroed. EXPECT_EQ(kTestData[0], buf[0]); EXPECT_EQ(kTestData[1], buf[1]); - for (size_t i = 2; i < old_size; i++) { - EXPECT_EQ(0, old_data[i]); - } + EXPECT_THAT(to_be_zeroed, Each(Eq(0))); } TEST(ZeroOnFreeBufferTest, TestZeroOnClear) { - ZeroOnFreeBuffer buf(kTestData, 7); + ZeroOnFreeBuffer buf(kTestData.data(), 7); + auto to_be_zeroed = ArrayView(buf); const uint8_t* old_data = buf.data(); const size_t old_capacity = buf.capacity(); - const size_t old_size = buf.size(); buf.Clear(); // Sanity checks to make sure the underlying heap memory was not reallocated. EXPECT_EQ(old_data, buf.data()); EXPECT_EQ(old_capacity, buf.capacity()); // The underlying memory was not released but cleared. - for (size_t i = 0; i < old_size; i++) { - EXPECT_EQ(0, old_data[i]); - } + EXPECT_THAT(to_be_zeroed, Each(Eq(0))); } } // namespace webrtc From dc0041e35ea3253f4606377511e4760a151901e5 Mon Sep 17 00:00:00 2001 From: AhmadDurrani579 Date: Fri, 6 Feb 2026 18:19:09 +0000 Subject: [PATCH 006/472] Add RTC_CHECK to fwrite calls in video_file_writer The compiler option `warn_unused_result` causes build failures if the return value of `fwrite` is ignored. Currently, `video_file_writer.cc` ignores these return values, which is also unsafe if the disk is full. This CL wraps `fwrite` calls in `RTC_CHECK_EQ` to ensure the correct number of bytes are written, crashing safely if the write fails. Bug: None Test: Compiled locally. Change-Id: I6cb62b673af2d3cefc6afdb9064d86bd9f080cd3 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/447020 Reviewed-by: Tomas Gunnarsson Commit-Queue: Mirko Bonadei Reviewed-by: Mirko Bonadei Cr-Commit-Position: refs/heads/main@{#46859} --- rtc_tools/video_file_writer.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rtc_tools/video_file_writer.cc b/rtc_tools/video_file_writer.cc index 2a1bc67cc6..abfeb90b6b 100644 --- a/rtc_tools/video_file_writer.cc +++ b/rtc_tools/video_file_writer.cc @@ -15,6 +15,7 @@ #include #include "absl/strings/match.h" +#include "absl/strings/string_view.h" #include "api/scoped_refptr.h" #include "api/video/video_frame_buffer.h" #include "rtc_base/checks.h" @@ -42,8 +43,9 @@ void WriteVideoToFile(const scoped_refptr