blob: 80395de61ea0dc1ff80f5a015b73aec5191025c0 [file] [log] [blame]
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001/*
kjellander1afca732016-02-07 20:46:45 -08002 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00003 *
kjellander1afca732016-02-07 20:46:45 -08004 * 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.
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00009 */
10
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010011#include "webrtc/media/engine/webrtcvideoengine2.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000012
asaperssonc5dabdd2016-03-21 04:15:50 -070013#include <stdio.h>
pbos@webrtc.orgc37e72e2015-01-05 18:51:13 +000014#include <algorithm>
pbos@webrtc.org3c107582014-07-20 15:27:35 +000015#include <set>
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000016#include <string>
perkjfa10b552016-10-02 23:45:26 -070017#include <utility>
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000018
jbaucheec21bd2016-03-20 06:15:43 -070019#include "webrtc/base/copyonwritebuffer.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000020#include "webrtc/base/logging.h"
21#include "webrtc/base/stringutils.h"
qiangchenc27d89f2015-07-16 10:27:16 -070022#include "webrtc/base/timeutils.h"
tommie4f96502015-10-20 23:00:48 -070023#include "webrtc/base/trace_event.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000024#include "webrtc/call.h"
magjed725e4842016-11-16 00:48:13 -080025#include "webrtc/common_video/h264/profile_level_id.h"
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010026#include "webrtc/media/engine/constants.h"
magjed509e4fe2016-11-18 01:34:11 -080027#include "webrtc/media/engine/internalencoderfactory.h"
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010028#include "webrtc/media/engine/simulcast.h"
magjed614d5b72016-11-15 06:30:54 -080029#include "webrtc/media/engine/videoencodersoftwarefallbackwrapper.h"
magjedf6acc2a2016-11-22 01:43:03 -080030#include "webrtc/media/engine/videodecodersoftwarefallbackwrapper.h"
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010031#include "webrtc/media/engine/webrtcmediaengine.h"
32#include "webrtc/media/engine/webrtcvideoencoderfactory.h"
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010033#include "webrtc/media/engine/webrtcvoiceengine.h"
Peter Boström81ea54e2015-05-07 11:41:09 +020034#include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010035#include "webrtc/system_wrappers/include/field_trial.h"
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000036#include "webrtc/video_decoder.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000037#include "webrtc/video_encoder.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000038
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000039namespace cricket {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +000040namespace {
Peter Boström81ea54e2015-05-07 11:41:09 +020041
42// Wrap cricket::WebRtcVideoEncoderFactory as a webrtc::VideoEncoderFactory.
43class EncoderFactoryAdapter : public webrtc::VideoEncoderFactory {
44 public:
45 // EncoderFactoryAdapter doesn't take ownership of |factory|, which is owned
46 // by e.g. PeerConnectionFactory.
47 explicit EncoderFactoryAdapter(cricket::WebRtcVideoEncoderFactory* factory)
48 : factory_(factory) {}
49 virtual ~EncoderFactoryAdapter() {}
50
51 // Implement webrtc::VideoEncoderFactory.
52 webrtc::VideoEncoder* Create() override {
magjed1e45cc62016-10-28 07:43:45 -070053 return factory_->CreateVideoEncoder(VideoCodec(kVp8CodecName));
Peter Boström81ea54e2015-05-07 11:41:09 +020054 }
55
56 void Destroy(webrtc::VideoEncoder* encoder) override {
57 return factory_->DestroyVideoEncoder(encoder);
58 }
59
60 private:
61 cricket::WebRtcVideoEncoderFactory* const factory_;
62};
63
Peter Boström3afc8c42016-01-27 16:45:21 +010064webrtc::Call::Config::BitrateConfig GetBitrateConfigForCodec(
65 const VideoCodec& codec) {
66 webrtc::Call::Config::BitrateConfig config;
67 int bitrate_kbps;
68 if (codec.GetParam(kCodecParamMinBitrate, &bitrate_kbps) &&
69 bitrate_kbps > 0) {
70 config.min_bitrate_bps = bitrate_kbps * 1000;
71 } else {
72 config.min_bitrate_bps = 0;
73 }
74 if (codec.GetParam(kCodecParamStartBitrate, &bitrate_kbps) &&
75 bitrate_kbps > 0) {
76 config.start_bitrate_bps = bitrate_kbps * 1000;
77 } else {
78 // Do not reconfigure start bitrate unless it's specified and positive.
79 config.start_bitrate_bps = -1;
80 }
81 if (codec.GetParam(kCodecParamMaxBitrate, &bitrate_kbps) &&
82 bitrate_kbps > 0) {
83 config.max_bitrate_bps = bitrate_kbps * 1000;
84 } else {
85 config.max_bitrate_bps = -1;
86 }
87 return config;
88}
89
Peter Boström81ea54e2015-05-07 11:41:09 +020090// An encoder factory that wraps Create requests for simulcastable codec types
91// with a webrtc::SimulcastEncoderAdapter. Non simulcastable codec type
92// requests are just passed through to the contained encoder factory.
93class WebRtcSimulcastEncoderFactory
94 : public cricket::WebRtcVideoEncoderFactory {
95 public:
96 // WebRtcSimulcastEncoderFactory doesn't take ownership of |factory|, which is
97 // owned by e.g. PeerConnectionFactory.
98 explicit WebRtcSimulcastEncoderFactory(
99 cricket::WebRtcVideoEncoderFactory* factory)
100 : factory_(factory) {}
101
102 static bool UseSimulcastEncoderFactory(
magjed1e45cc62016-10-28 07:43:45 -0700103 const std::vector<cricket::VideoCodec>& codecs) {
Peter Boström81ea54e2015-05-07 11:41:09 +0200104 // If any codec is VP8, use the simulcast factory. If asked to create a
105 // non-VP8 codec, we'll just return a contained factory encoder directly.
106 for (const auto& codec : codecs) {
magjed1e45cc62016-10-28 07:43:45 -0700107 if (CodecNamesEq(codec.name.c_str(), kVp8CodecName)) {
Peter Boström81ea54e2015-05-07 11:41:09 +0200108 return true;
109 }
110 }
111 return false;
112 }
113
114 webrtc::VideoEncoder* CreateVideoEncoder(
magjed1e45cc62016-10-28 07:43:45 -0700115 const cricket::VideoCodec& codec) override {
henrikg91d6ede2015-09-17 00:24:34 -0700116 RTC_DCHECK(factory_ != NULL);
Peter Boström81ea54e2015-05-07 11:41:09 +0200117 // If it's a codec type we can simulcast, create a wrapped encoder.
magjed1e45cc62016-10-28 07:43:45 -0700118 if (CodecNamesEq(codec.name.c_str(), kVp8CodecName)) {
Peter Boström81ea54e2015-05-07 11:41:09 +0200119 return new webrtc::SimulcastEncoderAdapter(
120 new EncoderFactoryAdapter(factory_));
121 }
magjed1e45cc62016-10-28 07:43:45 -0700122 webrtc::VideoEncoder* encoder = factory_->CreateVideoEncoder(codec);
Peter Boström81ea54e2015-05-07 11:41:09 +0200123 if (encoder) {
124 non_simulcast_encoders_.push_back(encoder);
125 }
126 return encoder;
127 }
128
magjed1e45cc62016-10-28 07:43:45 -0700129 const std::vector<cricket::VideoCodec>& supported_codecs() const override {
130 return factory_->supported_codecs();
Peter Boström81ea54e2015-05-07 11:41:09 +0200131 }
132
133 bool EncoderTypeHasInternalSource(
134 webrtc::VideoCodecType type) const override {
135 return factory_->EncoderTypeHasInternalSource(type);
136 }
137
138 void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override {
139 // Check first to see if the encoder wasn't wrapped in a
140 // SimulcastEncoderAdapter. In that case, ask the factory to destroy it.
141 if (std::remove(non_simulcast_encoders_.begin(),
142 non_simulcast_encoders_.end(),
143 encoder) != non_simulcast_encoders_.end()) {
144 factory_->DestroyVideoEncoder(encoder);
145 return;
146 }
147
148 // Otherwise, SimulcastEncoderAdapter can be deleted directly, and will call
149 // DestroyVideoEncoder on the factory for individual encoder instances.
150 delete encoder;
151 }
152
153 private:
magjedd2fce172016-11-02 11:08:29 -0700154 // Disable overloaded virtual function warning. TODO(magjed): Remove once
155 // http://crbug/webrtc/6402 is fixed.
156 using cricket::WebRtcVideoEncoderFactory::CreateVideoEncoder;
157
Peter Boström81ea54e2015-05-07 11:41:09 +0200158 cricket::WebRtcVideoEncoderFactory* factory_;
159 // A list of encoders that were created without being wrapped in a
160 // SimulcastEncoderAdapter.
161 std::vector<webrtc::VideoEncoder*> non_simulcast_encoders_;
162};
163
Peter Boström81ea54e2015-05-07 11:41:09 +0200164void AddDefaultFeedbackParams(VideoCodec* codec) {
165 codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir));
166 codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
167 codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli));
168 codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty));
stefan43edf0f2015-11-20 18:05:48 -0800169 codec->AddFeedbackParam(
170 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
Peter Boström81ea54e2015-05-07 11:41:09 +0200171}
172
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000173static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
174 std::stringstream out;
175 out << '{';
176 for (size_t i = 0; i < codecs.size(); ++i) {
177 out << codecs[i].ToString();
178 if (i != codecs.size() - 1) {
179 out << ", ";
180 }
181 }
182 out << '}';
183 return out.str();
184}
185
186static bool ValidateCodecFormats(const std::vector<VideoCodec>& codecs) {
187 bool has_video = false;
188 for (size_t i = 0; i < codecs.size(); ++i) {
189 if (!codecs[i].ValidateCodecFormat()) {
190 return false;
191 }
192 if (codecs[i].GetCodecType() == VideoCodec::CODEC_VIDEO) {
193 has_video = true;
194 }
195 }
196 if (!has_video) {
197 LOG(LS_ERROR) << "Setting codecs without a video codec is invalid: "
198 << CodecVectorToString(codecs);
199 return false;
200 }
201 return true;
202}
203
Peter Boströmd4362cd2015-03-25 14:17:23 +0100204static bool ValidateStreamParams(const StreamParams& sp) {
205 if (sp.ssrcs.empty()) {
206 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString();
207 return false;
208 }
209
Peter Boström0c4e06b2015-10-07 12:23:21 +0200210 std::vector<uint32_t> primary_ssrcs;
Peter Boströmd4362cd2015-03-25 14:17:23 +0100211 sp.GetPrimarySsrcs(&primary_ssrcs);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200212 std::vector<uint32_t> rtx_ssrcs;
Peter Boströmd4362cd2015-03-25 14:17:23 +0100213 sp.GetFidSsrcs(primary_ssrcs, &rtx_ssrcs);
214 for (uint32_t rtx_ssrc : rtx_ssrcs) {
215 bool rtx_ssrc_present = false;
216 for (uint32_t sp_ssrc : sp.ssrcs) {
217 if (sp_ssrc == rtx_ssrc) {
218 rtx_ssrc_present = true;
219 break;
220 }
221 }
222 if (!rtx_ssrc_present) {
223 LOG(LS_ERROR) << "RTX SSRC '" << rtx_ssrc
224 << "' missing from StreamParams ssrcs: " << sp.ToString();
225 return false;
226 }
227 }
228 if (!rtx_ssrcs.empty() && primary_ssrcs.size() != rtx_ssrcs.size()) {
229 LOG(LS_ERROR)
230 << "RTX SSRCs exist, but don't cover all SSRCs (unsupported): "
231 << sp.ToString();
232 return false;
233 }
234
235 return true;
236}
237
noahricfdac5162015-08-27 01:59:29 -0700238// Returns true if the given codec is disallowed from doing simulcast.
239bool IsCodecBlacklistedForSimulcast(const std::string& codec_name) {
asapersson3ed34872015-11-10 05:16:26 -0800240 return CodecNamesEq(codec_name, kH264CodecName) ||
241 CodecNamesEq(codec_name, kVp9CodecName);
noahricfdac5162015-08-27 01:59:29 -0700242}
243
Åsa Persson1c7d48d2015-09-08 09:21:43 +0200244// The selected thresholds for QVGA and VGA corresponded to a QP around 10.
245// The change in QP declined above the selected bitrates.
246static int GetMaxDefaultVideoBitrateKbps(int width, int height) {
247 if (width * height <= 320 * 240) {
248 return 600;
249 } else if (width * height <= 640 * 480) {
250 return 1700;
251 } else if (width * height <= 960 * 540) {
252 return 2000;
253 } else {
254 return 2500;
255 }
256}
perkj2d5f0912016-02-29 00:04:41 -0800257
asaperssonc5dabdd2016-03-21 04:15:50 -0700258bool GetVp9LayersFromFieldTrialGroup(int* num_spatial_layers,
259 int* num_temporal_layers) {
260 std::string group = webrtc::field_trial::FindFullName("WebRTC-SupportVP9SVC");
261 if (group.empty())
262 return false;
263
264 if (sscanf(group.c_str(), "EnabledByFlag_%dSL%dTL", num_spatial_layers,
265 num_temporal_layers) != 2) {
266 return false;
267 }
asaperssonaf9e4ac2016-03-31 00:36:49 -0700268 const int kMaxSpatialLayers = 2;
asaperssonc5dabdd2016-03-21 04:15:50 -0700269 if (*num_spatial_layers > kMaxSpatialLayers || *num_spatial_layers < 1)
270 return false;
271
272 const int kMaxTemporalLayers = 3;
273 if (*num_temporal_layers > kMaxTemporalLayers || *num_temporal_layers < 1)
274 return false;
275
276 return true;
277}
278
279int GetDefaultVp9SpatialLayers() {
280 int num_sl;
281 int num_tl;
282 if (GetVp9LayersFromFieldTrialGroup(&num_sl, &num_tl)) {
283 return num_sl;
284 }
285 return 1;
286}
287
288int GetDefaultVp9TemporalLayers() {
289 int num_sl;
290 int num_tl;
291 if (GetVp9LayersFromFieldTrialGroup(&num_sl, &num_tl)) {
292 return num_tl;
293 }
294 return 1;
295}
perkjfa10b552016-10-02 23:45:26 -0700296
297class EncoderStreamFactory
298 : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface {
299 public:
300 EncoderStreamFactory(std::string codec_name,
301 int max_qp,
302 int max_framerate,
303 bool is_screencast,
304 bool conference_mode)
305 : codec_name_(codec_name),
306 max_qp_(max_qp),
307 max_framerate_(max_framerate),
308 is_screencast_(is_screencast),
309 conference_mode_(conference_mode) {}
310
311 private:
312 std::vector<webrtc::VideoStream> CreateEncoderStreams(
313 int width,
314 int height,
315 const webrtc::VideoEncoderConfig& encoder_config) override {
316 RTC_DCHECK(encoder_config.number_of_streams > 1 ? !is_screencast_ : true);
317 if (encoder_config.number_of_streams > 1) {
318 return GetSimulcastConfig(encoder_config.number_of_streams, width, height,
319 encoder_config.max_bitrate_bps, max_qp_,
320 max_framerate_);
321 }
322
323 // For unset max bitrates set default bitrate for non-simulcast.
324 int max_bitrate_bps =
325 (encoder_config.max_bitrate_bps > 0)
326 ? encoder_config.max_bitrate_bps
327 : GetMaxDefaultVideoBitrateKbps(width, height) * 1000;
328
329 webrtc::VideoStream stream;
330 stream.width = width;
331 stream.height = height;
332 stream.max_framerate = max_framerate_;
333 stream.min_bitrate_bps = kMinVideoBitrateKbps * 1000;
334 stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate_bps;
335 stream.max_qp = max_qp_;
336
337 // Conference mode screencast uses 2 temporal layers split at 100kbit.
338 if (conference_mode_ && is_screencast_) {
339 ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault();
340 // For screenshare in conference mode, tl0 and tl1 bitrates are
341 // piggybacked
342 // on the VideoCodec struct as target and max bitrates, respectively.
343 // See eg. webrtc::VP8EncoderImpl::SetRates().
344 stream.target_bitrate_bps = config.tl0_bitrate_kbps * 1000;
345 stream.max_bitrate_bps = config.tl1_bitrate_kbps * 1000;
346 stream.temporal_layer_thresholds_bps.clear();
347 stream.temporal_layer_thresholds_bps.push_back(config.tl0_bitrate_kbps *
348 1000);
349 }
350
351 if (CodecNamesEq(codec_name_, kVp9CodecName) && !is_screencast_) {
352 stream.temporal_layer_thresholds_bps.resize(
353 GetDefaultVp9TemporalLayers() - 1);
354 }
355
356 std::vector<webrtc::VideoStream> streams;
357 streams.push_back(stream);
358 return streams;
359 }
360
361 const std::string codec_name_;
362 const int max_qp_;
363 const int max_framerate_;
364 const bool is_screencast_;
365 const bool conference_mode_;
366};
367
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000368} // namespace
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000369
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +0100370// Constants defined in webrtc/media/engine/constants.h
Peter Boström81ea54e2015-05-07 11:41:09 +0200371// TODO(pbos): Move these to a separate constants.cc file.
perkjfa10b552016-10-02 23:45:26 -0700372const int kMinVideoBitrateKbps = 30;
Peter Boström81ea54e2015-05-07 11:41:09 +0200373
374const int kVideoMtu = 1200;
375const int kVideoRtpBufferSize = 65536;
376
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000377// This constant is really an on/off, lower-level configurable NACK history
378// duration hasn't been implemented.
379static const int kNackHistoryMs = 1000;
380
buildbot@webrtc.org933d88a2014-09-18 20:23:05 +0000381static const int kDefaultQpMax = 56;
382
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000383static const int kDefaultRtcpReceiverReportSsrc = 1;
384
asapersson2e5cfcd2016-08-11 08:41:18 -0700385// Minimum time interval for logging stats.
386static const int64_t kStatsLogIntervalMs = 10000;
387
magjed1e45cc62016-10-28 07:43:45 -0700388static std::vector<VideoCodec> GetSupportedCodecs(
389 const WebRtcVideoEncoderFactory* external_encoder_factory);
390
kthelgason29a44e32016-09-27 03:52:02 -0700391rtc::scoped_refptr<webrtc::VideoEncoderConfig::EncoderSpecificSettings>
392WebRtcVideoChannel2::WebRtcVideoSendStream::ConfigureVideoEncoderSettings(
Niels Möller60653ba2016-03-02 11:41:36 +0100393 const VideoCodec& codec) {
perkjfa10b552016-10-02 23:45:26 -0700394 RTC_DCHECK_RUN_ON(&thread_checker_);
Niels Möller60653ba2016-03-02 11:41:36 +0100395 bool is_screencast = parameters_.options.is_screencast.value_or(false);
Peter Boström2feafdb2015-09-09 14:32:14 +0200396 // No automatic resizing when using simulcast or screencast.
397 bool automatic_resize =
398 !is_screencast && parameters_.config.rtp.ssrcs.size() == 1;
Erik Språng143cec12015-04-28 10:01:41 +0200399 bool frame_dropping = !is_screencast;
400 bool denoising;
pbos4cba4eb2015-10-26 11:18:18 -0700401 bool codec_default_denoising = false;
Erik Språng143cec12015-04-28 10:01:41 +0200402 if (is_screencast) {
403 denoising = false;
404 } else {
pbos4cba4eb2015-10-26 11:18:18 -0700405 // Use codec default if video_noise_reduction is unset.
Niels Möller60653ba2016-03-02 11:41:36 +0100406 codec_default_denoising = !parameters_.options.video_noise_reduction;
407 denoising = parameters_.options.video_noise_reduction.value_or(false);
Erik Språng143cec12015-04-28 10:01:41 +0200408 }
409
hbosbab934b2016-01-27 01:36:03 -0800410 if (CodecNamesEq(codec.name, kH264CodecName)) {
kthelgason29a44e32016-09-27 03:52:02 -0700411 webrtc::VideoCodecH264 h264_settings =
412 webrtc::VideoEncoder::GetDefaultH264Settings();
413 h264_settings.frameDroppingOn = frame_dropping;
414 return new rtc::RefCountedObject<
415 webrtc::VideoEncoderConfig::H264EncoderSpecificSettings>(h264_settings);
hbosbab934b2016-01-27 01:36:03 -0800416 }
Shao Changbine62202f2015-04-21 20:24:50 +0800417 if (CodecNamesEq(codec.name, kVp8CodecName)) {
kthelgason29a44e32016-09-27 03:52:02 -0700418 webrtc::VideoCodecVP8 vp8_settings =
419 webrtc::VideoEncoder::GetDefaultVp8Settings();
420 vp8_settings.automaticResizeOn = automatic_resize;
pbos4cba4eb2015-10-26 11:18:18 -0700421 // VP8 denoising is enabled by default.
kthelgason29a44e32016-09-27 03:52:02 -0700422 vp8_settings.denoisingOn = codec_default_denoising ? true : denoising;
423 vp8_settings.frameDroppingOn = frame_dropping;
424 return new rtc::RefCountedObject<
425 webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000426 }
Shao Changbine62202f2015-04-21 20:24:50 +0800427 if (CodecNamesEq(codec.name, kVp9CodecName)) {
kthelgason29a44e32016-09-27 03:52:02 -0700428 webrtc::VideoCodecVP9 vp9_settings =
429 webrtc::VideoEncoder::GetDefaultVp9Settings();
asaperssonc5dabdd2016-03-21 04:15:50 -0700430 if (is_screencast) {
431 // TODO(asapersson): Set to 2 for now since there is a DCHECK in
432 // VideoSendStream::ReconfigureVideoEncoder.
kthelgason29a44e32016-09-27 03:52:02 -0700433 vp9_settings.numberOfSpatialLayers = 2;
asaperssonc5dabdd2016-03-21 04:15:50 -0700434 } else {
kthelgason29a44e32016-09-27 03:52:02 -0700435 vp9_settings.numberOfSpatialLayers = GetDefaultVp9SpatialLayers();
asaperssonc5dabdd2016-03-21 04:15:50 -0700436 }
pbos4cba4eb2015-10-26 11:18:18 -0700437 // VP9 denoising is disabled by default.
kthelgason29a44e32016-09-27 03:52:02 -0700438 vp9_settings.denoisingOn = codec_default_denoising ? false : denoising;
439 vp9_settings.frameDroppingOn = frame_dropping;
440 return new rtc::RefCountedObject<
441 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
andresp@webrtc.org188d3b22014-11-07 13:21:04 +0000442 }
kthelgason29a44e32016-09-27 03:52:02 -0700443 return nullptr;
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000444}
445
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000446DefaultUnsignalledSsrcHandler::DefaultUnsignalledSsrcHandler()
nisse08582ff2016-02-04 01:24:52 -0800447 : default_recv_ssrc_(0), default_sink_(NULL) {}
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000448
449UnsignalledSsrcHandler::Action DefaultUnsignalledSsrcHandler::OnUnsignalledSsrc(
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +0000450 WebRtcVideoChannel2* channel,
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000451 uint32_t ssrc) {
452 if (default_recv_ssrc_ != 0) { // Already one default stream.
453 LOG(LS_WARNING) << "Unknown SSRC, but default receive stream already set.";
454 return kDropPacket;
455 }
456
457 StreamParams sp;
458 sp.ssrcs.push_back(ssrc);
459 LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << ".";
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +0000460 if (!channel->AddRecvStream(sp, true)) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000461 LOG(LS_WARNING) << "Could not create default receive stream.";
462 }
463
nisse08582ff2016-02-04 01:24:52 -0800464 channel->SetSink(ssrc, default_sink_);
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000465 default_recv_ssrc_ = ssrc;
466 return kDeliverPacket;
467}
468
nisseacd935b2016-11-11 03:55:13 -0800469rtc::VideoSinkInterface<webrtc::VideoFrame>*
nisse08582ff2016-02-04 01:24:52 -0800470DefaultUnsignalledSsrcHandler::GetDefaultSink() const {
471 return default_sink_;
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000472}
473
nisse08582ff2016-02-04 01:24:52 -0800474void DefaultUnsignalledSsrcHandler::SetDefaultSink(
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000475 VideoMediaChannel* channel,
nisseacd935b2016-11-11 03:55:13 -0800476 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
nisse08582ff2016-02-04 01:24:52 -0800477 default_sink_ = sink;
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000478 if (default_recv_ssrc_ != 0) {
nisse08582ff2016-02-04 01:24:52 -0800479 channel->SetSink(default_recv_ssrc_, default_sink_);
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000480 }
481}
482
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200483WebRtcVideoEngine2::WebRtcVideoEngine2()
484 : initialized_(false),
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000485 external_decoder_factory_(NULL),
486 external_encoder_factory_(NULL) {
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000487 LOG(LS_INFO) << "WebRtcVideoEngine2::WebRtcVideoEngine2()";
magjed3cf8ece2016-11-10 03:36:53 -0800488 video_codecs_ = GetSupportedCodecs(external_encoder_factory_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000489}
490
491WebRtcVideoEngine2::~WebRtcVideoEngine2() {
492 LOG(LS_INFO) << "WebRtcVideoEngine2::~WebRtcVideoEngine2";
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000493}
494
Fredrik Solenberg9a416bd2015-05-22 09:04:09 +0200495void WebRtcVideoEngine2::Init() {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000496 LOG(LS_INFO) << "WebRtcVideoEngine2::Init";
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000497 initialized_ = true;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000498}
499
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000500WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200501 webrtc::Call* call,
nisse51542be2016-02-12 02:27:06 -0800502 const MediaConfig& config,
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200503 const VideoOptions& options) {
henrikg91d6ede2015-09-17 00:24:34 -0700504 RTC_DCHECK(initialized_);
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200505 LOG(LS_INFO) << "CreateChannel. Options: " << options.ToString();
magjed23b7a4a2016-11-08 01:12:54 -0800506 return new WebRtcVideoChannel2(call, config, options,
nisse51542be2016-02-12 02:27:06 -0800507 external_encoder_factory_,
508 external_decoder_factory_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000509}
510
magjed3cf8ece2016-11-10 03:36:53 -0800511const std::vector<VideoCodec>& WebRtcVideoEngine2::codecs() const {
512 return video_codecs_;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000513}
514
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100515RtpCapabilities WebRtcVideoEngine2::GetCapabilities() const {
516 RtpCapabilities capabilities;
517 capabilities.header_extensions.push_back(
isheriff6f8d6862016-05-26 11:24:55 -0700518 webrtc::RtpExtension(webrtc::RtpExtension::kTimestampOffsetUri,
519 webrtc::RtpExtension::kTimestampOffsetDefaultId));
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100520 capabilities.header_extensions.push_back(
isheriff6f8d6862016-05-26 11:24:55 -0700521 webrtc::RtpExtension(webrtc::RtpExtension::kAbsSendTimeUri,
522 webrtc::RtpExtension::kAbsSendTimeDefaultId));
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100523 capabilities.header_extensions.push_back(
isheriff6f8d6862016-05-26 11:24:55 -0700524 webrtc::RtpExtension(webrtc::RtpExtension::kVideoRotationUri,
525 webrtc::RtpExtension::kVideoRotationDefaultId));
Stefan Holmer06a5e1a2016-09-02 12:36:49 +0200526 capabilities.header_extensions.push_back(webrtc::RtpExtension(
527 webrtc::RtpExtension::kTransportSequenceNumberUri,
528 webrtc::RtpExtension::kTransportSequenceNumberDefaultId));
isheriff6b4b5f32016-06-08 00:24:21 -0700529 capabilities.header_extensions.push_back(
530 webrtc::RtpExtension(webrtc::RtpExtension::kPlayoutDelayUri,
531 webrtc::RtpExtension::kPlayoutDelayDefaultId));
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100532 return capabilities;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000533}
534
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000535void WebRtcVideoEngine2::SetExternalDecoderFactory(
536 WebRtcVideoDecoderFactory* decoder_factory) {
henrikg91d6ede2015-09-17 00:24:34 -0700537 RTC_DCHECK(!initialized_);
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000538 external_decoder_factory_ = decoder_factory;
539}
540
541void WebRtcVideoEngine2::SetExternalEncoderFactory(
542 WebRtcVideoEncoderFactory* encoder_factory) {
henrikg91d6ede2015-09-17 00:24:34 -0700543 RTC_DCHECK(!initialized_);
pbos@webrtc.orgf18fba22015-01-14 16:26:23 +0000544 if (external_encoder_factory_ == encoder_factory)
545 return;
546
547 // No matter what happens we shouldn't hold on to a stale
548 // WebRtcSimulcastEncoderFactory.
549 simulcast_encoder_factory_.reset();
550
551 if (encoder_factory &&
552 WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory(
magjed1e45cc62016-10-28 07:43:45 -0700553 encoder_factory->supported_codecs())) {
pbos@webrtc.orgf18fba22015-01-14 16:26:23 +0000554 simulcast_encoder_factory_.reset(
555 new WebRtcSimulcastEncoderFactory(encoder_factory));
556 encoder_factory = simulcast_encoder_factory_.get();
557 }
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000558 external_encoder_factory_ = encoder_factory;
magjed3cf8ece2016-11-10 03:36:53 -0800559
560 video_codecs_ = GetSupportedCodecs(encoder_factory);
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000561}
562
magjed509e4fe2016-11-18 01:34:11 -0800563// This is a helper function for AppendVideoCodecs below. It will return the
564// first unused dynamic payload type (in the range [96, 127]), or nothing if no
565// payload type is unused.
566static rtc::Optional<int> NextFreePayloadType(
567 const std::vector<VideoCodec>& codecs) {
568 static const int kFirstDynamicPayloadType = 96;
569 static const int kLastDynamicPayloadType = 127;
570 bool is_payload_used[1 + kLastDynamicPayloadType - kFirstDynamicPayloadType] =
571 {false};
572 for (const VideoCodec& codec : codecs) {
573 if (kFirstDynamicPayloadType <= codec.id &&
574 codec.id <= kLastDynamicPayloadType) {
575 is_payload_used[codec.id - kFirstDynamicPayloadType] = true;
magjedeacbaea2016-11-17 08:51:59 -0800576 }
magjed509e4fe2016-11-18 01:34:11 -0800577 }
578 for (int i = kFirstDynamicPayloadType; i <= kLastDynamicPayloadType; ++i) {
579 if (!is_payload_used[i - kFirstDynamicPayloadType])
580 return rtc::Optional<int>(i);
581 }
582 // No free payload type.
583 return rtc::Optional<int>();
584}
585
586// This is a helper function for GetSupportedCodecs below. It will append new
587// unique codecs from |input_codecs| to |unified_codecs|. It will add default
588// feedback params to the codecs and will also add an associated RTX codec for
589// recognized codecs (VP8, VP9, H264, and Red).
590static void AppendVideoCodecs(const std::vector<VideoCodec>& input_codecs,
591 std::vector<VideoCodec>* unified_codecs) {
592 for (VideoCodec codec : input_codecs) {
593 const rtc::Optional<int> payload_type =
594 NextFreePayloadType(*unified_codecs);
595 if (!payload_type)
596 return;
597 codec.id = *payload_type;
598 // TODO(magjed): Move the responsibility of setting these parameters to the
599 // encoder factories instead.
600 if (codec.name != kRedCodecName && codec.name != kUlpfecCodecName)
601 AddDefaultFeedbackParams(&codec);
602 // Don't add same codec twice.
603 if (FindMatchingCodec(*unified_codecs, codec))
magjedeacbaea2016-11-17 08:51:59 -0800604 continue;
605
magjed509e4fe2016-11-18 01:34:11 -0800606 unified_codecs->push_back(codec);
magjedeacbaea2016-11-17 08:51:59 -0800607
magjed509e4fe2016-11-18 01:34:11 -0800608 // Add associated RTX codec for recognized codecs.
609 // TODO(deadbeef): Should we add RTX codecs for external codecs whose names
610 // we don't recognize?
611 if (CodecNamesEq(codec.name, kVp8CodecName) ||
612 CodecNamesEq(codec.name, kVp9CodecName) ||
613 CodecNamesEq(codec.name, kH264CodecName) ||
614 CodecNamesEq(codec.name, kRedCodecName)) {
615 const rtc::Optional<int> rtx_payload_type =
616 NextFreePayloadType(*unified_codecs);
617 if (!rtx_payload_type)
618 return;
619 unified_codecs->push_back(
620 VideoCodec::CreateRtxCodec(*rtx_payload_type, codec.id));
621 }
magjedeacbaea2016-11-17 08:51:59 -0800622 }
magjed509e4fe2016-11-18 01:34:11 -0800623}
624
625static std::vector<VideoCodec> GetSupportedCodecs(
626 const WebRtcVideoEncoderFactory* external_encoder_factory) {
627 const std::vector<VideoCodec> internal_codecs =
628 InternalEncoderFactory().supported_codecs();
629 LOG(LS_INFO) << "Internally supported codecs: "
630 << CodecVectorToString(internal_codecs);
631
632 std::vector<VideoCodec> unified_codecs;
633 AppendVideoCodecs(internal_codecs, &unified_codecs);
634
635 if (external_encoder_factory != nullptr) {
636 const std::vector<VideoCodec>& external_codecs =
637 external_encoder_factory->supported_codecs();
638 AppendVideoCodecs(external_codecs, &unified_codecs);
639 LOG(LS_INFO) << "Codecs supported by the external encoder factory: "
640 << CodecVectorToString(external_codecs);
641 }
642
643 return unified_codecs;
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000644}
645
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000646WebRtcVideoChannel2::WebRtcVideoChannel2(
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200647 webrtc::Call* call,
nisse51542be2016-02-12 02:27:06 -0800648 const MediaConfig& config,
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000649 const VideoOptions& options,
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000650 WebRtcVideoEncoderFactory* external_encoder_factory,
pbos@webrtc.orgf1c8b902015-01-14 17:29:27 +0000651 WebRtcVideoDecoderFactory* external_decoder_factory)
nisse51542be2016-02-12 02:27:06 -0800652 : VideoMediaChannel(config),
653 call_(call),
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200654 unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_),
nisse0db023a2016-03-01 04:29:59 -0800655 video_config_(config.video),
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000656 external_encoder_factory_(external_encoder_factory),
nisse05103312016-03-16 02:22:50 -0700657 external_decoder_factory_(external_decoder_factory),
Stefan Holmer2b1f6512016-05-17 16:33:30 +0200658 default_send_options_(options),
asapersson2e5cfcd2016-08-11 08:41:18 -0700659 last_stats_log_ms_(-1) {
henrikg91d6ede2015-09-17 00:24:34 -0700660 RTC_DCHECK(thread_checker_.CalledOnValidThread());
nissea293ef02016-02-17 07:24:50 -0800661
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000662 rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc;
663 sending_ = false;
magjed23b7a4a2016-11-08 01:12:54 -0800664 recv_codecs_ = MapCodecs(GetSupportedCodecs(external_encoder_factory));
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000665}
666
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000667WebRtcVideoChannel2::~WebRtcVideoChannel2() {
Peter Boströmdfd53fe2015-03-27 15:58:11 +0100668 for (auto& kv : send_streams_)
669 delete kv.second;
670 for (auto& kv : receive_streams_)
671 delete kv.second;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000672}
673
magjed23b7a4a2016-11-08 01:12:54 -0800674rtc::Optional<WebRtcVideoChannel2::VideoCodecSettings>
675WebRtcVideoChannel2::SelectSendVideoCodec(
676 const std::vector<VideoCodecSettings>& remote_mapped_codecs) const {
677 const std::vector<VideoCodec> local_supported_codecs =
magjed1e45cc62016-10-28 07:43:45 -0700678 GetSupportedCodecs(external_encoder_factory_);
magjed23b7a4a2016-11-08 01:12:54 -0800679 // Select the first remote codec that is supported locally.
680 for (const VideoCodecSettings& remote_mapped_codec : remote_mapped_codecs) {
magjedf823ede2016-11-12 09:53:04 -0800681 // For H264, we will limit the encode level to the remote offered level
682 // regardless if level asymmetry is allowed or not. This is strictly not
683 // following the spec in https://tools.ietf.org/html/rfc6184#section-8.2.2
684 // since we should limit the encode level to the lower of local and remote
685 // level when level asymmetry is not allowed.
686 if (FindMatchingCodec(local_supported_codecs, remote_mapped_codec.codec))
magjed23b7a4a2016-11-08 01:12:54 -0800687 return rtc::Optional<VideoCodecSettings>(remote_mapped_codec);
pbos@webrtc.org96a93252014-11-03 14:46:44 +0000688 }
magjed23b7a4a2016-11-08 01:12:54 -0800689 // No remote codec was supported.
690 return rtc::Optional<VideoCodecSettings>();
pbos@webrtc.org96a93252014-11-03 14:46:44 +0000691}
692
deadbeef874ca3a2015-08-20 17:19:20 -0700693bool WebRtcVideoChannel2::ReceiveCodecsHaveChanged(
694 std::vector<VideoCodecSettings> before,
695 std::vector<VideoCodecSettings> after) {
696 if (before.size() != after.size()) {
697 return true;
698 }
699 // The receive codec order doesn't matter, so we sort the codecs before
700 // comparing. This is necessary because currently the
701 // only way to change the send codec is to munge SDP, which causes
702 // the receive codec list to change order, which causes the streams
703 // to be recreates which causes a "blink" of black video. In order
704 // to support munging the SDP in this way without recreating receive
705 // streams, we ignore the order of the received codecs so that
706 // changing the order doesn't cause this "blink".
707 auto comparison =
708 [](const VideoCodecSettings& codec1, const VideoCodecSettings& codec2) {
709 return codec1.codec.id > codec2.codec.id;
710 };
711 std::sort(before.begin(), before.end(), comparison);
712 std::sort(after.begin(), after.end(), comparison);
deadbeef67cf2c12016-04-13 10:07:16 -0700713 return before != after;
deadbeef874ca3a2015-08-20 17:19:20 -0700714}
715
Peter Boström3afc8c42016-01-27 16:45:21 +0100716bool WebRtcVideoChannel2::GetChangedSendParameters(
717 const VideoSendParameters& params,
718 ChangedSendParameters* changed_params) const {
719 if (!ValidateCodecFormats(params.codecs) ||
720 !ValidateRtpExtensions(params.extensions)) {
721 return false;
722 }
723
magjed23b7a4a2016-11-08 01:12:54 -0800724 // Select one of the remote codecs that will be used as send codec.
725 const rtc::Optional<VideoCodecSettings> selected_send_codec =
726 SelectSendVideoCodec(MapCodecs(params.codecs));
Peter Boström3afc8c42016-01-27 16:45:21 +0100727
magjed23b7a4a2016-11-08 01:12:54 -0800728 if (!selected_send_codec) {
Peter Boström3afc8c42016-01-27 16:45:21 +0100729 LOG(LS_ERROR) << "No video codecs supported.";
730 return false;
731 }
732
magjed23b7a4a2016-11-08 01:12:54 -0800733 if (!send_codec_ || *selected_send_codec != *send_codec_)
734 changed_params->codec = selected_send_codec;
Peter Boström3afc8c42016-01-27 16:45:21 +0100735
pbos378dc772016-01-28 15:58:41 -0800736 // Handle RTP header extensions.
Peter Boström3afc8c42016-01-27 16:45:21 +0100737 std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions(
738 params.extensions, webrtc::RtpExtension::IsSupportedForVideo, true);
skvlad3abb7642016-06-16 12:08:03 -0700739 if (!send_rtp_extensions_ || (*send_rtp_extensions_ != filtered_extensions)) {
Peter Boström3afc8c42016-01-27 16:45:21 +0100740 changed_params->rtp_header_extensions =
741 rtc::Optional<std::vector<webrtc::RtpExtension>>(filtered_extensions);
742 }
743
pbos378dc772016-01-28 15:58:41 -0800744 // Handle max bitrate.
Taylor Brandstetter58f2bd92016-04-26 17:15:23 -0700745 if (params.max_bandwidth_bps != send_params_.max_bandwidth_bps &&
Peter Boström3afc8c42016-01-27 16:45:21 +0100746 params.max_bandwidth_bps >= 0) {
747 // 0 uncaps max bitrate (-1).
748 changed_params->max_bandwidth_bps = rtc::Optional<int>(
749 params.max_bandwidth_bps == 0 ? -1 : params.max_bandwidth_bps);
750 }
751
nisse4b4dc862016-02-17 05:25:36 -0800752 // Handle conference mode.
753 if (params.conference_mode != send_params_.conference_mode) {
754 changed_params->conference_mode =
755 rtc::Optional<bool>(params.conference_mode);
756 }
757
pbos378dc772016-01-28 15:58:41 -0800758 // Handle RTCP mode.
Peter Boström3afc8c42016-01-27 16:45:21 +0100759 if (params.rtcp.reduced_size != send_params_.rtcp.reduced_size) {
760 changed_params->rtcp_mode = rtc::Optional<webrtc::RtcpMode>(
761 params.rtcp.reduced_size ? webrtc::RtcpMode::kReducedSize
762 : webrtc::RtcpMode::kCompound);
763 }
764
765 return true;
766}
767
nisse51542be2016-02-12 02:27:06 -0800768rtc::DiffServCodePoint WebRtcVideoChannel2::PreferredDscp() const {
769 return rtc::DSCP_AF41;
770}
771
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700772bool WebRtcVideoChannel2::SetSendParameters(const VideoSendParameters& params) {
Peter Boström9f45a452015-12-08 13:25:57 +0100773 TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetSendParameters");
solenberg7e4e01a2015-12-02 08:05:01 -0800774 LOG(LS_INFO) << "SetSendParameters: " << params.ToString();
Peter Boström3afc8c42016-01-27 16:45:21 +0100775 ChangedSendParameters changed_params;
776 if (!GetChangedSendParameters(params, &changed_params)) {
deadbeef13871492015-12-09 12:37:51 -0800777 return false;
778 }
Peter Boström3afc8c42016-01-27 16:45:21 +0100779
Peter Boström3afc8c42016-01-27 16:45:21 +0100780 if (changed_params.codec) {
781 const VideoCodecSettings& codec_settings = *changed_params.codec;
782 send_codec_ = rtc::Optional<VideoCodecSettings>(codec_settings);
Peter Boström3afc8c42016-01-27 16:45:21 +0100783 LOG(LS_INFO) << "Using codec: " << codec_settings.codec.ToString();
Peter Boström3afc8c42016-01-27 16:45:21 +0100784 }
785
786 if (changed_params.rtp_header_extensions) {
skvlad3abb7642016-06-16 12:08:03 -0700787 send_rtp_extensions_ = changed_params.rtp_header_extensions;
Peter Boström3afc8c42016-01-27 16:45:21 +0100788 }
789
Taylor Brandstetter58f2bd92016-04-26 17:15:23 -0700790 if (changed_params.codec || changed_params.max_bandwidth_bps) {
791 if (send_codec_) {
792 // TODO(holmer): Changing the codec parameters shouldn't necessarily mean
793 // that we change the min/max of bandwidth estimation. Reevaluate this.
794 bitrate_config_ = GetBitrateConfigForCodec(send_codec_->codec);
795 if (!changed_params.codec) {
796 // If the codec isn't changing, set the start bitrate to -1 which means
797 // "unchanged" so that BWE isn't affected.
798 bitrate_config_.start_bitrate_bps = -1;
799 }
Peter Boström3afc8c42016-01-27 16:45:21 +0100800 }
Taylor Brandstetter58f2bd92016-04-26 17:15:23 -0700801 if (params.max_bandwidth_bps >= 0) {
802 // Note that max_bandwidth_bps intentionally takes priority over the
803 // bitrate config for the codec. This allows FEC to be applied above the
804 // codec target bitrate.
805 // TODO(pbos): Figure out whether b=AS means max bitrate for this
806 // WebRtcVideoChannel2 (in which case we're good), or per sender (SSRC),
807 // in which case this should not set a Call::BitrateConfig but rather
808 // reconfigure all senders.
809 bitrate_config_.max_bitrate_bps =
810 params.max_bandwidth_bps == 0 ? -1 : params.max_bandwidth_bps;
811 }
Peter Boström3afc8c42016-01-27 16:45:21 +0100812 call_->SetBitrateConfig(bitrate_config_);
813 }
814
Peter Boström3afc8c42016-01-27 16:45:21 +0100815 {
deadbeef13871492015-12-09 12:37:51 -0800816 rtc::CritScope stream_lock(&stream_crit_);
817 for (auto& kv : send_streams_) {
Peter Boström3afc8c42016-01-27 16:45:21 +0100818 kv.second->SetSendParameters(changed_params);
819 }
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700820 if (changed_params.codec || changed_params.rtcp_mode) {
821 // Update receive feedback parameters from new codec or RTCP mode.
Peter Boström3afc8c42016-01-27 16:45:21 +0100822 LOG(LS_INFO)
823 << "SetFeedbackOptions on all the receive streams because the send "
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700824 "codec or RTCP mode has changed.";
Peter Boström3afc8c42016-01-27 16:45:21 +0100825 for (auto& kv : receive_streams_) {
826 RTC_DCHECK(kv.second != nullptr);
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -0700827 kv.second->SetFeedbackParameters(
828 HasNack(send_codec_->codec), HasRemb(send_codec_->codec),
829 HasTransportCc(send_codec_->codec),
830 params.rtcp.reduced_size ? webrtc::RtcpMode::kReducedSize
831 : webrtc::RtcpMode::kCompound);
Peter Boström3afc8c42016-01-27 16:45:21 +0100832 }
deadbeef13871492015-12-09 12:37:51 -0800833 }
834 }
835 send_params_ = params;
836 return true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700837}
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -0700838
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700839webrtc::RtpParameters WebRtcVideoChannel2::GetRtpSendParameters(
skvladdc1c62c2016-03-16 19:07:43 -0700840 uint32_t ssrc) const {
841 rtc::CritScope stream_lock(&stream_crit_);
842 auto it = send_streams_.find(ssrc);
843 if (it == send_streams_.end()) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700844 LOG(LS_WARNING) << "Attempting to get RTP send parameters for stream "
845 << "with ssrc " << ssrc << " which doesn't exist.";
skvladdc1c62c2016-03-16 19:07:43 -0700846 return webrtc::RtpParameters();
847 }
848
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -0700849 webrtc::RtpParameters rtp_params = it->second->GetRtpParameters();
850 // Need to add the common list of codecs to the send stream-specific
851 // RTP parameters.
852 for (const VideoCodec& codec : send_params_.codecs) {
853 rtp_params.codecs.push_back(codec.ToCodecParameters());
854 }
855 return rtp_params;
skvladdc1c62c2016-03-16 19:07:43 -0700856}
857
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700858bool WebRtcVideoChannel2::SetRtpSendParameters(
skvladdc1c62c2016-03-16 19:07:43 -0700859 uint32_t ssrc,
860 const webrtc::RtpParameters& parameters) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700861 TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetRtpSendParameters");
skvladdc1c62c2016-03-16 19:07:43 -0700862 rtc::CritScope stream_lock(&stream_crit_);
863 auto it = send_streams_.find(ssrc);
864 if (it == send_streams_.end()) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700865 LOG(LS_ERROR) << "Attempting to set RTP send parameters for stream "
866 << "with ssrc " << ssrc << " which doesn't exist.";
skvladdc1c62c2016-03-16 19:07:43 -0700867 return false;
868 }
869
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -0700870 // TODO(deadbeef): Handle setting parameters with a list of codecs in a
871 // different order (which should change the send codec).
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700872 webrtc::RtpParameters current_parameters = GetRtpSendParameters(ssrc);
873 if (current_parameters.codecs != parameters.codecs) {
874 LOG(LS_ERROR) << "Using SetParameters to change the set of codecs "
875 << "is not currently supported.";
876 return false;
877 }
878
skvladdc1c62c2016-03-16 19:07:43 -0700879 return it->second->SetRtpParameters(parameters);
880}
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700881
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700882webrtc::RtpParameters WebRtcVideoChannel2::GetRtpReceiveParameters(
883 uint32_t ssrc) const {
884 rtc::CritScope stream_lock(&stream_crit_);
885 auto it = receive_streams_.find(ssrc);
886 if (it == receive_streams_.end()) {
887 LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
888 << "with ssrc " << ssrc << " which doesn't exist.";
889 return webrtc::RtpParameters();
890 }
891
892 // TODO(deadbeef): Return stream-specific parameters.
893 webrtc::RtpParameters rtp_params = CreateRtpParametersWithOneEncoding();
894 for (const VideoCodec& codec : recv_params_.codecs) {
895 rtp_params.codecs.push_back(codec.ToCodecParameters());
896 }
sakal1fd95952016-06-22 00:46:15 -0700897 rtp_params.encodings[0].ssrc = it->second->GetFirstPrimarySsrc();
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -0700898 return rtp_params;
899}
900
901bool WebRtcVideoChannel2::SetRtpReceiveParameters(
902 uint32_t ssrc,
903 const webrtc::RtpParameters& parameters) {
904 TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetRtpReceiveParameters");
905 rtc::CritScope stream_lock(&stream_crit_);
906 auto it = receive_streams_.find(ssrc);
907 if (it == receive_streams_.end()) {
908 LOG(LS_ERROR) << "Attempting to set RTP receive parameters for stream "
909 << "with ssrc " << ssrc << " which doesn't exist.";
910 return false;
911 }
912
913 webrtc::RtpParameters current_parameters = GetRtpReceiveParameters(ssrc);
914 if (current_parameters != parameters) {
915 LOG(LS_ERROR) << "Changing the RTP receive parameters is currently "
916 << "unsupported.";
917 return false;
918 }
919 return true;
920}
921
pbos378dc772016-01-28 15:58:41 -0800922bool WebRtcVideoChannel2::GetChangedRecvParameters(
923 const VideoRecvParameters& params,
924 ChangedRecvParameters* changed_params) const {
925 if (!ValidateCodecFormats(params.codecs) ||
926 !ValidateRtpExtensions(params.extensions)) {
927 return false;
928 }
929
930 // Handle receive codecs.
931 const std::vector<VideoCodecSettings> mapped_codecs =
932 MapCodecs(params.codecs);
933 if (mapped_codecs.empty()) {
934 LOG(LS_ERROR) << "SetRecvParameters called without any video codecs.";
935 return false;
936 }
937
magjed23b7a4a2016-11-08 01:12:54 -0800938 // Verify that every mapped codec is supported locally.
939 const std::vector<VideoCodec> local_supported_codecs =
940 GetSupportedCodecs(external_encoder_factory_);
941 for (const VideoCodecSettings& mapped_codec : mapped_codecs) {
magjedf823ede2016-11-12 09:53:04 -0800942 if (!FindMatchingCodec(local_supported_codecs, mapped_codec.codec)) {
magjed23b7a4a2016-11-08 01:12:54 -0800943 LOG(LS_ERROR) << "SetRecvParameters called with unsupported video codec: "
944 << mapped_codec.codec.ToString();
945 return false;
946 }
pbos378dc772016-01-28 15:58:41 -0800947 }
948
magjed23b7a4a2016-11-08 01:12:54 -0800949 if (ReceiveCodecsHaveChanged(recv_codecs_, mapped_codecs)) {
pbos378dc772016-01-28 15:58:41 -0800950 changed_params->codec_settings =
magjed23b7a4a2016-11-08 01:12:54 -0800951 rtc::Optional<std::vector<VideoCodecSettings>>(mapped_codecs);
pbos378dc772016-01-28 15:58:41 -0800952 }
953
954 // Handle RTP header extensions.
955 std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions(
956 params.extensions, webrtc::RtpExtension::IsSupportedForVideo, false);
957 if (filtered_extensions != recv_rtp_extensions_) {
958 changed_params->rtp_header_extensions =
959 rtc::Optional<std::vector<webrtc::RtpExtension>>(filtered_extensions);
960 }
961
pbos378dc772016-01-28 15:58:41 -0800962 return true;
963}
964
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700965bool WebRtcVideoChannel2::SetRecvParameters(const VideoRecvParameters& params) {
Peter Boström9f45a452015-12-08 13:25:57 +0100966 TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetRecvParameters");
solenberg7e4e01a2015-12-02 08:05:01 -0800967 LOG(LS_INFO) << "SetRecvParameters: " << params.ToString();
pbos378dc772016-01-28 15:58:41 -0800968 ChangedRecvParameters changed_params;
969 if (!GetChangedRecvParameters(params, &changed_params)) {
deadbeef13871492015-12-09 12:37:51 -0800970 return false;
971 }
pbos378dc772016-01-28 15:58:41 -0800972 if (changed_params.rtp_header_extensions) {
973 recv_rtp_extensions_ = *changed_params.rtp_header_extensions;
974 }
975 if (changed_params.codec_settings) {
976 LOG(LS_INFO) << "Changing recv codecs from "
977 << CodecSettingsVectorToString(recv_codecs_) << " to "
978 << CodecSettingsVectorToString(*changed_params.codec_settings);
979 recv_codecs_ = *changed_params.codec_settings;
980 }
981
982 {
deadbeef13871492015-12-09 12:37:51 -0800983 rtc::CritScope stream_lock(&stream_crit_);
984 for (auto& kv : receive_streams_) {
pbos378dc772016-01-28 15:58:41 -0800985 kv.second->SetRecvParameters(changed_params);
deadbeef13871492015-12-09 12:37:51 -0800986 }
987 }
988 recv_params_ = params;
989 return true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -0700990}
991
deadbeef874ca3a2015-08-20 17:19:20 -0700992std::string WebRtcVideoChannel2::CodecSettingsVectorToString(
993 const std::vector<VideoCodecSettings>& codecs) {
994 std::stringstream out;
995 out << '{';
996 for (size_t i = 0; i < codecs.size(); ++i) {
997 out << codecs[i].codec.ToString();
998 if (i != codecs.size() - 1) {
999 out << ", ";
1000 }
1001 }
1002 out << '}';
1003 return out.str();
1004}
1005
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001006bool WebRtcVideoChannel2::GetSendCodec(VideoCodec* codec) {
kwiberg102c6a62015-10-30 02:47:38 -07001007 if (!send_codec_) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001008 LOG(LS_VERBOSE) << "GetSendCodec: No send codec set.";
1009 return false;
1010 }
kwiberg102c6a62015-10-30 02:47:38 -07001011 *codec = send_codec_->codec;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001012 return true;
1013}
1014
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001015bool WebRtcVideoChannel2::SetSend(bool send) {
Peter Boströmdabc9442016-04-11 11:45:14 +02001016 TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetSend");
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001017 LOG(LS_VERBOSE) << "SetSend: " << (send ? "true" : "false");
kwiberg102c6a62015-10-30 02:47:38 -07001018 if (send && !send_codec_) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001019 LOG(LS_ERROR) << "SetSend(true) called before setting codec.";
1020 return false;
1021 }
deadbeefdbe2b872016-03-22 15:42:00 -07001022 {
1023 rtc::CritScope stream_lock(&stream_crit_);
1024 for (const auto& kv : send_streams_) {
1025 kv.second->SetSend(send);
1026 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001027 }
1028 sending_ = send;
1029 return true;
1030}
1031
nisse2ded9b12016-04-08 02:23:55 -07001032// TODO(nisse): The enable argument was used for mute logic which has
deadbeef5a4a75a2016-06-02 16:23:38 -07001033// been moved to VideoBroadcaster. So remove the argument from this
1034// method.
1035bool WebRtcVideoChannel2::SetVideoSend(
1036 uint32_t ssrc,
1037 bool enable,
1038 const VideoOptions* options,
nisseacd935b2016-11-11 03:55:13 -08001039 rtc::VideoSourceInterface<webrtc::VideoFrame>* source) {
Peter Boström3afc8c42016-01-27 16:45:21 +01001040 TRACE_EVENT0("webrtc", "SetVideoSend");
deadbeef5a4a75a2016-06-02 16:23:38 -07001041 RTC_DCHECK(ssrc != 0);
Peter Boström3afc8c42016-01-27 16:45:21 +01001042 LOG(LS_INFO) << "SetVideoSend (ssrc= " << ssrc << ", enable = " << enable
deadbeef5a4a75a2016-06-02 16:23:38 -07001043 << ", options: " << (options ? options->ToString() : "nullptr")
1044 << ", source = " << (source ? "(source)" : "nullptr") << ")";
Peter Boström3afc8c42016-01-27 16:45:21 +01001045
deadbeef5a4a75a2016-06-02 16:23:38 -07001046 rtc::CritScope stream_lock(&stream_crit_);
1047 const auto& kv = send_streams_.find(ssrc);
1048 if (kv == send_streams_.end()) {
1049 // Allow unknown ssrc only if source is null.
1050 RTC_CHECK(source == nullptr);
1051 LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
1052 return false;
solenberg1dd98f32015-09-10 01:57:14 -07001053 }
deadbeef5a4a75a2016-06-02 16:23:38 -07001054
1055 return kv->second->SetVideoSend(enable, options, source);
solenberg1dd98f32015-09-10 01:57:14 -07001056}
1057
Peter Boströmd6f4c252015-03-26 16:23:04 +01001058bool WebRtcVideoChannel2::ValidateSendSsrcAvailability(
1059 const StreamParams& sp) const {
Pera5092412016-02-12 13:30:57 +01001060 for (uint32_t ssrc : sp.ssrcs) {
Peter Boströmd6f4c252015-03-26 16:23:04 +01001061 if (send_ssrcs_.find(ssrc) != send_ssrcs_.end()) {
1062 LOG(LS_ERROR) << "Send stream with SSRC '" << ssrc << "' already exists.";
1063 return false;
1064 }
1065 }
1066 return true;
1067}
1068
1069bool WebRtcVideoChannel2::ValidateReceiveSsrcAvailability(
1070 const StreamParams& sp) const {
Pera5092412016-02-12 13:30:57 +01001071 for (uint32_t ssrc : sp.ssrcs) {
Peter Boströmd6f4c252015-03-26 16:23:04 +01001072 if (receive_ssrcs_.find(ssrc) != receive_ssrcs_.end()) {
1073 LOG(LS_ERROR) << "Receive stream with SSRC '" << ssrc
1074 << "' already exists.";
1075 return false;
1076 }
1077 }
1078 return true;
1079}
1080
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001081bool WebRtcVideoChannel2::AddSendStream(const StreamParams& sp) {
1082 LOG(LS_INFO) << "AddSendStream: " << sp.ToString();
Peter Boströmd4362cd2015-03-25 14:17:23 +01001083 if (!ValidateStreamParams(sp))
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001084 return false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001085
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001086 rtc::CritScope stream_lock(&stream_crit_);
Peter Boströmd6f4c252015-03-26 16:23:04 +01001087
1088 if (!ValidateSendSsrcAvailability(sp))
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001089 return false;
Peter Boströmd6f4c252015-03-26 16:23:04 +01001090
Peter Boström0c4e06b2015-10-07 12:23:21 +02001091 for (uint32_t used_ssrc : sp.ssrcs)
Peter Boströmd6f4c252015-03-26 16:23:04 +01001092 send_ssrcs_.insert(used_ssrc);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001093
solenberge5269742015-09-08 05:13:22 -07001094 webrtc::VideoSendStream::Config config(this);
nisse0db023a2016-03-01 04:29:59 -08001095 config.suspend_below_min_bitrate = video_config_.suspend_below_min_bitrate;
nisse05103312016-03-16 02:22:50 -07001096 WebRtcVideoSendStream* stream = new WebRtcVideoSendStream(
perkj26091b12016-09-01 01:17:40 -07001097 call_, sp, std::move(config), default_send_options_,
1098 external_encoder_factory_, video_config_.enable_cpu_overuse_detection,
nisse05103312016-03-16 02:22:50 -07001099 bitrate_config_.max_bitrate_bps, send_codec_, send_rtp_extensions_,
1100 send_params_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001101
Peter Boström0c4e06b2015-10-07 12:23:21 +02001102 uint32_t ssrc = sp.first_ssrc();
henrikg91d6ede2015-09-17 00:24:34 -07001103 RTC_DCHECK(ssrc != 0);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001104 send_streams_[ssrc] = stream;
1105
1106 if (rtcp_receiver_report_ssrc_ == kDefaultRtcpReceiverReportSsrc) {
1107 rtcp_receiver_report_ssrc_ = ssrc;
deadbeef874ca3a2015-08-20 17:19:20 -07001108 LOG(LS_INFO) << "SetLocalSsrc on all the receive streams because we added "
1109 "a send stream.";
Peter Boström3548dd22015-05-22 18:48:36 +02001110 for (auto& kv : receive_streams_)
1111 kv.second->SetLocalSsrc(ssrc);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001112 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001113 if (sending_) {
deadbeefdbe2b872016-03-22 15:42:00 -07001114 stream->SetSend(true);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001115 }
1116
1117 return true;
1118}
1119
Peter Boström0c4e06b2015-10-07 12:23:21 +02001120bool WebRtcVideoChannel2::RemoveSendStream(uint32_t ssrc) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001121 LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
1122
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001123 WebRtcVideoSendStream* removed_stream;
1124 {
1125 rtc::CritScope stream_lock(&stream_crit_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001126 std::map<uint32_t, WebRtcVideoSendStream*>::iterator it =
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001127 send_streams_.find(ssrc);
1128 if (it == send_streams_.end()) {
1129 return false;
1130 }
1131
Peter Boström0c4e06b2015-10-07 12:23:21 +02001132 for (uint32_t old_ssrc : it->second->GetSsrcs())
Peter Boströmd6f4c252015-03-26 16:23:04 +01001133 send_ssrcs_.erase(old_ssrc);
1134
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001135 removed_stream = it->second;
1136 send_streams_.erase(it);
Peter Boströmdfa28152015-10-21 17:21:10 +02001137
1138 // Switch receiver report SSRCs, the one in use is no longer valid.
1139 if (rtcp_receiver_report_ssrc_ == ssrc) {
1140 rtcp_receiver_report_ssrc_ = send_streams_.empty()
1141 ? kDefaultRtcpReceiverReportSsrc
1142 : send_streams_.begin()->first;
1143 LOG(LS_INFO) << "SetLocalSsrc on all the receive streams because the "
1144 "previous local SSRC was removed.";
1145
1146 for (auto& kv : receive_streams_) {
1147 kv.second->SetLocalSsrc(rtcp_receiver_report_ssrc_);
1148 }
1149 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001150 }
1151
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001152 delete removed_stream;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001153
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001154 return true;
1155}
1156
Peter Boströmd6f4c252015-03-26 16:23:04 +01001157void WebRtcVideoChannel2::DeleteReceiveStream(
1158 WebRtcVideoChannel2::WebRtcVideoReceiveStream* stream) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001159 for (uint32_t old_ssrc : stream->GetSsrcs())
Peter Boströmd6f4c252015-03-26 16:23:04 +01001160 receive_ssrcs_.erase(old_ssrc);
1161 delete stream;
1162}
1163
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001164bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +00001165 return AddRecvStream(sp, false);
1166}
1167
1168bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp,
1169 bool default_stream) {
henrikg91d6ede2015-09-17 00:24:34 -07001170 RTC_DCHECK(thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02001171
Peter Boströmd4362cd2015-03-25 14:17:23 +01001172 LOG(LS_INFO) << "AddRecvStream" << (default_stream ? " (default stream)" : "")
1173 << ": " << sp.ToString();
1174 if (!ValidateStreamParams(sp))
1175 return false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001176
Peter Boström0c4e06b2015-10-07 12:23:21 +02001177 uint32_t ssrc = sp.first_ssrc();
henrikg91d6ede2015-09-17 00:24:34 -07001178 RTC_DCHECK(ssrc != 0); // TODO(pbos): Is this ever valid?
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001179
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001180 rtc::CritScope stream_lock(&stream_crit_);
Peter Boströmd6f4c252015-03-26 16:23:04 +01001181 // Remove running stream if this was a default stream.
nissea293ef02016-02-17 07:24:50 -08001182 const auto& prev_stream = receive_streams_.find(ssrc);
Peter Boströmd6f4c252015-03-26 16:23:04 +01001183 if (prev_stream != receive_streams_.end()) {
1184 if (default_stream || !prev_stream->second->IsDefaultStream()) {
1185 LOG(LS_ERROR) << "Receive stream for SSRC '" << ssrc
1186 << "' already exists.";
1187 return false;
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +00001188 }
Peter Boströmd6f4c252015-03-26 16:23:04 +01001189 DeleteReceiveStream(prev_stream->second);
1190 receive_streams_.erase(prev_stream);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001191 }
1192
Peter Boströmd6f4c252015-03-26 16:23:04 +01001193 if (!ValidateReceiveSsrcAvailability(sp))
1194 return false;
1195
Peter Boström0c4e06b2015-10-07 12:23:21 +02001196 for (uint32_t used_ssrc : sp.ssrcs)
Peter Boströmd6f4c252015-03-26 16:23:04 +01001197 receive_ssrcs_.insert(used_ssrc);
1198
solenberg4fbae2b2015-08-28 04:07:10 -07001199 webrtc::VideoReceiveStream::Config config(this);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001200 ConfigureReceiverRtp(&config, sp);
pbos@webrtc.org3bf3d232014-10-31 12:59:34 +00001201
pbos8fc7fa72015-07-15 08:02:58 -07001202 // Set up A/V sync group based on sync label.
1203 config.sync_group = sp.sync_label;
pbos@webrtc.org3bf3d232014-10-31 12:59:34 +00001204
kwiberg102c6a62015-10-30 02:47:38 -07001205 config.rtp.remb = send_codec_ ? HasRemb(send_codec_->codec) : false;
stefan43edf0f2015-11-20 18:05:48 -08001206 config.rtp.transport_cc =
1207 send_codec_ ? HasTransportCc(send_codec_->codec) : false;
nisse7ade7b32016-03-23 04:48:10 -07001208 config.disable_prerenderer_smoothing =
1209 video_config_.disable_prerenderer_smoothing;
Peter Boström126c03e2015-05-11 12:48:12 +02001210
Peter Boströmd6f4c252015-03-26 16:23:04 +01001211 receive_streams_[ssrc] = new WebRtcVideoReceiveStream(
Tommi733b5472016-06-10 17:58:01 +02001212 call_, sp, std::move(config), external_decoder_factory_, default_stream,
brandtre6f98c72016-11-11 03:28:30 -08001213 recv_codecs_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001214
1215 return true;
1216}
1217
1218void WebRtcVideoChannel2::ConfigureReceiverRtp(
1219 webrtc::VideoReceiveStream::Config* config,
1220 const StreamParams& sp) const {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001221 uint32_t ssrc = sp.first_ssrc();
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001222
1223 config->rtp.remote_ssrc = ssrc;
1224 config->rtp.local_ssrc = rtcp_receiver_report_ssrc_;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001225
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001226 config->rtp.extensions = recv_rtp_extensions_;
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07001227 // Whether or not the receive stream sends reduced size RTCP is determined
1228 // by the send params.
1229 // TODO(deadbeef): Once we change "send_params" to "sender_params" and
1230 // "recv_params" to "receiver_params", we should get this out of
1231 // receiver_params_.
1232 config->rtp.rtcp_mode = send_params_.rtcp.reduced_size
deadbeef13871492015-12-09 12:37:51 -08001233 ? webrtc::RtcpMode::kReducedSize
1234 : webrtc::RtcpMode::kCompound;
pbos@webrtc.org257e1302014-07-25 19:01:32 +00001235
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001236 // TODO(pbos): This protection is against setting the same local ssrc as
1237 // remote which is not permitted by the lower-level API. RTCP requires a
1238 // corresponding sender SSRC. Figure out what to do when we don't have
1239 // (receive-only) or know a good local SSRC.
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001240 if (config->rtp.remote_ssrc == config->rtp.local_ssrc) {
1241 if (config->rtp.local_ssrc != kDefaultRtcpReceiverReportSsrc) {
1242 config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001243 } else {
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001244 config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc + 1;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001245 }
1246 }
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001247
1248 for (size_t i = 0; i < recv_codecs_.size(); ++i) {
Peter Boström0c4e06b2015-10-07 12:23:21 +02001249 uint32_t rtx_ssrc;
andresp@webrtc.org82775b12014-11-07 09:37:54 +00001250 if (recv_codecs_[i].rtx_payload_type != -1 &&
1251 sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
1252 webrtc::VideoReceiveStream::Config::Rtp::Rtx& rtx =
1253 config->rtp.rtx[recv_codecs_[i].codec.id];
1254 rtx.ssrc = rtx_ssrc;
1255 rtx.payload_type = recv_codecs_[i].rtx_payload_type;
1256 }
1257 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001258}
1259
Peter Boström0c4e06b2015-10-07 12:23:21 +02001260bool WebRtcVideoChannel2::RemoveRecvStream(uint32_t ssrc) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001261 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
1262 if (ssrc == 0) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001263 LOG(LS_ERROR) << "RemoveRecvStream with 0 ssrc is not supported.";
1264 return false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001265 }
1266
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001267 rtc::CritScope stream_lock(&stream_crit_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001268 std::map<uint32_t, WebRtcVideoReceiveStream*>::iterator stream =
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001269 receive_streams_.find(ssrc);
1270 if (stream == receive_streams_.end()) {
1271 LOG(LS_ERROR) << "Stream not found for ssrc: " << ssrc;
1272 return false;
1273 }
Peter Boströmd6f4c252015-03-26 16:23:04 +01001274 DeleteReceiveStream(stream->second);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001275 receive_streams_.erase(stream);
1276
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001277 return true;
1278}
1279
nisseacd935b2016-11-11 03:55:13 -08001280bool WebRtcVideoChannel2::SetSink(
1281 uint32_t ssrc,
1282 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
deadbeef5a4a75a2016-06-02 16:23:38 -07001283 LOG(LS_INFO) << "SetSink: ssrc:" << ssrc << " "
1284 << (sink ? "(ptr)" : "nullptr");
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001285 if (ssrc == 0) {
nisse08582ff2016-02-04 01:24:52 -08001286 default_unsignalled_ssrc_handler_.SetDefaultSink(this, sink);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001287 return true;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001288 }
1289
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001290 rtc::CritScope stream_lock(&stream_crit_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001291 std::map<uint32_t, WebRtcVideoReceiveStream*>::iterator it =
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001292 receive_streams_.find(ssrc);
1293 if (it == receive_streams_.end()) {
1294 return false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001295 }
1296
nisse08582ff2016-02-04 01:24:52 -08001297 it->second->SetSink(sink);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001298 return true;
1299}
1300
pbos@webrtc.org058b1f12015-03-04 08:54:32 +00001301bool WebRtcVideoChannel2::GetStats(VideoMediaInfo* info) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001302 TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::GetStats");
asapersson2e5cfcd2016-08-11 08:41:18 -07001303
1304 // Log stats periodically.
1305 bool log_stats = false;
1306 int64_t now_ms = rtc::TimeMillis();
1307 if (last_stats_log_ms_ == -1 ||
1308 now_ms - last_stats_log_ms_ > kStatsLogIntervalMs) {
1309 last_stats_log_ms_ = now_ms;
1310 log_stats = true;
1311 }
1312
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001313 info->Clear();
asapersson2e5cfcd2016-08-11 08:41:18 -07001314 FillSenderStats(info, log_stats);
1315 FillReceiverStats(info, log_stats);
hbosa65704b2016-11-14 02:28:16 -08001316 FillSendAndReceiveCodecStats(info);
pbos@webrtc.org2b19f062014-12-11 13:26:09 +00001317 webrtc::Call::Stats stats = call_->GetStats();
1318 FillBandwidthEstimationStats(stats, info);
1319 if (stats.rtt_ms != -1) {
1320 for (size_t i = 0; i < info->senders.size(); ++i) {
1321 info->senders[i].rtt_ms = stats.rtt_ms;
1322 }
1323 }
asapersson2e5cfcd2016-08-11 08:41:18 -07001324
1325 if (log_stats)
1326 LOG(LS_INFO) << stats.ToString(now_ms);
1327
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001328 return true;
1329}
1330
asapersson2e5cfcd2016-08-11 08:41:18 -07001331void WebRtcVideoChannel2::FillSenderStats(VideoMediaInfo* video_media_info,
1332 bool log_stats) {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001333 rtc::CritScope stream_lock(&stream_crit_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001334 for (std::map<uint32_t, WebRtcVideoSendStream*>::iterator it =
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001335 send_streams_.begin();
Peter Boström0c4e06b2015-10-07 12:23:21 +02001336 it != send_streams_.end(); ++it) {
asapersson2e5cfcd2016-08-11 08:41:18 -07001337 video_media_info->senders.push_back(
1338 it->second->GetVideoSenderInfo(log_stats));
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001339 }
1340}
1341
asapersson2e5cfcd2016-08-11 08:41:18 -07001342void WebRtcVideoChannel2::FillReceiverStats(VideoMediaInfo* video_media_info,
1343 bool log_stats) {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001344 rtc::CritScope stream_lock(&stream_crit_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001345 for (std::map<uint32_t, WebRtcVideoReceiveStream*>::iterator it =
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001346 receive_streams_.begin();
Peter Boström0c4e06b2015-10-07 12:23:21 +02001347 it != receive_streams_.end(); ++it) {
asapersson2e5cfcd2016-08-11 08:41:18 -07001348 video_media_info->receivers.push_back(
1349 it->second->GetVideoReceiverInfo(log_stats));
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001350 }
1351}
1352
1353void WebRtcVideoChannel2::FillBandwidthEstimationStats(
pbos@webrtc.org2b19f062014-12-11 13:26:09 +00001354 const webrtc::Call::Stats& stats,
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001355 VideoMediaInfo* video_media_info) {
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00001356 BandwidthEstimationInfo bwe_info;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00001357 bwe_info.available_send_bandwidth = stats.send_bandwidth_bps;
1358 bwe_info.available_recv_bandwidth = stats.recv_bandwidth_bps;
1359 bwe_info.bucket_delay = stats.pacer_delay_ms;
1360
1361 // Get send stream bitrate stats.
1362 rtc::CritScope stream_lock(&stream_crit_);
Peter Boström0c4e06b2015-10-07 12:23:21 +02001363 for (std::map<uint32_t, WebRtcVideoSendStream*>::iterator stream =
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00001364 send_streams_.begin();
Peter Boström0c4e06b2015-10-07 12:23:21 +02001365 stream != send_streams_.end(); ++stream) {
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00001366 stream->second->FillBandwidthEstimationInfo(&bwe_info);
1367 }
1368 video_media_info->bw_estimations.push_back(bwe_info);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001369}
1370
hbosa65704b2016-11-14 02:28:16 -08001371void WebRtcVideoChannel2::FillSendAndReceiveCodecStats(
1372 VideoMediaInfo* video_media_info) {
1373 for (const VideoCodec& codec : send_params_.codecs) {
1374 webrtc::RtpCodecParameters codec_params = codec.ToCodecParameters();
1375 video_media_info->send_codecs.insert(
1376 std::make_pair(codec_params.payload_type, std::move(codec_params)));
1377 }
1378 for (const VideoCodec& codec : recv_params_.codecs) {
1379 webrtc::RtpCodecParameters codec_params = codec.ToCodecParameters();
1380 video_media_info->receive_codecs.insert(
1381 std::make_pair(codec_params.payload_type, std::move(codec_params)));
1382 }
1383}
1384
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001385void WebRtcVideoChannel2::OnPacketReceived(
jbaucheec21bd2016-03-20 06:15:43 -07001386 rtc::CopyOnWriteBuffer* packet,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001387 const rtc::PacketTime& packet_time) {
stefan68786d22015-09-08 05:36:15 -07001388 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
1389 packet_time.not_before);
pbos@webrtc.org4e545cc2014-05-14 13:58:13 +00001390 const webrtc::PacketReceiver::DeliveryStatus delivery_result =
stefan68786d22015-09-08 05:36:15 -07001391 call_->Receiver()->DeliverPacket(
1392 webrtc::MediaType::VIDEO,
jbaucheec21bd2016-03-20 06:15:43 -07001393 packet->cdata(), packet->size(),
stefan68786d22015-09-08 05:36:15 -07001394 webrtc_packet_time);
pbos@webrtc.org4e545cc2014-05-14 13:58:13 +00001395 switch (delivery_result) {
1396 case webrtc::PacketReceiver::DELIVERY_OK:
1397 return;
1398 case webrtc::PacketReceiver::DELIVERY_PACKET_ERROR:
1399 return;
1400 case webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC:
1401 break;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001402 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001403
Peter Boström0c4e06b2015-10-07 12:23:21 +02001404 uint32_t ssrc = 0;
jbaucheec21bd2016-03-20 06:15:43 -07001405 if (!GetRtpSsrc(packet->cdata(), packet->size(), &ssrc)) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001406 return;
1407 }
1408
noahricd10a68e2015-07-10 11:27:55 -07001409 int payload_type = 0;
jbaucheec21bd2016-03-20 06:15:43 -07001410 if (!GetRtpPayloadType(packet->cdata(), packet->size(), &payload_type)) {
noahricd10a68e2015-07-10 11:27:55 -07001411 return;
1412 }
1413
1414 // See if this payload_type is registered as one that usually gets its own
1415 // SSRC (RTX) or at least is safe to drop either way (ULPFEC). If it is, and
1416 // it wasn't handled above by DeliverPacket, that means we don't know what
1417 // stream it associates with, and we shouldn't ever create an implicit channel
1418 // for these.
1419 for (auto& codec : recv_codecs_) {
1420 if (payload_type == codec.rtx_payload_type ||
brandtrb5f2c3f2016-10-04 23:28:39 -07001421 payload_type == codec.ulpfec.red_rtx_payload_type ||
1422 payload_type == codec.ulpfec.ulpfec_payload_type) {
noahricd10a68e2015-07-10 11:27:55 -07001423 return;
1424 }
1425 }
1426
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001427 switch (unsignalled_ssrc_handler_->OnUnsignalledSsrc(this, ssrc)) {
1428 case UnsignalledSsrcHandler::kDropPacket:
1429 return;
1430 case UnsignalledSsrcHandler::kDeliverPacket:
1431 break;
1432 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001433
stefan68786d22015-09-08 05:36:15 -07001434 if (call_->Receiver()->DeliverPacket(
1435 webrtc::MediaType::VIDEO,
jbaucheec21bd2016-03-20 06:15:43 -07001436 packet->cdata(), packet->size(),
stefan68786d22015-09-08 05:36:15 -07001437 webrtc_packet_time) != webrtc::PacketReceiver::DELIVERY_OK) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001438 LOG(LS_WARNING) << "Failed to deliver RTP packet on re-delivery.";
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001439 return;
1440 }
1441}
1442
1443void WebRtcVideoChannel2::OnRtcpReceived(
jbaucheec21bd2016-03-20 06:15:43 -07001444 rtc::CopyOnWriteBuffer* packet,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001445 const rtc::PacketTime& packet_time) {
stefan68786d22015-09-08 05:36:15 -07001446 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
1447 packet_time.not_before);
Peter Boström2aff6152015-11-18 13:47:16 +01001448 // TODO(pbos): Check webrtc::PacketReceiver::DELIVERY_OK once we deliver
1449 // for both audio and video on the same path. Since BundleFilter doesn't
1450 // filter RTCP anymore incoming RTCP packets could've been going to audio (so
1451 // logging failures spam the log).
1452 call_->Receiver()->DeliverPacket(
1453 webrtc::MediaType::VIDEO,
jbaucheec21bd2016-03-20 06:15:43 -07001454 packet->cdata(), packet->size(),
Peter Boström2aff6152015-11-18 13:47:16 +01001455 webrtc_packet_time);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001456}
1457
1458void WebRtcVideoChannel2::OnReadyToSend(bool ready) {
pbos@webrtc.org26c0c412014-09-03 16:17:12 +00001459 LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
skvlad7a43d252016-03-22 15:32:27 -07001460 call_->SignalChannelNetworkState(
1461 webrtc::MediaType::VIDEO,
1462 ready ? webrtc::kNetworkUp : webrtc::kNetworkDown);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001463}
1464
Honghai Zhangcc411c02016-03-29 17:27:21 -07001465void WebRtcVideoChannel2::OnNetworkRouteChanged(
1466 const std::string& transport_name,
Honghai Zhang0e533ef2016-04-19 15:41:36 -07001467 const rtc::NetworkRoute& network_route) {
1468 call_->OnNetworkRouteChanged(transport_name, network_route);
Honghai Zhangcc411c02016-03-29 17:27:21 -07001469}
1470
michaelt79e05882016-11-08 02:50:09 -08001471void WebRtcVideoChannel2::OnTransportOverheadChanged(
1472 int transport_overhead_per_packet) {
1473 call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
1474 transport_overhead_per_packet);
1475}
1476
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001477void WebRtcVideoChannel2::SetInterface(NetworkInterface* iface) {
1478 MediaChannel::SetInterface(iface);
1479 // Set the RTP recv/send buffer to a bigger size
1480 MediaChannel::SetOption(NetworkInterface::ST_RTP,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001481 rtc::Socket::OPT_RCVBUF,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001482 kVideoRtpBufferSize);
1483
buildbot@webrtc.orgae694ef2014-10-28 17:37:17 +00001484 // Speculative change to increase the outbound socket buffer size.
1485 // In b/15152257, we are seeing a significant number of packets discarded
1486 // due to lack of socket buffer space, although it's not yet clear what the
1487 // ideal value should be.
1488 MediaChannel::SetOption(NetworkInterface::ST_RTP,
1489 rtc::Socket::OPT_SNDBUF,
1490 kVideoRtpBufferSize);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001491}
1492
stefan1d8a5062015-10-02 03:39:33 -07001493bool WebRtcVideoChannel2::SendRtp(const uint8_t* data,
1494 size_t len,
1495 const webrtc::PacketOptions& options) {
jbaucheec21bd2016-03-20 06:15:43 -07001496 rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen);
stefanc1aeaf02015-10-15 07:26:07 -07001497 rtc::PacketOptions rtc_options;
1498 rtc_options.packet_id = options.packet_id;
1499 return MediaChannel::SendPacket(&packet, rtc_options);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001500}
1501
1502bool WebRtcVideoChannel2::SendRtcp(const uint8_t* data, size_t len) {
jbaucheec21bd2016-03-20 06:15:43 -07001503 rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen);
stefanc1aeaf02015-10-15 07:26:07 -07001504 return MediaChannel::SendRtcp(&packet, rtc::PacketOptions());
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001505}
1506
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001507WebRtcVideoChannel2::WebRtcVideoSendStream::VideoSendStreamParameters::
1508 VideoSendStreamParameters(
perkj26091b12016-09-01 01:17:40 -07001509 webrtc::VideoSendStream::Config config,
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001510 const VideoOptions& options,
Peter Boströmdfd53fe2015-03-27 15:58:11 +01001511 int max_bitrate_bps,
Karl Wibergbe579832015-11-10 22:34:18 +01001512 const rtc::Optional<VideoCodecSettings>& codec_settings)
perkj26091b12016-09-01 01:17:40 -07001513 : config(std::move(config)),
Peter Boströmdfd53fe2015-03-27 15:58:11 +01001514 options(options),
1515 max_bitrate_bps(max_bitrate_bps),
perkjfa10b552016-10-02 23:45:26 -07001516 conference_mode(false),
kwiberg102c6a62015-10-30 02:47:38 -07001517 codec_settings(codec_settings) {}
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001518
Peter Boström4d71ede2015-05-19 23:09:35 +02001519WebRtcVideoChannel2::WebRtcVideoSendStream::AllocatedEncoder::AllocatedEncoder(
1520 webrtc::VideoEncoder* encoder,
magjed509e4fe2016-11-18 01:34:11 -08001521 const cricket::VideoCodec& codec,
Peter Boström4d71ede2015-05-19 23:09:35 +02001522 bool external)
1523 : encoder(encoder),
1524 external_encoder(nullptr),
magjed509e4fe2016-11-18 01:34:11 -08001525 codec(codec),
Peter Boström4d71ede2015-05-19 23:09:35 +02001526 external(external) {
1527 if (external) {
1528 external_encoder = encoder;
1529 this->encoder =
magjed509e4fe2016-11-18 01:34:11 -08001530 new webrtc::VideoEncoderSoftwareFallbackWrapper(codec, encoder);
Peter Boström4d71ede2015-05-19 23:09:35 +02001531 }
1532}
1533
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001534WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
1535 webrtc::Call* call,
solenberg4fbae2b2015-08-28 04:07:10 -07001536 const StreamParams& sp,
perkj26091b12016-09-01 01:17:40 -07001537 webrtc::VideoSendStream::Config config,
nisse05103312016-03-16 02:22:50 -07001538 const VideoOptions& options,
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001539 WebRtcVideoEncoderFactory* external_encoder_factory,
perkj2d5f0912016-02-29 00:04:41 -08001540 bool enable_cpu_overuse_detection,
Peter Boströmdfd53fe2015-03-27 15:58:11 +01001541 int max_bitrate_bps,
Karl Wibergbe579832015-11-10 22:34:18 +01001542 const rtc::Optional<VideoCodecSettings>& codec_settings,
skvlad3abb7642016-06-16 12:08:03 -07001543 const rtc::Optional<std::vector<webrtc::RtpExtension>>& rtp_extensions,
deadbeef13871492015-12-09 12:37:51 -08001544 // TODO(deadbeef): Don't duplicate information between send_params,
1545 // rtp_extensions, options, etc.
1546 const VideoSendParameters& send_params)
perkj2d5f0912016-02-29 00:04:41 -08001547 : worker_thread_(rtc::Thread::Current()),
1548 ssrcs_(sp.ssrcs),
Peter Boström259bd202015-05-28 13:39:50 +02001549 ssrc_groups_(sp.ssrc_groups),
Henrik Kjellander7c027b62015-04-22 13:21:30 +02001550 call_(call),
perkj803d97f2016-11-01 11:45:46 -07001551 enable_cpu_overuse_detection_(enable_cpu_overuse_detection),
nisse2ded9b12016-04-08 02:23:55 -07001552 source_(nullptr),
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001553 external_encoder_factory_(external_encoder_factory),
perkj2d5f0912016-02-29 00:04:41 -08001554 stream_(nullptr),
perkja49cbd32016-09-16 07:53:41 -07001555 encoder_sink_(nullptr),
perkj26091b12016-09-01 01:17:40 -07001556 parameters_(std::move(config), options, max_bitrate_bps, codec_settings),
skvladdc1c62c2016-03-16 19:07:43 -07001557 rtp_parameters_(CreateRtpParametersWithOneEncoding()),
magjed509e4fe2016-11-18 01:34:11 -08001558 allocated_encoder_(nullptr, cricket::VideoCodec(), false),
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001559 sending_(false),
nisse74c10b52016-09-05 00:51:16 -07001560 last_frame_timestamp_us_(0) {
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001561 parameters_.config.rtp.max_packet_size = kVideoMtu;
nisse4b4dc862016-02-17 05:25:36 -08001562 parameters_.conference_mode = send_params.conference_mode;
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001563
1564 sp.GetPrimarySsrcs(&parameters_.config.rtp.ssrcs);
1565 sp.GetFidSsrcs(parameters_.config.rtp.ssrcs,
1566 &parameters_.config.rtp.rtx.ssrcs);
1567 parameters_.config.rtp.c_name = sp.cname;
skvlad3abb7642016-06-16 12:08:03 -07001568 if (rtp_extensions) {
1569 parameters_.config.rtp.extensions = *rtp_extensions;
1570 }
deadbeef13871492015-12-09 12:37:51 -08001571 parameters_.config.rtp.rtcp_mode = send_params.rtcp.reduced_size
1572 ? webrtc::RtcpMode::kReducedSize
1573 : webrtc::RtcpMode::kCompound;
kwiberg102c6a62015-10-30 02:47:38 -07001574 if (codec_settings) {
nisse0db023a2016-03-01 04:29:59 -08001575 SetCodec(*codec_settings);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001576 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001577}
1578
1579WebRtcVideoChannel2::WebRtcVideoSendStream::~WebRtcVideoSendStream() {
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001580 if (stream_ != NULL) {
1581 call_->DestroyVideoSendStream(stream_);
1582 }
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001583 DestroyVideoEncoder(&allocated_encoder_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001584}
1585
Pera5092412016-02-12 13:30:57 +01001586void WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame(
nisseacd935b2016-11-11 03:55:13 -08001587 const webrtc::VideoFrame& frame) {
Pera5092412016-02-12 13:30:57 +01001588 TRACE_EVENT0("webrtc", "WebRtcVideoSendStream::OnFrame");
nisse74c10b52016-09-05 00:51:16 -07001589 webrtc::VideoFrame video_frame(frame.video_frame_buffer(),
1590 frame.rotation(),
1591 frame.timestamp_us());
1592
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001593 rtc::CritScope cs(&lock_);
skvlad3abb7642016-06-16 12:08:03 -07001594
1595 if (video_frame.width() != last_frame_info_.width ||
1596 video_frame.height() != last_frame_info_.height ||
1597 video_frame.rotation() != last_frame_info_.rotation ||
1598 video_frame.is_texture() != last_frame_info_.is_texture) {
1599 last_frame_info_.width = video_frame.width();
1600 last_frame_info_.height = video_frame.height();
1601 last_frame_info_.rotation = video_frame.rotation();
1602 last_frame_info_.is_texture = video_frame.is_texture();
skvlad3abb7642016-06-16 12:08:03 -07001603
1604 LOG(LS_INFO) << "Video frame parameters changed: dimensions="
1605 << last_frame_info_.width << "x" << last_frame_info_.height
1606 << ", rotation=" << last_frame_info_.rotation
1607 << ", texture=" << last_frame_info_.is_texture;
1608 }
1609
perkja49cbd32016-09-16 07:53:41 -07001610 if (encoder_sink_ == NULL) {
Peter Boströmad1f9b62015-04-08 14:04:01 +02001611 // Frame input before send codecs are configured, dropping frame.
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001612 return;
1613 }
pbos@webrtc.org86196c42015-02-16 21:02:00 +00001614
nisse74c10b52016-09-05 00:51:16 -07001615 last_frame_timestamp_us_ = video_frame.timestamp_us();
skvlad3abb7642016-06-16 12:08:03 -07001616
perkjfa10b552016-10-02 23:45:26 -07001617 // Forward frame to the encoder regardless if we are sending or not. This is
1618 // to ensure that the encoder can be reconfigured with the correct frame size
1619 // as quickly as possible.
perkja49cbd32016-09-16 07:53:41 -07001620 encoder_sink_->OnFrame(video_frame);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001621}
1622
deadbeef5a4a75a2016-06-02 16:23:38 -07001623bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoSend(
1624 bool enable,
1625 const VideoOptions* options,
nisseacd935b2016-11-11 03:55:13 -08001626 rtc::VideoSourceInterface<webrtc::VideoFrame>* source) {
deadbeef5a4a75a2016-06-02 16:23:38 -07001627 TRACE_EVENT0("webrtc", "WebRtcVideoSendStream::SetVideoSend");
perkjfa10b552016-10-02 23:45:26 -07001628 RTC_DCHECK_RUN_ON(&thread_checker_);
nisse2ded9b12016-04-08 02:23:55 -07001629
deadbeef5a4a75a2016-06-02 16:23:38 -07001630 // Ignore |options| pointer if |enable| is false.
1631 bool options_present = enable && options;
1632 bool source_changing = source_ != source;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001633
perkjfa10b552016-10-02 23:45:26 -07001634 if (options_present) {
1635 VideoOptions old_options = parameters_.options;
1636 parameters_.options.SetAll(*options);
1637 if (parameters_.options != old_options) {
1638 ReconfigureEncoder();
perkj3b703ed2016-09-29 23:25:40 -07001639 }
perkj26105b42016-09-29 22:39:10 -07001640 }
1641
perkjfa10b552016-10-02 23:45:26 -07001642 if (source_changing) {
1643 rtc::CritScope cs(&lock_);
perkj803d97f2016-11-01 11:45:46 -07001644 if (source == nullptr && last_frame_info_.width > 0 && encoder_sink_) {
perkjfa10b552016-10-02 23:45:26 -07001645 LOG(LS_VERBOSE) << "Disabling capturer, sending black frame.";
1646 // Force this black frame not to be dropped due to timestamp order
1647 // check. As IncomingCapturedFrame will drop the frame if this frame's
1648 // timestamp is less than or equal to last frame's timestamp, it is
1649 // necessary to give this black frame a larger timestamp than the
1650 // previous one.
1651 last_frame_timestamp_us_ += rtc::kNumMicrosecsPerMillisec;
1652 rtc::scoped_refptr<webrtc::I420Buffer> black_buffer(
1653 webrtc::I420Buffer::Create(last_frame_info_.width,
1654 last_frame_info_.height));
1655 black_buffer->SetToBlack();
1656
1657 encoder_sink_->OnFrame(webrtc::VideoFrame(
1658 black_buffer, last_frame_info_.rotation, last_frame_timestamp_us_));
1659 }
perkjfa10b552016-10-02 23:45:26 -07001660 }
1661
perkj803d97f2016-11-01 11:45:46 -07001662 // TODO(perkj, nisse): Remove |source_| and directly call
1663 // |stream_|->SetSource(source) once the video frame types have been
1664 // merged.
1665 if (source_ && stream_) {
1666 stream_->SetSource(
1667 nullptr, webrtc::VideoSendStream::DegradationPreference::kBalanced);
1668 }
1669 // Switch to the new source.
1670 source_ = source;
1671 if (source && stream_) {
1672 // Do not adapt resolution for screen content as this will likely
1673 // result in blurry and unreadable text.
1674 stream_->SetSource(
1675 this, enable_cpu_overuse_detection_ &&
1676 !parameters_.options.is_screencast.value_or(false)
1677 ? webrtc::VideoSendStream::DegradationPreference::kBalanced
1678 : webrtc::VideoSendStream::DegradationPreference::
1679 kMaintainResolution);
nisse2ded9b12016-04-08 02:23:55 -07001680 }
deadbeef5a4a75a2016-06-02 16:23:38 -07001681 return true;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001682}
1683
Peter Boström0c4e06b2015-10-07 12:23:21 +02001684const std::vector<uint32_t>&
Peter Boströmd6f4c252015-03-26 16:23:04 +01001685WebRtcVideoChannel2::WebRtcVideoSendStream::GetSsrcs() const {
1686 return ssrcs_;
1687}
1688
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001689WebRtcVideoChannel2::WebRtcVideoSendStream::AllocatedEncoder
1690WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoder(
1691 const VideoCodec& codec) {
perkjfa10b552016-10-02 23:45:26 -07001692 RTC_DCHECK_RUN_ON(&thread_checker_);
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001693 // Do not re-create encoders of the same type.
magjed509e4fe2016-11-18 01:34:11 -08001694 if (codec == allocated_encoder_.codec &&
1695 allocated_encoder_.encoder != nullptr) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001696 return allocated_encoder_;
1697 }
1698
magjed509e4fe2016-11-18 01:34:11 -08001699 // Try creating external encoder.
1700 if (external_encoder_factory_ != nullptr &&
1701 FindMatchingCodec(external_encoder_factory_->supported_codecs(), codec)) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001702 webrtc::VideoEncoder* encoder =
magjed1e45cc62016-10-28 07:43:45 -07001703 external_encoder_factory_->CreateVideoEncoder(codec);
magjed509e4fe2016-11-18 01:34:11 -08001704 if (encoder != nullptr)
1705 return AllocatedEncoder(encoder, codec, true /* is_external */);
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001706 }
1707
magjed509e4fe2016-11-18 01:34:11 -08001708 // Try creating internal encoder.
1709 InternalEncoderFactory internal_encoder_factory;
1710 if (FindMatchingCodec(internal_encoder_factory.supported_codecs(), codec)) {
1711 return AllocatedEncoder(internal_encoder_factory.CreateVideoEncoder(codec),
1712 codec, false /* is_external */);
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001713 }
1714
1715 // This shouldn't happen, we should not be trying to create something we don't
1716 // support.
henrikg91d6ede2015-09-17 00:24:34 -07001717 RTC_DCHECK(false);
magjed509e4fe2016-11-18 01:34:11 -08001718 return AllocatedEncoder(NULL, cricket::VideoCodec(), false);
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001719}
1720
1721void WebRtcVideoChannel2::WebRtcVideoSendStream::DestroyVideoEncoder(
1722 AllocatedEncoder* encoder) {
perkjfa10b552016-10-02 23:45:26 -07001723 RTC_DCHECK_RUN_ON(&thread_checker_);
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001724 if (encoder->external) {
Peter Boström4d71ede2015-05-19 23:09:35 +02001725 external_encoder_factory_->DestroyVideoEncoder(encoder->external_encoder);
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001726 }
Peter Boström4d71ede2015-05-19 23:09:35 +02001727 delete encoder->encoder;
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001728}
1729
nisse0db023a2016-03-01 04:29:59 -08001730void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodec(
1731 const VideoCodecSettings& codec_settings) {
perkjfa10b552016-10-02 23:45:26 -07001732 RTC_DCHECK_RUN_ON(&thread_checker_);
skvlad3abb7642016-06-16 12:08:03 -07001733 parameters_.encoder_config = CreateVideoEncoderConfig(codec_settings.codec);
perkjfa10b552016-10-02 23:45:26 -07001734 RTC_DCHECK_GT(parameters_.encoder_config.number_of_streams, 0u);
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001735
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001736 AllocatedEncoder new_encoder = CreateVideoEncoder(codec_settings.codec);
1737 parameters_.config.encoder_settings.encoder = new_encoder.encoder;
Peter Boströme4499152016-02-05 11:13:28 +01001738 parameters_.config.encoder_settings.full_overuse_time = new_encoder.external;
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001739 parameters_.config.encoder_settings.payload_name = codec_settings.codec.name;
1740 parameters_.config.encoder_settings.payload_type = codec_settings.codec.id;
sophiechang47d78cc2015-09-03 18:24:44 -07001741 if (new_encoder.external) {
1742 webrtc::VideoCodecType type = CodecTypeFromName(codec_settings.codec.name);
1743 parameters_.config.encoder_settings.internal_source =
1744 external_encoder_factory_->EncoderTypeHasInternalSource(type);
1745 }
brandtrb5f2c3f2016-10-04 23:28:39 -07001746 parameters_.config.rtp.ulpfec = codec_settings.ulpfec;
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001747
1748 // Set RTX payload type if RTX is enabled.
1749 if (!parameters_.config.rtp.rtx.ssrcs.empty()) {
pbos@webrtc.orgb9557a92015-03-20 19:52:56 +00001750 if (codec_settings.rtx_payload_type == -1) {
1751 LOG(LS_WARNING) << "RTX SSRCs configured but there's no configured RTX "
1752 "payload type. Ignoring.";
1753 parameters_.config.rtp.rtx.ssrcs.clear();
1754 } else {
1755 parameters_.config.rtp.rtx.payload_type = codec_settings.rtx_payload_type;
1756 }
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001757 }
1758
Peter Boström67c9df72015-05-11 14:34:58 +02001759 parameters_.config.rtp.nack.rtp_history_ms =
1760 HasNack(codec_settings.codec) ? kNackHistoryMs : 0;
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001761
kwiberg102c6a62015-10-30 02:47:38 -07001762 parameters_.codec_settings =
Karl Wibergbe579832015-11-10 22:34:18 +01001763 rtc::Optional<WebRtcVideoChannel2::VideoCodecSettings>(codec_settings);
Niels Möller60653ba2016-03-02 11:41:36 +01001764
1765 LOG(LS_INFO) << "RecreateWebRtcStream (send) because of SetCodec.";
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001766 RecreateWebRtcStream();
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001767 if (allocated_encoder_.encoder != new_encoder.encoder) {
1768 DestroyVideoEncoder(&allocated_encoder_);
1769 allocated_encoder_ = new_encoder;
1770 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001771}
1772
deadbeef13871492015-12-09 12:37:51 -08001773void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSendParameters(
Peter Boström3afc8c42016-01-27 16:45:21 +01001774 const ChangedSendParameters& params) {
perkjfa10b552016-10-02 23:45:26 -07001775 RTC_DCHECK_RUN_ON(&thread_checker_);
1776 // |recreate_stream| means construction-time parameters have changed and the
1777 // sending stream needs to be reset with the new config.
1778 bool recreate_stream = false;
1779 if (params.rtcp_mode) {
1780 parameters_.config.rtp.rtcp_mode = *params.rtcp_mode;
1781 recreate_stream = true;
1782 }
1783 if (params.rtp_header_extensions) {
1784 parameters_.config.rtp.extensions = *params.rtp_header_extensions;
1785 recreate_stream = true;
1786 }
1787 if (params.max_bandwidth_bps) {
1788 parameters_.max_bitrate_bps = *params.max_bandwidth_bps;
1789 ReconfigureEncoder();
1790 }
1791 if (params.conference_mode) {
1792 parameters_.conference_mode = *params.conference_mode;
1793 }
perkjf0dcfe22016-03-10 18:32:00 +01001794
perkjfa10b552016-10-02 23:45:26 -07001795 // Set codecs and options.
1796 if (params.codec) {
1797 SetCodec(*params.codec);
1798 recreate_stream = false; // SetCodec has already recreated the stream.
1799 } else if (params.conference_mode && parameters_.codec_settings) {
1800 SetCodec(*parameters_.codec_settings);
1801 recreate_stream = false; // SetCodec has already recreated the stream.
1802 }
1803 if (recreate_stream) {
1804 LOG(LS_INFO) << "RecreateWebRtcStream (send) because of SetSendParameters";
1805 RecreateWebRtcStream();
1806 }
deadbeef13871492015-12-09 12:37:51 -08001807}
1808
skvladdc1c62c2016-03-16 19:07:43 -07001809bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpParameters(
1810 const webrtc::RtpParameters& new_parameters) {
perkjfa10b552016-10-02 23:45:26 -07001811 RTC_DCHECK_RUN_ON(&thread_checker_);
skvladdc1c62c2016-03-16 19:07:43 -07001812 if (!ValidateRtpParameters(new_parameters)) {
1813 return false;
1814 }
1815
perkjfa10b552016-10-02 23:45:26 -07001816 bool reconfigure_encoder = new_parameters.encodings[0].max_bitrate_bps !=
1817 rtp_parameters_.encodings[0].max_bitrate_bps;
skvladdc1c62c2016-03-16 19:07:43 -07001818 rtp_parameters_ = new_parameters;
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001819 // Codecs are currently handled at the WebRtcVideoChannel2 level.
1820 rtp_parameters_.codecs.clear();
perkjfa10b552016-10-02 23:45:26 -07001821 if (reconfigure_encoder) {
1822 ReconfigureEncoder();
1823 }
deadbeefdbe2b872016-03-22 15:42:00 -07001824 // Encoding may have been activated/deactivated.
1825 UpdateSendState();
skvladdc1c62c2016-03-16 19:07:43 -07001826 return true;
1827}
1828
deadbeefdbe2b872016-03-22 15:42:00 -07001829webrtc::RtpParameters
1830WebRtcVideoChannel2::WebRtcVideoSendStream::GetRtpParameters() const {
perkjfa10b552016-10-02 23:45:26 -07001831 RTC_DCHECK_RUN_ON(&thread_checker_);
deadbeefdbe2b872016-03-22 15:42:00 -07001832 return rtp_parameters_;
1833}
1834
skvladdc1c62c2016-03-16 19:07:43 -07001835bool WebRtcVideoChannel2::WebRtcVideoSendStream::ValidateRtpParameters(
1836 const webrtc::RtpParameters& rtp_parameters) {
1837 if (rtp_parameters.encodings.size() != 1) {
1838 LOG(LS_ERROR)
1839 << "Attempted to set RtpParameters without exactly one encoding";
1840 return false;
1841 }
1842 return true;
1843}
1844
deadbeefdbe2b872016-03-22 15:42:00 -07001845void WebRtcVideoChannel2::WebRtcVideoSendStream::UpdateSendState() {
perkjfa10b552016-10-02 23:45:26 -07001846 RTC_DCHECK_RUN_ON(&thread_checker_);
deadbeefdbe2b872016-03-22 15:42:00 -07001847 // TODO(deadbeef): Need to handle more than one encoding in the future.
1848 RTC_DCHECK(rtp_parameters_.encodings.size() == 1u);
1849 if (sending_ && rtp_parameters_.encodings[0].active) {
1850 RTC_DCHECK(stream_ != nullptr);
1851 stream_->Start();
1852 } else {
1853 if (stream_ != nullptr) {
1854 stream_->Stop();
1855 }
1856 }
1857}
1858
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001859webrtc::VideoEncoderConfig
1860WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig(
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001861 const VideoCodec& codec) const {
perkjfa10b552016-10-02 23:45:26 -07001862 RTC_DCHECK_RUN_ON(&thread_checker_);
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001863 webrtc::VideoEncoderConfig encoder_config;
Niels Möller60653ba2016-03-02 11:41:36 +01001864 bool is_screencast = parameters_.options.is_screencast.value_or(false);
1865 if (is_screencast) {
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +00001866 encoder_config.min_transmit_bitrate_bps =
nisse51542be2016-02-12 02:27:06 -08001867 1000 * parameters_.options.screencast_min_bitrate_kbps.value_or(0);
Erik Språng143cec12015-04-28 10:01:41 +02001868 encoder_config.content_type =
1869 webrtc::VideoEncoderConfig::ContentType::kScreen;
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +00001870 } else {
1871 encoder_config.min_transmit_bitrate_bps = 0;
Erik Språng143cec12015-04-28 10:01:41 +02001872 encoder_config.content_type =
1873 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo;
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +00001874 }
1875
noahricfdac5162015-08-27 01:59:29 -07001876 // By default, the stream count for the codec configuration should match the
1877 // number of negotiated ssrcs. But if the codec is blacklisted for simulcast
1878 // or a screencast, only configure a single stream.
perkjfa10b552016-10-02 23:45:26 -07001879 encoder_config.number_of_streams = parameters_.config.rtp.ssrcs.size();
Niels Möller60653ba2016-03-02 11:41:36 +01001880 if (IsCodecBlacklistedForSimulcast(codec.name) || is_screencast) {
perkjfa10b552016-10-02 23:45:26 -07001881 encoder_config.number_of_streams = 1;
noahricfdac5162015-08-27 01:59:29 -07001882 }
1883
skvladdc1c62c2016-03-16 19:07:43 -07001884 int stream_max_bitrate =
1885 MinPositive(rtp_parameters_.encodings[0].max_bitrate_bps,
1886 parameters_.max_bitrate_bps);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001887
perkjfa10b552016-10-02 23:45:26 -07001888 int codec_max_bitrate_kbps;
1889 if (codec.GetParam(kCodecParamMaxBitrate, &codec_max_bitrate_kbps)) {
1890 stream_max_bitrate = codec_max_bitrate_kbps * 1000;
1891 }
1892 encoder_config.max_bitrate_bps = stream_max_bitrate;
perkj3b703ed2016-09-29 23:25:40 -07001893
perkjfa10b552016-10-02 23:45:26 -07001894 int max_qp = kDefaultQpMax;
1895 codec.GetParam(kCodecParamMaxQuantization, &max_qp);
perkjfa10b552016-10-02 23:45:26 -07001896 encoder_config.video_stream_factory =
1897 new rtc::RefCountedObject<EncoderStreamFactory>(
perkj26752742016-10-24 01:21:16 -07001898 codec.name, max_qp, kDefaultVideoMaxFramerate, is_screencast,
perkjfa10b552016-10-02 23:45:26 -07001899 parameters_.conference_mode);
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001900 return encoder_config;
1901}
1902
skvlad3abb7642016-06-16 12:08:03 -07001903void WebRtcVideoChannel2::WebRtcVideoSendStream::ReconfigureEncoder() {
perkjfa10b552016-10-02 23:45:26 -07001904 RTC_DCHECK_RUN_ON(&thread_checker_);
1905 if (!stream_) {
1906 // The webrtc::VideoSendStream |stream_|has not yet been created but other
1907 // parameters has changed.
1908 return;
1909 }
1910
1911 RTC_DCHECK_GT(parameters_.encoder_config.number_of_streams, 0u);
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001912
kwiberg102c6a62015-10-30 02:47:38 -07001913 RTC_CHECK(parameters_.codec_settings);
1914 VideoCodecSettings codec_settings = *parameters_.codec_settings;
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001915
1916 webrtc::VideoEncoderConfig encoder_config =
skvlad3abb7642016-06-16 12:08:03 -07001917 CreateVideoEncoderConfig(codec_settings.codec);
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00001918
Erik Språng143cec12015-04-28 10:01:41 +02001919 encoder_config.encoder_specific_settings = ConfigureVideoEncoderSettings(
Niels Möller60653ba2016-03-02 11:41:36 +01001920 codec_settings.codec);
pbos@webrtc.orgb7ed7792014-10-31 13:08:10 +00001921
perkj26091b12016-09-01 01:17:40 -07001922 stream_->ReconfigureVideoEncoder(encoder_config.Copy());
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001923
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001924 encoder_config.encoder_specific_settings = NULL;
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001925
perkj26091b12016-09-01 01:17:40 -07001926 parameters_.encoder_config = std::move(encoder_config);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001927}
1928
deadbeefdbe2b872016-03-22 15:42:00 -07001929void WebRtcVideoChannel2::WebRtcVideoSendStream::SetSend(bool send) {
perkjfa10b552016-10-02 23:45:26 -07001930 RTC_DCHECK_RUN_ON(&thread_checker_);
deadbeefdbe2b872016-03-22 15:42:00 -07001931 sending_ = send;
1932 UpdateSendState();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001933}
1934
perkj803d97f2016-11-01 11:45:46 -07001935void WebRtcVideoChannel2::WebRtcVideoSendStream::RemoveSink(
1936 VideoSinkInterface<webrtc::VideoFrame>* sink) {
1937 RTC_DCHECK_RUN_ON(&thread_checker_);
1938 {
1939 rtc::CritScope cs(&lock_);
1940 RTC_DCHECK(encoder_sink_ == sink);
1941 encoder_sink_ = nullptr;
1942 }
1943 source_->RemoveSink(this);
1944}
1945
perkja49cbd32016-09-16 07:53:41 -07001946void WebRtcVideoChannel2::WebRtcVideoSendStream::AddOrUpdateSink(
1947 VideoSinkInterface<webrtc::VideoFrame>* sink,
1948 const rtc::VideoSinkWants& wants) {
perkj803d97f2016-11-01 11:45:46 -07001949 if (worker_thread_ == rtc::Thread::Current()) {
1950 // AddOrUpdateSink is called on |worker_thread_| if this is the first
1951 // registration of |sink|.
1952 RTC_DCHECK_RUN_ON(&thread_checker_);
1953 {
1954 rtc::CritScope cs(&lock_);
1955 encoder_sink_ = sink;
perkj2d5f0912016-02-29 00:04:41 -08001956 }
perkj803d97f2016-11-01 11:45:46 -07001957 source_->AddOrUpdateSink(this, wants);
perkjfa10b552016-10-02 23:45:26 -07001958 } else {
perkj803d97f2016-11-01 11:45:46 -07001959 // Subsequent calls to AddOrUpdateSink will happen on the encoder task
1960 // queue.
1961 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, [this, wants] {
1962 RTC_DCHECK_RUN_ON(&thread_checker_);
1963 bool encoder_sink_valid = true;
1964 {
1965 rtc::CritScope cs(&lock_);
1966 encoder_sink_valid = encoder_sink_ != nullptr;
1967 }
1968 // Since |source_| is still valid after a call to RemoveSink, check if
1969 // |encoder_sink_| is still valid to check if this call should be
1970 // cancelled.
1971 if (source_ && encoder_sink_valid) {
1972 source_->AddOrUpdateSink(this, wants);
1973 }
1974 });
perkj2d5f0912016-02-29 00:04:41 -08001975 }
perkj2d5f0912016-02-29 00:04:41 -08001976}
1977
asapersson2e5cfcd2016-08-11 08:41:18 -07001978VideoSenderInfo WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo(
1979 bool log_stats) {
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001980 VideoSenderInfo info;
perkjfa10b552016-10-02 23:45:26 -07001981 RTC_DCHECK_RUN_ON(&thread_checker_);
1982 for (uint32_t ssrc : parameters_.config.rtp.ssrcs)
1983 info.add_ssrc(ssrc);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001984
hbosa65704b2016-11-14 02:28:16 -08001985 if (parameters_.codec_settings) {
perkjfa10b552016-10-02 23:45:26 -07001986 info.codec_name = parameters_.codec_settings->codec.name;
hbos1acfbd22016-11-17 23:43:29 -08001987 info.codec_payload_type = rtc::Optional<int>(
1988 parameters_.codec_settings->codec.id);
hbosa65704b2016-11-14 02:28:16 -08001989 }
pbos@webrtc.orgc3d2bd22014-08-12 20:55:10 +00001990
perkjfa10b552016-10-02 23:45:26 -07001991 if (stream_ == NULL)
1992 return info;
pbos@webrtc.org77e11bb2015-02-23 16:39:07 +00001993
perkjfa10b552016-10-02 23:45:26 -07001994 webrtc::VideoSendStream::Stats stats = stream_->GetStats();
asapersson2e5cfcd2016-08-11 08:41:18 -07001995
1996 if (log_stats)
1997 LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());
1998
perkj803d97f2016-11-01 11:45:46 -07001999 info.adapt_changes = stats.number_of_cpu_adapt_changes;
Per766ad3b2016-04-05 15:23:49 +02002000 info.adapt_reason =
perkj803d97f2016-11-01 11:45:46 -07002001 stats.cpu_limited_resolution ? ADAPTREASON_CPU : ADAPTREASON_NONE;
pbos@webrtc.org77e11bb2015-02-23 16:39:07 +00002002
asapersson17821db2015-12-14 02:08:12 -08002003 // Get bandwidth limitation info from stream_->GetStats().
2004 // Input resolution (output from video_adapter) can be further scaled down or
2005 // higher video layer(s) can be dropped due to bitrate constraints.
2006 // Note, adapt_changes only include changes from the video_adapter.
2007 if (stats.bw_limited_resolution)
Per766ad3b2016-04-05 15:23:49 +02002008 info.adapt_reason |= ADAPTREASON_BANDWIDTH;
asapersson17821db2015-12-14 02:08:12 -08002009
Peter Boströmb7d9a972015-12-18 16:01:11 +01002010 info.encoder_implementation_name = stats.encoder_implementation_name;
Peter Boström259bd202015-05-28 13:39:50 +02002011 info.ssrc_groups = ssrc_groups_;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002012 info.framerate_input = stats.input_frame_rate;
2013 info.framerate_sent = stats.encode_frame_rate;
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +00002014 info.avg_encode_ms = stats.avg_encode_time_ms;
2015 info.encode_usage_percent = stats.encode_usage_percent;
sakal43536c32016-10-24 01:46:43 -07002016 info.frames_encoded = stats.frames_encoded;
sakal87da4042016-10-31 06:53:47 -07002017 info.qp_sum = stats.qp_sum;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002018
pbos@webrtc.org77e11bb2015-02-23 16:39:07 +00002019 info.nominal_bitrate = stats.media_bitrate_bps;
Pera48ddb72016-09-29 11:48:50 +02002020 info.preferred_bitrate = stats.preferred_media_bitrate_bps;
pbos@webrtc.org77e11bb2015-02-23 16:39:07 +00002021
pbos@webrtc.org273a4142014-12-01 15:23:21 +00002022 info.send_frame_width = 0;
2023 info.send_frame_height = 0;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002024 for (std::map<uint32_t, webrtc::VideoSendStream::StreamStats>::iterator it =
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002025 stats.substreams.begin();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002026 it != stats.substreams.end(); ++it) {
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002027 // TODO(pbos): Wire up additional stats, such as padding bytes.
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002028 webrtc::VideoSendStream::StreamStats stream_stats = it->second;
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +00002029 info.bytes_sent += stream_stats.rtp_stats.transmitted.payload_bytes +
2030 stream_stats.rtp_stats.transmitted.header_bytes +
2031 stream_stats.rtp_stats.transmitted.padding_bytes;
2032 info.packets_sent += stream_stats.rtp_stats.transmitted.packets;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002033 info.packets_lost += stream_stats.rtcp_stats.cumulative_lost;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002034 if (stream_stats.width > info.send_frame_width)
2035 info.send_frame_width = stream_stats.width;
2036 if (stream_stats.height > info.send_frame_height)
2037 info.send_frame_height = stream_stats.height;
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00002038 info.firs_rcvd += stream_stats.rtcp_packet_type_counts.fir_packets;
2039 info.nacks_rcvd += stream_stats.rtcp_packet_type_counts.nack_packets;
2040 info.plis_rcvd += stream_stats.rtcp_packet_type_counts.pli_packets;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002041 }
2042
2043 if (!stats.substreams.empty()) {
2044 // TODO(pbos): Report fraction lost per SSRC.
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002045 webrtc::VideoSendStream::StreamStats first_stream_stats =
2046 stats.substreams.begin()->second;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002047 info.fraction_lost =
2048 static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
2049 (1 << 8);
2050 }
2051
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002052 return info;
2053}
2054
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00002055void WebRtcVideoChannel2::WebRtcVideoSendStream::FillBandwidthEstimationInfo(
2056 BandwidthEstimationInfo* bwe_info) {
perkjfa10b552016-10-02 23:45:26 -07002057 RTC_DCHECK_RUN_ON(&thread_checker_);
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00002058 if (stream_ == NULL) {
2059 return;
2060 }
2061 webrtc::VideoSendStream::Stats stats = stream_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002062 for (std::map<uint32_t, webrtc::VideoSendStream::StreamStats>::iterator it =
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00002063 stats.substreams.begin();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002064 it != stats.substreams.end(); ++it) {
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00002065 bwe_info->transmit_bitrate += it->second.total_bitrate_bps;
2066 bwe_info->retransmit_bitrate += it->second.retransmit_bitrate_bps;
2067 }
pbos@webrtc.org891d4832015-02-26 13:15:22 +00002068 bwe_info->target_enc_bitrate += stats.target_media_bitrate_bps;
pbos@webrtc.org77e11bb2015-02-23 16:39:07 +00002069 bwe_info->actual_enc_bitrate += stats.media_bitrate_bps;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +00002070}
2071
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002072void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
perkjfa10b552016-10-02 23:45:26 -07002073 RTC_DCHECK_RUN_ON(&thread_checker_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002074 if (stream_ != NULL) {
2075 call_->DestroyVideoSendStream(stream_);
2076 }
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00002077
kwiberg102c6a62015-10-30 02:47:38 -07002078 RTC_CHECK(parameters_.codec_settings);
Niels Möller60653ba2016-03-02 11:41:36 +01002079 RTC_DCHECK_EQ((parameters_.encoder_config.content_type ==
2080 webrtc::VideoEncoderConfig::ContentType::kScreen),
2081 parameters_.options.is_screencast.value_or(false))
2082 << "encoder content type inconsistent with screencast option";
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00002083 parameters_.encoder_config.encoder_specific_settings =
Niels Möller60653ba2016-03-02 11:41:36 +01002084 ConfigureVideoEncoderSettings(parameters_.codec_settings->codec);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00002085
perkj26091b12016-09-01 01:17:40 -07002086 webrtc::VideoSendStream::Config config = parameters_.config.Copy();
pbos@webrtc.orgb9557a92015-03-20 19:52:56 +00002087 if (!config.rtp.rtx.ssrcs.empty() && config.rtp.rtx.payload_type == -1) {
2088 LOG(LS_WARNING) << "RTX SSRCs configured but there's no configured RTX "
2089 "payload type the set codec. Ignoring RTX.";
2090 config.rtp.rtx.ssrcs.clear();
2091 }
perkj26091b12016-09-01 01:17:40 -07002092 stream_ = call_->CreateVideoSendStream(std::move(config),
2093 parameters_.encoder_config.Copy());
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00002094
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00002095 parameters_.encoder_config.encoder_specific_settings = NULL;
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00002096
perkj803d97f2016-11-01 11:45:46 -07002097 if (source_) {
2098 // TODO(perkj, nisse): Remove |source_| and directly call
2099 // |stream_|->SetSource(source) once the video frame types have been
2100 // merged and |stream_| internally reconfigure the encoder on frame
2101 // resolution change.
2102 // Do not adapt resolution for screen content as this will likely result in
2103 // blurry and unreadable text.
2104 stream_->SetSource(
2105 this, enable_cpu_overuse_detection_ &&
2106 !parameters_.options.is_screencast.value_or(false)
2107 ? webrtc::VideoSendStream::DegradationPreference::kBalanced
2108 : webrtc::VideoSendStream::DegradationPreference::
2109 kMaintainResolution);
2110 }
2111
Taylor Brandstetter14b9d792016-09-07 17:16:54 -07002112 // Call stream_->Start() if necessary conditions are met.
2113 UpdateSendState();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002114}
2115
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002116WebRtcVideoChannel2::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream(
2117 webrtc::Call* call,
Peter Boström259bd202015-05-28 13:39:50 +02002118 const StreamParams& sp,
Tommi733b5472016-06-10 17:58:01 +02002119 webrtc::VideoReceiveStream::Config config,
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00002120 WebRtcVideoDecoderFactory* external_decoder_factory,
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +00002121 bool default_stream,
brandtre6f98c72016-11-11 03:28:30 -08002122 const std::vector<VideoCodecSettings>& recv_codecs)
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002123 : call_(call),
sakal1fd95952016-06-22 00:46:15 -07002124 stream_params_(sp),
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002125 stream_(NULL),
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +00002126 default_stream_(default_stream),
Tommi733b5472016-06-10 17:58:01 +02002127 config_(std::move(config)),
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00002128 external_decoder_factory_(external_decoder_factory),
nissee73afba2016-01-28 04:47:08 -08002129 sink_(NULL),
magjed@webrtc.orgfc5ad952015-01-27 09:57:01 +00002130 first_frame_timestamp_(-1),
2131 estimated_remote_start_ntp_time_ms_(0) {
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002132 config_.renderer = this;
pbos378dc772016-01-28 15:58:41 -08002133 std::vector<AllocatedDecoder> old_decoders;
2134 ConfigureCodecs(recv_codecs, &old_decoders);
2135 RecreateWebRtcStream();
2136 RTC_DCHECK(old_decoders.empty());
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002137}
2138
Peter Boström7252a2b2015-05-18 19:42:03 +02002139WebRtcVideoChannel2::WebRtcVideoReceiveStream::AllocatedDecoder::
2140 AllocatedDecoder(webrtc::VideoDecoder* decoder,
2141 webrtc::VideoCodecType type,
2142 bool external)
2143 : decoder(decoder),
2144 external_decoder(nullptr),
2145 type(type),
2146 external(external) {
2147 if (external) {
2148 external_decoder = decoder;
2149 this->decoder =
2150 new webrtc::VideoDecoderSoftwareFallbackWrapper(type, external_decoder);
2151 }
2152}
2153
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002154WebRtcVideoChannel2::WebRtcVideoReceiveStream::~WebRtcVideoReceiveStream() {
2155 call_->DestroyVideoReceiveStream(stream_);
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002156 ClearDecoders(&allocated_decoders_);
2157}
2158
Peter Boström0c4e06b2015-10-07 12:23:21 +02002159const std::vector<uint32_t>&
Peter Boströmd6f4c252015-03-26 16:23:04 +01002160WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetSsrcs() const {
sakal1fd95952016-06-22 00:46:15 -07002161 return stream_params_.ssrcs;
2162}
2163
2164rtc::Optional<uint32_t>
2165WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetFirstPrimarySsrc() const {
2166 std::vector<uint32_t> primary_ssrcs;
2167 stream_params_.GetPrimarySsrcs(&primary_ssrcs);
2168
2169 if (primary_ssrcs.empty()) {
2170 LOG(LS_WARNING) << "Empty primary ssrcs vector, returning empty optional";
2171 return rtc::Optional<uint32_t>();
2172 } else {
2173 return rtc::Optional<uint32_t>(primary_ssrcs[0]);
2174 }
Peter Boströmd6f4c252015-03-26 16:23:04 +01002175}
2176
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002177WebRtcVideoChannel2::WebRtcVideoReceiveStream::AllocatedDecoder
2178WebRtcVideoChannel2::WebRtcVideoReceiveStream::CreateOrReuseVideoDecoder(
2179 std::vector<AllocatedDecoder>* old_decoders,
2180 const VideoCodec& codec) {
2181 webrtc::VideoCodecType type = CodecTypeFromName(codec.name);
2182
2183 for (size_t i = 0; i < old_decoders->size(); ++i) {
2184 if ((*old_decoders)[i].type == type) {
2185 AllocatedDecoder decoder = (*old_decoders)[i];
2186 (*old_decoders)[i] = old_decoders->back();
2187 old_decoders->pop_back();
2188 return decoder;
2189 }
2190 }
2191
2192 if (external_decoder_factory_ != NULL) {
2193 webrtc::VideoDecoder* decoder =
sakal1fd95952016-06-22 00:46:15 -07002194 external_decoder_factory_->CreateVideoDecoderWithParams(
2195 type, {stream_params_.id});
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002196 if (decoder != NULL) {
2197 return AllocatedDecoder(decoder, type, true);
2198 }
2199 }
2200
2201 if (type == webrtc::kVideoCodecVP8) {
2202 return AllocatedDecoder(
2203 webrtc::VideoDecoder::Create(webrtc::VideoDecoder::kVp8), type, false);
2204 }
2205
pbos@webrtc.orgb9557a92015-03-20 19:52:56 +00002206 if (type == webrtc::kVideoCodecVP9) {
2207 return AllocatedDecoder(
2208 webrtc::VideoDecoder::Create(webrtc::VideoDecoder::kVp9), type, false);
2209 }
2210
Zeke Chin71f6f442015-06-29 14:34:58 -07002211 if (type == webrtc::kVideoCodecH264) {
2212 return AllocatedDecoder(
2213 webrtc::VideoDecoder::Create(webrtc::VideoDecoder::kH264), type, false);
2214 }
2215
jbauche03ac512016-02-03 05:51:48 -08002216 return AllocatedDecoder(
2217 webrtc::VideoDecoder::Create(webrtc::VideoDecoder::kUnsupportedCodec),
2218 webrtc::kVideoCodecUnknown, false);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002219}
2220
johan3859c892016-08-05 09:19:25 -07002221void ConfigureDecoderSpecifics(webrtc::VideoReceiveStream::Decoder* decoder,
2222 const cricket::VideoCodec& recv_video_codec) {
2223 if (recv_video_codec.name.compare("H264") == 0) {
2224 auto it = recv_video_codec.params.find("sprop-parameter-sets");
2225 if (it != recv_video_codec.params.end()) {
2226 decoder->decoder_specific.h264_extra_settings =
2227 rtc::Optional<webrtc::VideoDecoderH264Settings>(
2228 webrtc::VideoDecoderH264Settings());
2229 decoder->decoder_specific.h264_extra_settings->sprop_parameter_sets =
2230 it->second;
2231 }
2232 }
2233}
2234
pbos378dc772016-01-28 15:58:41 -08002235void WebRtcVideoChannel2::WebRtcVideoReceiveStream::ConfigureCodecs(
2236 const std::vector<VideoCodecSettings>& recv_codecs,
2237 std::vector<AllocatedDecoder>* old_decoders) {
2238 *old_decoders = allocated_decoders_;
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002239 allocated_decoders_.clear();
2240 config_.decoders.clear();
2241 for (size_t i = 0; i < recv_codecs.size(); ++i) {
2242 AllocatedDecoder allocated_decoder =
pbos378dc772016-01-28 15:58:41 -08002243 CreateOrReuseVideoDecoder(old_decoders, recv_codecs[i].codec);
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002244 allocated_decoders_.push_back(allocated_decoder);
2245
2246 webrtc::VideoReceiveStream::Decoder decoder;
2247 decoder.decoder = allocated_decoder.decoder;
2248 decoder.payload_type = recv_codecs[i].codec.id;
2249 decoder.payload_name = recv_codecs[i].codec.name;
johan3859c892016-08-05 09:19:25 -07002250 ConfigureDecoderSpecifics(&decoder, recv_codecs[i].codec);
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002251 config_.decoders.push_back(decoder);
2252 }
2253
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002254 // TODO(pbos): Reconfigure RTX based on incoming recv_codecs.
brandtrb5f2c3f2016-10-04 23:28:39 -07002255 config_.rtp.ulpfec = recv_codecs.front().ulpfec;
pbos@webrtc.org257e1302014-07-25 19:01:32 +00002256 config_.rtp.nack.rtp_history_ms =
Shao Changbine62202f2015-04-21 20:24:50 +08002257 HasNack(recv_codecs.begin()->codec) ? kNackHistoryMs : 0;
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002258}
2259
Peter Boström3548dd22015-05-22 18:48:36 +02002260void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetLocalSsrc(
2261 uint32_t local_ssrc) {
henrikg91d6ede2015-09-17 00:24:34 -07002262 // TODO(pbos): Consider turning this sanity check into a RTC_DCHECK. You
2263 // should not be able to create a sender with the same SSRC as a receiver, but
2264 // right now this can't be done due to unittests depending on receiving what
2265 // they are sending from the same MediaChannel.
deadbeef874ca3a2015-08-20 17:19:20 -07002266 if (local_ssrc == config_.rtp.remote_ssrc) {
2267 LOG(LS_INFO) << "Ignoring call to SetLocalSsrc because parameters are "
2268 "unchanged; local_ssrc=" << local_ssrc;
Peter Boström3548dd22015-05-22 18:48:36 +02002269 return;
deadbeef874ca3a2015-08-20 17:19:20 -07002270 }
Peter Boström3548dd22015-05-22 18:48:36 +02002271
2272 config_.rtp.local_ssrc = local_ssrc;
deadbeef874ca3a2015-08-20 17:19:20 -07002273 LOG(LS_INFO)
2274 << "RecreateWebRtcStream (recv) because of SetLocalSsrc; local_ssrc="
2275 << local_ssrc;
Peter Boström3548dd22015-05-22 18:48:36 +02002276 RecreateWebRtcStream();
2277}
2278
stefan43edf0f2015-11-20 18:05:48 -08002279void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetFeedbackParameters(
2280 bool nack_enabled,
2281 bool remb_enabled,
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07002282 bool transport_cc_enabled,
2283 webrtc::RtcpMode rtcp_mode) {
Peter Boström67c9df72015-05-11 14:34:58 +02002284 int nack_history_ms = nack_enabled ? kNackHistoryMs : 0;
2285 if (config_.rtp.nack.rtp_history_ms == nack_history_ms &&
stefan43edf0f2015-11-20 18:05:48 -08002286 config_.rtp.remb == remb_enabled &&
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07002287 config_.rtp.transport_cc == transport_cc_enabled &&
2288 config_.rtp.rtcp_mode == rtcp_mode) {
stefan43edf0f2015-11-20 18:05:48 -08002289 LOG(LS_INFO)
2290 << "Ignoring call to SetFeedbackParameters because parameters are "
2291 "unchanged; nack="
2292 << nack_enabled << ", remb=" << remb_enabled
2293 << ", transport_cc=" << transport_cc_enabled;
Peter Boström126c03e2015-05-11 12:48:12 +02002294 return;
Peter Boström67c9df72015-05-11 14:34:58 +02002295 }
2296 config_.rtp.remb = remb_enabled;
2297 config_.rtp.nack.rtp_history_ms = nack_history_ms;
stefan43edf0f2015-11-20 18:05:48 -08002298 config_.rtp.transport_cc = transport_cc_enabled;
Taylor Brandstetter5f0b83b2016-03-18 15:02:07 -07002299 config_.rtp.rtcp_mode = rtcp_mode;
stefan43edf0f2015-11-20 18:05:48 -08002300 LOG(LS_INFO)
2301 << "RecreateWebRtcStream (recv) because of SetFeedbackParameters; nack="
2302 << nack_enabled << ", remb=" << remb_enabled
2303 << ", transport_cc=" << transport_cc_enabled;
Peter Boström126c03e2015-05-11 12:48:12 +02002304 RecreateWebRtcStream();
2305}
2306
deadbeef13871492015-12-09 12:37:51 -08002307void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRecvParameters(
pbos378dc772016-01-28 15:58:41 -08002308 const ChangedRecvParameters& params) {
2309 bool needs_recreation = false;
2310 std::vector<AllocatedDecoder> old_decoders;
2311 if (params.codec_settings) {
2312 ConfigureCodecs(*params.codec_settings, &old_decoders);
2313 needs_recreation = true;
2314 }
2315 if (params.rtp_header_extensions) {
2316 config_.rtp.extensions = *params.rtp_header_extensions;
2317 needs_recreation = true;
2318 }
pbos378dc772016-01-28 15:58:41 -08002319 if (needs_recreation) {
2320 LOG(LS_INFO) << "RecreateWebRtcStream (recv) because of SetRecvParameters";
2321 RecreateWebRtcStream();
2322 ClearDecoders(&old_decoders);
2323 }
deadbeef13871492015-12-09 12:37:51 -08002324}
2325
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002326void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RecreateWebRtcStream() {
2327 if (stream_ != NULL) {
2328 call_->DestroyVideoReceiveStream(stream_);
2329 }
brandtre6f98c72016-11-11 03:28:30 -08002330 stream_ = call_->CreateVideoReceiveStream(config_.Copy());
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002331 stream_->Start();
2332}
2333
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002334void WebRtcVideoChannel2::WebRtcVideoReceiveStream::ClearDecoders(
2335 std::vector<AllocatedDecoder>* allocated_decoders) {
2336 for (size_t i = 0; i < allocated_decoders->size(); ++i) {
2337 if ((*allocated_decoders)[i].external) {
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00002338 external_decoder_factory_->DestroyVideoDecoder(
Peter Boström7252a2b2015-05-18 19:42:03 +02002339 (*allocated_decoders)[i].external_decoder);
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00002340 }
Peter Boström7252a2b2015-05-18 19:42:03 +02002341 delete (*allocated_decoders)[i].decoder;
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00002342 }
pbos@webrtc.org96a93252014-11-03 14:46:44 +00002343 allocated_decoders->clear();
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00002344}
2345
nisseeb83a1a2016-03-21 01:27:56 -07002346void WebRtcVideoChannel2::WebRtcVideoReceiveStream::OnFrame(
2347 const webrtc::VideoFrame& frame) {
nissee73afba2016-01-28 04:47:08 -08002348 rtc::CritScope crit(&sink_lock_);
magjed@webrtc.orgfc5ad952015-01-27 09:57:01 +00002349
2350 if (first_frame_timestamp_ < 0)
2351 first_frame_timestamp_ = frame.timestamp();
2352 int64_t rtp_time_elapsed_since_first_frame =
2353 (timestamp_wraparound_handler_.Unwrap(frame.timestamp()) -
2354 first_frame_timestamp_);
2355 int64_t elapsed_time_ms = rtp_time_elapsed_since_first_frame /
2356 (cricket::kVideoCodecClockrate / 1000);
2357 if (frame.ntp_time_ms() > 0)
2358 estimated_remote_start_ntp_time_ms_ = frame.ntp_time_ms() - elapsed_time_ms;
2359
nissee73afba2016-01-28 04:47:08 -08002360 if (sink_ == NULL) {
2361 LOG(LS_WARNING) << "VideoReceiveStream not connected to a VideoSink.";
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002362 return;
2363 }
2364
nisse09347852016-10-19 00:30:30 -07002365 sink_->OnFrame(frame);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002366}
2367
pbos@webrtc.orga2a6fe62015-03-06 15:35:19 +00002368bool WebRtcVideoChannel2::WebRtcVideoReceiveStream::IsDefaultStream() const {
2369 return default_stream_;
2370}
2371
nissee73afba2016-01-28 04:47:08 -08002372void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetSink(
nisseacd935b2016-11-11 03:55:13 -08002373 rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
nissee73afba2016-01-28 04:47:08 -08002374 rtc::CritScope crit(&sink_lock_);
2375 sink_ = sink;
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00002376}
2377
pbosf42376c2015-08-28 07:35:32 -07002378std::string
2379WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetCodecNameFromPayloadType(
2380 int payload_type) {
2381 for (const webrtc::VideoReceiveStream::Decoder& decoder : config_.decoders) {
2382 if (decoder.payload_type == payload_type) {
2383 return decoder.payload_name;
2384 }
2385 }
2386 return "";
2387}
2388
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002389VideoReceiverInfo
asapersson2e5cfcd2016-08-11 08:41:18 -07002390WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo(
2391 bool log_stats) {
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002392 VideoReceiverInfo info;
sakal1fd95952016-06-22 00:46:15 -07002393 info.ssrc_groups = stream_params_.ssrc_groups;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002394 info.add_ssrc(config_.rtp.remote_ssrc);
2395 webrtc::VideoReceiveStream::Stats stats = stream_->GetStats();
Peter Boströmb7d9a972015-12-18 16:01:11 +01002396 info.decoder_implementation_name = stats.decoder_implementation_name;
hbosa65704b2016-11-14 02:28:16 -08002397 if (stats.current_payload_type != -1) {
hbos1acfbd22016-11-17 23:43:29 -08002398 info.codec_payload_type = rtc::Optional<int>(
2399 stats.current_payload_type);
hbosa65704b2016-11-14 02:28:16 -08002400 }
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +00002401 info.bytes_rcvd = stats.rtp_stats.transmitted.payload_bytes +
2402 stats.rtp_stats.transmitted.header_bytes +
2403 stats.rtp_stats.transmitted.padding_bytes;
2404 info.packets_rcvd = stats.rtp_stats.transmitted.packets;
Peter Boström393347f2015-04-22 14:52:45 +02002405 info.packets_lost = stats.rtcp_stats.cumulative_lost;
2406 info.fraction_lost =
2407 static_cast<float>(stats.rtcp_stats.fraction_lost) / (1 << 8);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002408
2409 info.framerate_rcvd = stats.network_frame_rate;
2410 info.framerate_decoded = stats.decode_frame_rate;
2411 info.framerate_output = stats.render_frame_rate;
asapersson26dd92b2016-08-30 00:45:45 -07002412 info.frame_width = stats.width;
2413 info.frame_height = stats.height;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002414
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00002415 {
nissee73afba2016-01-28 04:47:08 -08002416 rtc::CritScope frame_cs(&sink_lock_);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00002417 info.capture_start_ntp_time_ms = estimated_remote_start_ntp_time_ms_;
2418 }
2419
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002420 info.decode_ms = stats.decode_ms;
2421 info.max_decode_ms = stats.max_decode_ms;
2422 info.current_delay_ms = stats.current_delay_ms;
2423 info.target_delay_ms = stats.target_delay_ms;
2424 info.jitter_buffer_ms = stats.jitter_buffer_ms;
2425 info.min_playout_delay_ms = stats.min_playout_delay_ms;
2426 info.render_delay_ms = stats.render_delay_ms;
sakale5ba44e2016-10-26 07:09:24 -07002427 info.frames_decoded = stats.frames_decoded;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00002428
pbosf42376c2015-08-28 07:35:32 -07002429 info.codec_name = GetCodecNameFromPayloadType(stats.current_payload_type);
2430
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00002431 info.firs_sent = stats.rtcp_packet_type_counts.fir_packets;
2432 info.plis_sent = stats.rtcp_packet_type_counts.pli_packets;
2433 info.nacks_sent = stats.rtcp_packet_type_counts.nack_packets;
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002434
asapersson2e5cfcd2016-08-11 08:41:18 -07002435 if (log_stats)
2436 LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());
2437
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00002438 return info;
2439}
2440
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002441WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings()
2442 : rtx_payload_type(-1) {}
2443
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00002444bool WebRtcVideoChannel2::VideoCodecSettings::operator==(
2445 const WebRtcVideoChannel2::VideoCodecSettings& other) const {
2446 return codec == other.codec &&
brandtrb5f2c3f2016-10-04 23:28:39 -07002447 ulpfec.ulpfec_payload_type == other.ulpfec.ulpfec_payload_type &&
2448 ulpfec.red_payload_type == other.ulpfec.red_payload_type &&
2449 ulpfec.red_rtx_payload_type == other.ulpfec.red_rtx_payload_type &&
pbos@webrtc.orga2ef4fe2014-11-07 10:54:43 +00002450 rtx_payload_type == other.rtx_payload_type;
2451}
2452
Peter Boströmee0b00e2015-04-22 18:41:14 +02002453bool WebRtcVideoChannel2::VideoCodecSettings::operator!=(
2454 const WebRtcVideoChannel2::VideoCodecSettings& other) const {
2455 return !(*this == other);
2456}
2457
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002458std::vector<WebRtcVideoChannel2::VideoCodecSettings>
2459WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) {
henrikg91d6ede2015-09-17 00:24:34 -07002460 RTC_DCHECK(!codecs.empty());
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002461
2462 std::vector<VideoCodecSettings> video_codecs;
2463 std::map<int, bool> payload_used;
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002464 std::map<int, VideoCodec::CodecType> payload_codec_type;
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00002465 // |rtx_mapping| maps video payload type to rtx payload type.
2466 std::map<int, int> rtx_mapping;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002467
brandtrb5f2c3f2016-10-04 23:28:39 -07002468 webrtc::UlpfecConfig ulpfec_config;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002469
2470 for (size_t i = 0; i < codecs.size(); ++i) {
2471 const VideoCodec& in_codec = codecs[i];
2472 int payload_type = in_codec.id;
2473
2474 if (payload_used[payload_type]) {
2475 LOG(LS_ERROR) << "Payload type already registered: "
2476 << in_codec.ToString();
2477 return std::vector<VideoCodecSettings>();
2478 }
2479 payload_used[payload_type] = true;
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002480 payload_codec_type[payload_type] = in_codec.GetCodecType();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002481
2482 switch (in_codec.GetCodecType()) {
2483 case VideoCodec::CODEC_RED: {
2484 // RED payload type, should not have duplicates.
brandtrb5f2c3f2016-10-04 23:28:39 -07002485 RTC_DCHECK(ulpfec_config.red_payload_type == -1);
2486 ulpfec_config.red_payload_type = in_codec.id;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002487 continue;
2488 }
2489
2490 case VideoCodec::CODEC_ULPFEC: {
2491 // ULPFEC payload type, should not have duplicates.
brandtrb5f2c3f2016-10-04 23:28:39 -07002492 RTC_DCHECK(ulpfec_config.ulpfec_payload_type == -1);
2493 ulpfec_config.ulpfec_payload_type = in_codec.id;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002494 continue;
2495 }
2496
brandtr87d7d772016-11-07 03:03:41 -08002497 case VideoCodec::CODEC_FLEXFEC: {
2498 // TODO(brandtr): To be implemented.
2499 continue;
2500 }
2501
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002502 case VideoCodec::CODEC_RTX: {
2503 int associated_payload_type;
2504 if (!in_codec.GetParam(kCodecParamAssociatedPayloadType,
pkasting@chromium.orge9facf82015-02-17 20:36:28 +00002505 &associated_payload_type) ||
2506 !IsValidRtpPayloadType(associated_payload_type)) {
2507 LOG(LS_ERROR)
2508 << "RTX codec with invalid or no associated payload type: "
2509 << in_codec.ToString();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002510 return std::vector<VideoCodecSettings>();
2511 }
2512 rtx_mapping[associated_payload_type] = in_codec.id;
2513 continue;
2514 }
2515
2516 case VideoCodec::CODEC_VIDEO:
2517 break;
2518 }
2519
2520 video_codecs.push_back(VideoCodecSettings());
2521 video_codecs.back().codec = in_codec;
2522 }
2523
2524 // One of these codecs should have been a video codec. Only having FEC
2525 // parameters into this code is a logic error.
henrikg91d6ede2015-09-17 00:24:34 -07002526 RTC_DCHECK(!video_codecs.empty());
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002527
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002528 for (std::map<int, int>::const_iterator it = rtx_mapping.begin();
2529 it != rtx_mapping.end();
2530 ++it) {
2531 if (!payload_used[it->first]) {
2532 LOG(LS_ERROR) << "RTX mapped to payload not in codec list.";
2533 return std::vector<VideoCodecSettings>();
2534 }
Shao Changbine62202f2015-04-21 20:24:50 +08002535 if (payload_codec_type[it->first] != VideoCodec::CODEC_VIDEO &&
2536 payload_codec_type[it->first] != VideoCodec::CODEC_RED) {
2537 LOG(LS_ERROR) << "RTX not mapped to regular video codec or RED codec.";
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002538 return std::vector<VideoCodecSettings>();
2539 }
Shao Changbine62202f2015-04-21 20:24:50 +08002540
brandtrb5f2c3f2016-10-04 23:28:39 -07002541 if (it->first == ulpfec_config.red_payload_type) {
2542 ulpfec_config.red_rtx_payload_type = it->second;
Shao Changbine62202f2015-04-21 20:24:50 +08002543 }
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002544 }
2545
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002546 for (size_t i = 0; i < video_codecs.size(); ++i) {
brandtrb5f2c3f2016-10-04 23:28:39 -07002547 video_codecs[i].ulpfec = ulpfec_config;
Shao Changbine62202f2015-04-21 20:24:50 +08002548 if (rtx_mapping[video_codecs[i].codec.id] != 0 &&
2549 rtx_mapping[video_codecs[i].codec.id] !=
brandtrb5f2c3f2016-10-04 23:28:39 -07002550 ulpfec_config.red_payload_type) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002551 video_codecs[i].rtx_payload_type = rtx_mapping[video_codecs[i].codec.id];
2552 }
2553 }
2554
2555 return video_codecs;
2556}
2557
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002558} // namespace cricket