diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/audio/channel_receive_unittest.cc | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/audio/channel_receive_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/audio/channel_receive_unittest.cc | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/third_party/libwebrtc/audio/channel_receive_unittest.cc b/third_party/libwebrtc/audio/channel_receive_unittest.cc new file mode 100644 index 0000000000..4b7b7c0231 --- /dev/null +++ b/third_party/libwebrtc/audio/channel_receive_unittest.cc @@ -0,0 +1,231 @@ +/* + * Copyright 2023 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "audio/channel_receive.h" + +#include "absl/strings/escaping.h" +#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "api/crypto/frame_decryptor_interface.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "logging/rtc_event_log/mock/mock_rtc_event_log.h" +#include "modules/audio_device/include/audio_device.h" +#include "modules/audio_device/include/mock_audio_device.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" +#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h" +#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/time_util.h" +#include "rtc_base/logging.h" +#include "rtc_base/thread.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/mock_audio_decoder_factory.h" +#include "test/mock_transport.h" +#include "test/time_controller/simulated_time_controller.h" + +namespace webrtc { +namespace voe { +namespace { + +using ::testing::NiceMock; +using ::testing::NotNull; +using ::testing::Return; +using ::testing::Test; + +constexpr uint32_t kLocalSsrc = 1111; +constexpr uint32_t kRemoteSsrc = 2222; +// We run RTP data with 8 kHz PCMA (fixed payload type 8). +constexpr char kPayloadName[] = "PCMA"; +constexpr int kPayloadType = 8; +constexpr int kSampleRateHz = 8000; + +class ChannelReceiveTest : public Test { + public: + ChannelReceiveTest() + : time_controller_(Timestamp::Seconds(5555)), + audio_device_module_(test::MockAudioDeviceModule::CreateNice()), + audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()) { + ON_CALL(*audio_device_module_, PlayoutDelay).WillByDefault(Return(0)); + } + + std::unique_ptr<ChannelReceiveInterface> CreateTestChannelReceive() { + CryptoOptions crypto_options; + auto channel = CreateChannelReceive( + time_controller_.GetClock(), + /* neteq_factory= */ nullptr, audio_device_module_.get(), &transport_, + &event_log_, kLocalSsrc, kRemoteSsrc, + /* jitter_buffer_max_packets= */ 0, + /* jitter_buffer_fast_playout= */ false, + /* jitter_buffer_min_delay_ms= */ 0, + /* enable_non_sender_rtt= */ false, audio_decoder_factory_, + /* codec_pair_id= */ absl::nullopt, + /* frame_decryptor_interface= */ nullptr, crypto_options, + /* frame_transformer= */ nullptr); + channel->SetReceiveCodecs( + {{kPayloadType, {kPayloadName, kSampleRateHz, 1}}}); + return channel; + } + + NtpTime NtpNow() { return time_controller_.GetClock()->CurrentNtpTime(); } + + uint32_t RtpNow() { + // Note - the "random" offset of this timestamp is zero. + return rtc::TimeMillis() * 1000 / kSampleRateHz; + } + + RtpPacketReceived CreateRtpPacket() { + RtpPacketReceived packet; + packet.set_arrival_time(time_controller_.GetClock()->CurrentTime()); + packet.SetTimestamp(RtpNow()); + packet.SetSsrc(kLocalSsrc); + packet.SetPayloadType(kPayloadType); + // Packet size should be enough to give at least 10 ms of data. + // For PCMA, that's 80 bytes; this should be enough. + uint8_t* datapos = packet.SetPayloadSize(100); + memset(datapos, 0, 100); + return packet; + } + + std::vector<uint8_t> CreateRtcpSenderReport() { + std::vector<uint8_t> packet(1024); + size_t pos = 0; + rtcp::SenderReport report; + report.SetSenderSsrc(kRemoteSsrc); + report.SetNtp(NtpNow()); + report.SetRtpTimestamp(RtpNow()); + report.SetPacketCount(0); + report.SetOctetCount(0); + report.Create(&packet[0], &pos, packet.size(), nullptr); + // No report blocks. + packet.resize(pos); + return packet; + } + + std::vector<uint8_t> CreateRtcpReceiverReport() { + rtcp::ReportBlock block; + block.SetMediaSsrc(kLocalSsrc); + // Middle 32 bits of the NTP timestamp from received SR + block.SetLastSr(CompactNtp(NtpNow())); + block.SetDelayLastSr(0); + + rtcp::ReceiverReport report; + report.SetSenderSsrc(kRemoteSsrc); + report.AddReportBlock(block); + + std::vector<uint8_t> packet(1024); + size_t pos = 0; + report.Create(&packet[0], &pos, packet.size(), nullptr); + packet.resize(pos); + return packet; + } + + void HandleGeneratedRtcp(ChannelReceiveInterface& channel, + rtc::ArrayView<const uint8_t> packet) { + if (packet[1] == rtcp::ReceiverReport::kPacketType) { + // Ignore RR, it requires no response + } else { + RTC_LOG(LS_ERROR) << "Unexpected RTCP packet generated"; + RTC_LOG(LS_ERROR) << "Packet content " + << rtc::hex_encode_with_delimiter( + absl::string_view( + reinterpret_cast<char*>(packet.data()[0]), + packet.size()), + ' '); + } + } + + int64_t ProbeCaptureStartNtpTime(ChannelReceiveInterface& channel) { + // Computation of the capture_start_ntp_time_ms_ occurs when the + // audio data is pulled, not when it is received. So we need to + // inject an RTP packet, and then fetch its data. + AudioFrame audio_frame; + channel.OnRtpPacket(CreateRtpPacket()); + channel.GetAudioFrameWithInfo(kSampleRateHz, &audio_frame); + CallReceiveStatistics stats = channel.GetRTCPStatistics(); + return stats.capture_start_ntp_time_ms_; + } + + protected: + GlobalSimulatedTimeController time_controller_; + rtc::scoped_refptr<test::MockAudioDeviceModule> audio_device_module_; + rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory_; + MockTransport transport_; + NiceMock<MockRtcEventLog> event_log_; +}; + +TEST_F(ChannelReceiveTest, CreateAndDestroy) { + auto channel = CreateTestChannelReceive(); + EXPECT_THAT(channel, NotNull()); +} + +TEST_F(ChannelReceiveTest, ReceiveReportGeneratedOnTime) { + auto channel = CreateTestChannelReceive(); + + bool receiver_report_sent = false; + EXPECT_CALL(transport_, SendRtcp) + .WillRepeatedly([&](rtc::ArrayView<const uint8_t> packet) { + if (packet.size() >= 2 && + packet[1] == rtcp::ReceiverReport::kPacketType) { + receiver_report_sent = true; + } + return true; + }); + // RFC 3550 section 6.2 mentions 5 seconds as a reasonable expectation + // for the interval between RTCP packets. + time_controller_.AdvanceTime(TimeDelta::Seconds(5)); + + EXPECT_TRUE(receiver_report_sent); +} + +TEST_F(ChannelReceiveTest, CaptureStartTimeBecomesValid) { + auto channel = CreateTestChannelReceive(); + + EXPECT_CALL(transport_, SendRtcp) + .WillRepeatedly([&](rtc::ArrayView<const uint8_t> packet) { + HandleGeneratedRtcp(*channel, packet); + return true; + }); + // Before any packets are sent, CaptureStartTime is invalid. + EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1); + + // Must start playout, otherwise packet is discarded. + channel->StartPlayout(); + // Send one RTP packet. This causes registration of the SSRC. + channel->OnRtpPacket(CreateRtpPacket()); + EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1); + + // Receive a sender report. + auto rtcp_packet_1 = CreateRtcpSenderReport(); + channel->ReceivedRTCPPacket(rtcp_packet_1.data(), rtcp_packet_1.size()); + EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1); + + time_controller_.AdvanceTime(TimeDelta::Seconds(5)); + + // Receive a receiver report. This is necessary, which is odd. + // Presumably it is because the receiver needs to know the RTT + // before it can compute the capture start NTP time. + // The receiver report must happen before the second sender report. + auto rtcp_rr = CreateRtcpReceiverReport(); + channel->ReceivedRTCPPacket(rtcp_rr.data(), rtcp_rr.size()); + EXPECT_EQ(ProbeCaptureStartNtpTime(*channel), -1); + + // Receive another sender report after 5 seconds. + // This should be enough to establish the capture start NTP time. + auto rtcp_packet_2 = CreateRtcpSenderReport(); + channel->ReceivedRTCPPacket(rtcp_packet_2.data(), rtcp_packet_2.size()); + + EXPECT_NE(ProbeCaptureStartNtpTime(*channel), -1); +} + +} // namespace +} // namespace voe +} // namespace webrtc |