| /* | |
| * Copyright 2019 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 "test/network/feedback_generator.h" | |
| #include <cstddef> | |
| #include <memory> | |
| #include <utility> | |
| #include <vector> | |
| #include "absl/memory/memory.h" | |
| #include "api/environment/environment.h" | |
| #include "api/environment/environment_factory.h" | |
| #include "api/rtc_event_log/rtc_event_log.h" | |
| #include "api/rtc_event_log/rtc_event_log_factory.h" | |
| #include "api/rtp_parameters.h" | |
| #include "api/test/create_network_emulation_manager.h" | |
| #include "api/test/network_emulation_manager.h" | |
| #include "api/test/simulated_network.h" | |
| #include "api/transport/network_types.h" | |
| #include "api/transport/test/feedback_generator_interface.h" | |
| #include "api/units/data_rate.h" | |
| #include "api/units/data_size.h" | |
| #include "api/units/time_delta.h" | |
| #include "api/units/timestamp.h" | |
| #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h" | |
| #include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" | |
| #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" | |
| #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" | |
| #include "modules/rtp_rtcp/source/rtp_header_extensions.h" | |
| #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" | |
| #include "rtc_base/checks.h" | |
| #include "test/network/network_emulation.h" | |
| #include "test/network/simulated_network.h" | |
| namespace webrtc { | |
| namespace { | |
| Environment GetEnvironment(NetworkEmulationManager& net) { | |
| EnvironmentFactory factory; | |
| factory.Set(net.time_controller()->GetClock()); | |
| factory.Set(net.time_controller()->GetTaskQueueFactory()); | |
| return factory.Create(); | |
| } | |
| EmulatedRoute* CreateRoute(NetworkEmulationManager& net, | |
| std::vector<EmulatedNetworkNode*> link) { | |
| if (!link.empty()) { | |
| return net.CreateRoute(link); | |
| } else { | |
| return net.CreateRoute({net.CreateUnconstrainedEmulatedNode()}); | |
| } | |
| } | |
| } // namespace | |
| FeedbackGeneratorWithoutNetworkImpl::FeedbackGeneratorWithoutNetworkImpl( | |
| Config config, | |
| NetworkEmulationManager& net) | |
| : net_(net), | |
| feedback_interval_(config.feedback_interval), | |
| feedback_packet_size_(config.feedback_packet_size), | |
| event_log_(RtcEventLogFactory().Create(GetEnvironment(net))), | |
| route_(this, | |
| CreateRoute(net, std::move(config.sent_via_nodes)), | |
| CreateRoute(net, std::move(config.received_via_nodes))) { | |
| RtpExtension transport_sequence_number_extension; | |
| transport_sequence_number_extension.uri = | |
| RtpExtension::kTransportSequenceNumberUri; | |
| transport_sequence_number_extension.id = 1; | |
| transport_sequence_number_extension.encrypt = false; | |
| rtp_extensions_.RegisterByUri(transport_sequence_number_extension.id, | |
| transport_sequence_number_extension.uri); | |
| } | |
| void FeedbackGeneratorWithoutNetworkImpl::SendPacket(size_t total_size, | |
| size_t overhead) { | |
| SentPacket sent; | |
| sent.send_time = Now(); | |
| sent.size = DataSize::Bytes(total_size); | |
| sent.sequence_number = sequence_number_++; | |
| sent_packets_.push(sent); | |
| RtpPacketToSend packet_to_send(&rtp_extensions_); | |
| packet_to_send.set_transport_sequence_number(sent.sequence_number); | |
| packet_to_send.SetExtension<TransportSequenceNumber>(sent.sequence_number); | |
| RTC_DCHECK(total_size > packet_to_send.headers_size() + overhead); | |
| if (total_size > packet_to_send.headers_size() + overhead) { | |
| packet_to_send.SetPayloadSize(total_size - packet_to_send.headers_size() - | |
| overhead); | |
| RTC_DCHECK_EQ(packet_to_send.size(), total_size - overhead); | |
| } | |
| event_log_->Log(std::make_unique<RtcEventRtpPacketOutgoing>( | |
| packet_to_send, /*probe_cluster_id*/ 0)); | |
| route_.SendRequest(total_size, sent); | |
| } | |
| std::vector<TransportPacketsFeedback> | |
| FeedbackGeneratorWithoutNetworkImpl::PopFeedback() { | |
| std::vector<TransportPacketsFeedback> ret; | |
| ret.swap(feedback_); | |
| return ret; | |
| } | |
| Timestamp FeedbackGeneratorWithoutNetworkImpl::Now() { | |
| return net_.time_controller()->GetClock()->CurrentTime(); | |
| } | |
| void FeedbackGeneratorWithoutNetworkImpl::OnRequest(SentPacket packet, | |
| Timestamp arrival_time) { | |
| PacketResult result; | |
| result.sent_packet = packet; | |
| result.receive_time = arrival_time; | |
| received_packets_.push_back(result); | |
| Timestamp first_recv = received_packets_.front().receive_time; | |
| if (Now() - first_recv > feedback_interval_) { | |
| route_.SendResponse(feedback_packet_size_.bytes<size_t>(), | |
| std::move(received_packets_)); | |
| received_packets_ = {}; | |
| } | |
| } | |
| void FeedbackGeneratorWithoutNetworkImpl::OnResponse( | |
| std::vector<PacketResult> packet_results, | |
| Timestamp arrival_time) { | |
| TransportPacketsFeedback feedback; | |
| feedback.feedback_time = arrival_time; | |
| std::vector<PacketResult>::const_iterator received_packet_iterator = | |
| packet_results.begin(); | |
| while (received_packet_iterator != packet_results.end()) { | |
| RTC_DCHECK(!sent_packets_.empty() && | |
| sent_packets_.front().sequence_number <= | |
| received_packet_iterator->sent_packet.sequence_number) | |
| << "reordering not implemented"; | |
| if (sent_packets_.front().sequence_number < | |
| received_packet_iterator->sent_packet.sequence_number) { | |
| // Packet lost. | |
| PacketResult lost; | |
| lost.sent_packet = sent_packets_.front(); | |
| feedback.packet_feedbacks.push_back(lost); | |
| } | |
| if (sent_packets_.front().sequence_number == | |
| received_packet_iterator->sent_packet.sequence_number) { | |
| feedback.packet_feedbacks.push_back(*received_packet_iterator); | |
| ++received_packet_iterator; | |
| } | |
| sent_packets_.pop(); | |
| } | |
| rtcp::TransportFeedback transport_feedback; | |
| transport_feedback.SetBase( | |
| feedback.ReceivedWithSendInfo()[0].sent_packet.sequence_number, | |
| feedback.ReceivedWithSendInfo()[0].receive_time); | |
| for (const auto& received_packet : feedback.ReceivedWithSendInfo()) { | |
| transport_feedback.AddReceivedPacket( | |
| received_packet.sent_packet.sequence_number, | |
| received_packet.receive_time); | |
| } | |
| event_log_->Log( | |
| std::make_unique<RtcEventRtcpPacketIncoming>(transport_feedback.Build())); | |
| feedback_.push_back(feedback); | |
| } | |
| FeedbackGeneratorImpl::FeedbackGeneratorImpl( | |
| FeedbackGeneratorImpl::Config config) | |
| : conf_(config), | |
| net_(CreateNetworkEmulationManager({.time_mode = TimeMode::kSimulated})), | |
| send_link_{new SimulatedNetwork(conf_.send_link)}, | |
| ret_link_{new SimulatedNetwork(conf_.return_link)}, | |
| delegate_({.sent_via_nodes = {net_->CreateEmulatedNode( | |
| absl::WrapUnique(send_link_))}, | |
| .received_via_nodes = {net_->CreateEmulatedNode( | |
| absl::WrapUnique(ret_link_))}, | |
| .feedback_interval = config.feedback_interval, | |
| .feedback_packet_size = config.feedback_packet_size}, | |
| *net_) {} | |
| Timestamp FeedbackGeneratorImpl::Now() { | |
| return delegate_.Now(); | |
| } | |
| void FeedbackGeneratorImpl::Sleep(TimeDelta duration) { | |
| net_->time_controller()->AdvanceTime(duration); | |
| } | |
| void FeedbackGeneratorImpl::SendPacket(size_t size) { | |
| delegate_.SendPacket(size, /*overhead=*/0); | |
| } | |
| std::vector<TransportPacketsFeedback> FeedbackGeneratorImpl::PopFeedback() { | |
| return delegate_.PopFeedback(); | |
| } | |
| void FeedbackGeneratorImpl::SetSendConfig(BuiltInNetworkBehaviorConfig config) { | |
| conf_.send_link = config; | |
| send_link_->SetConfig(conf_.send_link); | |
| } | |
| void FeedbackGeneratorImpl::SetReturnConfig( | |
| BuiltInNetworkBehaviorConfig config) { | |
| conf_.return_link = config; | |
| ret_link_->SetConfig(conf_.return_link); | |
| } | |
| void FeedbackGeneratorImpl::SetSendLinkCapacity(DataRate capacity) { | |
| conf_.send_link.link_capacity = capacity; | |
| send_link_->SetConfig(conf_.send_link); | |
| } | |
| } // namespace webrtc |