Refactoring PayloadRouter.
- Move PayloadRouter to RtpTransportControllerInterface.
- Move RetransmissionLimiter inside RtpTransportControllerSend from
VideoSendStreamImpl.
- Move video RTP specifics into PayloadRouter, in particular ownership
of the RTP modules.
- PayloadRouter now contains all video specific RTP code, and will be
renamed in a follow-up to VideoRtpSender.
- Introduce VideoRtpSenderInterface.
Bug: webrtc:9517
Change-Id: I1c7b293fa6f9c320286c80533b3c584498034a38
Reviewed-on: https://webrtc-review.googlesource.com/88240
Commit-Queue: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24009}
diff --git a/call/BUILD.gn b/call/BUILD.gn
index 821a164..7204dcc 100644
--- a/call/BUILD.gn
+++ b/call/BUILD.gn
@@ -62,6 +62,8 @@
"../api:array_view",
"../api:libjingle_peerconnection_api",
"../api/transport:bitrate_settings",
+ "../logging:rtc_event_log_api",
+ "../modules/rtp_rtcp:rtp_rtcp_format",
"../rtc_base:rtc_base_approved",
"//third_party/abseil-cpp/absl/types:optional",
]
@@ -104,13 +106,16 @@
"rtp_payload_params.h",
"rtp_transport_controller_send.cc",
"rtp_transport_controller_send.h",
+ "video_rtp_sender_interface.h",
]
deps = [
":bitrate_configurator",
":rtp_interfaces",
"..:webrtc_common",
+ "../api:transport_api",
"../api/transport:network_control",
"../api/video_codecs:video_codecs_api",
+ "../logging:rtc_event_log_api",
"../modules/congestion_controller",
"../modules/congestion_controller/rtp:congestion_controller",
"../modules/pacing",
@@ -120,6 +125,7 @@
"../modules/utility",
"../modules/video_coding:video_codec_interface",
"../rtc_base:checks",
+ "../rtc_base:rate_limiter",
"../rtc_base:rtc_base",
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_task_queue",
@@ -318,6 +324,7 @@
"../modules/utility:mock_process_thread",
"../modules/video_coding:video_codec_interface",
"../rtc_base:checks",
+ "../rtc_base:rate_limiter",
"../rtc_base:rtc_base_approved",
"../system_wrappers",
"../test:audio_codec_mocks",
@@ -326,6 +333,7 @@
"../test:test_common",
"../test:test_support",
"../test:video_test_common",
+ "../video:video",
"//testing/gtest",
"//third_party/abseil-cpp/absl/memory",
]
diff --git a/call/bitrate_allocator.h b/call/bitrate_allocator.h
index 36d05de..c29ea5e 100644
--- a/call/bitrate_allocator.h
+++ b/call/bitrate_allocator.h
@@ -98,7 +98,7 @@
};
explicit BitrateAllocator(LimitObserver* limit_observer);
- ~BitrateAllocator();
+ ~BitrateAllocator() override;
// Allocate target_bitrate across the registered BitrateAllocatorObservers.
void OnNetworkChanged(uint32_t target_bitrate_bps,
diff --git a/call/call.cc b/call/call.cc
index 8b4da25..4f27146 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -51,7 +51,6 @@
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_minmax.h"
-#include "rtc_base/rate_limiter.h"
#include "rtc_base/sequenced_task_checker.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/synchronization/rw_lock_wrapper.h"
@@ -70,8 +69,6 @@
namespace webrtc {
namespace {
-static const int64_t kRetransmitWindowSizeMs = 500;
-
// TODO(nisse): This really begs for a shared context struct.
bool UseSendSideBwe(const std::vector<RtpExtension>& extensions,
bool transport_cc) {
@@ -361,7 +358,6 @@
RTC_GUARDED_BY(&bitrate_crit_);
AvgCounter pacer_bitrate_kbps_counter_ RTC_GUARDED_BY(&bitrate_crit_);
- RateLimiter retransmission_rate_limiter_;
ReceiveSideCongestionController receive_side_cc_;
const std::unique_ptr<ReceiveTimeCalculator> receive_time_calculator_;
@@ -442,7 +438,6 @@
configured_max_padding_bitrate_bps_(0),
estimated_send_bitrate_kbps_counter_(clock_, nullptr, true),
pacer_bitrate_kbps_counter_(clock_, nullptr, true),
- retransmission_rate_limiter_(clock_, kRetransmitWindowSizeMs),
receive_side_cc_(clock_, transport_send->packet_router()),
receive_time_calculator_(ReceiveTimeCalculator::CreateFromFieldTrial()),
video_send_delay_stats_(new SendDelayStats(clock_)),
@@ -732,8 +727,7 @@
transport_send_ptr_, bitrate_allocator_.get(),
video_send_delay_stats_.get(), event_log_, std::move(config),
std::move(encoder_config), suspended_video_send_ssrcs_,
- suspended_video_payload_states_, std::move(fec_controller),
- &retransmission_rate_limiter_);
+ suspended_video_payload_states_, std::move(fec_controller));
{
WriteLockScoped write_lock(*send_crit_);
@@ -743,7 +737,6 @@
}
video_send_streams_.insert(send_stream);
}
- send_stream->SignalNetworkState(video_network_state_);
UpdateAggregateNetworkState();
return send_stream;
@@ -991,9 +984,6 @@
for (auto& kv : audio_send_ssrcs_) {
kv.second->SignalNetworkState(audio_network_state_);
}
- for (auto& kv : video_send_ssrcs_) {
- kv.second->SignalNetworkState(video_network_state_);
- }
}
{
ReadLockScoped read_lock(*receive_crit_);
@@ -1081,7 +1071,6 @@
rtc::CritScope cs(&last_bandwidth_bps_crit_);
last_bandwidth_bps_ = bandwidth_bps;
}
- retransmission_rate_limiter_.SetMaxRate(bandwidth_bps);
// For controlling the rate of feedback messages.
receive_side_cc_.OnBitrateChanged(target_bitrate_bps);
bitrate_allocator_->OnNetworkChanged(target_bitrate_bps, fraction_loss,
diff --git a/call/payload_router.cc b/call/payload_router.cc
index cca4bd3..4e7d13e 100644
--- a/call/payload_router.cc
+++ b/call/payload_router.cc
@@ -10,14 +10,90 @@
#include "call/payload_router.h"
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "call/rtp_transport_controller_send_interface.h"
+#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtp_sender.h"
+#include "modules/utility/include/process_thread.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "rtc_base/checks.h"
+#include "rtc_base/location.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
+static const int kMinSendSidePacketHistorySize = 600;
+
+std::vector<std::unique_ptr<RtpRtcp>> CreateRtpRtcpModules(
+ const std::vector<uint32_t>& ssrcs,
+ const std::vector<uint32_t>& protected_media_ssrcs,
+ const RtcpConfig& rtcp_config,
+ Transport* send_transport,
+ RtcpIntraFrameObserver* intra_frame_callback,
+ RtcpBandwidthObserver* bandwidth_callback,
+ RtpTransportControllerSendInterface* transport,
+ RtcpRttStats* rtt_stats,
+ FlexfecSender* flexfec_sender,
+ BitrateStatisticsObserver* bitrate_observer,
+ FrameCountObserver* frame_count_observer,
+ RtcpPacketTypeCounterObserver* rtcp_type_observer,
+ SendSideDelayObserver* send_delay_observer,
+ SendPacketObserver* send_packet_observer,
+ RtcEventLog* event_log,
+ RateLimiter* retransmission_rate_limiter,
+ OverheadObserver* overhead_observer,
+ RtpKeepAliveConfig keepalive_config) {
+ RTC_DCHECK_GT(ssrcs.size(), 0);
+ RtpRtcp::Configuration configuration;
+ configuration.audio = false;
+ configuration.receiver_only = false;
+ configuration.outgoing_transport = send_transport;
+ configuration.intra_frame_callback = intra_frame_callback;
+ configuration.bandwidth_callback = bandwidth_callback;
+ configuration.transport_feedback_callback =
+ transport->transport_feedback_observer();
+ configuration.rtt_stats = rtt_stats;
+ configuration.rtcp_packet_type_counter_observer = rtcp_type_observer;
+ configuration.paced_sender = transport->packet_sender();
+ configuration.transport_sequence_number_allocator =
+ transport->packet_router();
+ configuration.send_bitrate_observer = bitrate_observer;
+ configuration.send_frame_count_observer = frame_count_observer;
+ configuration.send_side_delay_observer = send_delay_observer;
+ configuration.send_packet_observer = send_packet_observer;
+ configuration.event_log = event_log;
+ configuration.retransmission_rate_limiter = retransmission_rate_limiter;
+ configuration.overhead_observer = overhead_observer;
+ configuration.keepalive_config = keepalive_config;
+ configuration.rtcp_interval_config.video_interval_ms =
+ rtcp_config.video_report_interval_ms;
+ configuration.rtcp_interval_config.audio_interval_ms =
+ rtcp_config.audio_report_interval_ms;
+ std::vector<std::unique_ptr<RtpRtcp>> modules;
+ const std::vector<uint32_t>& flexfec_protected_ssrcs = protected_media_ssrcs;
+ for (uint32_t ssrc : ssrcs) {
+ bool enable_flexfec = flexfec_sender != nullptr &&
+ std::find(flexfec_protected_ssrcs.begin(),
+ flexfec_protected_ssrcs.end(),
+ ssrc) != flexfec_protected_ssrcs.end();
+ configuration.flexfec_sender = enable_flexfec ? flexfec_sender : nullptr;
+ std::unique_ptr<RtpRtcp> rtp_rtcp =
+ std::unique_ptr<RtpRtcp>(RtpRtcp::CreateRtpRtcp(configuration));
+ rtp_rtcp->SetSendingStatus(false);
+ rtp_rtcp->SetSendingMediaStatus(false);
+ rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound);
+ modules.push_back(std::move(rtp_rtcp));
+ }
+ return modules;
+}
+
absl::optional<size_t> GetSimulcastIdx(const CodecSpecificInfo* info) {
if (!info)
return absl::nullopt;
@@ -33,14 +109,95 @@
return absl::nullopt;
}
}
+bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) {
+ const VideoCodecType codecType = PayloadStringToCodecType(payload_name);
+ if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) {
+ return true;
+ }
+ return false;
+}
+
+// TODO(brandtr): Update this function when we support multistream protection.
+std::unique_ptr<FlexfecSender> MaybeCreateFlexfecSender(
+ const RtpConfig& rtp,
+ const std::map<uint32_t, RtpState>& suspended_ssrcs) {
+ if (rtp.flexfec.payload_type < 0) {
+ return nullptr;
+ }
+ RTC_DCHECK_GE(rtp.flexfec.payload_type, 0);
+ RTC_DCHECK_LE(rtp.flexfec.payload_type, 127);
+ if (rtp.flexfec.ssrc == 0) {
+ RTC_LOG(LS_WARNING) << "FlexFEC is enabled, but no FlexFEC SSRC given. "
+ "Therefore disabling FlexFEC.";
+ return nullptr;
+ }
+ if (rtp.flexfec.protected_media_ssrcs.empty()) {
+ RTC_LOG(LS_WARNING)
+ << "FlexFEC is enabled, but no protected media SSRC given. "
+ "Therefore disabling FlexFEC.";
+ return nullptr;
+ }
+
+ if (rtp.flexfec.protected_media_ssrcs.size() > 1) {
+ RTC_LOG(LS_WARNING)
+ << "The supplied FlexfecConfig contained multiple protected "
+ "media streams, but our implementation currently only "
+ "supports protecting a single media stream. "
+ "To avoid confusion, disabling FlexFEC completely.";
+ return nullptr;
+ }
+
+ const RtpState* rtp_state = nullptr;
+ auto it = suspended_ssrcs.find(rtp.flexfec.ssrc);
+ if (it != suspended_ssrcs.end()) {
+ rtp_state = &it->second;
+ }
+
+ RTC_DCHECK_EQ(1U, rtp.flexfec.protected_media_ssrcs.size());
+ return absl::make_unique<FlexfecSender>(
+ rtp.flexfec.payload_type, rtp.flexfec.ssrc,
+ rtp.flexfec.protected_media_ssrcs[0], rtp.mid, rtp.extensions,
+ RTPSender::FecExtensionSizes(), rtp_state, Clock::GetRealTimeClock());
+}
} // namespace
-PayloadRouter::PayloadRouter(const std::vector<RtpRtcp*>& rtp_modules,
- const std::vector<uint32_t>& ssrcs,
- int payload_type,
- const std::map<uint32_t, RtpPayloadState>& states)
- : active_(false), rtp_modules_(rtp_modules), payload_type_(payload_type) {
- RTC_DCHECK_EQ(ssrcs.size(), rtp_modules.size());
+PayloadRouter::PayloadRouter(const std::vector<uint32_t>& ssrcs,
+ std::map<uint32_t, RtpState> suspended_ssrcs,
+ const std::map<uint32_t, RtpPayloadState>& states,
+ const RtpConfig& rtp_config,
+ const RtcpConfig& rtcp_config,
+ Transport* send_transport,
+ const RtpSenderObservers& observers,
+ RtpTransportControllerSendInterface* transport,
+ RtcEventLog* event_log,
+ RateLimiter* retransmission_limiter)
+ : active_(false),
+ module_process_thread_(nullptr),
+ suspended_ssrcs_(std::move(suspended_ssrcs)),
+ flexfec_sender_(MaybeCreateFlexfecSender(rtp_config, suspended_ssrcs_)),
+ rtp_modules_(
+ CreateRtpRtcpModules(ssrcs,
+ rtp_config.flexfec.protected_media_ssrcs,
+ rtcp_config,
+ send_transport,
+ observers.intra_frame_callback,
+ transport->GetBandwidthObserver(),
+ transport,
+ observers.rtcp_rtt_stats,
+ flexfec_sender_.get(),
+ observers.bitrate_observer,
+ observers.frame_count_observer,
+ observers.rtcp_type_observer,
+ observers.send_delay_observer,
+ observers.send_packet_observer,
+ event_log,
+ retransmission_limiter,
+ observers.overhead_observer,
+ transport->keepalive_config())),
+ rtp_config_(rtp_config),
+ transport_(transport) {
+ RTC_DCHECK_EQ(ssrcs.size(), rtp_modules_.size());
+ module_process_thread_checker_.DetachFromThread();
// SSRCs are assumed to be sorted in the same order as |rtp_modules|.
for (uint32_t ssrc : ssrcs) {
// Restore state if it previously existed.
@@ -51,9 +208,73 @@
}
params_.push_back(RtpPayloadParams(ssrc, state));
}
+
+ // RTP/RTCP initialization.
+
+ // We add the highest spatial layer first to ensure it'll be prioritized
+ // when sending padding, with the hope that the packet rate will be smaller,
+ // and that it's more important to protect than the lower layers.
+ for (auto& rtp_rtcp : rtp_modules_) {
+ constexpr bool remb_candidate = true;
+ transport->packet_router()->AddSendRtpModule(rtp_rtcp.get(),
+ remb_candidate);
+ }
+
+ for (size_t i = 0; i < rtp_config_.extensions.size(); ++i) {
+ const std::string& extension = rtp_config_.extensions[i].uri;
+ int id = rtp_config_.extensions[i].id;
+ // One-byte-extension local identifiers are in the range 1-14 inclusive.
+ RTC_DCHECK_GE(id, 1);
+ RTC_DCHECK_LE(id, 14);
+ RTC_DCHECK(RtpExtension::IsSupportedForVideo(extension));
+ for (auto& rtp_rtcp : rtp_modules_) {
+ RTC_CHECK_EQ(0, rtp_rtcp->RegisterSendRtpHeaderExtension(
+ StringToRtpExtensionType(extension), id));
+ }
+ }
+
+ ConfigureProtection(rtp_config);
+ ConfigureSsrcs(rtp_config);
+
+ if (!rtp_config.mid.empty()) {
+ for (auto& rtp_rtcp : rtp_modules_) {
+ rtp_rtcp->SetMid(rtp_config.mid);
+ }
+ }
+
+ // TODO(pbos): Should we set CNAME on all RTP modules?
+ rtp_modules_.front()->SetCNAME(rtp_config.c_name.c_str());
+
+ for (auto& rtp_rtcp : rtp_modules_) {
+ rtp_rtcp->RegisterRtcpStatisticsCallback(observers.rtcp_stats);
+ rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(observers.rtp_stats);
+ rtp_rtcp->SetMaxRtpPacketSize(rtp_config.max_packet_size);
+ rtp_rtcp->RegisterVideoSendPayload(rtp_config.payload_type,
+ rtp_config.payload_name.c_str());
+ }
}
-PayloadRouter::~PayloadRouter() {}
+PayloadRouter::~PayloadRouter() {
+ for (auto& rtp_rtcp : rtp_modules_) {
+ transport_->packet_router()->RemoveSendRtpModule(rtp_rtcp.get());
+ }
+}
+
+void PayloadRouter::RegisterProcessThread(
+ ProcessThread* module_process_thread) {
+ RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
+ RTC_DCHECK(!module_process_thread_);
+ module_process_thread_ = module_process_thread;
+
+ for (auto& rtp_rtcp : rtp_modules_)
+ module_process_thread_->RegisterModule(rtp_rtcp.get(), RTC_FROM_HERE);
+}
+
+void PayloadRouter::DeRegisterProcessThread() {
+ RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
+ for (auto& rtp_rtcp : rtp_modules_)
+ module_process_thread_->DeRegisterModule(rtp_rtcp.get());
+}
void PayloadRouter::SetActive(bool active) {
rtc::CritScope lock(&crit_);
@@ -83,15 +304,6 @@
return active_ && !rtp_modules_.empty();
}
-std::map<uint32_t, RtpPayloadState> PayloadRouter::GetRtpPayloadStates() const {
- rtc::CritScope lock(&crit_);
- std::map<uint32_t, RtpPayloadState> payload_states;
- for (const auto& param : params_) {
- payload_states[param.ssrc()] = param.state();
- }
- return payload_states;
-}
-
EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
@@ -112,9 +324,10 @@
return Result(Result::ERROR_SEND_FAILED);
}
bool send_result = rtp_modules_[stream_index]->SendOutgoingData(
- encoded_image._frameType, payload_type_, encoded_image._timeStamp,
- encoded_image.capture_time_ms_, encoded_image._buffer,
- encoded_image._length, fragmentation, &rtp_video_header, &frame_id);
+ encoded_image._frameType, rtp_config_.payload_type,
+ encoded_image._timeStamp, encoded_image.capture_time_ms_,
+ encoded_image._buffer, encoded_image._length, fragmentation,
+ &rtp_video_header, &frame_id);
if (!send_result)
return Result(Result::ERROR_SEND_FAILED);
@@ -144,4 +357,189 @@
}
}
+void PayloadRouter::ConfigureProtection(const RtpConfig& rtp_config) {
+ // Consistency of FlexFEC parameters is checked in MaybeCreateFlexfecSender.
+ const bool flexfec_enabled = (flexfec_sender_ != nullptr);
+
+ // Consistency of NACK and RED+ULPFEC parameters is checked in this function.
+ const bool nack_enabled = rtp_config.nack.rtp_history_ms > 0;
+ int red_payload_type = rtp_config.ulpfec.red_payload_type;
+ int ulpfec_payload_type = rtp_config.ulpfec.ulpfec_payload_type;
+
+ // Shorthands.
+ auto IsRedEnabled = [&]() { return red_payload_type >= 0; };
+ auto IsUlpfecEnabled = [&]() { return ulpfec_payload_type >= 0; };
+ auto DisableRedAndUlpfec = [&]() {
+ red_payload_type = -1;
+ ulpfec_payload_type = -1;
+ };
+
+ if (webrtc::field_trial::IsEnabled("WebRTC-DisableUlpFecExperiment")) {
+ RTC_LOG(LS_INFO) << "Experiment to disable sending ULPFEC is enabled.";
+ DisableRedAndUlpfec();
+ }
+
+ // If enabled, FlexFEC takes priority over RED+ULPFEC.
+ if (flexfec_enabled) {
+ if (IsUlpfecEnabled()) {
+ RTC_LOG(LS_INFO)
+ << "Both FlexFEC and ULPFEC are configured. Disabling ULPFEC.";
+ }
+ DisableRedAndUlpfec();
+ }
+
+ // Payload types without picture ID cannot determine that a stream is complete
+ // without retransmitting FEC, so using ULPFEC + NACK for H.264 (for instance)
+ // is a waste of bandwidth since FEC packets still have to be transmitted.
+ // Note that this is not the case with FlexFEC.
+ if (nack_enabled && IsUlpfecEnabled() &&
+ !PayloadTypeSupportsSkippingFecPackets(rtp_config.payload_name)) {
+ RTC_LOG(LS_WARNING)
+ << "Transmitting payload type without picture ID using "
+ "NACK+ULPFEC is a waste of bandwidth since ULPFEC packets "
+ "also have to be retransmitted. Disabling ULPFEC.";
+ DisableRedAndUlpfec();
+ }
+
+ // Verify payload types.
+ if (IsUlpfecEnabled() ^ IsRedEnabled()) {
+ RTC_LOG(LS_WARNING)
+ << "Only RED or only ULPFEC enabled, but not both. Disabling both.";
+ DisableRedAndUlpfec();
+ }
+
+ for (auto& rtp_rtcp : rtp_modules_) {
+ // Set NACK.
+ rtp_rtcp->SetStorePacketsStatus(true, kMinSendSidePacketHistorySize);
+ // Set RED/ULPFEC information.
+ rtp_rtcp->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
+ }
+}
+
+bool PayloadRouter::FecEnabled() const {
+ const bool flexfec_enabled = (flexfec_sender_ != nullptr);
+ int ulpfec_payload_type = rtp_config_.ulpfec.ulpfec_payload_type;
+ return flexfec_enabled || ulpfec_payload_type >= 0;
+}
+
+bool PayloadRouter::NackEnabled() const {
+ const bool nack_enabled = rtp_config_.nack.rtp_history_ms > 0;
+ return nack_enabled;
+}
+
+void PayloadRouter::DeliverRtcp(const uint8_t* packet, size_t length) {
+ // Runs on a network thread.
+ for (auto& rtp_rtcp : rtp_modules_)
+ rtp_rtcp->IncomingRtcpPacket(packet, length);
+}
+
+void PayloadRouter::ProtectionRequest(const FecProtectionParams* delta_params,
+ const FecProtectionParams* key_params,
+ uint32_t* sent_video_rate_bps,
+ uint32_t* sent_nack_rate_bps,
+ uint32_t* sent_fec_rate_bps) {
+ *sent_video_rate_bps = 0;
+ *sent_nack_rate_bps = 0;
+ *sent_fec_rate_bps = 0;
+ for (auto& rtp_rtcp : rtp_modules_) {
+ uint32_t not_used = 0;
+ uint32_t module_video_rate = 0;
+ uint32_t module_fec_rate = 0;
+ uint32_t module_nack_rate = 0;
+ rtp_rtcp->SetFecParameters(*delta_params, *key_params);
+ rtp_rtcp->BitrateSent(¬_used, &module_video_rate, &module_fec_rate,
+ &module_nack_rate);
+ *sent_video_rate_bps += module_video_rate;
+ *sent_nack_rate_bps += module_nack_rate;
+ *sent_fec_rate_bps += module_fec_rate;
+ }
+}
+
+void PayloadRouter::SetMaxRtpPacketSize(size_t max_rtp_packet_size) {
+ for (auto& rtp_rtcp : rtp_modules_) {
+ rtp_rtcp->SetMaxRtpPacketSize(max_rtp_packet_size);
+ }
+}
+
+void PayloadRouter::ConfigureSsrcs(const RtpConfig& rtp_config) {
+ // Configure regular SSRCs.
+ for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) {
+ uint32_t ssrc = rtp_config.ssrcs[i];
+ RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
+ rtp_rtcp->SetSSRC(ssrc);
+
+ // Restore RTP state if previous existed.
+ auto it = suspended_ssrcs_.find(ssrc);
+ if (it != suspended_ssrcs_.end())
+ rtp_rtcp->SetRtpState(it->second);
+ }
+
+ // Set up RTX if available.
+ if (rtp_config.rtx.ssrcs.empty())
+ return;
+
+ // Configure RTX SSRCs.
+ RTC_DCHECK_EQ(rtp_config.rtx.ssrcs.size(), rtp_config.ssrcs.size());
+ for (size_t i = 0; i < rtp_config.rtx.ssrcs.size(); ++i) {
+ uint32_t ssrc = rtp_config.rtx.ssrcs[i];
+ RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
+ rtp_rtcp->SetRtxSsrc(ssrc);
+ auto it = suspended_ssrcs_.find(ssrc);
+ if (it != suspended_ssrcs_.end())
+ rtp_rtcp->SetRtxState(it->second);
+ }
+
+ // Configure RTX payload types.
+ RTC_DCHECK_GE(rtp_config.rtx.payload_type, 0);
+ for (auto& rtp_rtcp : rtp_modules_) {
+ rtp_rtcp->SetRtxSendPayloadType(rtp_config.rtx.payload_type,
+ rtp_config.payload_type);
+ rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
+ }
+ if (rtp_config.ulpfec.red_payload_type != -1 &&
+ rtp_config.ulpfec.red_rtx_payload_type != -1) {
+ for (auto& rtp_rtcp : rtp_modules_) {
+ rtp_rtcp->SetRtxSendPayloadType(rtp_config.ulpfec.red_rtx_payload_type,
+ rtp_config.ulpfec.red_payload_type);
+ }
+ }
+}
+
+void PayloadRouter::OnNetworkAvailability(bool network_available) {
+ for (auto& rtp_rtcp : rtp_modules_) {
+ rtp_rtcp->SetRTCPStatus(network_available ? rtp_config_.rtcp_mode
+ : RtcpMode::kOff);
+ }
+}
+
+std::map<uint32_t, RtpState> PayloadRouter::GetRtpStates() const {
+ std::map<uint32_t, RtpState> rtp_states;
+
+ for (size_t i = 0; i < rtp_config_.ssrcs.size(); ++i) {
+ uint32_t ssrc = rtp_config_.ssrcs[i];
+ RTC_DCHECK_EQ(ssrc, rtp_modules_[i]->SSRC());
+ rtp_states[ssrc] = rtp_modules_[i]->GetRtpState();
+ }
+
+ for (size_t i = 0; i < rtp_config_.rtx.ssrcs.size(); ++i) {
+ uint32_t ssrc = rtp_config_.rtx.ssrcs[i];
+ rtp_states[ssrc] = rtp_modules_[i]->GetRtxState();
+ }
+
+ if (flexfec_sender_) {
+ uint32_t ssrc = rtp_config_.flexfec.ssrc;
+ rtp_states[ssrc] = flexfec_sender_->GetRtpState();
+ }
+
+ return rtp_states;
+}
+
+std::map<uint32_t, RtpPayloadState> PayloadRouter::GetRtpPayloadStates() const {
+ rtc::CritScope lock(&crit_);
+ std::map<uint32_t, RtpPayloadState> payload_states;
+ for (const auto& param : params_) {
+ payload_states[param.ssrc()] = param.state();
+ }
+ return payload_states;
+}
} // namespace webrtc
diff --git a/call/payload_router.h b/call/payload_router.h
index c62bc75..cb43f27 100644
--- a/call/payload_router.h
+++ b/call/payload_router.h
@@ -12,41 +12,83 @@
#define CALL_PAYLOAD_ROUTER_H_
#include <map>
+#include <memory>
#include <vector>
+#include "api/call/transport.h"
#include "api/video_codecs/video_encoder.h"
+#include "call/rtp_config.h"
#include "call/rtp_payload_params.h"
+#include "call/rtp_transport_controller_send_interface.h"
+#include "call/video_rtp_sender_interface.h"
#include "common_types.h" // NOLINT(build/include)
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "modules/rtp_rtcp/include/flexfec_sender.h"
#include "modules/rtp_rtcp/source/rtp_video_header.h"
+#include "modules/utility/include/process_thread.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/criticalsection.h"
+#include "rtc_base/rate_limiter.h"
#include "rtc_base/thread_annotations.h"
+#include "rtc_base/thread_checker.h"
namespace webrtc {
class RTPFragmentationHeader;
class RtpRtcp;
+class RtpTransportControllerSendInterface;
// PayloadRouter routes outgoing data to the correct sending RTP module, based
// on the simulcast layer in RTPVideoHeader.
-class PayloadRouter : public EncodedImageCallback {
+class PayloadRouter : public VideoRtpSenderInterface {
public:
// Rtp modules are assumed to be sorted in simulcast index order.
- PayloadRouter(const std::vector<RtpRtcp*>& rtp_modules,
- const std::vector<uint32_t>& ssrcs,
- int payload_type,
- const std::map<uint32_t, RtpPayloadState>& states);
+ PayloadRouter(
+ const std::vector<uint32_t>& ssrcs,
+ std::map<uint32_t, RtpState> suspended_ssrcs,
+ const std::map<uint32_t, RtpPayloadState>& states,
+ const RtpConfig& rtp_config,
+ const RtcpConfig& rtcp_config,
+ Transport* send_transport,
+ const RtpSenderObservers& observers,
+ RtpTransportControllerSendInterface* transport,
+ RtcEventLog* event_log,
+ RateLimiter* retransmission_limiter); // move inside RtpTransport
~PayloadRouter() override;
+ // RegisterProcessThread register |module_process_thread| with those objects
+ // that use it. Registration has to happen on the thread were
+ // |module_process_thread| was created (libjingle's worker thread).
+ // TODO(perkj): Replace the use of |module_process_thread| with a TaskQueue,
+ // maybe |worker_queue|.
+ void RegisterProcessThread(ProcessThread* module_process_thread) override;
+ void DeRegisterProcessThread() override;
+
// PayloadRouter will only route packets if being active, all packets will be
// dropped otherwise.
- void SetActive(bool active);
+ void SetActive(bool active) override;
// Sets the sending status of the rtp modules and appropriately sets the
// payload router to active if any rtp modules are active.
- void SetActiveModules(const std::vector<bool> active_modules);
- bool IsActive();
+ void SetActiveModules(const std::vector<bool> active_modules) override;
+ bool IsActive() override;
- std::map<uint32_t, RtpPayloadState> GetRtpPayloadStates() const;
+ void OnNetworkAvailability(bool network_available) override;
+ std::map<uint32_t, RtpState> GetRtpStates() const override;
+ std::map<uint32_t, RtpPayloadState> GetRtpPayloadStates() const override;
+
+ bool FecEnabled() const override;
+
+ bool NackEnabled() const override;
+
+ void DeliverRtcp(const uint8_t* packet, size_t length) override;
+
+ void ProtectionRequest(const FecProtectionParams* delta_params,
+ const FecProtectionParams* key_params,
+ uint32_t* sent_video_rate_bps,
+ uint32_t* sent_nack_rate_bps,
+ uint32_t* sent_fec_rate_bps) override;
+
+ void SetMaxRtpPacketSize(size_t max_rtp_packet_size) override;
// Implements EncodedImageCallback.
// Returns 0 if the packet was routed / sent, -1 otherwise.
@@ -55,17 +97,26 @@
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) override;
- void OnBitrateAllocationUpdated(const VideoBitrateAllocation& bitrate);
+ void OnBitrateAllocationUpdated(
+ const VideoBitrateAllocation& bitrate) override;
private:
void UpdateModuleSendingState() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
+ void ConfigureProtection(const RtpConfig& rtp_config);
+ void ConfigureSsrcs(const RtpConfig& rtp_config);
rtc::CriticalSection crit_;
bool active_ RTC_GUARDED_BY(crit_);
+ ProcessThread* module_process_thread_;
+ rtc::ThreadChecker module_process_thread_checker_;
+ std::map<uint32_t, RtpState> suspended_ssrcs_;
+
+ std::unique_ptr<FlexfecSender> flexfec_sender_;
// Rtp modules are assumed to be sorted in simulcast index order. Not owned.
- const std::vector<RtpRtcp*> rtp_modules_;
- const int payload_type_;
+ const std::vector<std::unique_ptr<RtpRtcp>> rtp_modules_;
+ const RtpConfig rtp_config_;
+ RtpTransportControllerSendInterface* const transport_;
std::vector<RtpPayloadParams> params_ RTC_GUARDED_BY(crit_);
diff --git a/call/payload_router_unittest.cc b/call/payload_router_unittest.cc
index 9c3e1de..c02bad9 100644
--- a/call/payload_router_unittest.cc
+++ b/call/payload_router_unittest.cc
@@ -12,12 +12,16 @@
#include <string>
#include "call/payload_router.h"
-#include "modules/rtp_rtcp/include/rtp_rtcp.h"
-#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "call/rtp_transport_controller_send.h"
#include "modules/video_coding/include/video_codec_interface.h"
+#include "rtc_base/rate_limiter.h"
#include "test/field_trial.h"
#include "test/gmock.h"
#include "test/gtest.h"
+#include "test/mock_transport.h"
+#include "video/call_stats.h"
+#include "video/send_delay_stats.h"
+#include "video/send_statistics_proxy.h"
using ::testing::_;
using ::testing::AnyNumber;
@@ -35,12 +39,105 @@
const int16_t kInitialPictureId2 = 44;
const int16_t kInitialTl0PicIdx1 = 99;
const int16_t kInitialTl0PicIdx2 = 199;
+const int64_t kRetransmitWindowSizeMs = 500;
+
+class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver {
+ public:
+ MOCK_METHOD1(OnReceivedIntraFrameRequest, void(uint32_t));
+};
+
+class MockOverheadObserver : public OverheadObserver {
+ public:
+ MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet));
+};
+
+class MockCongestionObserver : public NetworkChangedObserver {
+ public:
+ MOCK_METHOD4(OnNetworkChanged,
+ void(uint32_t bitrate_bps,
+ uint8_t fraction_loss,
+ int64_t rtt_ms,
+ int64_t probing_interval_ms));
+};
+
+RtpSenderObservers CreateObservers(
+ RtcpRttStats* rtcp_rtt_stats,
+ RtcpIntraFrameObserver* intra_frame_callback,
+ RtcpStatisticsCallback* rtcp_stats,
+ StreamDataCountersCallback* rtp_stats,
+ BitrateStatisticsObserver* bitrate_observer,
+ FrameCountObserver* frame_count_observer,
+ RtcpPacketTypeCounterObserver* rtcp_type_observer,
+ SendSideDelayObserver* send_delay_observer,
+ SendPacketObserver* send_packet_observer,
+ OverheadObserver* overhead_observer) {
+ RtpSenderObservers observers;
+ observers.rtcp_rtt_stats = rtcp_rtt_stats;
+ observers.intra_frame_callback = intra_frame_callback;
+ observers.rtcp_stats = rtcp_stats;
+ observers.rtp_stats = rtp_stats;
+ observers.bitrate_observer = bitrate_observer;
+ observers.frame_count_observer = frame_count_observer;
+ observers.rtcp_type_observer = rtcp_type_observer;
+ observers.send_delay_observer = send_delay_observer;
+ observers.send_packet_observer = send_packet_observer;
+ observers.overhead_observer = overhead_observer;
+ return observers;
+}
+
+class PayloadRouterTestFixture {
+ public:
+ PayloadRouterTestFixture(
+ const std::vector<uint32_t>& ssrcs,
+ int payload_type,
+ const std::map<uint32_t, RtpPayloadState>& suspended_payload_states)
+ : clock_(0),
+ config_(&transport_),
+ send_delay_stats_(&clock_),
+ transport_controller_(&clock_, &event_log_, nullptr, bitrate_config_),
+ process_thread_(ProcessThread::Create("test_thread")),
+ call_stats_(&clock_, process_thread_.get()),
+ stats_proxy_(&clock_,
+ config_,
+ VideoEncoderConfig::ContentType::kRealtimeVideo),
+ retransmission_rate_limiter_(&clock_, kRetransmitWindowSizeMs) {
+ for (uint32_t ssrc : ssrcs) {
+ config_.rtp.ssrcs.push_back(ssrc);
+ }
+ config_.rtp.payload_type = payload_type;
+ std::map<uint32_t, RtpState> suspended_ssrcs;
+ router_ = absl::make_unique<PayloadRouter>(
+ config_.rtp.ssrcs, suspended_ssrcs, suspended_payload_states,
+ config_.rtp, config_.rtcp, &transport_,
+ CreateObservers(&call_stats_, &encoder_feedback_, &stats_proxy_,
+ &stats_proxy_, &stats_proxy_, &stats_proxy_,
+ &stats_proxy_, &stats_proxy_, &send_delay_stats_,
+ &overhead_observer_),
+ &transport_controller_, &event_log_, &retransmission_rate_limiter_);
+ }
+
+ PayloadRouter* router() { return router_.get(); }
+
+ private:
+ NiceMock<MockTransport> transport_;
+ NiceMock<MockCongestionObserver> congestion_observer_;
+ NiceMock<MockOverheadObserver> overhead_observer_;
+ NiceMock<MockRtcpIntraFrameObserver> encoder_feedback_;
+ SimulatedClock clock_;
+ RtcEventLogNullImpl event_log_;
+ VideoSendStream::Config config_;
+ SendDelayStats send_delay_stats_;
+ BitrateConstraints bitrate_config_;
+ RtpTransportControllerSend transport_controller_;
+ std::unique_ptr<ProcessThread> process_thread_;
+ CallStats call_stats_;
+ SendStatisticsProxy stats_proxy_;
+ RateLimiter retransmission_rate_limiter_;
+ std::unique_ptr<PayloadRouter> router_;
+};
} // namespace
TEST(PayloadRouterTest, SendOnOneModule) {
- NiceMock<MockRtpRtcp> rtp;
- std::vector<RtpRtcp*> modules(1, &rtp);
-
uint8_t payload = 'a';
EncodedImage encoded_image;
encoded_image._timeStamp = 1;
@@ -49,57 +146,28 @@
encoded_image._buffer = &payload;
encoded_image._length = 1;
- PayloadRouter payload_router(modules, {kSsrc1}, kPayloadType, {});
-
- EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(0);
+ PayloadRouterTestFixture test({kSsrc1}, kPayloadType, {});
EXPECT_NE(
EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, nullptr, nullptr).error);
+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
- payload_router.SetActive(true);
- EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(rtp, Sending()).WillOnce(Return(true));
+ test.router()->SetActive(true);
EXPECT_EQ(
EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, nullptr, nullptr).error);
+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
- payload_router.SetActive(false);
- EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(0);
+ test.router()->SetActive(false);
EXPECT_NE(
EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, nullptr, nullptr).error);
+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
- payload_router.SetActive(true);
- EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(rtp, Sending()).WillOnce(Return(true));
+ test.router()->SetActive(true);
EXPECT_EQ(
EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, nullptr, nullptr).error);
+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
}
TEST(PayloadRouterTest, SendSimulcastSetActive) {
- NiceMock<MockRtpRtcp> rtp_1;
- NiceMock<MockRtpRtcp> rtp_2;
- std::vector<RtpRtcp*> modules = {&rtp_1, &rtp_2};
-
uint8_t payload = 'a';
EncodedImage encoded_image;
encoded_image._timeStamp = 1;
@@ -108,64 +176,45 @@
encoded_image._buffer = &payload;
encoded_image._length = 1;
- PayloadRouter payload_router(modules, {kSsrc1, kSsrc2}, kPayloadType, {});
+ PayloadRouterTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {});
CodecSpecificInfo codec_info_1;
memset(&codec_info_1, 0, sizeof(CodecSpecificInfo));
codec_info_1.codecType = kVideoCodecVP8;
codec_info_1.codecSpecific.VP8.simulcastIdx = 0;
- payload_router.SetActive(true);
- EXPECT_CALL(rtp_1, Sending()).WillOnce(Return(true));
- EXPECT_CALL(rtp_1, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _, _)).Times(0);
+ test.router()->SetActive(true);
EXPECT_EQ(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_1, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr)
.error);
CodecSpecificInfo codec_info_2;
memset(&codec_info_2, 0, sizeof(CodecSpecificInfo));
codec_info_2.codecType = kVideoCodecVP8;
codec_info_2.codecSpecific.VP8.simulcastIdx = 1;
-
- EXPECT_CALL(rtp_2, Sending()).WillOnce(Return(true));
- EXPECT_CALL(rtp_2, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(1)
- .WillOnce(Return(true));
- EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _, _)).Times(0);
EXPECT_EQ(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_2, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_2, nullptr)
.error);
// Inactive.
- payload_router.SetActive(false);
- EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _, _)).Times(0);
- EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _, _)).Times(0);
+ test.router()->SetActive(false);
EXPECT_NE(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_1, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr)
.error);
EXPECT_NE(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_2, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_2, nullptr)
.error);
}
// Tests how setting individual rtp modules to active affects the overall
// behavior of the payload router. First sets one module to active and checks
-// that outgoing data can be sent on this module, and checks that no data can be
-// sent if both modules are inactive.
+// that outgoing data can be sent on this module, and checks that no data can
+// be sent if both modules are inactive.
TEST(PayloadRouterTest, SendSimulcastSetActiveModules) {
- NiceMock<MockRtpRtcp> rtp_1;
- NiceMock<MockRtpRtcp> rtp_2;
- std::vector<RtpRtcp*> modules = {&rtp_1, &rtp_2};
-
uint8_t payload = 'a';
EncodedImage encoded_image;
encoded_image._timeStamp = 1;
@@ -173,7 +222,8 @@
encoded_image._frameType = kVideoFrameKey;
encoded_image._buffer = &payload;
encoded_image._length = 1;
- PayloadRouter payload_router(modules, {kSsrc1, kSsrc2}, kPayloadType, {});
+
+ PayloadRouterTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {});
CodecSpecificInfo codec_info_1;
memset(&codec_info_1, 0, sizeof(CodecSpecificInfo));
codec_info_1.codecType = kVideoCodecVP8;
@@ -186,45 +236,34 @@
// Only setting one stream to active will still set the payload router to
// active and allow sending data on the active stream.
std::vector<bool> active_modules({true, false});
- payload_router.SetActiveModules(active_modules);
-
- EXPECT_CALL(rtp_1, Sending()).WillOnce(Return(true));
- EXPECT_CALL(rtp_1, SendOutgoingData(encoded_image._frameType, kPayloadType,
- encoded_image._timeStamp,
- encoded_image.capture_time_ms_, &payload,
- encoded_image._length, nullptr, _, _))
- .Times(1)
- .WillOnce(Return(true));
+ test.router()->SetActiveModules(active_modules);
EXPECT_EQ(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_1, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr)
.error);
- // Setting both streams to inactive will turn the payload router to inactive.
+ // Setting both streams to inactive will turn the payload router to
+ // inactive.
active_modules = {false, false};
- payload_router.SetActiveModules(active_modules);
+ test.router()->SetActiveModules(active_modules);
// An incoming encoded image will not ask the module to send outgoing data
// because the payload router is inactive.
- EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _, _)).Times(0);
- EXPECT_CALL(rtp_1, Sending()).Times(0);
- EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _, _)).Times(0);
- EXPECT_CALL(rtp_2, Sending()).Times(0);
EXPECT_NE(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_1, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr)
.error);
EXPECT_NE(EncodedImageCallback::Result::OK,
- payload_router.OnEncodedImage(encoded_image, &codec_info_2, nullptr)
+ test.router()
+ ->OnEncodedImage(encoded_image, &codec_info_2, nullptr)
.error);
}
TEST(PayloadRouterTest, CreateWithNoPreviousStates) {
- NiceMock<MockRtpRtcp> rtp1;
- NiceMock<MockRtpRtcp> rtp2;
- std::vector<RtpRtcp*> modules = {&rtp1, &rtp2};
- PayloadRouter payload_router(modules, {kSsrc1, kSsrc2}, kPayloadType, {});
- payload_router.SetActive(true);
+ PayloadRouterTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {});
+ test.router()->SetActive(true);
std::map<uint32_t, RtpPayloadState> initial_states =
- payload_router.GetRtpPayloadStates();
+ test.router()->GetRtpPayloadStates();
EXPECT_EQ(2u, initial_states.size());
EXPECT_NE(initial_states.find(kSsrc1), initial_states.end());
EXPECT_NE(initial_states.find(kSsrc2), initial_states.end());
@@ -240,14 +279,11 @@
std::map<uint32_t, RtpPayloadState> states = {{kSsrc1, state1},
{kSsrc2, state2}};
- NiceMock<MockRtpRtcp> rtp1;
- NiceMock<MockRtpRtcp> rtp2;
- std::vector<RtpRtcp*> modules = {&rtp1, &rtp2};
- PayloadRouter payload_router(modules, {kSsrc1, kSsrc2}, kPayloadType, states);
- payload_router.SetActive(true);
+ PayloadRouterTestFixture test({kSsrc1, kSsrc2}, kPayloadType, states);
+ test.router()->SetActive(true);
std::map<uint32_t, RtpPayloadState> initial_states =
- payload_router.GetRtpPayloadStates();
+ test.router()->GetRtpPayloadStates();
EXPECT_EQ(2u, initial_states.size());
EXPECT_EQ(kInitialPictureId1, initial_states[kSsrc1].picture_id);
EXPECT_EQ(kInitialTl0PicIdx1, initial_states[kSsrc1].tl0_pic_idx);
diff --git a/call/rtp_config.cc b/call/rtp_config.cc
index 71322f9..1445c25 100644
--- a/call/rtp_config.cc
+++ b/call/rtp_config.cc
@@ -9,6 +9,7 @@
*/
#include "call/rtp_config.h"
+
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
@@ -36,4 +37,89 @@
red_payload_type == other.red_payload_type &&
red_rtx_payload_type == other.red_rtx_payload_type;
}
+
+RtpConfig::RtpConfig() = default;
+RtpConfig::RtpConfig(const RtpConfig&) = default;
+RtpConfig::~RtpConfig() = default;
+
+RtpConfig::Flexfec::Flexfec() = default;
+RtpConfig::Flexfec::Flexfec(const Flexfec&) = default;
+RtpConfig::Flexfec::~Flexfec() = default;
+
+std::string RtpConfig::ToString() const {
+ char buf[2 * 1024];
+ rtc::SimpleStringBuilder ss(buf);
+ ss << "{ssrcs: [";
+ for (size_t i = 0; i < ssrcs.size(); ++i) {
+ ss << ssrcs[i];
+ if (i != ssrcs.size() - 1)
+ ss << ", ";
+ }
+ ss << ']';
+ ss << ", rtcp_mode: "
+ << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound"
+ : "RtcpMode::kReducedSize");
+ ss << ", max_packet_size: " << max_packet_size;
+ ss << ", extensions: [";
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ ss << extensions[i].ToString();
+ if (i != extensions.size() - 1)
+ ss << ", ";
+ }
+ ss << ']';
+
+ ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
+ ss << ", ulpfec: " << ulpfec.ToString();
+ ss << ", payload_name: " << payload_name;
+ ss << ", payload_type: " << payload_type;
+
+ ss << ", flexfec: {payload_type: " << flexfec.payload_type;
+ ss << ", ssrc: " << flexfec.ssrc;
+ ss << ", protected_media_ssrcs: [";
+ for (size_t i = 0; i < flexfec.protected_media_ssrcs.size(); ++i) {
+ ss << flexfec.protected_media_ssrcs[i];
+ if (i != flexfec.protected_media_ssrcs.size() - 1)
+ ss << ", ";
+ }
+ ss << "]}";
+
+ ss << ", rtx: " << rtx.ToString();
+ ss << ", c_name: " << c_name;
+ ss << '}';
+ return ss.str();
+}
+
+RtpConfig::Rtx::Rtx() = default;
+RtpConfig::Rtx::Rtx(const Rtx&) = default;
+RtpConfig::Rtx::~Rtx() = default;
+
+std::string RtpConfig::Rtx::ToString() const {
+ char buf[1024];
+ rtc::SimpleStringBuilder ss(buf);
+ ss << "{ssrcs: [";
+ for (size_t i = 0; i < ssrcs.size(); ++i) {
+ ss << ssrcs[i];
+ if (i != ssrcs.size() - 1)
+ ss << ", ";
+ }
+ ss << ']';
+
+ ss << ", payload_type: " << payload_type;
+ ss << '}';
+ return ss.str();
+}
+
+RtcpConfig::RtcpConfig() = default;
+RtcpConfig::RtcpConfig(const RtcpConfig&) = default;
+RtcpConfig::~RtcpConfig() = default;
+
+std::string RtcpConfig::ToString() const {
+ char buf[1024];
+ rtc::SimpleStringBuilder ss(buf);
+ ss << "{video_report_interval_ms: " << video_report_interval_ms;
+ ss << ", audio_report_interval_ms: " << audio_report_interval_ms;
+ ss << '}';
+ return ss.str();
+}
+
} // namespace webrtc
diff --git a/call/rtp_config.h b/call/rtp_config.h
index 86d32ac..96fe15f 100644
--- a/call/rtp_config.h
+++ b/call/rtp_config.h
@@ -12,8 +12,17 @@
#define CALL_RTP_CONFIG_H_
#include <string>
+#include <vector>
+
+#include "api/rtp_headers.h"
+#include "api/rtpparameters.h"
namespace webrtc {
+// Currently only VP8/VP9 specific.
+struct RtpPayloadState {
+ int16_t picture_id = -1;
+ uint8_t tl0_pic_idx = 0;
+};
// Settings for NACK, see RFC 4585 for details.
struct NackConfig {
NackConfig() : rtp_history_ms(0) {}
@@ -44,5 +53,92 @@
// RTX payload type for RED payload.
int red_rtx_payload_type;
};
+
+static const size_t kDefaultMaxPacketSize = 1500 - 40; // TCP over IPv4.
+struct RtpConfig {
+ RtpConfig();
+ RtpConfig(const RtpConfig&);
+ ~RtpConfig();
+ std::string ToString() const;
+
+ std::vector<uint32_t> ssrcs;
+
+ // The value to send in the MID RTP header extension if the extension is
+ // included in the list of extensions.
+ std::string mid;
+
+ // See RtcpMode for description.
+ RtcpMode rtcp_mode = RtcpMode::kCompound;
+
+ // Max RTP packet size delivered to send transport from VideoEngine.
+ size_t max_packet_size = kDefaultMaxPacketSize;
+
+ // RTP header extensions to use for this send stream.
+ std::vector<RtpExtension> extensions;
+
+ // TODO(nisse): For now, these are fixed, but we'd like to support
+ // changing codec without recreating the VideoSendStream. Then these
+ // fields must be removed, and association between payload type and codec
+ // must move above the per-stream level. Ownership could be with
+ // RtpTransportControllerSend, with a reference from PayloadRouter, where
+ // the latter would be responsible for mapping the codec type of encoded
+ // images to the right payload type.
+ std::string payload_name;
+ int payload_type = -1;
+
+ // See NackConfig for description.
+ NackConfig nack;
+
+ // See UlpfecConfig for description.
+ UlpfecConfig ulpfec;
+
+ struct Flexfec {
+ Flexfec();
+ Flexfec(const Flexfec&);
+ ~Flexfec();
+ // Payload type of FlexFEC. Set to -1 to disable sending FlexFEC.
+ int payload_type = -1;
+
+ // SSRC of FlexFEC stream.
+ uint32_t ssrc = 0;
+
+ // Vector containing a single element, corresponding to the SSRC of the
+ // media stream being protected by this FlexFEC stream.
+ // The vector MUST have size 1.
+ //
+ // TODO(brandtr): Update comment above when we support
+ // multistream protection.
+ std::vector<uint32_t> protected_media_ssrcs;
+ } flexfec;
+
+ // Settings for RTP retransmission payload format, see RFC 4588 for
+ // details.
+ struct Rtx {
+ Rtx();
+ Rtx(const Rtx&);
+ ~Rtx();
+ std::string ToString() const;
+ // SSRCs to use for the RTX streams.
+ std::vector<uint32_t> ssrcs;
+
+ // Payload type to use for the RTX stream.
+ int payload_type = -1;
+ } rtx;
+
+ // RTCP CNAME, see RFC 3550.
+ std::string c_name;
+};
+
+struct RtcpConfig {
+ RtcpConfig();
+ RtcpConfig(const RtcpConfig&);
+ ~RtcpConfig();
+ std::string ToString() const;
+
+ // Time interval between RTCP report for video
+ int64_t video_report_interval_ms = 1000;
+ // Time interval between RTCP report for audio
+ int64_t audio_report_interval_ms = 5000;
+};
} // namespace webrtc
#endif // CALL_RTP_CONFIG_H_
diff --git a/call/rtp_payload_params.h b/call/rtp_payload_params.h
index b85fb42..0c71a7b 100644
--- a/call/rtp_payload_params.h
+++ b/call/rtp_payload_params.h
@@ -15,6 +15,7 @@
#include <vector>
#include "api/video_codecs/video_encoder.h"
+#include "call/rtp_config.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/source/rtp_video_header.h"
@@ -23,12 +24,6 @@
class RTPFragmentationHeader;
class RtpRtcp;
-// Currently only VP8/VP9 specific.
-struct RtpPayloadState {
- int16_t picture_id = -1;
- uint8_t tl0_pic_idx = 0;
-};
-
// State for setting picture id and tl0 pic idx, for VP8 and VP9
// TODO(nisse): Make these properties not codec specific.
class RtpPayloadParams final {
diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc
index e2b8a5e..10b39e5 100644
--- a/call/rtp_transport_controller_send.cc
+++ b/call/rtp_transport_controller_send.cc
@@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <utility>
+#include <vector>
#include "absl/memory/memory.h"
#include "call/rtp_transport_controller_send.h"
@@ -15,10 +16,12 @@
#include "modules/congestion_controller/rtp/include/send_side_congestion_controller.h"
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
+#include "rtc_base/rate_limiter.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
+static const int64_t kRetransmitWindowSizeMs = 500;
const char kTaskQueueExperiment[] = "WebRTC-TaskQueueCongestionControl";
using TaskQueueController = webrtc::webrtc_cc::SendSideCongestionController;
@@ -63,6 +66,7 @@
bitrate_configurator_(bitrate_config),
process_thread_(ProcessThread::Create("SendControllerThread")),
observer_(nullptr),
+ retransmission_rate_limiter_(clock, kRetransmitWindowSizeMs),
task_queue_("rtp_send_controller") {
// Created after task_queue to be able to post to the task queue internally.
send_side_cc_ =
@@ -80,6 +84,24 @@
process_thread_->DeRegisterModule(&pacer_);
}
+PayloadRouter* RtpTransportControllerSend::CreateVideoRtpSender(
+ const std::vector<uint32_t>& ssrcs,
+ std::map<uint32_t, RtpState> suspended_ssrcs,
+ const std::map<uint32_t, RtpPayloadState>& states,
+ const RtpConfig& rtp_config,
+ const RtcpConfig& rtcp_config,
+ Transport* send_transport,
+ const RtpSenderObservers& observers,
+ RtcEventLog* event_log) {
+ video_rtp_senders_.push_back(absl::make_unique<PayloadRouter>(
+ ssrcs, suspended_ssrcs, states, rtp_config, rtcp_config, send_transport,
+ observers,
+ // TODO(holmer): Remove this circular dependency by injecting
+ // the parts of RtpTransportControllerSendInterface that are really used.
+ this, event_log, &retransmission_rate_limiter_));
+ return video_rtp_senders_.back().get();
+}
+
void RtpTransportControllerSend::OnNetworkChanged(uint32_t bitrate_bps,
uint8_t fraction_loss,
int64_t rtt_ms,
@@ -97,16 +119,18 @@
msg.network_estimate.loss_rate_ratio = fraction_loss / 255.0;
msg.network_estimate.round_trip_time = TimeDelta::ms(rtt_ms);
+ retransmission_rate_limiter_.SetMaxRate(bandwidth_bps);
+
if (!task_queue_.IsCurrent()) {
task_queue_.PostTask([this, msg] {
rtc::CritScope cs(&observer_crit_);
- // We won't register as observer until we have an observer.
+ // We won't register as observer until we have an observers.
RTC_DCHECK(observer_ != nullptr);
observer_->OnTargetTransferRate(msg);
});
} else {
rtc::CritScope cs(&observer_crit_);
- // We won't register as observer until we have an observer.
+ // We won't register as observer until we have an observers.
RTC_DCHECK(observer_ != nullptr);
observer_->OnTargetTransferRate(msg);
}
@@ -214,6 +238,9 @@
void RtpTransportControllerSend::OnNetworkAvailability(bool network_available) {
send_side_cc_->SignalNetworkState(network_available ? kNetworkUp
: kNetworkDown);
+ for (auto& rtp_sender : video_rtp_senders_) {
+ rtp_sender->OnNetworkAvailability(network_available);
+ }
}
RtcpBandwidthObserver* RtpTransportControllerSend::GetBandwidthObserver() {
return send_side_cc_->GetBandwidthObserver();
diff --git a/call/rtp_transport_controller_send.h b/call/rtp_transport_controller_send.h
index d9a4e18..ce7ee1e 100644
--- a/call/rtp_transport_controller_send.h
+++ b/call/rtp_transport_controller_send.h
@@ -14,8 +14,10 @@
#include <map>
#include <memory>
#include <string>
+#include <vector>
#include "api/transport/network_control.h"
+#include "call/payload_router.h"
#include "call/rtp_bitrate_configurator.h"
#include "call/rtp_transport_controller_send_interface.h"
#include "common_types.h" // NOLINT(build/include)
@@ -44,6 +46,17 @@
const BitrateConstraints& bitrate_config);
~RtpTransportControllerSend() override;
+ PayloadRouter* CreateVideoRtpSender(
+ const std::vector<uint32_t>& ssrcs,
+ std::map<uint32_t, RtpState> suspended_ssrcs,
+ const std::map<uint32_t, RtpPayloadState>&
+ states, // move states into RtpTransportControllerSend
+ const RtpConfig& rtp_config,
+ const RtcpConfig& rtcp_config,
+ Transport* send_transport,
+ const RtpSenderObservers& observers,
+ RtcEventLog* event_log) override;
+
// Implements NetworkChangedObserver interface.
void OnNetworkChanged(uint32_t bitrate_bps,
uint8_t fraction_loss,
@@ -90,6 +103,7 @@
private:
const Clock* const clock_;
PacketRouter packet_router_;
+ std::vector<std::unique_ptr<PayloadRouter>> video_rtp_senders_;
PacedSender pacer_;
RtpKeepAliveConfig keepalive_;
RtpBitrateConfigurator bitrate_configurator_;
@@ -98,6 +112,8 @@
rtc::CriticalSection observer_crit_;
TargetTransferRateObserver* observer_ RTC_GUARDED_BY(observer_crit_);
std::unique_ptr<SendSideCongestionControllerInterface> send_side_cc_;
+ RateLimiter retransmission_rate_limiter_;
+
// TODO(perkj): |task_queue_| is supposed to replace |process_thread_|.
// |task_queue_| is defined last to ensure all pending tasks are cancelled
// and deleted before any other members.
diff --git a/call/rtp_transport_controller_send_interface.h b/call/rtp_transport_controller_send_interface.h
index c3a56ad..e954b02 100644
--- a/call/rtp_transport_controller_send_interface.h
+++ b/call/rtp_transport_controller_send_interface.h
@@ -13,11 +13,16 @@
#include <stddef.h>
#include <stdint.h>
+#include <map>
#include <string>
+#include <vector>
#include "absl/types/optional.h"
#include "api/bitrate_constraints.h"
#include "api/transport/bitrate_settings.h"
+#include "call/rtp_config.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace rtc {
struct SentPacket;
@@ -26,18 +31,36 @@
} // namespace rtc
namespace webrtc {
+class CallStats;
class CallStatsObserver;
class TargetTransferRateObserver;
+class Transport;
class Module;
class PacedSender;
class PacketFeedbackObserver;
class PacketRouter;
+class VideoRtpSenderInterface;
class RateLimiter;
class RtcpBandwidthObserver;
class RtpPacketSender;
struct RtpKeepAliveConfig;
+class SendDelayStats;
+class SendStatisticsProxy;
class TransportFeedbackObserver;
+struct RtpSenderObservers {
+ RtcpRttStats* rtcp_rtt_stats;
+ RtcpIntraFrameObserver* intra_frame_callback;
+ RtcpStatisticsCallback* rtcp_stats;
+ StreamDataCountersCallback* rtp_stats;
+ BitrateStatisticsObserver* bitrate_observer;
+ FrameCountObserver* frame_count_observer;
+ RtcpPacketTypeCounterObserver* rtcp_type_observer;
+ SendSideDelayObserver* send_delay_observer;
+ SendPacketObserver* send_packet_observer;
+ OverheadObserver* overhead_observer;
+};
+
// An RtpTransportController should own everything related to the RTP
// transport to/from a remote endpoint. We should have separate
// interfaces for send and receive side, even if they are implemented
@@ -66,6 +89,18 @@
virtual ~RtpTransportControllerSendInterface() {}
virtual rtc::TaskQueue* GetWorkerQueue() = 0;
virtual PacketRouter* packet_router() = 0;
+
+ virtual VideoRtpSenderInterface* CreateVideoRtpSender(
+ const std::vector<uint32_t>& ssrcs,
+ std::map<uint32_t, RtpState> suspended_ssrcs,
+ // TODO(holmer): Move states into RtpTransportControllerSend.
+ const std::map<uint32_t, RtpPayloadState>& states,
+ const RtpConfig& rtp_config,
+ const RtcpConfig& rtcp_config,
+ Transport* send_transport,
+ const RtpSenderObservers& observers,
+ RtcEventLog* event_log) = 0;
+
virtual TransportFeedbackObserver* transport_feedback_observer() = 0;
virtual RtpPacketSender* packet_sender() = 0;
diff --git a/call/test/mock_rtp_transport_controller_send.h b/call/test/mock_rtp_transport_controller_send.h
index 419ad77..d184e69 100644
--- a/call/test/mock_rtp_transport_controller_send.h
+++ b/call/test/mock_rtp_transport_controller_send.h
@@ -11,7 +11,9 @@
#ifndef CALL_TEST_MOCK_RTP_TRANSPORT_CONTROLLER_SEND_H_
#define CALL_TEST_MOCK_RTP_TRANSPORT_CONTROLLER_SEND_H_
+#include <map>
#include <string>
+#include <vector>
#include "api/bitrate_constraints.h"
#include "call/rtp_transport_controller_send_interface.h"
@@ -27,6 +29,16 @@
class MockRtpTransportControllerSend
: public RtpTransportControllerSendInterface {
public:
+ MOCK_METHOD8(
+ CreateVideoRtpSender,
+ VideoRtpSenderInterface*(const std::vector<uint32_t>&,
+ std::map<uint32_t, RtpState>,
+ const std::map<uint32_t, RtpPayloadState>&,
+ const RtpConfig&,
+ const RtcpConfig&,
+ Transport*,
+ const RtpSenderObservers&,
+ RtcEventLog*));
MOCK_METHOD0(GetWorkerQueue, rtc::TaskQueue*());
MOCK_METHOD0(packet_router, PacketRouter*());
MOCK_METHOD0(transport_feedback_observer, TransportFeedbackObserver*());
diff --git a/call/video_rtp_sender_interface.h b/call/video_rtp_sender_interface.h
new file mode 100644
index 0000000..0d47845
--- /dev/null
+++ b/call/video_rtp_sender_interface.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#ifndef CALL_VIDEO_RTP_SENDER_INTERFACE_H_
+#define CALL_VIDEO_RTP_SENDER_INTERFACE_H_
+
+#include <map>
+#include <vector>
+
+#include "call/rtp_config.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/utility/include/process_thread.h"
+#include "modules/video_coding/include/video_codec_interface.h"
+
+namespace webrtc {
+class VideoBitrateAllocation;
+struct FecProtectionParams;
+
+class VideoRtpSenderInterface : public EncodedImageCallback {
+ public:
+ virtual void RegisterProcessThread(ProcessThread* module_process_thread) = 0;
+ virtual void DeRegisterProcessThread() = 0;
+
+ // PayloadRouter will only route packets if being active, all packets will be
+ // dropped otherwise.
+ virtual void SetActive(bool active) = 0;
+ // Sets the sending status of the rtp modules and appropriately sets the
+ // payload router to active if any rtp modules are active.
+ virtual void SetActiveModules(const std::vector<bool> active_modules) = 0;
+ virtual bool IsActive() = 0;
+
+ virtual void OnNetworkAvailability(bool network_available) = 0;
+ virtual std::map<uint32_t, RtpState> GetRtpStates() const = 0;
+ virtual std::map<uint32_t, RtpPayloadState> GetRtpPayloadStates() const = 0;
+
+ virtual bool FecEnabled() const = 0;
+
+ virtual bool NackEnabled() const = 0;
+
+ virtual void DeliverRtcp(const uint8_t* packet, size_t length) = 0;
+
+ virtual void ProtectionRequest(const FecProtectionParams* delta_params,
+ const FecProtectionParams* key_params,
+ uint32_t* sent_video_rate_bps,
+ uint32_t* sent_nack_rate_bps,
+ uint32_t* sent_fec_rate_bps) = 0;
+
+ virtual void SetMaxRtpPacketSize(size_t max_rtp_packet_size) = 0;
+ virtual void OnBitrateAllocationUpdated(
+ const VideoBitrateAllocation& bitrate) = 0;
+};
+} // namespace webrtc
+#endif // CALL_VIDEO_RTP_SENDER_INTERFACE_H_
diff --git a/call/video_send_stream.cc b/call/video_send_stream.cc
index 9024e3a..bb590fa 100644
--- a/call/video_send_stream.cc
+++ b/call/video_send_stream.cc
@@ -95,89 +95,4 @@
ss << '}';
return ss.str();
}
-
-VideoSendStream::Config::Rtp::Rtp() = default;
-VideoSendStream::Config::Rtp::Rtp(const Rtp&) = default;
-VideoSendStream::Config::Rtp::~Rtp() = default;
-
-VideoSendStream::Config::Rtp::Flexfec::Flexfec() = default;
-VideoSendStream::Config::Rtp::Flexfec::Flexfec(const Flexfec&) = default;
-VideoSendStream::Config::Rtp::Flexfec::~Flexfec() = default;
-
-std::string VideoSendStream::Config::Rtp::ToString() const {
- char buf[2 * 1024];
- rtc::SimpleStringBuilder ss(buf);
- ss << "{ssrcs: [";
- for (size_t i = 0; i < ssrcs.size(); ++i) {
- ss << ssrcs[i];
- if (i != ssrcs.size() - 1)
- ss << ", ";
- }
- ss << ']';
- ss << ", rtcp_mode: "
- << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound"
- : "RtcpMode::kReducedSize");
- ss << ", max_packet_size: " << max_packet_size;
- ss << ", extensions: [";
- for (size_t i = 0; i < extensions.size(); ++i) {
- ss << extensions[i].ToString();
- if (i != extensions.size() - 1)
- ss << ", ";
- }
- ss << ']';
-
- ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}';
- ss << ", ulpfec: " << ulpfec.ToString();
- ss << ", payload_name: " << payload_name;
- ss << ", payload_type: " << payload_type;
-
- ss << ", flexfec: {payload_type: " << flexfec.payload_type;
- ss << ", ssrc: " << flexfec.ssrc;
- ss << ", protected_media_ssrcs: [";
- for (size_t i = 0; i < flexfec.protected_media_ssrcs.size(); ++i) {
- ss << flexfec.protected_media_ssrcs[i];
- if (i != flexfec.protected_media_ssrcs.size() - 1)
- ss << ", ";
- }
- ss << "]}";
-
- ss << ", rtx: " << rtx.ToString();
- ss << ", c_name: " << c_name;
- ss << '}';
- return ss.str();
-}
-
-VideoSendStream::Config::Rtp::Rtx::Rtx() = default;
-VideoSendStream::Config::Rtp::Rtx::Rtx(const Rtx&) = default;
-VideoSendStream::Config::Rtp::Rtx::~Rtx() = default;
-
-std::string VideoSendStream::Config::Rtp::Rtx::ToString() const {
- char buf[1024];
- rtc::SimpleStringBuilder ss(buf);
- ss << "{ssrcs: [";
- for (size_t i = 0; i < ssrcs.size(); ++i) {
- ss << ssrcs[i];
- if (i != ssrcs.size() - 1)
- ss << ", ";
- }
- ss << ']';
-
- ss << ", payload_type: " << payload_type;
- ss << '}';
- return ss.str();
-}
-
-VideoSendStream::Config::Rtcp::Rtcp() = default;
-VideoSendStream::Config::Rtcp::Rtcp(const Rtcp&) = default;
-VideoSendStream::Config::Rtcp::~Rtcp() = default;
-
-std::string VideoSendStream::Config::Rtcp::ToString() const {
- char buf[1024];
- rtc::SimpleStringBuilder ss(buf);
- ss << "{video_report_interval_ms: " << video_report_interval_ms;
- ss << ", audio_report_interval_ms: " << audio_report_interval_ms;
- ss << '}';
- return ss.str();
-}
-
} // namespace webrtc
diff --git a/call/video_send_stream.h b/call/video_send_stream.h
index b5bd199..eada8fe 100644
--- a/call/video_send_stream.h
+++ b/call/video_send_stream.h
@@ -118,92 +118,9 @@
VideoEncoderFactory* encoder_factory = nullptr;
} encoder_settings;
- static const size_t kDefaultMaxPacketSize = 1500 - 40; // TCP over IPv4.
- struct Rtp {
- Rtp();
- Rtp(const Rtp&);
- ~Rtp();
- std::string ToString() const;
+ RtpConfig rtp;
- std::vector<uint32_t> ssrcs;
-
- // The value to send in the MID RTP header extension if the extension is
- // included in the list of extensions.
- std::string mid;
-
- // See RtcpMode for description.
- RtcpMode rtcp_mode = RtcpMode::kCompound;
-
- // Max RTP packet size delivered to send transport from VideoEngine.
- size_t max_packet_size = kDefaultMaxPacketSize;
-
- // RTP header extensions to use for this send stream.
- std::vector<RtpExtension> extensions;
-
- // TODO(nisse): For now, these are fixed, but we'd like to support
- // changing codec without recreating the VideoSendStream. Then these
- // fields must be removed, and association between payload type and codec
- // must move above the per-stream level. Ownership could be with
- // RtpTransportControllerSend, with a reference from PayloadRouter, where
- // the latter would be responsible for mapping the codec type of encoded
- // images to the right payload type.
- std::string payload_name;
- int payload_type = -1;
-
- // See NackConfig for description.
- NackConfig nack;
-
- // See UlpfecConfig for description.
- UlpfecConfig ulpfec;
-
- struct Flexfec {
- Flexfec();
- Flexfec(const Flexfec&);
- ~Flexfec();
- // Payload type of FlexFEC. Set to -1 to disable sending FlexFEC.
- int payload_type = -1;
-
- // SSRC of FlexFEC stream.
- uint32_t ssrc = 0;
-
- // Vector containing a single element, corresponding to the SSRC of the
- // media stream being protected by this FlexFEC stream.
- // The vector MUST have size 1.
- //
- // TODO(brandtr): Update comment above when we support
- // multistream protection.
- std::vector<uint32_t> protected_media_ssrcs;
- } flexfec;
-
- // Settings for RTP retransmission payload format, see RFC 4588 for
- // details.
- struct Rtx {
- Rtx();
- Rtx(const Rtx&);
- ~Rtx();
- std::string ToString() const;
- // SSRCs to use for the RTX streams.
- std::vector<uint32_t> ssrcs;
-
- // Payload type to use for the RTX stream.
- int payload_type = -1;
- } rtx;
-
- // RTCP CNAME, see RFC 3550.
- std::string c_name;
- } rtp;
-
- struct Rtcp {
- Rtcp();
- Rtcp(const Rtcp&);
- ~Rtcp();
- std::string ToString() const;
-
- // Time interval between RTCP report for video
- int64_t video_report_interval_ms = 1000;
- // Time interval between RTCP report for audio
- int64_t audio_report_interval_ms = 5000;
- } rtcp;
+ RtcpConfig rtcp;
// Transport for outgoing packets.
Transport* send_transport = nullptr;