|  | /* | 
|  | *  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/audio_device.h" | 
|  | #include "api/audio_codecs/builtin_audio_decoder_factory.h" | 
|  | #include "api/crypto/frame_decryptor_interface.h" | 
|  | #include "api/environment/environment_factory.h" | 
|  | #include "api/test/mock_frame_transformer.h" | 
|  | #include "modules/audio_device/include/mock_audio_device.h" | 
|  | #include "modules/rtp_rtcp/source/byte_io.h" | 
|  | #include "modules/rtp_rtcp/source/ntp_time_util.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 "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( | 
|  | CreateEnvironment(time_controller_.GetClock()), | 
|  | /* neteq_factory= */ nullptr, audio_device_module_.get(), &transport_, | 
|  | 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= */ std::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 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 */, | 
|  | 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 " | 
|  | << 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_; | 
|  | scoped_refptr<test::MockAudioDeviceModule> audio_device_module_; | 
|  | scoped_refptr<AudioDecoderFactory> audio_decoder_factory_; | 
|  | MockTransport transport_; | 
|  | }; | 
|  |  | 
|  | 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([&](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([&](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); | 
|  | } | 
|  |  | 
|  | TEST_F(ChannelReceiveTest, SettingFrameTransformer) { | 
|  | auto channel = CreateTestChannelReceive(); | 
|  |  | 
|  | scoped_refptr<MockFrameTransformer> mock_frame_transformer = | 
|  | make_ref_counted<MockFrameTransformer>(); | 
|  |  | 
|  | 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(); | 
|  |  | 
|  | scoped_refptr<MockFrameTransformer> mock_frame_transformer = | 
|  | make_ref_counted<MockFrameTransformer>(); | 
|  |  | 
|  | 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 |