blob: 8c627b498b76d2bb277c2248474b2378743cb135 [file] [log] [blame]
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +00001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Stefan Holmer9416ef82018-07-19 10:34:38 +020011#include "call/rtp_video_sender.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000012
philipel25d31ec2018-08-08 16:33:01 +020013#include <algorithm>
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020014#include <memory>
15#include <string>
16#include <utility>
17
18#include "call/rtp_transport_controller_send_interface.h"
19#include "modules/pacing/packet_router.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/rtp_rtcp/include/rtp_rtcp.h"
21#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020022#include "modules/rtp_rtcp/source/rtp_sender.h"
23#include "modules/utility/include/process_thread.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/video_coding/include/video_codec_interface.h"
25#include "rtc_base/checks.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020026#include "rtc_base/location.h"
27#include "rtc_base/logging.h"
28#include "system_wrappers/include/field_trial.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000029
30namespace webrtc {
31
kjellander02b3d272016-04-20 05:05:54 -070032namespace {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020033static const int kMinSendSidePacketHistorySize = 600;
34
35std::vector<std::unique_ptr<RtpRtcp>> CreateRtpRtcpModules(
36 const std::vector<uint32_t>& ssrcs,
37 const std::vector<uint32_t>& protected_media_ssrcs,
38 const RtcpConfig& rtcp_config,
39 Transport* send_transport,
40 RtcpIntraFrameObserver* intra_frame_callback,
41 RtcpBandwidthObserver* bandwidth_callback,
42 RtpTransportControllerSendInterface* transport,
43 RtcpRttStats* rtt_stats,
44 FlexfecSender* flexfec_sender,
45 BitrateStatisticsObserver* bitrate_observer,
46 FrameCountObserver* frame_count_observer,
47 RtcpPacketTypeCounterObserver* rtcp_type_observer,
48 SendSideDelayObserver* send_delay_observer,
49 SendPacketObserver* send_packet_observer,
50 RtcEventLog* event_log,
51 RateLimiter* retransmission_rate_limiter,
52 OverheadObserver* overhead_observer,
53 RtpKeepAliveConfig keepalive_config) {
54 RTC_DCHECK_GT(ssrcs.size(), 0);
55 RtpRtcp::Configuration configuration;
56 configuration.audio = false;
57 configuration.receiver_only = false;
58 configuration.outgoing_transport = send_transport;
59 configuration.intra_frame_callback = intra_frame_callback;
60 configuration.bandwidth_callback = bandwidth_callback;
61 configuration.transport_feedback_callback =
62 transport->transport_feedback_observer();
63 configuration.rtt_stats = rtt_stats;
64 configuration.rtcp_packet_type_counter_observer = rtcp_type_observer;
65 configuration.paced_sender = transport->packet_sender();
66 configuration.transport_sequence_number_allocator =
67 transport->packet_router();
68 configuration.send_bitrate_observer = bitrate_observer;
69 configuration.send_frame_count_observer = frame_count_observer;
70 configuration.send_side_delay_observer = send_delay_observer;
71 configuration.send_packet_observer = send_packet_observer;
72 configuration.event_log = event_log;
73 configuration.retransmission_rate_limiter = retransmission_rate_limiter;
74 configuration.overhead_observer = overhead_observer;
75 configuration.keepalive_config = keepalive_config;
76 configuration.rtcp_interval_config.video_interval_ms =
77 rtcp_config.video_report_interval_ms;
78 configuration.rtcp_interval_config.audio_interval_ms =
79 rtcp_config.audio_report_interval_ms;
80 std::vector<std::unique_ptr<RtpRtcp>> modules;
81 const std::vector<uint32_t>& flexfec_protected_ssrcs = protected_media_ssrcs;
82 for (uint32_t ssrc : ssrcs) {
83 bool enable_flexfec = flexfec_sender != nullptr &&
84 std::find(flexfec_protected_ssrcs.begin(),
85 flexfec_protected_ssrcs.end(),
86 ssrc) != flexfec_protected_ssrcs.end();
87 configuration.flexfec_sender = enable_flexfec ? flexfec_sender : nullptr;
88 std::unique_ptr<RtpRtcp> rtp_rtcp =
89 std::unique_ptr<RtpRtcp>(RtpRtcp::CreateRtpRtcp(configuration));
90 rtp_rtcp->SetSendingStatus(false);
91 rtp_rtcp->SetSendingMediaStatus(false);
92 rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound);
93 modules.push_back(std::move(rtp_rtcp));
94 }
95 return modules;
96}
97
Stefan Holmerf7044682018-07-17 10:16:41 +020098absl::optional<size_t> GetSimulcastIdx(const CodecSpecificInfo* info) {
99 if (!info)
100 return absl::nullopt;
kjellander02b3d272016-04-20 05:05:54 -0700101 switch (info->codecType) {
Stefan Holmerf7044682018-07-17 10:16:41 +0200102 case kVideoCodecVP8:
103 return absl::optional<size_t>(info->codecSpecific.VP8.simulcastIdx);
JT Teh5daeff92018-07-16 17:17:17 +0000104 case kVideoCodecH264:
Stefan Holmerf7044682018-07-17 10:16:41 +0200105 return absl::optional<size_t>(info->codecSpecific.H264.simulcast_idx);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800106 case kVideoCodecMultiplex:
kjellander02b3d272016-04-20 05:05:54 -0700107 case kVideoCodecGeneric:
Stefan Holmerf7044682018-07-17 10:16:41 +0200108 return absl::optional<size_t>(info->codecSpecific.generic.simulcast_idx);
kjellander02b3d272016-04-20 05:05:54 -0700109 default:
Stefan Holmerf7044682018-07-17 10:16:41 +0200110 return absl::nullopt;
kjellander02b3d272016-04-20 05:05:54 -0700111 }
112}
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200113bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) {
114 const VideoCodecType codecType = PayloadStringToCodecType(payload_name);
115 if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) {
116 return true;
117 }
118 return false;
119}
120
121// TODO(brandtr): Update this function when we support multistream protection.
122std::unique_ptr<FlexfecSender> MaybeCreateFlexfecSender(
123 const RtpConfig& rtp,
124 const std::map<uint32_t, RtpState>& suspended_ssrcs) {
125 if (rtp.flexfec.payload_type < 0) {
126 return nullptr;
127 }
128 RTC_DCHECK_GE(rtp.flexfec.payload_type, 0);
129 RTC_DCHECK_LE(rtp.flexfec.payload_type, 127);
130 if (rtp.flexfec.ssrc == 0) {
131 RTC_LOG(LS_WARNING) << "FlexFEC is enabled, but no FlexFEC SSRC given. "
132 "Therefore disabling FlexFEC.";
133 return nullptr;
134 }
135 if (rtp.flexfec.protected_media_ssrcs.empty()) {
136 RTC_LOG(LS_WARNING)
137 << "FlexFEC is enabled, but no protected media SSRC given. "
138 "Therefore disabling FlexFEC.";
139 return nullptr;
140 }
141
142 if (rtp.flexfec.protected_media_ssrcs.size() > 1) {
143 RTC_LOG(LS_WARNING)
144 << "The supplied FlexfecConfig contained multiple protected "
145 "media streams, but our implementation currently only "
146 "supports protecting a single media stream. "
147 "To avoid confusion, disabling FlexFEC completely.";
148 return nullptr;
149 }
150
151 const RtpState* rtp_state = nullptr;
152 auto it = suspended_ssrcs.find(rtp.flexfec.ssrc);
153 if (it != suspended_ssrcs.end()) {
154 rtp_state = &it->second;
155 }
156
157 RTC_DCHECK_EQ(1U, rtp.flexfec.protected_media_ssrcs.size());
158 return absl::make_unique<FlexfecSender>(
159 rtp.flexfec.payload_type, rtp.flexfec.ssrc,
160 rtp.flexfec.protected_media_ssrcs[0], rtp.mid, rtp.extensions,
161 RTPSender::FecExtensionSizes(), rtp_state, Clock::GetRealTimeClock());
162}
kjellander02b3d272016-04-20 05:05:54 -0700163} // namespace
164
Stefan Holmer9416ef82018-07-19 10:34:38 +0200165RtpVideoSender::RtpVideoSender(
166 const std::vector<uint32_t>& ssrcs,
167 std::map<uint32_t, RtpState> suspended_ssrcs,
168 const std::map<uint32_t, RtpPayloadState>& states,
169 const RtpConfig& rtp_config,
170 const RtcpConfig& rtcp_config,
171 Transport* send_transport,
172 const RtpSenderObservers& observers,
173 RtpTransportControllerSendInterface* transport,
174 RtcEventLog* event_log,
175 RateLimiter* retransmission_limiter)
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200176 : active_(false),
177 module_process_thread_(nullptr),
178 suspended_ssrcs_(std::move(suspended_ssrcs)),
179 flexfec_sender_(MaybeCreateFlexfecSender(rtp_config, suspended_ssrcs_)),
180 rtp_modules_(
181 CreateRtpRtcpModules(ssrcs,
182 rtp_config.flexfec.protected_media_ssrcs,
183 rtcp_config,
184 send_transport,
185 observers.intra_frame_callback,
186 transport->GetBandwidthObserver(),
187 transport,
188 observers.rtcp_rtt_stats,
189 flexfec_sender_.get(),
190 observers.bitrate_observer,
191 observers.frame_count_observer,
192 observers.rtcp_type_observer,
193 observers.send_delay_observer,
194 observers.send_packet_observer,
195 event_log,
196 retransmission_limiter,
197 observers.overhead_observer,
198 transport->keepalive_config())),
199 rtp_config_(rtp_config),
200 transport_(transport) {
201 RTC_DCHECK_EQ(ssrcs.size(), rtp_modules_.size());
202 module_process_thread_checker_.DetachFromThread();
Ã…sa Persson4bece9a2017-10-06 10:04:04 +0200203 // SSRCs are assumed to be sorted in the same order as |rtp_modules|.
204 for (uint32_t ssrc : ssrcs) {
205 // Restore state if it previously existed.
206 const RtpPayloadState* state = nullptr;
207 auto it = states.find(ssrc);
208 if (it != states.end()) {
209 state = &it->second;
philipel25d31ec2018-08-08 16:33:01 +0200210 shared_frame_id_ = std::max(shared_frame_id_, state->shared_frame_id);
Ã…sa Persson4bece9a2017-10-06 10:04:04 +0200211 }
212 params_.push_back(RtpPayloadParams(ssrc, state));
213 }
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200214
215 // RTP/RTCP initialization.
216
217 // We add the highest spatial layer first to ensure it'll be prioritized
218 // when sending padding, with the hope that the packet rate will be smaller,
219 // and that it's more important to protect than the lower layers.
220 for (auto& rtp_rtcp : rtp_modules_) {
221 constexpr bool remb_candidate = true;
222 transport->packet_router()->AddSendRtpModule(rtp_rtcp.get(),
223 remb_candidate);
224 }
225
226 for (size_t i = 0; i < rtp_config_.extensions.size(); ++i) {
227 const std::string& extension = rtp_config_.extensions[i].uri;
228 int id = rtp_config_.extensions[i].id;
229 // One-byte-extension local identifiers are in the range 1-14 inclusive.
230 RTC_DCHECK_GE(id, 1);
231 RTC_DCHECK_LE(id, 14);
232 RTC_DCHECK(RtpExtension::IsSupportedForVideo(extension));
233 for (auto& rtp_rtcp : rtp_modules_) {
234 RTC_CHECK_EQ(0, rtp_rtcp->RegisterSendRtpHeaderExtension(
235 StringToRtpExtensionType(extension), id));
236 }
237 }
238
239 ConfigureProtection(rtp_config);
240 ConfigureSsrcs(rtp_config);
241
242 if (!rtp_config.mid.empty()) {
243 for (auto& rtp_rtcp : rtp_modules_) {
244 rtp_rtcp->SetMid(rtp_config.mid);
245 }
246 }
247
248 // TODO(pbos): Should we set CNAME on all RTP modules?
249 rtp_modules_.front()->SetCNAME(rtp_config.c_name.c_str());
250
251 for (auto& rtp_rtcp : rtp_modules_) {
252 rtp_rtcp->RegisterRtcpStatisticsCallback(observers.rtcp_stats);
253 rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(observers.rtp_stats);
254 rtp_rtcp->SetMaxRtpPacketSize(rtp_config.max_packet_size);
255 rtp_rtcp->RegisterVideoSendPayload(rtp_config.payload_type,
256 rtp_config.payload_name.c_str());
257 }
Per83d09102016-04-15 14:59:13 +0200258}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000259
Stefan Holmer9416ef82018-07-19 10:34:38 +0200260RtpVideoSender::~RtpVideoSender() {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200261 for (auto& rtp_rtcp : rtp_modules_) {
262 transport_->packet_router()->RemoveSendRtpModule(rtp_rtcp.get());
263 }
264}
265
Stefan Holmer9416ef82018-07-19 10:34:38 +0200266void RtpVideoSender::RegisterProcessThread(
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200267 ProcessThread* module_process_thread) {
268 RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
269 RTC_DCHECK(!module_process_thread_);
270 module_process_thread_ = module_process_thread;
271
272 for (auto& rtp_rtcp : rtp_modules_)
273 module_process_thread_->RegisterModule(rtp_rtcp.get(), RTC_FROM_HERE);
274}
275
Stefan Holmer9416ef82018-07-19 10:34:38 +0200276void RtpVideoSender::DeRegisterProcessThread() {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200277 RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
278 for (auto& rtp_rtcp : rtp_modules_)
279 module_process_thread_->DeRegisterModule(rtp_rtcp.get());
280}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000281
Stefan Holmer9416ef82018-07-19 10:34:38 +0200282void RtpVideoSender::SetActive(bool active) {
Tommi97888bd2016-01-21 23:24:59 +0100283 rtc::CritScope lock(&crit_);
Peter Boström8b79b072016-02-26 16:31:37 +0100284 if (active_ == active)
285 return;
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800286 const std::vector<bool> active_modules(rtp_modules_.size(), active);
287 SetActiveModules(active_modules);
288}
Per512ecb32016-09-23 15:52:06 +0200289
Stefan Holmer9416ef82018-07-19 10:34:38 +0200290void RtpVideoSender::SetActiveModules(const std::vector<bool> active_modules) {
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800291 rtc::CritScope lock(&crit_);
292 RTC_DCHECK_EQ(rtp_modules_.size(), active_modules.size());
293 active_ = false;
294 for (size_t i = 0; i < active_modules.size(); ++i) {
295 if (active_modules[i]) {
296 active_ = true;
297 }
298 // Sends a kRtcpByeCode when going from true to false.
299 rtp_modules_[i]->SetSendingStatus(active_modules[i]);
300 // If set to false this module won't send media.
301 rtp_modules_[i]->SetSendingMediaStatus(active_modules[i]);
Per512ecb32016-09-23 15:52:06 +0200302 }
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000303}
304
Stefan Holmer9416ef82018-07-19 10:34:38 +0200305bool RtpVideoSender::IsActive() {
Tommi97888bd2016-01-21 23:24:59 +0100306 rtc::CritScope lock(&crit_);
mflodman@webrtc.org47d657b2015-02-19 10:29:32 +0000307 return active_ && !rtp_modules_.empty();
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000308}
309
Stefan Holmer9416ef82018-07-19 10:34:38 +0200310EncodedImageCallback::Result RtpVideoSender::OnEncodedImage(
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700311 const EncodedImage& encoded_image,
312 const CodecSpecificInfo* codec_specific_info,
313 const RTPFragmentationHeader* fragmentation) {
Tommi97888bd2016-01-21 23:24:59 +0100314 rtc::CritScope lock(&crit_);
Peter Boström8b79b072016-02-26 16:31:37 +0100315 RTC_DCHECK(!rtp_modules_.empty());
Per512ecb32016-09-23 15:52:06 +0200316 if (!active_)
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700317 return Result(Result::ERROR_SEND_FAILED);
mflodman@webrtc.org50e28162015-02-23 07:45:11 +0000318
Stefan Holmerf7044682018-07-17 10:16:41 +0200319 size_t stream_index = GetSimulcastIdx(codec_specific_info).value_or(0);
sergeyu7b9feee2016-11-17 16:16:14 -0800320 RTC_DCHECK_LT(stream_index, rtp_modules_.size());
Stefan Holmerf7044682018-07-17 10:16:41 +0200321 RTPVideoHeader rtp_video_header = params_[stream_index].GetRtpVideoHeader(
322 encoded_image, codec_specific_info);
Niels Möllerbb894ff2018-03-15 12:28:53 +0100323
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700324 uint32_t frame_id;
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800325 if (!rtp_modules_[stream_index]->Sending()) {
326 // The payload router could be active but this module isn't sending.
327 return Result(Result::ERROR_SEND_FAILED);
328 }
sergeyu7b9feee2016-11-17 16:16:14 -0800329 bool send_result = rtp_modules_[stream_index]->SendOutgoingData(
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200330 encoded_image._frameType, rtp_config_.payload_type,
331 encoded_image._timeStamp, encoded_image.capture_time_ms_,
332 encoded_image._buffer, encoded_image._length, fragmentation,
333 &rtp_video_header, &frame_id);
sergeyu7b9feee2016-11-17 16:16:14 -0800334 if (!send_result)
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700335 return Result(Result::ERROR_SEND_FAILED);
336
337 return Result(Result::OK, frame_id);
mflodman@webrtc.orga4ef2ce2015-02-12 09:54:18 +0000338}
339
Stefan Holmer9416ef82018-07-19 10:34:38 +0200340void RtpVideoSender::OnBitrateAllocationUpdated(
Erik Språng566124a2018-04-23 12:32:22 +0200341 const VideoBitrateAllocation& bitrate) {
sprang1a646ee2016-12-01 06:34:11 -0800342 rtc::CritScope lock(&crit_);
343 if (IsActive()) {
344 if (rtp_modules_.size() == 1) {
345 // If spatial scalability is enabled, it is covered by a single stream.
346 rtp_modules_[0]->SetVideoBitrateAllocation(bitrate);
347 } else {
Stefan Holmerf7044682018-07-17 10:16:41 +0200348 std::vector<absl::optional<VideoBitrateAllocation>> layer_bitrates =
349 bitrate.GetSimulcastAllocations();
Erik Språng566124a2018-04-23 12:32:22 +0200350 // Simulcast is in use, split the VideoBitrateAllocation into one struct
351 // per rtp stream, moving over the temporal layer allocation.
Stefan Holmerf7044682018-07-17 10:16:41 +0200352 for (size_t i = 0; i < rtp_modules_.size(); ++i) {
353 // The next spatial layer could be used if the current one is
354 // inactive.
355 if (layer_bitrates[i]) {
356 rtp_modules_[i]->SetVideoBitrateAllocation(*layer_bitrates[i]);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800357 }
sprang1a646ee2016-12-01 06:34:11 -0800358 }
359 }
360 }
361}
362
Stefan Holmer9416ef82018-07-19 10:34:38 +0200363void RtpVideoSender::ConfigureProtection(const RtpConfig& rtp_config) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200364 // Consistency of FlexFEC parameters is checked in MaybeCreateFlexfecSender.
365 const bool flexfec_enabled = (flexfec_sender_ != nullptr);
366
367 // Consistency of NACK and RED+ULPFEC parameters is checked in this function.
368 const bool nack_enabled = rtp_config.nack.rtp_history_ms > 0;
369 int red_payload_type = rtp_config.ulpfec.red_payload_type;
370 int ulpfec_payload_type = rtp_config.ulpfec.ulpfec_payload_type;
371
372 // Shorthands.
373 auto IsRedEnabled = [&]() { return red_payload_type >= 0; };
374 auto IsUlpfecEnabled = [&]() { return ulpfec_payload_type >= 0; };
375 auto DisableRedAndUlpfec = [&]() {
376 red_payload_type = -1;
377 ulpfec_payload_type = -1;
378 };
379
380 if (webrtc::field_trial::IsEnabled("WebRTC-DisableUlpFecExperiment")) {
381 RTC_LOG(LS_INFO) << "Experiment to disable sending ULPFEC is enabled.";
382 DisableRedAndUlpfec();
383 }
384
385 // If enabled, FlexFEC takes priority over RED+ULPFEC.
386 if (flexfec_enabled) {
387 if (IsUlpfecEnabled()) {
388 RTC_LOG(LS_INFO)
389 << "Both FlexFEC and ULPFEC are configured. Disabling ULPFEC.";
390 }
391 DisableRedAndUlpfec();
392 }
393
394 // Payload types without picture ID cannot determine that a stream is complete
395 // without retransmitting FEC, so using ULPFEC + NACK for H.264 (for instance)
396 // is a waste of bandwidth since FEC packets still have to be transmitted.
397 // Note that this is not the case with FlexFEC.
398 if (nack_enabled && IsUlpfecEnabled() &&
399 !PayloadTypeSupportsSkippingFecPackets(rtp_config.payload_name)) {
400 RTC_LOG(LS_WARNING)
401 << "Transmitting payload type without picture ID using "
402 "NACK+ULPFEC is a waste of bandwidth since ULPFEC packets "
403 "also have to be retransmitted. Disabling ULPFEC.";
404 DisableRedAndUlpfec();
405 }
406
407 // Verify payload types.
408 if (IsUlpfecEnabled() ^ IsRedEnabled()) {
409 RTC_LOG(LS_WARNING)
410 << "Only RED or only ULPFEC enabled, but not both. Disabling both.";
411 DisableRedAndUlpfec();
412 }
413
414 for (auto& rtp_rtcp : rtp_modules_) {
415 // Set NACK.
416 rtp_rtcp->SetStorePacketsStatus(true, kMinSendSidePacketHistorySize);
417 // Set RED/ULPFEC information.
418 rtp_rtcp->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
419 }
420}
421
Stefan Holmer9416ef82018-07-19 10:34:38 +0200422bool RtpVideoSender::FecEnabled() const {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200423 const bool flexfec_enabled = (flexfec_sender_ != nullptr);
424 int ulpfec_payload_type = rtp_config_.ulpfec.ulpfec_payload_type;
425 return flexfec_enabled || ulpfec_payload_type >= 0;
426}
427
Stefan Holmer9416ef82018-07-19 10:34:38 +0200428bool RtpVideoSender::NackEnabled() const {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200429 const bool nack_enabled = rtp_config_.nack.rtp_history_ms > 0;
430 return nack_enabled;
431}
432
Stefan Holmer9416ef82018-07-19 10:34:38 +0200433void RtpVideoSender::DeliverRtcp(const uint8_t* packet, size_t length) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200434 // Runs on a network thread.
435 for (auto& rtp_rtcp : rtp_modules_)
436 rtp_rtcp->IncomingRtcpPacket(packet, length);
437}
438
Stefan Holmer9416ef82018-07-19 10:34:38 +0200439void RtpVideoSender::ProtectionRequest(const FecProtectionParams* delta_params,
440 const FecProtectionParams* key_params,
441 uint32_t* sent_video_rate_bps,
442 uint32_t* sent_nack_rate_bps,
443 uint32_t* sent_fec_rate_bps) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200444 *sent_video_rate_bps = 0;
445 *sent_nack_rate_bps = 0;
446 *sent_fec_rate_bps = 0;
447 for (auto& rtp_rtcp : rtp_modules_) {
448 uint32_t not_used = 0;
449 uint32_t module_video_rate = 0;
450 uint32_t module_fec_rate = 0;
451 uint32_t module_nack_rate = 0;
452 rtp_rtcp->SetFecParameters(*delta_params, *key_params);
453 rtp_rtcp->BitrateSent(&not_used, &module_video_rate, &module_fec_rate,
454 &module_nack_rate);
455 *sent_video_rate_bps += module_video_rate;
456 *sent_nack_rate_bps += module_nack_rate;
457 *sent_fec_rate_bps += module_fec_rate;
458 }
459}
460
Stefan Holmer9416ef82018-07-19 10:34:38 +0200461void RtpVideoSender::SetMaxRtpPacketSize(size_t max_rtp_packet_size) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200462 for (auto& rtp_rtcp : rtp_modules_) {
463 rtp_rtcp->SetMaxRtpPacketSize(max_rtp_packet_size);
464 }
465}
466
Stefan Holmer9416ef82018-07-19 10:34:38 +0200467void RtpVideoSender::ConfigureSsrcs(const RtpConfig& rtp_config) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200468 // Configure regular SSRCs.
469 for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) {
470 uint32_t ssrc = rtp_config.ssrcs[i];
471 RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
472 rtp_rtcp->SetSSRC(ssrc);
473
474 // Restore RTP state if previous existed.
475 auto it = suspended_ssrcs_.find(ssrc);
476 if (it != suspended_ssrcs_.end())
477 rtp_rtcp->SetRtpState(it->second);
478 }
479
480 // Set up RTX if available.
481 if (rtp_config.rtx.ssrcs.empty())
482 return;
483
484 // Configure RTX SSRCs.
485 RTC_DCHECK_EQ(rtp_config.rtx.ssrcs.size(), rtp_config.ssrcs.size());
486 for (size_t i = 0; i < rtp_config.rtx.ssrcs.size(); ++i) {
487 uint32_t ssrc = rtp_config.rtx.ssrcs[i];
488 RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
489 rtp_rtcp->SetRtxSsrc(ssrc);
490 auto it = suspended_ssrcs_.find(ssrc);
491 if (it != suspended_ssrcs_.end())
492 rtp_rtcp->SetRtxState(it->second);
493 }
494
495 // Configure RTX payload types.
496 RTC_DCHECK_GE(rtp_config.rtx.payload_type, 0);
497 for (auto& rtp_rtcp : rtp_modules_) {
498 rtp_rtcp->SetRtxSendPayloadType(rtp_config.rtx.payload_type,
499 rtp_config.payload_type);
500 rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
501 }
502 if (rtp_config.ulpfec.red_payload_type != -1 &&
503 rtp_config.ulpfec.red_rtx_payload_type != -1) {
504 for (auto& rtp_rtcp : rtp_modules_) {
505 rtp_rtcp->SetRtxSendPayloadType(rtp_config.ulpfec.red_rtx_payload_type,
506 rtp_config.ulpfec.red_payload_type);
507 }
508 }
509}
510
Stefan Holmer9416ef82018-07-19 10:34:38 +0200511void RtpVideoSender::OnNetworkAvailability(bool network_available) {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200512 for (auto& rtp_rtcp : rtp_modules_) {
513 rtp_rtcp->SetRTCPStatus(network_available ? rtp_config_.rtcp_mode
514 : RtcpMode::kOff);
515 }
516}
517
Stefan Holmer9416ef82018-07-19 10:34:38 +0200518std::map<uint32_t, RtpState> RtpVideoSender::GetRtpStates() const {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200519 std::map<uint32_t, RtpState> rtp_states;
520
521 for (size_t i = 0; i < rtp_config_.ssrcs.size(); ++i) {
522 uint32_t ssrc = rtp_config_.ssrcs[i];
523 RTC_DCHECK_EQ(ssrc, rtp_modules_[i]->SSRC());
524 rtp_states[ssrc] = rtp_modules_[i]->GetRtpState();
525 }
526
527 for (size_t i = 0; i < rtp_config_.rtx.ssrcs.size(); ++i) {
528 uint32_t ssrc = rtp_config_.rtx.ssrcs[i];
529 rtp_states[ssrc] = rtp_modules_[i]->GetRtxState();
530 }
531
532 if (flexfec_sender_) {
533 uint32_t ssrc = rtp_config_.flexfec.ssrc;
534 rtp_states[ssrc] = flexfec_sender_->GetRtpState();
535 }
536
537 return rtp_states;
538}
539
Stefan Holmer9416ef82018-07-19 10:34:38 +0200540std::map<uint32_t, RtpPayloadState> RtpVideoSender::GetRtpPayloadStates()
541 const {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200542 rtc::CritScope lock(&crit_);
543 std::map<uint32_t, RtpPayloadState> payload_states;
544 for (const auto& param : params_) {
545 payload_states[param.ssrc()] = param.state();
philipel25d31ec2018-08-08 16:33:01 +0200546 payload_states[param.ssrc()].shared_frame_id = shared_frame_id_;
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200547 }
548 return payload_states;
549}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000550} // namespace webrtc