| /* |
| * 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 |