blob: 908d938b18021da6ffd7a2067fcb715ae1c41715 [file] [log] [blame]
deadbeef6979b022015-09-24 16:47:53 -07001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
deadbeef6979b022015-09-24 16:47:53 -07003 *
kjellanderb24317b2016-02-10 07:54:43 -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.
deadbeef6979b022015-09-24 16:47:53 -07009 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/rtp_sender.h"
deadbeef6979b022015-09-24 16:47:53 -070012
Benjamin Wrightd81ac952018-08-29 17:02:10 -070013#include <utility>
Steve Anton36b29d12017-10-30 09:57:42 -070014#include <vector>
15
Yves Gerey3e707812018-11-28 16:47:49 +010016#include "api/audio_options.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "api/media_stream_interface.h"
18#include "media/base/media_engine.h"
19#include "pc/stats_collector.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/checks.h"
21#include "rtc_base/helpers.h"
Yves Gerey3e707812018-11-28 16:47:49 +010022#include "rtc_base/location.h"
23#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/trace_event.h"
deadbeef70ab1a12015-09-28 16:53:55 -070025
26namespace webrtc {
27
Harald Alvestrandc72af932018-01-11 17:18:19 +010028namespace {
29
30// This function is only expected to be called on the signalling thread.
31int GenerateUniqueId() {
32 static int g_unique_id = 0;
33
34 return ++g_unique_id;
35}
36
Seth Hampson2d2c8882018-05-16 16:02:32 -070037// Returns an true if any RtpEncodingParameters member that isn't implemented
38// contains a value.
39bool UnimplementedRtpEncodingParameterHasValue(
40 const RtpEncodingParameters& encoding_params) {
Henrik Grunelle1301a82018-12-13 12:13:22 +000041 if (encoding_params.codec_payload_type.has_value() ||
42 encoding_params.fec.has_value() || encoding_params.rtx.has_value() ||
Seth Hampson2d2c8882018-05-16 16:02:32 -070043 encoding_params.dtx.has_value() || encoding_params.ptime.has_value() ||
Seth Hampson2d2c8882018-05-16 16:02:32 -070044 encoding_params.scale_framerate_down_by.has_value() ||
45 !encoding_params.dependency_rids.empty()) {
46 return true;
47 }
48 return false;
49}
50
51// Returns true if a "per-sender" encoding parameter contains a value that isn't
52// its default. Currently max_bitrate_bps and bitrate_priority both are
53// implemented "per-sender," meaning that these encoding parameters
54// are used for the RtpSender as a whole, not for a specific encoding layer.
55// This is done by setting these encoding parameters at index 0 of
56// RtpParameters.encodings. This function can be used to check if these
57// parameters are set at any index other than 0 of RtpParameters.encodings,
58// because they are currently unimplemented to be used for a specific encoding
59// layer.
60bool PerSenderRtpEncodingParameterHasValue(
61 const RtpEncodingParameters& encoding_params) {
Tim Haloun648d28a2018-10-18 16:52:22 -070062 if (encoding_params.bitrate_priority != kDefaultBitratePriority ||
63 encoding_params.network_priority != kDefaultBitratePriority) {
Seth Hampson2d2c8882018-05-16 16:02:32 -070064 return true;
65 }
66 return false;
67}
68
Amit Hilbuch2297d332019-02-19 12:49:22 -080069void RemoveEncodingLayers(const std::vector<std::string>& rids,
70 std::vector<RtpEncodingParameters>* encodings) {
71 RTC_DCHECK(encodings);
72 encodings->erase(
73 std::remove_if(encodings->begin(), encodings->end(),
74 [&rids](const RtpEncodingParameters& encoding) {
75 return absl::c_linear_search(rids, encoding.rid);
76 }),
77 encodings->end());
78}
79
80RtpParameters RestoreEncodingLayers(
81 const RtpParameters& parameters,
82 const std::vector<std::string>& removed_rids,
83 const std::vector<RtpEncodingParameters>& all_layers) {
84 RTC_DCHECK_EQ(parameters.encodings.size() + removed_rids.size(),
85 all_layers.size());
86 RtpParameters result(parameters);
87 result.encodings.clear();
88 size_t index = 0;
89 for (const RtpEncodingParameters& encoding : all_layers) {
90 if (absl::c_linear_search(removed_rids, encoding.rid)) {
91 result.encodings.push_back(encoding);
92 continue;
93 }
94 result.encodings.push_back(parameters.encodings[index++]);
95 }
96 return result;
97}
98
Florent Castelli892acf02018-10-01 22:47:20 +020099} // namespace
100
Seth Hampson2d2c8882018-05-16 16:02:32 -0700101// Returns true if any RtpParameters member that isn't implemented contains a
102// value.
103bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
Florent Castelli87b3c512018-07-18 16:00:28 +0200104 if (!parameters.mid.empty()) {
Seth Hampson2d2c8882018-05-16 16:02:32 -0700105 return true;
106 }
107 for (size_t i = 0; i < parameters.encodings.size(); ++i) {
108 if (UnimplementedRtpEncodingParameterHasValue(parameters.encodings[i])) {
109 return true;
110 }
111 // Encoding parameters that are per-sender should only contain value at
112 // index 0.
113 if (i != 0 &&
114 PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
115 return true;
116 }
117 }
118 return false;
119}
120
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800121RtpSenderBase::RtpSenderBase(rtc::Thread* worker_thread, const std::string& id)
122 : worker_thread_(worker_thread), id_(id) {
Steve Anton47136dd2018-01-12 10:49:35 -0800123 RTC_DCHECK(worker_thread);
Florent Castelli892acf02018-10-01 22:47:20 +0200124 init_parameters_.encodings.emplace_back();
deadbeef20cb0c12017-02-01 20:27:00 -0800125}
deadbeeffac06552015-11-25 11:26:01 -0800126
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800127void RtpSenderBase::SetFrameEncryptor(
Benjamin Wrightd81ac952018-08-29 17:02:10 -0700128 rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
129 frame_encryptor_ = std::move(frame_encryptor);
Benjamin Wright6cc9cca2018-10-09 17:29:54 -0700130 // Special Case: Set the frame encryptor to any value on any existing channel.
Benjamin Wrightc462a6e2018-10-26 13:16:16 -0700131 if (media_channel_ && ssrc_ && !stopped_) {
Benjamin Wright6cc9cca2018-10-09 17:29:54 -0700132 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
133 media_channel_->SetFrameEncryptor(ssrc_, frame_encryptor_);
134 });
135 }
Benjamin Wrightd81ac952018-08-29 17:02:10 -0700136}
137
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800138void RtpSenderBase::SetMediaChannel(cricket::MediaChannel* media_channel) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800139 RTC_DCHECK(media_channel == nullptr ||
140 media_channel->media_type() == media_type());
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800141 media_channel_ = media_channel;
Benjamin Wrightbfd412e2018-09-10 14:06:02 -0700142}
143
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800144RtpParameters RtpSenderBase::GetParameters() const {
Florent Castelli892acf02018-10-01 22:47:20 +0200145 if (stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700146 return RtpParameters();
147 }
Amit Hilbuchaa584152019-02-06 17:09:52 -0800148 if (!media_channel_ || !ssrc_) {
Florent Castelli892acf02018-10-01 22:47:20 +0200149 RtpParameters result = init_parameters_;
150 last_transaction_id_ = rtc::CreateRandomUuid();
151 result.transaction_id = last_transaction_id_.value();
152 return result;
153 }
Steve Anton47136dd2018-01-12 10:49:35 -0800154 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200155 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
Amit Hilbuch2297d332019-02-19 12:49:22 -0800156 RemoveEncodingLayers(disabled_rids_, &result.encodings);
Florent Castellicebf50f2018-05-03 15:31:53 +0200157 last_transaction_id_ = rtc::CreateRandomUuid();
158 result.transaction_id = last_transaction_id_.value();
159 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800160 });
deadbeefa601f5c2016-06-06 14:27:39 -0700161}
162
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800163RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
164 TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
Florent Castelli892acf02018-10-01 22:47:20 +0200165 if (stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800166 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700167 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200168 if (!last_transaction_id_) {
169 LOG_AND_RETURN_ERROR(
170 RTCErrorType::INVALID_STATE,
171 "Failed to set parameters since getParameters() has never been called"
172 " on this sender");
173 }
174 if (last_transaction_id_ != parameters.transaction_id) {
175 LOG_AND_RETURN_ERROR(
176 RTCErrorType::INVALID_MODIFICATION,
177 "Failed to set parameters since the transaction_id doesn't match"
178 " the last value returned from getParameters()");
179 }
180
Seth Hampson2d2c8882018-05-16 16:02:32 -0700181 if (UnimplementedRtpParameterHasValue(parameters)) {
182 LOG_AND_RETURN_ERROR(
183 RTCErrorType::UNSUPPORTED_PARAMETER,
184 "Attempted to set an unimplemented parameter of RtpParameters.");
185 }
Amit Hilbuchaa584152019-02-06 17:09:52 -0800186 if (!media_channel_ || !ssrc_) {
Florent Castellic1a0bcb2019-01-29 14:26:48 +0100187 auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
188 init_parameters_, parameters);
Florent Castelli892acf02018-10-01 22:47:20 +0200189 if (result.ok()) {
190 init_parameters_ = parameters;
191 }
192 return result;
193 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800194 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Amit Hilbuch2297d332019-02-19 12:49:22 -0800195 RtpParameters rtp_parameters = parameters;
196 if (!disabled_rids_.empty()) {
197 // Need to add the inactive layers.
198 RtpParameters old_parameters =
199 media_channel_->GetRtpSendParameters(ssrc_);
200 rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
201 old_parameters.encodings);
202 }
203 RTCError result =
204 media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
Florent Castellicebf50f2018-05-03 15:31:53 +0200205 last_transaction_id_.reset();
206 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800207 });
deadbeefa601f5c2016-06-06 14:27:39 -0700208}
209
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800210bool RtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
211 TRACE_EVENT0("webrtc", "RtpSenderBase::SetTrack");
212 if (stopped_) {
213 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
214 return false;
Benjamin Wright6cc9cca2018-10-09 17:29:54 -0700215 }
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800216 if (track && track->kind() != track_kind()) {
217 RTC_LOG(LS_ERROR) << "SetTrack with " << track->kind()
218 << " called on RtpSender with " << track_kind()
219 << " track.";
220 return false;
221 }
222
223 // Detach from old track.
224 if (track_) {
225 DetachTrack();
226 track_->UnregisterObserver(this);
227 RemoveTrackFromStats();
228 }
229
230 // Attach to new track.
231 bool prev_can_send_track = can_send_track();
232 // Keep a reference to the old track to keep it alive until we call SetSend.
233 rtc::scoped_refptr<MediaStreamTrackInterface> old_track = track_;
234 track_ = track;
235 if (track_) {
236 track_->RegisterObserver(this);
237 AttachTrack();
238 }
239
240 // Update channel.
241 if (can_send_track()) {
242 SetSend();
243 AddTrackToStats();
244 } else if (prev_can_send_track) {
245 ClearSend();
246 }
247 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
248 return true;
Benjamin Wrightd81ac952018-08-29 17:02:10 -0700249}
250
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800251void RtpSenderBase::SetSsrc(uint32_t ssrc) {
252 TRACE_EVENT0("webrtc", "RtpSenderBase::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800253 if (stopped_ || ssrc == ssrc_) {
254 return;
255 }
256 // If we are already sending with a particular SSRC, stop sending.
257 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800258 ClearSend();
259 RemoveTrackFromStats();
deadbeeffac06552015-11-25 11:26:01 -0800260 }
261 ssrc_ = ssrc;
262 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800263 SetSend();
264 AddTrackToStats();
deadbeeffac06552015-11-25 11:26:01 -0800265 }
Florent Castelli892acf02018-10-01 22:47:20 +0200266 if (!init_parameters_.encodings.empty()) {
267 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
268 RTC_DCHECK(media_channel_);
269 // Get the current parameters, which are constructed from the SDP.
270 // The number of layers in the SDP is currently authoritative to support
271 // SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
272 // lines as described in RFC 5576.
273 // All fields should be default constructed and the SSRC field set, which
274 // we need to copy.
275 RtpParameters current_parameters =
276 media_channel_->GetRtpSendParameters(ssrc_);
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800277 RTC_DCHECK_GE(current_parameters.encodings.size(),
278 init_parameters_.encodings.size());
Florent Castelli892acf02018-10-01 22:47:20 +0200279 for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
280 init_parameters_.encodings[i].ssrc =
281 current_parameters.encodings[i].ssrc;
Amit Hilbuch2297d332019-02-19 12:49:22 -0800282 init_parameters_.encodings[i].rid = current_parameters.encodings[i].rid;
Florent Castelli892acf02018-10-01 22:47:20 +0200283 current_parameters.encodings[i] = init_parameters_.encodings[i];
284 }
285 current_parameters.degradation_preference =
286 init_parameters_.degradation_preference;
287 media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
288 init_parameters_.encodings.clear();
289 });
290 }
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800291 // Attempt to attach the frame decryptor to the current media channel.
292 if (frame_encryptor_) {
293 SetFrameEncryptor(frame_encryptor_);
294 }
deadbeeffac06552015-11-25 11:26:01 -0800295}
296
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800297void RtpSenderBase::Stop() {
298 TRACE_EVENT0("webrtc", "RtpSenderBase::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700299 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800300 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700301 return;
302 }
deadbeeffac06552015-11-25 11:26:01 -0800303 if (track_) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800304 DetachTrack();
deadbeeffac06552015-11-25 11:26:01 -0800305 track_->UnregisterObserver(this);
306 }
307 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800308 ClearSend();
309 RemoveTrackFromStats();
deadbeeffac06552015-11-25 11:26:01 -0800310 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100311 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800312 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700313}
314
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800315RTCError RtpSenderBase::DisableEncodingLayers(
Amit Hilbuch2297d332019-02-19 12:49:22 -0800316 const std::vector<std::string>& rids) {
317 if (stopped_) {
318 return RTCError(RTCErrorType::INVALID_STATE);
319 }
320
321 if (!media_channel_ || !ssrc_) {
322 RemoveEncodingLayers(rids, &init_parameters_.encodings);
323 return RTCError::OK();
324 }
325
326 // Check that all the specified layers exist and disable them in the channel.
327 RtpParameters parameters = GetParameters();
328 for (const std::string& rid : rids) {
329 auto iter = absl::c_find_if(parameters.encodings,
330 [&rid](const RtpEncodingParameters& encoding) {
331 return encoding.rid == rid;
332 });
333 if (iter == parameters.encodings.end()) {
334 return RTCError(RTCErrorType::INVALID_PARAMETER,
335 "RID: " + rid + " does not refer to a valid layer.");
336 }
337 iter->active = false;
338 }
339
340 RTCError result = SetParameters(parameters);
341 if (result.ok()) {
342 disabled_rids_.insert(disabled_rids_.end(), rids.begin(), rids.end());
343 }
344 return result;
345}
346
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800347LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
348
349LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
350 rtc::CritScope lock(&lock_);
351 if (sink_)
352 sink_->OnClose();
353}
354
355void LocalAudioSinkAdapter::OnData(const void* audio_data,
356 int bits_per_sample,
357 int sample_rate,
358 size_t number_of_channels,
359 size_t number_of_frames) {
360 rtc::CritScope lock(&lock_);
361 if (sink_) {
362 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
363 number_of_frames);
364 }
365}
366
367void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
368 rtc::CritScope lock(&lock_);
369 RTC_DCHECK(!sink || !sink_);
370 sink_ = sink;
371}
372
373rtc::scoped_refptr<AudioRtpSender> AudioRtpSender::Create(
374 rtc::Thread* worker_thread,
375 const std::string& id,
376 StatsCollector* stats) {
377 return rtc::scoped_refptr<AudioRtpSender>(
378 new rtc::RefCountedObject<AudioRtpSender>(worker_thread, id, stats));
379}
380
381AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
382 const std::string& id,
383 StatsCollector* stats)
384 : RtpSenderBase(worker_thread, id),
385 stats_(stats),
386 dtmf_sender_proxy_(DtmfSenderProxy::Create(
387 rtc::Thread::Current(),
388 DtmfSender::Create(rtc::Thread::Current(), this))),
389 sink_adapter_(new LocalAudioSinkAdapter()) {}
390
391AudioRtpSender::~AudioRtpSender() {
392 // For DtmfSender.
393 SignalDestroyed();
394 Stop();
395}
396
397bool AudioRtpSender::CanInsertDtmf() {
398 if (!media_channel_) {
399 RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
400 return false;
401 }
402 // Check that this RTP sender is active (description has been applied that
403 // matches an SSRC to its ID).
404 if (!ssrc_) {
405 RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
406 return false;
407 }
408 return worker_thread_->Invoke<bool>(
409 RTC_FROM_HERE, [&] { return voice_media_channel()->CanInsertDtmf(); });
410}
411
412bool AudioRtpSender::InsertDtmf(int code, int duration) {
413 if (!media_channel_) {
414 RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
415 return false;
416 }
417 if (!ssrc_) {
418 RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
419 return false;
420 }
421 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
422 return voice_media_channel()->InsertDtmf(ssrc_, code, duration);
423 });
424 if (!success) {
425 RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
426 }
427 return success;
428}
429
430sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
431 return &SignalDestroyed;
432}
433
434void AudioRtpSender::OnChanged() {
435 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
436 RTC_DCHECK(!stopped_);
437 if (cached_track_enabled_ != track_->enabled()) {
438 cached_track_enabled_ = track_->enabled();
439 if (can_send_track()) {
440 SetSend();
441 }
442 }
443}
444
445void AudioRtpSender::DetachTrack() {
446 RTC_DCHECK(track_);
447 audio_track()->RemoveSink(sink_adapter_.get());
448}
449
450void AudioRtpSender::AttachTrack() {
451 RTC_DCHECK(track_);
452 cached_track_enabled_ = track_->enabled();
453 audio_track()->AddSink(sink_adapter_.get());
454}
455
456void AudioRtpSender::AddTrackToStats() {
457 if (can_send_track() && stats_) {
458 stats_->AddLocalAudioTrack(audio_track().get(), ssrc_);
459 }
460}
461
462void AudioRtpSender::RemoveTrackFromStats() {
463 if (can_send_track() && stats_) {
464 stats_->RemoveLocalAudioTrack(audio_track().get(), ssrc_);
465 }
466}
467
468rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
469 return dtmf_sender_proxy_;
470}
471
472void AudioRtpSender::SetSend() {
473 RTC_DCHECK(!stopped_);
474 RTC_DCHECK(can_send_track());
475 if (!media_channel_) {
476 RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
477 return;
478 }
479 cricket::AudioOptions options;
480#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
481 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
482 // PeerConnection. This is a bit of a strange way to apply local audio
483 // options since it is also applied to all streams/channels, local or remote.
484 if (track_->enabled() && audio_track()->GetSource() &&
485 !audio_track()->GetSource()->remote()) {
486 options = audio_track()->GetSource()->options();
487 }
488#endif
489
490 // |track_->enabled()| hops to the signaling thread, so call it before we hop
491 // to the worker thread or else it will deadlock.
492 bool track_enabled = track_->enabled();
493 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
494 return voice_media_channel()->SetAudioSend(ssrc_, track_enabled, &options,
495 sink_adapter_.get());
496 });
497 if (!success) {
498 RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
499 }
500}
501
502void AudioRtpSender::ClearSend() {
503 RTC_DCHECK(ssrc_ != 0);
504 RTC_DCHECK(!stopped_);
505 if (!media_channel_) {
506 RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
507 return;
508 }
509 cricket::AudioOptions options;
510 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
511 return voice_media_channel()->SetAudioSend(ssrc_, false, &options, nullptr);
512 });
513 if (!success) {
514 RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
515 }
516}
517
518rtc::scoped_refptr<VideoRtpSender> VideoRtpSender::Create(
519 rtc::Thread* worker_thread,
520 const std::string& id) {
521 return rtc::scoped_refptr<VideoRtpSender>(
522 new rtc::RefCountedObject<VideoRtpSender>(worker_thread, id));
523}
524
525VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
526 const std::string& id)
527 : RtpSenderBase(worker_thread, id) {}
528
529VideoRtpSender::~VideoRtpSender() {
530 Stop();
531}
532
533void VideoRtpSender::OnChanged() {
534 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
535 RTC_DCHECK(!stopped_);
536 if (cached_track_content_hint_ != video_track()->content_hint()) {
537 cached_track_content_hint_ = video_track()->content_hint();
538 if (can_send_track()) {
539 SetSend();
540 }
541 }
542}
543
544void VideoRtpSender::AttachTrack() {
545 RTC_DCHECK(track_);
546 cached_track_content_hint_ = video_track()->content_hint();
547}
548
549rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
550 RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
551 return nullptr;
552}
553
554void VideoRtpSender::SetSend() {
555 RTC_DCHECK(!stopped_);
556 RTC_DCHECK(can_send_track());
557 if (!media_channel_) {
558 RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
559 return;
560 }
561 cricket::VideoOptions options;
562 VideoTrackSourceInterface* source = video_track()->GetSource();
563 if (source) {
564 options.is_screencast = source->is_screencast();
565 options.video_noise_reduction = source->needs_denoising();
566 }
567 switch (cached_track_content_hint_) {
568 case VideoTrackInterface::ContentHint::kNone:
569 break;
570 case VideoTrackInterface::ContentHint::kFluid:
571 options.is_screencast = false;
572 break;
573 case VideoTrackInterface::ContentHint::kDetailed:
574 case VideoTrackInterface::ContentHint::kText:
575 options.is_screencast = true;
576 break;
577 }
578 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
579 return video_media_channel()->SetVideoSend(ssrc_, &options, video_track());
580 });
581 RTC_DCHECK(success);
582}
583
584void VideoRtpSender::ClearSend() {
585 RTC_DCHECK(ssrc_ != 0);
586 RTC_DCHECK(!stopped_);
587 if (!media_channel_) {
588 RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
589 return;
590 }
591 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
592 // This the normal case when the underlying media channel has already been
593 // deleted.
594 worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
595 return video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr);
596 });
597}
598
deadbeef70ab1a12015-09-28 16:53:55 -0700599} // namespace webrtc