1 /*
2  *  Copyright 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "pc/rtp_sender.h"
12 
13 #include <atomic>
14 #include <utility>
15 #include <vector>
16 
17 #include "api/audio_options.h"
18 #include "api/media_stream_interface.h"
19 #include "media/base/media_engine.h"
20 #include "pc/stats_collector_interface.h"
21 #include "rtc_base/checks.h"
22 #include "rtc_base/helpers.h"
23 #include "rtc_base/location.h"
24 #include "rtc_base/logging.h"
25 #include "rtc_base/trace_event.h"
26 
27 namespace webrtc {
28 
29 namespace {
30 
31 // This function is only expected to be called on the signaling thread.
32 // On the other hand, some test or even production setups may use
33 // several signaling threads.
GenerateUniqueId()34 int GenerateUniqueId() {
35   static std::atomic<int> g_unique_id{0};
36 
37   return ++g_unique_id;
38 }
39 
40 // Returns true if a "per-sender" encoding parameter contains a value that isn't
41 // its default. Currently max_bitrate_bps and bitrate_priority both are
42 // implemented "per-sender," meaning that these encoding parameters
43 // are used for the RtpSender as a whole, not for a specific encoding layer.
44 // This is done by setting these encoding parameters at index 0 of
45 // RtpParameters.encodings. This function can be used to check if these
46 // parameters are set at any index other than 0 of RtpParameters.encodings,
47 // because they are currently unimplemented to be used for a specific encoding
48 // layer.
PerSenderRtpEncodingParameterHasValue(const RtpEncodingParameters & encoding_params)49 bool PerSenderRtpEncodingParameterHasValue(
50     const RtpEncodingParameters& encoding_params) {
51   if (encoding_params.bitrate_priority != kDefaultBitratePriority ||
52       encoding_params.network_priority != Priority::kLow) {
53     return true;
54   }
55   return false;
56 }
57 
RemoveEncodingLayers(const std::vector<std::string> & rids,std::vector<RtpEncodingParameters> * encodings)58 void RemoveEncodingLayers(const std::vector<std::string>& rids,
59                           std::vector<RtpEncodingParameters>* encodings) {
60   RTC_DCHECK(encodings);
61   encodings->erase(
62       std::remove_if(encodings->begin(), encodings->end(),
63                      [&rids](const RtpEncodingParameters& encoding) {
64                        return absl::c_linear_search(rids, encoding.rid);
65                      }),
66       encodings->end());
67 }
68 
RestoreEncodingLayers(const RtpParameters & parameters,const std::vector<std::string> & removed_rids,const std::vector<RtpEncodingParameters> & all_layers)69 RtpParameters RestoreEncodingLayers(
70     const RtpParameters& parameters,
71     const std::vector<std::string>& removed_rids,
72     const std::vector<RtpEncodingParameters>& all_layers) {
73   RTC_DCHECK_EQ(parameters.encodings.size() + removed_rids.size(),
74                 all_layers.size());
75   RtpParameters result(parameters);
76   result.encodings.clear();
77   size_t index = 0;
78   for (const RtpEncodingParameters& encoding : all_layers) {
79     if (absl::c_linear_search(removed_rids, encoding.rid)) {
80       result.encodings.push_back(encoding);
81       continue;
82     }
83     result.encodings.push_back(parameters.encodings[index++]);
84   }
85   return result;
86 }
87 
88 }  // namespace
89 
90 // Returns true if any RtpParameters member that isn't implemented contains a
91 // value.
UnimplementedRtpParameterHasValue(const RtpParameters & parameters)92 bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
93   if (!parameters.mid.empty()) {
94     return true;
95   }
96   for (size_t i = 0; i < parameters.encodings.size(); ++i) {
97     // Encoding parameters that are per-sender should only contain value at
98     // index 0.
99     if (i != 0 &&
100         PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
101       return true;
102     }
103   }
104   return false;
105 }
106 
RtpSenderBase(rtc::Thread * worker_thread,const std::string & id,SetStreamsObserver * set_streams_observer)107 RtpSenderBase::RtpSenderBase(rtc::Thread* worker_thread,
108                              const std::string& id,
109                              SetStreamsObserver* set_streams_observer)
110     : worker_thread_(worker_thread),
111       id_(id),
112       set_streams_observer_(set_streams_observer) {
113   RTC_DCHECK(worker_thread);
114   init_parameters_.encodings.emplace_back();
115 }
116 
SetFrameEncryptor(rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor)117 void RtpSenderBase::SetFrameEncryptor(
118     rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
119   frame_encryptor_ = std::move(frame_encryptor);
120   // Special Case: Set the frame encryptor to any value on any existing channel.
121   if (media_channel_ && ssrc_ && !stopped_) {
122     worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
123       media_channel_->SetFrameEncryptor(ssrc_, frame_encryptor_);
124     });
125   }
126 }
127 
SetMediaChannel(cricket::MediaChannel * media_channel)128 void RtpSenderBase::SetMediaChannel(cricket::MediaChannel* media_channel) {
129   RTC_DCHECK(media_channel == nullptr ||
130              media_channel->media_type() == media_type());
131   media_channel_ = media_channel;
132 }
133 
GetParametersInternal() const134 RtpParameters RtpSenderBase::GetParametersInternal() const {
135   if (stopped_) {
136     return RtpParameters();
137   }
138   if (!media_channel_ || !ssrc_) {
139     return init_parameters_;
140   }
141   return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
142     RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
143     RemoveEncodingLayers(disabled_rids_, &result.encodings);
144     return result;
145   });
146 }
147 
GetParameters() const148 RtpParameters RtpSenderBase::GetParameters() const {
149   RtpParameters result = GetParametersInternal();
150   last_transaction_id_ = rtc::CreateRandomUuid();
151   result.transaction_id = last_transaction_id_.value();
152   return result;
153 }
154 
SetParametersInternal(const RtpParameters & parameters)155 RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
156   RTC_DCHECK(!stopped_);
157 
158   if (UnimplementedRtpParameterHasValue(parameters)) {
159     LOG_AND_RETURN_ERROR(
160         RTCErrorType::UNSUPPORTED_PARAMETER,
161         "Attempted to set an unimplemented parameter of RtpParameters.");
162   }
163   if (!media_channel_ || !ssrc_) {
164     auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
165         init_parameters_, parameters);
166     if (result.ok()) {
167       init_parameters_ = parameters;
168     }
169     return result;
170   }
171   return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
172     RtpParameters rtp_parameters = parameters;
173     if (!disabled_rids_.empty()) {
174       // Need to add the inactive layers.
175       RtpParameters old_parameters =
176           media_channel_->GetRtpSendParameters(ssrc_);
177       rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
178                                              old_parameters.encodings);
179     }
180     return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
181   });
182 }
183 
SetParameters(const RtpParameters & parameters)184 RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
185   TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
186   if (is_transceiver_stopped_) {
187     LOG_AND_RETURN_ERROR(
188         RTCErrorType::INVALID_STATE,
189         "Cannot set parameters on sender of a stopped transceiver.");
190   }
191   if (stopped_) {
192     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
193                          "Cannot set parameters on a stopped sender.");
194   }
195   if (stopped_) {
196     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
197                          "Cannot set parameters on a stopped sender.");
198   }
199   if (!last_transaction_id_) {
200     LOG_AND_RETURN_ERROR(
201         RTCErrorType::INVALID_STATE,
202         "Failed to set parameters since getParameters() has never been called"
203         " on this sender");
204   }
205   if (last_transaction_id_ != parameters.transaction_id) {
206     LOG_AND_RETURN_ERROR(
207         RTCErrorType::INVALID_MODIFICATION,
208         "Failed to set parameters since the transaction_id doesn't match"
209         " the last value returned from getParameters()");
210   }
211 
212   RTCError result = SetParametersInternal(parameters);
213   last_transaction_id_.reset();
214   return result;
215 }
216 
SetStreams(const std::vector<std::string> & stream_ids)217 void RtpSenderBase::SetStreams(const std::vector<std::string>& stream_ids) {
218   set_stream_ids(stream_ids);
219   if (set_streams_observer_)
220     set_streams_observer_->OnSetStreams();
221 }
222 
SetTrack(MediaStreamTrackInterface * track)223 bool RtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
224   TRACE_EVENT0("webrtc", "RtpSenderBase::SetTrack");
225   if (stopped_) {
226     RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
227     return false;
228   }
229   if (track && track->kind() != track_kind()) {
230     RTC_LOG(LS_ERROR) << "SetTrack with " << track->kind()
231                       << " called on RtpSender with " << track_kind()
232                       << " track.";
233     return false;
234   }
235 
236   // Detach from old track.
237   if (track_) {
238     DetachTrack();
239     track_->UnregisterObserver(this);
240     RemoveTrackFromStats();
241   }
242 
243   // Attach to new track.
244   bool prev_can_send_track = can_send_track();
245   // Keep a reference to the old track to keep it alive until we call SetSend.
246   rtc::scoped_refptr<MediaStreamTrackInterface> old_track = track_;
247   track_ = track;
248   if (track_) {
249     track_->RegisterObserver(this);
250     AttachTrack();
251   }
252 
253   // Update channel.
254   if (can_send_track()) {
255     SetSend();
256     AddTrackToStats();
257   } else if (prev_can_send_track) {
258     ClearSend();
259   }
260   attachment_id_ = (track_ ? GenerateUniqueId() : 0);
261   return true;
262 }
263 
SetSsrc(uint32_t ssrc)264 void RtpSenderBase::SetSsrc(uint32_t ssrc) {
265   TRACE_EVENT0("webrtc", "RtpSenderBase::SetSsrc");
266   if (stopped_ || ssrc == ssrc_) {
267     return;
268   }
269   // If we are already sending with a particular SSRC, stop sending.
270   if (can_send_track()) {
271     ClearSend();
272     RemoveTrackFromStats();
273   }
274   ssrc_ = ssrc;
275   if (can_send_track()) {
276     SetSend();
277     AddTrackToStats();
278   }
279   if (!init_parameters_.encodings.empty()) {
280     worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
281       RTC_DCHECK(media_channel_);
282       // Get the current parameters, which are constructed from the SDP.
283       // The number of layers in the SDP is currently authoritative to support
284       // SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
285       // lines as described in RFC 5576.
286       // All fields should be default constructed and the SSRC field set, which
287       // we need to copy.
288       RtpParameters current_parameters =
289           media_channel_->GetRtpSendParameters(ssrc_);
290       RTC_DCHECK_GE(current_parameters.encodings.size(),
291                     init_parameters_.encodings.size());
292       for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
293         init_parameters_.encodings[i].ssrc =
294             current_parameters.encodings[i].ssrc;
295         init_parameters_.encodings[i].rid = current_parameters.encodings[i].rid;
296         current_parameters.encodings[i] = init_parameters_.encodings[i];
297       }
298       current_parameters.degradation_preference =
299           init_parameters_.degradation_preference;
300       media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
301       init_parameters_.encodings.clear();
302     });
303   }
304   // Attempt to attach the frame decryptor to the current media channel.
305   if (frame_encryptor_) {
306     SetFrameEncryptor(frame_encryptor_);
307   }
308   if (frame_transformer_) {
309     SetEncoderToPacketizerFrameTransformer(frame_transformer_);
310   }
311 }
312 
Stop()313 void RtpSenderBase::Stop() {
314   TRACE_EVENT0("webrtc", "RtpSenderBase::Stop");
315   // TODO(deadbeef): Need to do more here to fully stop sending packets.
316   if (stopped_) {
317     return;
318   }
319   if (track_) {
320     DetachTrack();
321     track_->UnregisterObserver(this);
322   }
323   if (can_send_track()) {
324     ClearSend();
325     RemoveTrackFromStats();
326   }
327   media_channel_ = nullptr;
328   set_streams_observer_ = nullptr;
329   stopped_ = true;
330 }
331 
DisableEncodingLayers(const std::vector<std::string> & rids)332 RTCError RtpSenderBase::DisableEncodingLayers(
333     const std::vector<std::string>& rids) {
334   if (stopped_) {
335     LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
336                          "Cannot disable encodings on a stopped sender.");
337   }
338 
339   if (rids.empty()) {
340     return RTCError::OK();
341   }
342 
343   // Check that all the specified layers exist and disable them in the channel.
344   RtpParameters parameters = GetParametersInternal();
345   for (const std::string& rid : rids) {
346     if (absl::c_none_of(parameters.encodings,
347                         [&rid](const RtpEncodingParameters& encoding) {
348                           return encoding.rid == rid;
349                         })) {
350       LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
351                            "RID: " + rid + " does not refer to a valid layer.");
352     }
353   }
354 
355   if (!media_channel_ || !ssrc_) {
356     RemoveEncodingLayers(rids, &init_parameters_.encodings);
357     // Invalidate any transaction upon success.
358     last_transaction_id_.reset();
359     return RTCError::OK();
360   }
361 
362   for (RtpEncodingParameters& encoding : parameters.encodings) {
363     // Remain active if not in the disable list.
364     encoding.active &= absl::c_none_of(
365         rids,
366         [&encoding](const std::string& rid) { return encoding.rid == rid; });
367   }
368 
369   RTCError result = SetParametersInternal(parameters);
370   if (result.ok()) {
371     disabled_rids_.insert(disabled_rids_.end(), rids.begin(), rids.end());
372     // Invalidate any transaction upon success.
373     last_transaction_id_.reset();
374   }
375   return result;
376 }
377 
SetEncoderToPacketizerFrameTransformer(rtc::scoped_refptr<FrameTransformerInterface> frame_transformer)378 void RtpSenderBase::SetEncoderToPacketizerFrameTransformer(
379     rtc::scoped_refptr<FrameTransformerInterface> frame_transformer) {
380   frame_transformer_ = std::move(frame_transformer);
381   if (media_channel_ && ssrc_ && !stopped_) {
382     worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
383       media_channel_->SetEncoderToPacketizerFrameTransformer(
384           ssrc_, frame_transformer_);
385     });
386   }
387 }
388 
LocalAudioSinkAdapter()389 LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
390 
~LocalAudioSinkAdapter()391 LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
392   MutexLock lock(&lock_);
393   if (sink_)
394     sink_->OnClose();
395 }
396 
OnData(const void * audio_data,int bits_per_sample,int sample_rate,size_t number_of_channels,size_t number_of_frames,absl::optional<int64_t> absolute_capture_timestamp_ms)397 void LocalAudioSinkAdapter::OnData(
398     const void* audio_data,
399     int bits_per_sample,
400     int sample_rate,
401     size_t number_of_channels,
402     size_t number_of_frames,
403     absl::optional<int64_t> absolute_capture_timestamp_ms) {
404   MutexLock lock(&lock_);
405   if (sink_) {
406     sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
407                   number_of_frames, absolute_capture_timestamp_ms);
408   }
409 }
410 
SetSink(cricket::AudioSource::Sink * sink)411 void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
412   MutexLock lock(&lock_);
413   RTC_DCHECK(!sink || !sink_);
414   sink_ = sink;
415 }
416 
Create(rtc::Thread * worker_thread,const std::string & id,StatsCollectorInterface * stats,SetStreamsObserver * set_streams_observer)417 rtc::scoped_refptr<AudioRtpSender> AudioRtpSender::Create(
418     rtc::Thread* worker_thread,
419     const std::string& id,
420     StatsCollectorInterface* stats,
421     SetStreamsObserver* set_streams_observer) {
422   return rtc::scoped_refptr<AudioRtpSender>(
423       new rtc::RefCountedObject<AudioRtpSender>(worker_thread, id, stats,
424                                                 set_streams_observer));
425 }
426 
AudioRtpSender(rtc::Thread * worker_thread,const std::string & id,StatsCollectorInterface * stats,SetStreamsObserver * set_streams_observer)427 AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
428                                const std::string& id,
429                                StatsCollectorInterface* stats,
430                                SetStreamsObserver* set_streams_observer)
431     : RtpSenderBase(worker_thread, id, set_streams_observer),
432       stats_(stats),
433       dtmf_sender_proxy_(DtmfSenderProxy::Create(
434           rtc::Thread::Current(),
435           DtmfSender::Create(rtc::Thread::Current(), this))),
436       sink_adapter_(new LocalAudioSinkAdapter()) {}
437 
~AudioRtpSender()438 AudioRtpSender::~AudioRtpSender() {
439   // For DtmfSender.
440   SignalDestroyed();
441   Stop();
442 }
443 
CanInsertDtmf()444 bool AudioRtpSender::CanInsertDtmf() {
445   if (!media_channel_) {
446     RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
447     return false;
448   }
449   // Check that this RTP sender is active (description has been applied that
450   // matches an SSRC to its ID).
451   if (!ssrc_) {
452     RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
453     return false;
454   }
455   return worker_thread_->Invoke<bool>(
456       RTC_FROM_HERE, [&] { return voice_media_channel()->CanInsertDtmf(); });
457 }
458 
InsertDtmf(int code,int duration)459 bool AudioRtpSender::InsertDtmf(int code, int duration) {
460   if (!media_channel_) {
461     RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
462     return false;
463   }
464   if (!ssrc_) {
465     RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
466     return false;
467   }
468   bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
469     return voice_media_channel()->InsertDtmf(ssrc_, code, duration);
470   });
471   if (!success) {
472     RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
473   }
474   return success;
475 }
476 
GetOnDestroyedSignal()477 sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
478   return &SignalDestroyed;
479 }
480 
OnChanged()481 void AudioRtpSender::OnChanged() {
482   TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
483   RTC_DCHECK(!stopped_);
484   if (cached_track_enabled_ != track_->enabled()) {
485     cached_track_enabled_ = track_->enabled();
486     if (can_send_track()) {
487       SetSend();
488     }
489   }
490 }
491 
DetachTrack()492 void AudioRtpSender::DetachTrack() {
493   RTC_DCHECK(track_);
494   audio_track()->RemoveSink(sink_adapter_.get());
495 }
496 
AttachTrack()497 void AudioRtpSender::AttachTrack() {
498   RTC_DCHECK(track_);
499   cached_track_enabled_ = track_->enabled();
500   audio_track()->AddSink(sink_adapter_.get());
501 }
502 
AddTrackToStats()503 void AudioRtpSender::AddTrackToStats() {
504   if (can_send_track() && stats_) {
505     stats_->AddLocalAudioTrack(audio_track().get(), ssrc_);
506   }
507 }
508 
RemoveTrackFromStats()509 void AudioRtpSender::RemoveTrackFromStats() {
510   if (can_send_track() && stats_) {
511     stats_->RemoveLocalAudioTrack(audio_track().get(), ssrc_);
512   }
513 }
514 
GetDtmfSender() const515 rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
516   return dtmf_sender_proxy_;
517 }
518 
SetSend()519 void AudioRtpSender::SetSend() {
520   RTC_DCHECK(!stopped_);
521   RTC_DCHECK(can_send_track());
522   if (!media_channel_) {
523     RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
524     return;
525   }
526   cricket::AudioOptions options;
527 #if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
528   // TODO(tommi): Remove this hack when we move CreateAudioSource out of
529   // PeerConnection.  This is a bit of a strange way to apply local audio
530   // options since it is also applied to all streams/channels, local or remote.
531   if (track_->enabled() && audio_track()->GetSource() &&
532       !audio_track()->GetSource()->remote()) {
533     options = audio_track()->GetSource()->options();
534   }
535 #endif
536 
537   // |track_->enabled()| hops to the signaling thread, so call it before we hop
538   // to the worker thread or else it will deadlock.
539   bool track_enabled = track_->enabled();
540   bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
541     return voice_media_channel()->SetAudioSend(ssrc_, track_enabled, &options,
542                                                sink_adapter_.get());
543   });
544   if (!success) {
545     RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
546   }
547 }
548 
ClearSend()549 void AudioRtpSender::ClearSend() {
550   RTC_DCHECK(ssrc_ != 0);
551   RTC_DCHECK(!stopped_);
552   if (!media_channel_) {
553     RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
554     return;
555   }
556   cricket::AudioOptions options;
557   bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
558     return voice_media_channel()->SetAudioSend(ssrc_, false, &options, nullptr);
559   });
560   if (!success) {
561     RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
562   }
563 }
564 
Create(rtc::Thread * worker_thread,const std::string & id,SetStreamsObserver * set_streams_observer)565 rtc::scoped_refptr<VideoRtpSender> VideoRtpSender::Create(
566     rtc::Thread* worker_thread,
567     const std::string& id,
568     SetStreamsObserver* set_streams_observer) {
569   return rtc::scoped_refptr<VideoRtpSender>(
570       new rtc::RefCountedObject<VideoRtpSender>(worker_thread, id,
571                                                 set_streams_observer));
572 }
573 
VideoRtpSender(rtc::Thread * worker_thread,const std::string & id,SetStreamsObserver * set_streams_observer)574 VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
575                                const std::string& id,
576                                SetStreamsObserver* set_streams_observer)
577     : RtpSenderBase(worker_thread, id, set_streams_observer) {}
578 
~VideoRtpSender()579 VideoRtpSender::~VideoRtpSender() {
580   Stop();
581 }
582 
OnChanged()583 void VideoRtpSender::OnChanged() {
584   TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
585   RTC_DCHECK(!stopped_);
586   if (cached_track_content_hint_ != video_track()->content_hint()) {
587     cached_track_content_hint_ = video_track()->content_hint();
588     if (can_send_track()) {
589       SetSend();
590     }
591   }
592 }
593 
AttachTrack()594 void VideoRtpSender::AttachTrack() {
595   RTC_DCHECK(track_);
596   cached_track_content_hint_ = video_track()->content_hint();
597 }
598 
GetDtmfSender() const599 rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
600   RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
601   return nullptr;
602 }
603 
SetSend()604 void VideoRtpSender::SetSend() {
605   RTC_DCHECK(!stopped_);
606   RTC_DCHECK(can_send_track());
607   if (!media_channel_) {
608     RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
609     return;
610   }
611   cricket::VideoOptions options;
612   VideoTrackSourceInterface* source = video_track()->GetSource();
613   if (source) {
614     options.is_screencast = source->is_screencast();
615     options.video_noise_reduction = source->needs_denoising();
616   }
617   options.content_hint = cached_track_content_hint_;
618   switch (cached_track_content_hint_) {
619     case VideoTrackInterface::ContentHint::kNone:
620       break;
621     case VideoTrackInterface::ContentHint::kFluid:
622       options.is_screencast = false;
623       break;
624     case VideoTrackInterface::ContentHint::kDetailed:
625     case VideoTrackInterface::ContentHint::kText:
626       options.is_screencast = true;
627       break;
628   }
629   bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
630     return video_media_channel()->SetVideoSend(ssrc_, &options, video_track());
631   });
632   RTC_DCHECK(success);
633 }
634 
ClearSend()635 void VideoRtpSender::ClearSend() {
636   RTC_DCHECK(ssrc_ != 0);
637   RTC_DCHECK(!stopped_);
638   if (!media_channel_) {
639     RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
640     return;
641   }
642   // Allow SetVideoSend to fail since |enable| is false and |source| is null.
643   // This the normal case when the underlying media channel has already been
644   // deleted.
645   worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
646     return video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr);
647   });
648 }
649 
650 }  // namespace webrtc
651