/* * 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_frame_transformer.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 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 CreateRtcpSenderReport() { std::vector 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 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 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 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(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 audio_device_module_; rtc::scoped_refptr audio_decoder_factory_; MockTransport transport_; NiceMock 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 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 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); } TEST_F(ChannelReceiveTest, SettingFrameTransformer) { auto channel = CreateTestChannelReceive(); rtc::scoped_refptr mock_frame_transformer = rtc::make_ref_counted(); EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback); channel->SetDepacketizerToDecoderFrameTransformer(mock_frame_transformer); // Must start playout, otherwise packet is discarded. channel->StartPlayout(); RtpPacketReceived packet = CreateRtpPacket(); // Receive one RTP packet, this should be transformed. EXPECT_CALL(*mock_frame_transformer, Transform); channel->OnRtpPacket(packet); } TEST_F(ChannelReceiveTest, SettingFrameTransformerMultipleTimes) { auto channel = CreateTestChannelReceive(); rtc::scoped_refptr mock_frame_transformer = rtc::make_ref_counted(); EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback); channel->SetDepacketizerToDecoderFrameTransformer(mock_frame_transformer); // Set the same transformer again, shouldn't cause any additional callback // registration calls. EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback) .Times(0); channel->SetDepacketizerToDecoderFrameTransformer(mock_frame_transformer); } } // namespace } // namespace voe } // namespace webrtc