blob: 22957d3ae179a5acbe4495b6cd332743c1384bf4 [file] [log] [blame]
deadbeef6979b022015-09-24 23:47:531/*
kjellanderb24317b2016-02-10 15:54:432 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
deadbeef6979b022015-09-24 23:47:533 *
kjellanderb24317b2016-02-10 15:54:434 * 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 23:47:539 */
10
Steve Anton10542f22019-01-11 17:11:0011#include "pc/rtp_sender.h"
deadbeef6979b022015-09-24 23:47:5312
Benjamin Wrightd81ac952018-08-30 00:02:1013#include <utility>
Steve Anton36b29d12017-10-30 16:57:4214#include <vector>
15
Yves Gerey3e707812018-11-28 15:47:4916#include "api/audio_options.h"
Steve Anton10542f22019-01-11 17:11:0017#include "api/media_stream_interface.h"
18#include "media/base/media_engine.h"
19#include "pc/stats_collector.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3120#include "rtc_base/checks.h"
21#include "rtc_base/helpers.h"
Yves Gerey3e707812018-11-28 15:47:4922#include "rtc_base/location.h"
23#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3124#include "rtc_base/trace_event.h"
deadbeef70ab1a12015-09-28 23:53:5525
26namespace webrtc {
27
Harald Alvestrandc72af932018-01-11 16:18:1928namespace {
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 23:02:3237// 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:2241 if (encoding_params.codec_payload_type.has_value() ||
42 encoding_params.fec.has_value() || encoding_params.rtx.has_value() ||
Seth Hampson2d2c8882018-05-16 23:02:3243 encoding_params.dtx.has_value() || encoding_params.ptime.has_value() ||
Seth Hampson2d2c8882018-05-16 23:02:3244 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 23:52:2262 if (encoding_params.bitrate_priority != kDefaultBitratePriority ||
63 encoding_params.network_priority != kDefaultBitratePriority) {
Seth Hampson2d2c8882018-05-16 23:02:3264 return true;
65 }
66 return false;
67}
68
Amit Hilbuch2297d332019-02-19 20:49:2269void 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 20:47:2099} // namespace
100
Seth Hampson2d2c8882018-05-16 23:02:32101// Returns true if any RtpParameters member that isn't implemented contains a
102// value.
103bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
Florent Castelli87b3c512018-07-18 14:00:28104 if (!parameters.mid.empty()) {
Seth Hampson2d2c8882018-05-16 23:02:32105 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 23:20:21121RtpSenderBase::RtpSenderBase(rtc::Thread* worker_thread, const std::string& id)
122 : worker_thread_(worker_thread), id_(id) {
Steve Anton47136dd2018-01-12 18:49:35123 RTC_DCHECK(worker_thread);
Florent Castelli892acf02018-10-01 20:47:20124 init_parameters_.encodings.emplace_back();
deadbeef20cb0c12017-02-02 04:27:00125}
deadbeeffac06552015-11-25 19:26:01126
Amit Hilbuchea7ef2a2019-02-19 23:20:21127void RtpSenderBase::SetFrameEncryptor(
Benjamin Wrightd81ac952018-08-30 00:02:10128 rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
129 frame_encryptor_ = std::move(frame_encryptor);
Benjamin Wright6cc9cca2018-10-10 00:29:54130 // Special Case: Set the frame encryptor to any value on any existing channel.
Benjamin Wrightc462a6e2018-10-26 20:16:16131 if (media_channel_ && ssrc_ && !stopped_) {
Benjamin Wright6cc9cca2018-10-10 00:29:54132 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
133 media_channel_->SetFrameEncryptor(ssrc_, frame_encryptor_);
134 });
135 }
Benjamin Wrightd81ac952018-08-30 00:02:10136}
137
Amit Hilbuchea7ef2a2019-02-19 23:20:21138void RtpSenderBase::SetMediaChannel(cricket::MediaChannel* media_channel) {
Amit Hilbuchdd9390c2018-11-14 00:26:05139 RTC_DCHECK(media_channel == nullptr ||
140 media_channel->media_type() == media_type());
Amit Hilbuchea7ef2a2019-02-19 23:20:21141 media_channel_ = media_channel;
Benjamin Wrightbfd412e2018-09-10 21:06:02142}
143
Amit Hilbuch619b2942019-02-26 23:55:19144RtpParameters RtpSenderBase::GetParametersInternal() const {
Florent Castelli892acf02018-10-01 20:47:20145 if (stopped_) {
Taylor Brandstetterba29c6a2016-06-27 23:30:35146 return RtpParameters();
147 }
Amit Hilbuchaa584152019-02-07 01:09:52148 if (!media_channel_ || !ssrc_) {
Amit Hilbuch619b2942019-02-26 23:55:19149 return init_parameters_;
Florent Castelli892acf02018-10-01 20:47:20150 }
Steve Anton47136dd2018-01-12 18:49:35151 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 13:31:53152 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
Amit Hilbuch2297d332019-02-19 20:49:22153 RemoveEncodingLayers(disabled_rids_, &result.encodings);
Florent Castellicebf50f2018-05-03 13:31:53154 return result;
Steve Anton47136dd2018-01-12 18:49:35155 });
deadbeefa601f5c2016-06-06 21:27:39156}
157
Amit Hilbuch619b2942019-02-26 23:55:19158RtpParameters RtpSenderBase::GetParameters() const {
159 RtpParameters result = GetParametersInternal();
160 last_transaction_id_ = rtc::CreateRandomUuid();
161 result.transaction_id = last_transaction_id_.value();
162 return result;
163}
164
165RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
166 RTC_DCHECK(!stopped_);
Florent Castellicebf50f2018-05-03 13:31:53167
Seth Hampson2d2c8882018-05-16 23:02:32168 if (UnimplementedRtpParameterHasValue(parameters)) {
169 LOG_AND_RETURN_ERROR(
170 RTCErrorType::UNSUPPORTED_PARAMETER,
171 "Attempted to set an unimplemented parameter of RtpParameters.");
172 }
Amit Hilbuchaa584152019-02-07 01:09:52173 if (!media_channel_ || !ssrc_) {
Florent Castellic1a0bcb2019-01-29 13:26:48174 auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
175 init_parameters_, parameters);
Florent Castelli892acf02018-10-01 20:47:20176 if (result.ok()) {
177 init_parameters_ = parameters;
178 }
179 return result;
180 }
Zach Steinba37b4b2018-01-23 23:02:36181 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Amit Hilbuch2297d332019-02-19 20:49:22182 RtpParameters rtp_parameters = parameters;
183 if (!disabled_rids_.empty()) {
184 // Need to add the inactive layers.
185 RtpParameters old_parameters =
186 media_channel_->GetRtpSendParameters(ssrc_);
187 rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
188 old_parameters.encodings);
189 }
Amit Hilbuch619b2942019-02-26 23:55:19190 return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
Steve Anton47136dd2018-01-12 18:49:35191 });
deadbeefa601f5c2016-06-06 21:27:39192}
193
Amit Hilbuch619b2942019-02-26 23:55:19194RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
195 TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
196 if (stopped_) {
197 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
198 "Cannot set parameters on a stopped sender.");
199 }
200 if (!last_transaction_id_) {
201 LOG_AND_RETURN_ERROR(
202 RTCErrorType::INVALID_STATE,
203 "Failed to set parameters since getParameters() has never been called"
204 " on this sender");
205 }
206 if (last_transaction_id_ != parameters.transaction_id) {
207 LOG_AND_RETURN_ERROR(
208 RTCErrorType::INVALID_MODIFICATION,
209 "Failed to set parameters since the transaction_id doesn't match"
210 " the last value returned from getParameters()");
211 }
212
213 RTCError result = SetParametersInternal(parameters);
214 last_transaction_id_.reset();
215 return result;
216}
217
Amit Hilbuchea7ef2a2019-02-19 23:20:21218bool RtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
219 TRACE_EVENT0("webrtc", "RtpSenderBase::SetTrack");
220 if (stopped_) {
221 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
222 return false;
Benjamin Wright6cc9cca2018-10-10 00:29:54223 }
Amit Hilbuchea7ef2a2019-02-19 23:20:21224 if (track && track->kind() != track_kind()) {
225 RTC_LOG(LS_ERROR) << "SetTrack with " << track->kind()
226 << " called on RtpSender with " << track_kind()
227 << " track.";
228 return false;
229 }
230
231 // Detach from old track.
232 if (track_) {
233 DetachTrack();
234 track_->UnregisterObserver(this);
235 RemoveTrackFromStats();
236 }
237
238 // Attach to new track.
239 bool prev_can_send_track = can_send_track();
240 // Keep a reference to the old track to keep it alive until we call SetSend.
241 rtc::scoped_refptr<MediaStreamTrackInterface> old_track = track_;
242 track_ = track;
243 if (track_) {
244 track_->RegisterObserver(this);
245 AttachTrack();
246 }
247
248 // Update channel.
249 if (can_send_track()) {
250 SetSend();
251 AddTrackToStats();
252 } else if (prev_can_send_track) {
253 ClearSend();
254 }
255 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
256 return true;
Benjamin Wrightd81ac952018-08-30 00:02:10257}
258
Amit Hilbuchea7ef2a2019-02-19 23:20:21259void RtpSenderBase::SetSsrc(uint32_t ssrc) {
260 TRACE_EVENT0("webrtc", "RtpSenderBase::SetSsrc");
deadbeeffac06552015-11-25 19:26:01261 if (stopped_ || ssrc == ssrc_) {
262 return;
263 }
264 // If we are already sending with a particular SSRC, stop sending.
265 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 23:20:21266 ClearSend();
267 RemoveTrackFromStats();
deadbeeffac06552015-11-25 19:26:01268 }
269 ssrc_ = ssrc;
270 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 23:20:21271 SetSend();
272 AddTrackToStats();
deadbeeffac06552015-11-25 19:26:01273 }
Florent Castelli892acf02018-10-01 20:47:20274 if (!init_parameters_.encodings.empty()) {
275 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
276 RTC_DCHECK(media_channel_);
277 // Get the current parameters, which are constructed from the SDP.
278 // The number of layers in the SDP is currently authoritative to support
279 // SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
280 // lines as described in RFC 5576.
281 // All fields should be default constructed and the SSRC field set, which
282 // we need to copy.
283 RtpParameters current_parameters =
284 media_channel_->GetRtpSendParameters(ssrc_);
Amit Hilbuchea7ef2a2019-02-19 23:20:21285 RTC_DCHECK_GE(current_parameters.encodings.size(),
286 init_parameters_.encodings.size());
Florent Castelli892acf02018-10-01 20:47:20287 for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
288 init_parameters_.encodings[i].ssrc =
289 current_parameters.encodings[i].ssrc;
Amit Hilbuch2297d332019-02-19 20:49:22290 init_parameters_.encodings[i].rid = current_parameters.encodings[i].rid;
Florent Castelli892acf02018-10-01 20:47:20291 current_parameters.encodings[i] = init_parameters_.encodings[i];
292 }
293 current_parameters.degradation_preference =
294 init_parameters_.degradation_preference;
295 media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
296 init_parameters_.encodings.clear();
297 });
298 }
Amit Hilbuchea7ef2a2019-02-19 23:20:21299 // Attempt to attach the frame decryptor to the current media channel.
300 if (frame_encryptor_) {
301 SetFrameEncryptor(frame_encryptor_);
302 }
deadbeeffac06552015-11-25 19:26:01303}
304
Amit Hilbuchea7ef2a2019-02-19 23:20:21305void RtpSenderBase::Stop() {
306 TRACE_EVENT0("webrtc", "RtpSenderBase::Stop");
deadbeef70ab1a12015-09-28 23:53:55307 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 19:26:01308 if (stopped_) {
deadbeef70ab1a12015-09-28 23:53:55309 return;
310 }
deadbeeffac06552015-11-25 19:26:01311 if (track_) {
Amit Hilbuchea7ef2a2019-02-19 23:20:21312 DetachTrack();
deadbeeffac06552015-11-25 19:26:01313 track_->UnregisterObserver(this);
314 }
315 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 23:20:21316 ClearSend();
317 RemoveTrackFromStats();
deadbeeffac06552015-11-25 19:26:01318 }
Harald Alvestrand3d976f62018-03-19 18:05:06319 media_channel_ = nullptr;
deadbeeffac06552015-11-25 19:26:01320 stopped_ = true;
deadbeef70ab1a12015-09-28 23:53:55321}
322
Amit Hilbuchea7ef2a2019-02-19 23:20:21323RTCError RtpSenderBase::DisableEncodingLayers(
Amit Hilbuch2297d332019-02-19 20:49:22324 const std::vector<std::string>& rids) {
325 if (stopped_) {
Amit Hilbuch619b2942019-02-26 23:55:19326 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
327 "Cannot disable encodings on a stopped sender.");
Amit Hilbuch2297d332019-02-19 20:49:22328 }
329
Amit Hilbuch619b2942019-02-26 23:55:19330 if (rids.empty()) {
Amit Hilbuch2297d332019-02-19 20:49:22331 return RTCError::OK();
332 }
333
334 // Check that all the specified layers exist and disable them in the channel.
Amit Hilbuch619b2942019-02-26 23:55:19335 RtpParameters parameters = GetParametersInternal();
Amit Hilbuch2297d332019-02-19 20:49:22336 for (const std::string& rid : rids) {
Amit Hilbuch619b2942019-02-26 23:55:19337 if (absl::c_none_of(parameters.encodings,
338 [&rid](const RtpEncodingParameters& encoding) {
339 return encoding.rid == rid;
340 })) {
341 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
342 "RID: " + rid + " does not refer to a valid layer.");
Amit Hilbuch2297d332019-02-19 20:49:22343 }
Amit Hilbuch2297d332019-02-19 20:49:22344 }
345
Amit Hilbuch619b2942019-02-26 23:55:19346 if (!media_channel_ || !ssrc_) {
347 RemoveEncodingLayers(rids, &init_parameters_.encodings);
348 // Invalidate any transaction upon success.
349 last_transaction_id_.reset();
350 return RTCError::OK();
351 }
352
353 for (RtpEncodingParameters& encoding : parameters.encodings) {
354 // Remain active if not in the disable list.
355 encoding.active &= absl::c_none_of(
356 rids,
357 [&encoding](const std::string& rid) { return encoding.rid == rid; });
358 }
359
360 RTCError result = SetParametersInternal(parameters);
Amit Hilbuch2297d332019-02-19 20:49:22361 if (result.ok()) {
362 disabled_rids_.insert(disabled_rids_.end(), rids.begin(), rids.end());
Amit Hilbuch619b2942019-02-26 23:55:19363 // Invalidate any transaction upon success.
364 last_transaction_id_.reset();
Amit Hilbuch2297d332019-02-19 20:49:22365 }
366 return result;
367}
368
Amit Hilbuchea7ef2a2019-02-19 23:20:21369LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
370
371LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
372 rtc::CritScope lock(&lock_);
373 if (sink_)
374 sink_->OnClose();
375}
376
377void LocalAudioSinkAdapter::OnData(const void* audio_data,
378 int bits_per_sample,
379 int sample_rate,
380 size_t number_of_channels,
381 size_t number_of_frames) {
382 rtc::CritScope lock(&lock_);
383 if (sink_) {
384 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
385 number_of_frames);
386 }
387}
388
389void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
390 rtc::CritScope lock(&lock_);
391 RTC_DCHECK(!sink || !sink_);
392 sink_ = sink;
393}
394
395rtc::scoped_refptr<AudioRtpSender> AudioRtpSender::Create(
396 rtc::Thread* worker_thread,
397 const std::string& id,
398 StatsCollector* stats) {
399 return rtc::scoped_refptr<AudioRtpSender>(
400 new rtc::RefCountedObject<AudioRtpSender>(worker_thread, id, stats));
401}
402
403AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
404 const std::string& id,
405 StatsCollector* stats)
406 : RtpSenderBase(worker_thread, id),
407 stats_(stats),
408 dtmf_sender_proxy_(DtmfSenderProxy::Create(
409 rtc::Thread::Current(),
410 DtmfSender::Create(rtc::Thread::Current(), this))),
411 sink_adapter_(new LocalAudioSinkAdapter()) {}
412
413AudioRtpSender::~AudioRtpSender() {
414 // For DtmfSender.
415 SignalDestroyed();
416 Stop();
417}
418
419bool AudioRtpSender::CanInsertDtmf() {
420 if (!media_channel_) {
421 RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
422 return false;
423 }
424 // Check that this RTP sender is active (description has been applied that
425 // matches an SSRC to its ID).
426 if (!ssrc_) {
427 RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
428 return false;
429 }
430 return worker_thread_->Invoke<bool>(
431 RTC_FROM_HERE, [&] { return voice_media_channel()->CanInsertDtmf(); });
432}
433
434bool AudioRtpSender::InsertDtmf(int code, int duration) {
435 if (!media_channel_) {
436 RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
437 return false;
438 }
439 if (!ssrc_) {
440 RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
441 return false;
442 }
443 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
444 return voice_media_channel()->InsertDtmf(ssrc_, code, duration);
445 });
446 if (!success) {
447 RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
448 }
449 return success;
450}
451
452sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
453 return &SignalDestroyed;
454}
455
456void AudioRtpSender::OnChanged() {
457 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
458 RTC_DCHECK(!stopped_);
459 if (cached_track_enabled_ != track_->enabled()) {
460 cached_track_enabled_ = track_->enabled();
461 if (can_send_track()) {
462 SetSend();
463 }
464 }
465}
466
467void AudioRtpSender::DetachTrack() {
468 RTC_DCHECK(track_);
469 audio_track()->RemoveSink(sink_adapter_.get());
470}
471
472void AudioRtpSender::AttachTrack() {
473 RTC_DCHECK(track_);
474 cached_track_enabled_ = track_->enabled();
475 audio_track()->AddSink(sink_adapter_.get());
476}
477
478void AudioRtpSender::AddTrackToStats() {
479 if (can_send_track() && stats_) {
480 stats_->AddLocalAudioTrack(audio_track().get(), ssrc_);
481 }
482}
483
484void AudioRtpSender::RemoveTrackFromStats() {
485 if (can_send_track() && stats_) {
486 stats_->RemoveLocalAudioTrack(audio_track().get(), ssrc_);
487 }
488}
489
490rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
491 return dtmf_sender_proxy_;
492}
493
494void AudioRtpSender::SetSend() {
495 RTC_DCHECK(!stopped_);
496 RTC_DCHECK(can_send_track());
497 if (!media_channel_) {
498 RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
499 return;
500 }
501 cricket::AudioOptions options;
502#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
503 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
504 // PeerConnection. This is a bit of a strange way to apply local audio
505 // options since it is also applied to all streams/channels, local or remote.
506 if (track_->enabled() && audio_track()->GetSource() &&
507 !audio_track()->GetSource()->remote()) {
508 options = audio_track()->GetSource()->options();
509 }
510#endif
511
512 // |track_->enabled()| hops to the signaling thread, so call it before we hop
513 // to the worker thread or else it will deadlock.
514 bool track_enabled = track_->enabled();
515 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
516 return voice_media_channel()->SetAudioSend(ssrc_, track_enabled, &options,
517 sink_adapter_.get());
518 });
519 if (!success) {
520 RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
521 }
522}
523
524void AudioRtpSender::ClearSend() {
525 RTC_DCHECK(ssrc_ != 0);
526 RTC_DCHECK(!stopped_);
527 if (!media_channel_) {
528 RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
529 return;
530 }
531 cricket::AudioOptions options;
532 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
533 return voice_media_channel()->SetAudioSend(ssrc_, false, &options, nullptr);
534 });
535 if (!success) {
536 RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
537 }
538}
539
540rtc::scoped_refptr<VideoRtpSender> VideoRtpSender::Create(
541 rtc::Thread* worker_thread,
542 const std::string& id) {
543 return rtc::scoped_refptr<VideoRtpSender>(
544 new rtc::RefCountedObject<VideoRtpSender>(worker_thread, id));
545}
546
547VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
548 const std::string& id)
549 : RtpSenderBase(worker_thread, id) {}
550
551VideoRtpSender::~VideoRtpSender() {
552 Stop();
553}
554
555void VideoRtpSender::OnChanged() {
556 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
557 RTC_DCHECK(!stopped_);
558 if (cached_track_content_hint_ != video_track()->content_hint()) {
559 cached_track_content_hint_ = video_track()->content_hint();
560 if (can_send_track()) {
561 SetSend();
562 }
563 }
564}
565
566void VideoRtpSender::AttachTrack() {
567 RTC_DCHECK(track_);
568 cached_track_content_hint_ = video_track()->content_hint();
569}
570
571rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
572 RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
573 return nullptr;
574}
575
576void VideoRtpSender::SetSend() {
577 RTC_DCHECK(!stopped_);
578 RTC_DCHECK(can_send_track());
579 if (!media_channel_) {
580 RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
581 return;
582 }
583 cricket::VideoOptions options;
584 VideoTrackSourceInterface* source = video_track()->GetSource();
585 if (source) {
586 options.is_screencast = source->is_screencast();
587 options.video_noise_reduction = source->needs_denoising();
588 }
589 switch (cached_track_content_hint_) {
590 case VideoTrackInterface::ContentHint::kNone:
591 break;
592 case VideoTrackInterface::ContentHint::kFluid:
593 options.is_screencast = false;
594 break;
595 case VideoTrackInterface::ContentHint::kDetailed:
596 case VideoTrackInterface::ContentHint::kText:
597 options.is_screencast = true;
598 break;
599 }
600 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
601 return video_media_channel()->SetVideoSend(ssrc_, &options, video_track());
602 });
603 RTC_DCHECK(success);
604}
605
606void VideoRtpSender::ClearSend() {
607 RTC_DCHECK(ssrc_ != 0);
608 RTC_DCHECK(!stopped_);
609 if (!media_channel_) {
610 RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
611 return;
612 }
613 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
614 // This the normal case when the underlying media channel has already been
615 // deleted.
616 worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
617 return video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr);
618 });
619}
620
deadbeef70ab1a12015-09-28 23:53:55621} // namespace webrtc