blob: 4e7d13eef4af1eb122017fbea373f179bb69509a [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 Holmera2f15332018-07-11 17:11:31 +020011#include "call/payload_router.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000012
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020013#include <memory>
14#include <string>
15#include <utility>
16
17#include "call/rtp_transport_controller_send_interface.h"
18#include "modules/pacing/packet_router.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/rtp_rtcp/include/rtp_rtcp.h"
20#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020021#include "modules/rtp_rtcp/source/rtp_sender.h"
22#include "modules/utility/include/process_thread.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/include/video_codec_interface.h"
24#include "rtc_base/checks.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020025#include "rtc_base/location.h"
26#include "rtc_base/logging.h"
27#include "system_wrappers/include/field_trial.h"
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +000028
29namespace webrtc {
30
kjellander02b3d272016-04-20 05:05:54 -070031namespace {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020032static const int kMinSendSidePacketHistorySize = 600;
33
34std::vector<std::unique_ptr<RtpRtcp>> CreateRtpRtcpModules(
35 const std::vector<uint32_t>& ssrcs,
36 const std::vector<uint32_t>& protected_media_ssrcs,
37 const RtcpConfig& rtcp_config,
38 Transport* send_transport,
39 RtcpIntraFrameObserver* intra_frame_callback,
40 RtcpBandwidthObserver* bandwidth_callback,
41 RtpTransportControllerSendInterface* transport,
42 RtcpRttStats* rtt_stats,
43 FlexfecSender* flexfec_sender,
44 BitrateStatisticsObserver* bitrate_observer,
45 FrameCountObserver* frame_count_observer,
46 RtcpPacketTypeCounterObserver* rtcp_type_observer,
47 SendSideDelayObserver* send_delay_observer,
48 SendPacketObserver* send_packet_observer,
49 RtcEventLog* event_log,
50 RateLimiter* retransmission_rate_limiter,
51 OverheadObserver* overhead_observer,
52 RtpKeepAliveConfig keepalive_config) {
53 RTC_DCHECK_GT(ssrcs.size(), 0);
54 RtpRtcp::Configuration configuration;
55 configuration.audio = false;
56 configuration.receiver_only = false;
57 configuration.outgoing_transport = send_transport;
58 configuration.intra_frame_callback = intra_frame_callback;
59 configuration.bandwidth_callback = bandwidth_callback;
60 configuration.transport_feedback_callback =
61 transport->transport_feedback_observer();
62 configuration.rtt_stats = rtt_stats;
63 configuration.rtcp_packet_type_counter_observer = rtcp_type_observer;
64 configuration.paced_sender = transport->packet_sender();
65 configuration.transport_sequence_number_allocator =
66 transport->packet_router();
67 configuration.send_bitrate_observer = bitrate_observer;
68 configuration.send_frame_count_observer = frame_count_observer;
69 configuration.send_side_delay_observer = send_delay_observer;
70 configuration.send_packet_observer = send_packet_observer;
71 configuration.event_log = event_log;
72 configuration.retransmission_rate_limiter = retransmission_rate_limiter;
73 configuration.overhead_observer = overhead_observer;
74 configuration.keepalive_config = keepalive_config;
75 configuration.rtcp_interval_config.video_interval_ms =
76 rtcp_config.video_report_interval_ms;
77 configuration.rtcp_interval_config.audio_interval_ms =
78 rtcp_config.audio_report_interval_ms;
79 std::vector<std::unique_ptr<RtpRtcp>> modules;
80 const std::vector<uint32_t>& flexfec_protected_ssrcs = protected_media_ssrcs;
81 for (uint32_t ssrc : ssrcs) {
82 bool enable_flexfec = flexfec_sender != nullptr &&
83 std::find(flexfec_protected_ssrcs.begin(),
84 flexfec_protected_ssrcs.end(),
85 ssrc) != flexfec_protected_ssrcs.end();
86 configuration.flexfec_sender = enable_flexfec ? flexfec_sender : nullptr;
87 std::unique_ptr<RtpRtcp> rtp_rtcp =
88 std::unique_ptr<RtpRtcp>(RtpRtcp::CreateRtpRtcp(configuration));
89 rtp_rtcp->SetSendingStatus(false);
90 rtp_rtcp->SetSendingMediaStatus(false);
91 rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound);
92 modules.push_back(std::move(rtp_rtcp));
93 }
94 return modules;
95}
96
Stefan Holmerf7044682018-07-17 10:16:41 +020097absl::optional<size_t> GetSimulcastIdx(const CodecSpecificInfo* info) {
98 if (!info)
99 return absl::nullopt;
kjellander02b3d272016-04-20 05:05:54 -0700100 switch (info->codecType) {
Stefan Holmerf7044682018-07-17 10:16:41 +0200101 case kVideoCodecVP8:
102 return absl::optional<size_t>(info->codecSpecific.VP8.simulcastIdx);
JT Teh5daeff92018-07-16 17:17:17 +0000103 case kVideoCodecH264:
Stefan Holmerf7044682018-07-17 10:16:41 +0200104 return absl::optional<size_t>(info->codecSpecific.H264.simulcast_idx);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800105 case kVideoCodecMultiplex:
kjellander02b3d272016-04-20 05:05:54 -0700106 case kVideoCodecGeneric:
Stefan Holmerf7044682018-07-17 10:16:41 +0200107 return absl::optional<size_t>(info->codecSpecific.generic.simulcast_idx);
kjellander02b3d272016-04-20 05:05:54 -0700108 default:
Stefan Holmerf7044682018-07-17 10:16:41 +0200109 return absl::nullopt;
kjellander02b3d272016-04-20 05:05:54 -0700110 }
111}
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200112bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) {
113 const VideoCodecType codecType = PayloadStringToCodecType(payload_name);
114 if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) {
115 return true;
116 }
117 return false;
118}
119
120// TODO(brandtr): Update this function when we support multistream protection.
121std::unique_ptr<FlexfecSender> MaybeCreateFlexfecSender(
122 const RtpConfig& rtp,
123 const std::map<uint32_t, RtpState>& suspended_ssrcs) {
124 if (rtp.flexfec.payload_type < 0) {
125 return nullptr;
126 }
127 RTC_DCHECK_GE(rtp.flexfec.payload_type, 0);
128 RTC_DCHECK_LE(rtp.flexfec.payload_type, 127);
129 if (rtp.flexfec.ssrc == 0) {
130 RTC_LOG(LS_WARNING) << "FlexFEC is enabled, but no FlexFEC SSRC given. "
131 "Therefore disabling FlexFEC.";
132 return nullptr;
133 }
134 if (rtp.flexfec.protected_media_ssrcs.empty()) {
135 RTC_LOG(LS_WARNING)
136 << "FlexFEC is enabled, but no protected media SSRC given. "
137 "Therefore disabling FlexFEC.";
138 return nullptr;
139 }
140
141 if (rtp.flexfec.protected_media_ssrcs.size() > 1) {
142 RTC_LOG(LS_WARNING)
143 << "The supplied FlexfecConfig contained multiple protected "
144 "media streams, but our implementation currently only "
145 "supports protecting a single media stream. "
146 "To avoid confusion, disabling FlexFEC completely.";
147 return nullptr;
148 }
149
150 const RtpState* rtp_state = nullptr;
151 auto it = suspended_ssrcs.find(rtp.flexfec.ssrc);
152 if (it != suspended_ssrcs.end()) {
153 rtp_state = &it->second;
154 }
155
156 RTC_DCHECK_EQ(1U, rtp.flexfec.protected_media_ssrcs.size());
157 return absl::make_unique<FlexfecSender>(
158 rtp.flexfec.payload_type, rtp.flexfec.ssrc,
159 rtp.flexfec.protected_media_ssrcs[0], rtp.mid, rtp.extensions,
160 RTPSender::FecExtensionSizes(), rtp_state, Clock::GetRealTimeClock());
161}
kjellander02b3d272016-04-20 05:05:54 -0700162} // namespace
163
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200164PayloadRouter::PayloadRouter(const std::vector<uint32_t>& ssrcs,
165 std::map<uint32_t, RtpState> suspended_ssrcs,
166 const std::map<uint32_t, RtpPayloadState>& states,
167 const RtpConfig& rtp_config,
168 const RtcpConfig& rtcp_config,
169 Transport* send_transport,
170 const RtpSenderObservers& observers,
171 RtpTransportControllerSendInterface* transport,
172 RtcEventLog* event_log,
173 RateLimiter* retransmission_limiter)
174 : active_(false),
175 module_process_thread_(nullptr),
176 suspended_ssrcs_(std::move(suspended_ssrcs)),
177 flexfec_sender_(MaybeCreateFlexfecSender(rtp_config, suspended_ssrcs_)),
178 rtp_modules_(
179 CreateRtpRtcpModules(ssrcs,
180 rtp_config.flexfec.protected_media_ssrcs,
181 rtcp_config,
182 send_transport,
183 observers.intra_frame_callback,
184 transport->GetBandwidthObserver(),
185 transport,
186 observers.rtcp_rtt_stats,
187 flexfec_sender_.get(),
188 observers.bitrate_observer,
189 observers.frame_count_observer,
190 observers.rtcp_type_observer,
191 observers.send_delay_observer,
192 observers.send_packet_observer,
193 event_log,
194 retransmission_limiter,
195 observers.overhead_observer,
196 transport->keepalive_config())),
197 rtp_config_(rtp_config),
198 transport_(transport) {
199 RTC_DCHECK_EQ(ssrcs.size(), rtp_modules_.size());
200 module_process_thread_checker_.DetachFromThread();
Ã…sa Persson4bece9a2017-10-06 10:04:04 +0200201 // SSRCs are assumed to be sorted in the same order as |rtp_modules|.
202 for (uint32_t ssrc : ssrcs) {
203 // Restore state if it previously existed.
204 const RtpPayloadState* state = nullptr;
205 auto it = states.find(ssrc);
206 if (it != states.end()) {
207 state = &it->second;
208 }
209 params_.push_back(RtpPayloadParams(ssrc, state));
210 }
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200211
212 // RTP/RTCP initialization.
213
214 // We add the highest spatial layer first to ensure it'll be prioritized
215 // when sending padding, with the hope that the packet rate will be smaller,
216 // and that it's more important to protect than the lower layers.
217 for (auto& rtp_rtcp : rtp_modules_) {
218 constexpr bool remb_candidate = true;
219 transport->packet_router()->AddSendRtpModule(rtp_rtcp.get(),
220 remb_candidate);
221 }
222
223 for (size_t i = 0; i < rtp_config_.extensions.size(); ++i) {
224 const std::string& extension = rtp_config_.extensions[i].uri;
225 int id = rtp_config_.extensions[i].id;
226 // One-byte-extension local identifiers are in the range 1-14 inclusive.
227 RTC_DCHECK_GE(id, 1);
228 RTC_DCHECK_LE(id, 14);
229 RTC_DCHECK(RtpExtension::IsSupportedForVideo(extension));
230 for (auto& rtp_rtcp : rtp_modules_) {
231 RTC_CHECK_EQ(0, rtp_rtcp->RegisterSendRtpHeaderExtension(
232 StringToRtpExtensionType(extension), id));
233 }
234 }
235
236 ConfigureProtection(rtp_config);
237 ConfigureSsrcs(rtp_config);
238
239 if (!rtp_config.mid.empty()) {
240 for (auto& rtp_rtcp : rtp_modules_) {
241 rtp_rtcp->SetMid(rtp_config.mid);
242 }
243 }
244
245 // TODO(pbos): Should we set CNAME on all RTP modules?
246 rtp_modules_.front()->SetCNAME(rtp_config.c_name.c_str());
247
248 for (auto& rtp_rtcp : rtp_modules_) {
249 rtp_rtcp->RegisterRtcpStatisticsCallback(observers.rtcp_stats);
250 rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(observers.rtp_stats);
251 rtp_rtcp->SetMaxRtpPacketSize(rtp_config.max_packet_size);
252 rtp_rtcp->RegisterVideoSendPayload(rtp_config.payload_type,
253 rtp_config.payload_name.c_str());
254 }
Per83d09102016-04-15 14:59:13 +0200255}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000256
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200257PayloadRouter::~PayloadRouter() {
258 for (auto& rtp_rtcp : rtp_modules_) {
259 transport_->packet_router()->RemoveSendRtpModule(rtp_rtcp.get());
260 }
261}
262
263void PayloadRouter::RegisterProcessThread(
264 ProcessThread* module_process_thread) {
265 RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
266 RTC_DCHECK(!module_process_thread_);
267 module_process_thread_ = module_process_thread;
268
269 for (auto& rtp_rtcp : rtp_modules_)
270 module_process_thread_->RegisterModule(rtp_rtcp.get(), RTC_FROM_HERE);
271}
272
273void PayloadRouter::DeRegisterProcessThread() {
274 RTC_DCHECK_RUN_ON(&module_process_thread_checker_);
275 for (auto& rtp_rtcp : rtp_modules_)
276 module_process_thread_->DeRegisterModule(rtp_rtcp.get());
277}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000278
sprang1a646ee2016-12-01 06:34:11 -0800279void PayloadRouter::SetActive(bool active) {
Tommi97888bd2016-01-21 23:24:59 +0100280 rtc::CritScope lock(&crit_);
Peter Boström8b79b072016-02-26 16:31:37 +0100281 if (active_ == active)
282 return;
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800283 const std::vector<bool> active_modules(rtp_modules_.size(), active);
284 SetActiveModules(active_modules);
285}
Per512ecb32016-09-23 15:52:06 +0200286
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800287void PayloadRouter::SetActiveModules(const std::vector<bool> active_modules) {
288 rtc::CritScope lock(&crit_);
289 RTC_DCHECK_EQ(rtp_modules_.size(), active_modules.size());
290 active_ = false;
291 for (size_t i = 0; i < active_modules.size(); ++i) {
292 if (active_modules[i]) {
293 active_ = true;
294 }
295 // Sends a kRtcpByeCode when going from true to false.
296 rtp_modules_[i]->SetSendingStatus(active_modules[i]);
297 // If set to false this module won't send media.
298 rtp_modules_[i]->SetSendingMediaStatus(active_modules[i]);
Per512ecb32016-09-23 15:52:06 +0200299 }
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000300}
301
sprang1a646ee2016-12-01 06:34:11 -0800302bool PayloadRouter::IsActive() {
Tommi97888bd2016-01-21 23:24:59 +0100303 rtc::CritScope lock(&crit_);
mflodman@webrtc.org47d657b2015-02-19 10:29:32 +0000304 return active_ && !rtp_modules_.empty();
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000305}
306
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700307EncodedImageCallback::Result PayloadRouter::OnEncodedImage(
308 const EncodedImage& encoded_image,
309 const CodecSpecificInfo* codec_specific_info,
310 const RTPFragmentationHeader* fragmentation) {
Tommi97888bd2016-01-21 23:24:59 +0100311 rtc::CritScope lock(&crit_);
Peter Boström8b79b072016-02-26 16:31:37 +0100312 RTC_DCHECK(!rtp_modules_.empty());
Per512ecb32016-09-23 15:52:06 +0200313 if (!active_)
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700314 return Result(Result::ERROR_SEND_FAILED);
mflodman@webrtc.org50e28162015-02-23 07:45:11 +0000315
Stefan Holmerf7044682018-07-17 10:16:41 +0200316 size_t stream_index = GetSimulcastIdx(codec_specific_info).value_or(0);
sergeyu7b9feee2016-11-17 16:16:14 -0800317 RTC_DCHECK_LT(stream_index, rtp_modules_.size());
Stefan Holmerf7044682018-07-17 10:16:41 +0200318 RTPVideoHeader rtp_video_header = params_[stream_index].GetRtpVideoHeader(
319 encoded_image, codec_specific_info);
Niels Möllerbb894ff2018-03-15 12:28:53 +0100320
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700321 uint32_t frame_id;
Seth Hampsoncc7125f2018-02-02 08:46:16 -0800322 if (!rtp_modules_[stream_index]->Sending()) {
323 // The payload router could be active but this module isn't sending.
324 return Result(Result::ERROR_SEND_FAILED);
325 }
sergeyu7b9feee2016-11-17 16:16:14 -0800326 bool send_result = rtp_modules_[stream_index]->SendOutgoingData(
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200327 encoded_image._frameType, rtp_config_.payload_type,
328 encoded_image._timeStamp, encoded_image.capture_time_ms_,
329 encoded_image._buffer, encoded_image._length, fragmentation,
330 &rtp_video_header, &frame_id);
sergeyu7b9feee2016-11-17 16:16:14 -0800331 if (!send_result)
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700332 return Result(Result::ERROR_SEND_FAILED);
333
334 return Result(Result::OK, frame_id);
mflodman@webrtc.orga4ef2ce2015-02-12 09:54:18 +0000335}
336
sprang1a646ee2016-12-01 06:34:11 -0800337void PayloadRouter::OnBitrateAllocationUpdated(
Erik Språng566124a2018-04-23 12:32:22 +0200338 const VideoBitrateAllocation& bitrate) {
sprang1a646ee2016-12-01 06:34:11 -0800339 rtc::CritScope lock(&crit_);
340 if (IsActive()) {
341 if (rtp_modules_.size() == 1) {
342 // If spatial scalability is enabled, it is covered by a single stream.
343 rtp_modules_[0]->SetVideoBitrateAllocation(bitrate);
344 } else {
Stefan Holmerf7044682018-07-17 10:16:41 +0200345 std::vector<absl::optional<VideoBitrateAllocation>> layer_bitrates =
346 bitrate.GetSimulcastAllocations();
Erik Språng566124a2018-04-23 12:32:22 +0200347 // Simulcast is in use, split the VideoBitrateAllocation into one struct
348 // per rtp stream, moving over the temporal layer allocation.
Stefan Holmerf7044682018-07-17 10:16:41 +0200349 for (size_t i = 0; i < rtp_modules_.size(); ++i) {
350 // The next spatial layer could be used if the current one is
351 // inactive.
352 if (layer_bitrates[i]) {
353 rtp_modules_[i]->SetVideoBitrateAllocation(*layer_bitrates[i]);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800354 }
sprang1a646ee2016-12-01 06:34:11 -0800355 }
356 }
357 }
358}
359
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200360void PayloadRouter::ConfigureProtection(const RtpConfig& rtp_config) {
361 // Consistency of FlexFEC parameters is checked in MaybeCreateFlexfecSender.
362 const bool flexfec_enabled = (flexfec_sender_ != nullptr);
363
364 // Consistency of NACK and RED+ULPFEC parameters is checked in this function.
365 const bool nack_enabled = rtp_config.nack.rtp_history_ms > 0;
366 int red_payload_type = rtp_config.ulpfec.red_payload_type;
367 int ulpfec_payload_type = rtp_config.ulpfec.ulpfec_payload_type;
368
369 // Shorthands.
370 auto IsRedEnabled = [&]() { return red_payload_type >= 0; };
371 auto IsUlpfecEnabled = [&]() { return ulpfec_payload_type >= 0; };
372 auto DisableRedAndUlpfec = [&]() {
373 red_payload_type = -1;
374 ulpfec_payload_type = -1;
375 };
376
377 if (webrtc::field_trial::IsEnabled("WebRTC-DisableUlpFecExperiment")) {
378 RTC_LOG(LS_INFO) << "Experiment to disable sending ULPFEC is enabled.";
379 DisableRedAndUlpfec();
380 }
381
382 // If enabled, FlexFEC takes priority over RED+ULPFEC.
383 if (flexfec_enabled) {
384 if (IsUlpfecEnabled()) {
385 RTC_LOG(LS_INFO)
386 << "Both FlexFEC and ULPFEC are configured. Disabling ULPFEC.";
387 }
388 DisableRedAndUlpfec();
389 }
390
391 // Payload types without picture ID cannot determine that a stream is complete
392 // without retransmitting FEC, so using ULPFEC + NACK for H.264 (for instance)
393 // is a waste of bandwidth since FEC packets still have to be transmitted.
394 // Note that this is not the case with FlexFEC.
395 if (nack_enabled && IsUlpfecEnabled() &&
396 !PayloadTypeSupportsSkippingFecPackets(rtp_config.payload_name)) {
397 RTC_LOG(LS_WARNING)
398 << "Transmitting payload type without picture ID using "
399 "NACK+ULPFEC is a waste of bandwidth since ULPFEC packets "
400 "also have to be retransmitted. Disabling ULPFEC.";
401 DisableRedAndUlpfec();
402 }
403
404 // Verify payload types.
405 if (IsUlpfecEnabled() ^ IsRedEnabled()) {
406 RTC_LOG(LS_WARNING)
407 << "Only RED or only ULPFEC enabled, but not both. Disabling both.";
408 DisableRedAndUlpfec();
409 }
410
411 for (auto& rtp_rtcp : rtp_modules_) {
412 // Set NACK.
413 rtp_rtcp->SetStorePacketsStatus(true, kMinSendSidePacketHistorySize);
414 // Set RED/ULPFEC information.
415 rtp_rtcp->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
416 }
417}
418
419bool PayloadRouter::FecEnabled() const {
420 const bool flexfec_enabled = (flexfec_sender_ != nullptr);
421 int ulpfec_payload_type = rtp_config_.ulpfec.ulpfec_payload_type;
422 return flexfec_enabled || ulpfec_payload_type >= 0;
423}
424
425bool PayloadRouter::NackEnabled() const {
426 const bool nack_enabled = rtp_config_.nack.rtp_history_ms > 0;
427 return nack_enabled;
428}
429
430void PayloadRouter::DeliverRtcp(const uint8_t* packet, size_t length) {
431 // Runs on a network thread.
432 for (auto& rtp_rtcp : rtp_modules_)
433 rtp_rtcp->IncomingRtcpPacket(packet, length);
434}
435
436void PayloadRouter::ProtectionRequest(const FecProtectionParams* delta_params,
437 const FecProtectionParams* key_params,
438 uint32_t* sent_video_rate_bps,
439 uint32_t* sent_nack_rate_bps,
440 uint32_t* sent_fec_rate_bps) {
441 *sent_video_rate_bps = 0;
442 *sent_nack_rate_bps = 0;
443 *sent_fec_rate_bps = 0;
444 for (auto& rtp_rtcp : rtp_modules_) {
445 uint32_t not_used = 0;
446 uint32_t module_video_rate = 0;
447 uint32_t module_fec_rate = 0;
448 uint32_t module_nack_rate = 0;
449 rtp_rtcp->SetFecParameters(*delta_params, *key_params);
450 rtp_rtcp->BitrateSent(&not_used, &module_video_rate, &module_fec_rate,
451 &module_nack_rate);
452 *sent_video_rate_bps += module_video_rate;
453 *sent_nack_rate_bps += module_nack_rate;
454 *sent_fec_rate_bps += module_fec_rate;
455 }
456}
457
458void PayloadRouter::SetMaxRtpPacketSize(size_t max_rtp_packet_size) {
459 for (auto& rtp_rtcp : rtp_modules_) {
460 rtp_rtcp->SetMaxRtpPacketSize(max_rtp_packet_size);
461 }
462}
463
464void PayloadRouter::ConfigureSsrcs(const RtpConfig& rtp_config) {
465 // Configure regular SSRCs.
466 for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) {
467 uint32_t ssrc = rtp_config.ssrcs[i];
468 RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
469 rtp_rtcp->SetSSRC(ssrc);
470
471 // Restore RTP state if previous existed.
472 auto it = suspended_ssrcs_.find(ssrc);
473 if (it != suspended_ssrcs_.end())
474 rtp_rtcp->SetRtpState(it->second);
475 }
476
477 // Set up RTX if available.
478 if (rtp_config.rtx.ssrcs.empty())
479 return;
480
481 // Configure RTX SSRCs.
482 RTC_DCHECK_EQ(rtp_config.rtx.ssrcs.size(), rtp_config.ssrcs.size());
483 for (size_t i = 0; i < rtp_config.rtx.ssrcs.size(); ++i) {
484 uint32_t ssrc = rtp_config.rtx.ssrcs[i];
485 RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
486 rtp_rtcp->SetRtxSsrc(ssrc);
487 auto it = suspended_ssrcs_.find(ssrc);
488 if (it != suspended_ssrcs_.end())
489 rtp_rtcp->SetRtxState(it->second);
490 }
491
492 // Configure RTX payload types.
493 RTC_DCHECK_GE(rtp_config.rtx.payload_type, 0);
494 for (auto& rtp_rtcp : rtp_modules_) {
495 rtp_rtcp->SetRtxSendPayloadType(rtp_config.rtx.payload_type,
496 rtp_config.payload_type);
497 rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
498 }
499 if (rtp_config.ulpfec.red_payload_type != -1 &&
500 rtp_config.ulpfec.red_rtx_payload_type != -1) {
501 for (auto& rtp_rtcp : rtp_modules_) {
502 rtp_rtcp->SetRtxSendPayloadType(rtp_config.ulpfec.red_rtx_payload_type,
503 rtp_config.ulpfec.red_payload_type);
504 }
505 }
506}
507
508void PayloadRouter::OnNetworkAvailability(bool network_available) {
509 for (auto& rtp_rtcp : rtp_modules_) {
510 rtp_rtcp->SetRTCPStatus(network_available ? rtp_config_.rtcp_mode
511 : RtcpMode::kOff);
512 }
513}
514
515std::map<uint32_t, RtpState> PayloadRouter::GetRtpStates() const {
516 std::map<uint32_t, RtpState> rtp_states;
517
518 for (size_t i = 0; i < rtp_config_.ssrcs.size(); ++i) {
519 uint32_t ssrc = rtp_config_.ssrcs[i];
520 RTC_DCHECK_EQ(ssrc, rtp_modules_[i]->SSRC());
521 rtp_states[ssrc] = rtp_modules_[i]->GetRtpState();
522 }
523
524 for (size_t i = 0; i < rtp_config_.rtx.ssrcs.size(); ++i) {
525 uint32_t ssrc = rtp_config_.rtx.ssrcs[i];
526 rtp_states[ssrc] = rtp_modules_[i]->GetRtxState();
527 }
528
529 if (flexfec_sender_) {
530 uint32_t ssrc = rtp_config_.flexfec.ssrc;
531 rtp_states[ssrc] = flexfec_sender_->GetRtpState();
532 }
533
534 return rtp_states;
535}
536
537std::map<uint32_t, RtpPayloadState> PayloadRouter::GetRtpPayloadStates() const {
538 rtc::CritScope lock(&crit_);
539 std::map<uint32_t, RtpPayloadState> payload_states;
540 for (const auto& param : params_) {
541 payload_states[param.ssrc()] = param.state();
542 }
543 return payload_states;
544}
mflodman@webrtc.org02270cd2015-02-06 13:10:19 +0000545} // namespace webrtc