blob: 9eaed311a759228782d21e98e328498db2732224 [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
Yves Gereycb11a312019-07-26 18:51:59 +020013#include <atomic>
Benjamin Wrightd81ac952018-08-29 17:02:10 -070014#include <utility>
Steve Anton36b29d12017-10-30 09:57:42 -070015#include <vector>
16
Yves Gerey3e707812018-11-28 16:47:49 +010017#include "api/audio_options.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "api/media_stream_interface.h"
19#include "media/base/media_engine.h"
Guido Urdaneta1ff16c82019-05-20 19:31:53 +020020#include "pc/peer_connection.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "pc/stats_collector.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
23#include "rtc_base/helpers.h"
Yves Gerey3e707812018-11-28 16:47:49 +010024#include "rtc_base/location.h"
25#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/trace_event.h"
deadbeef70ab1a12015-09-28 16:53:55 -070027
28namespace webrtc {
29
Harald Alvestrandc72af932018-01-11 17:18:19 +010030namespace {
31
Yves Gereycb11a312019-07-26 18:51:59 +020032// This function is only expected to be called on the signaling thread.
33// On the other hand, some test or even production setups may use
34// several signaling threads.
Harald Alvestrandc72af932018-01-11 17:18:19 +010035int GenerateUniqueId() {
Yves Gereycb11a312019-07-26 18:51:59 +020036 static std::atomic<int> g_unique_id{0};
Harald Alvestrandc72af932018-01-11 17:18:19 +010037
38 return ++g_unique_id;
39}
40
Seth Hampson2d2c8882018-05-16 16:02:32 -070041// Returns an true if any RtpEncodingParameters member that isn't implemented
42// contains a value.
43bool UnimplementedRtpEncodingParameterHasValue(
44 const RtpEncodingParameters& encoding_params) {
Henrik Grunelle1301a82018-12-13 12:13:22 +000045 if (encoding_params.codec_payload_type.has_value() ||
46 encoding_params.fec.has_value() || encoding_params.rtx.has_value() ||
Seth Hampson2d2c8882018-05-16 16:02:32 -070047 encoding_params.dtx.has_value() || encoding_params.ptime.has_value() ||
Seth Hampson2d2c8882018-05-16 16:02:32 -070048 encoding_params.scale_framerate_down_by.has_value() ||
49 !encoding_params.dependency_rids.empty()) {
50 return true;
51 }
52 return false;
53}
54
55// Returns true if a "per-sender" encoding parameter contains a value that isn't
56// its default. Currently max_bitrate_bps and bitrate_priority both are
57// implemented "per-sender," meaning that these encoding parameters
58// are used for the RtpSender as a whole, not for a specific encoding layer.
59// This is done by setting these encoding parameters at index 0 of
60// RtpParameters.encodings. This function can be used to check if these
61// parameters are set at any index other than 0 of RtpParameters.encodings,
62// because they are currently unimplemented to be used for a specific encoding
63// layer.
64bool PerSenderRtpEncodingParameterHasValue(
65 const RtpEncodingParameters& encoding_params) {
Tim Haloun648d28a2018-10-18 16:52:22 -070066 if (encoding_params.bitrate_priority != kDefaultBitratePriority ||
67 encoding_params.network_priority != kDefaultBitratePriority) {
Seth Hampson2d2c8882018-05-16 16:02:32 -070068 return true;
69 }
70 return false;
71}
72
Amit Hilbuch2297d332019-02-19 12:49:22 -080073void RemoveEncodingLayers(const std::vector<std::string>& rids,
74 std::vector<RtpEncodingParameters>* encodings) {
75 RTC_DCHECK(encodings);
76 encodings->erase(
77 std::remove_if(encodings->begin(), encodings->end(),
78 [&rids](const RtpEncodingParameters& encoding) {
79 return absl::c_linear_search(rids, encoding.rid);
80 }),
81 encodings->end());
82}
83
84RtpParameters RestoreEncodingLayers(
85 const RtpParameters& parameters,
86 const std::vector<std::string>& removed_rids,
87 const std::vector<RtpEncodingParameters>& all_layers) {
88 RTC_DCHECK_EQ(parameters.encodings.size() + removed_rids.size(),
89 all_layers.size());
90 RtpParameters result(parameters);
91 result.encodings.clear();
92 size_t index = 0;
93 for (const RtpEncodingParameters& encoding : all_layers) {
94 if (absl::c_linear_search(removed_rids, encoding.rid)) {
95 result.encodings.push_back(encoding);
96 continue;
97 }
98 result.encodings.push_back(parameters.encodings[index++]);
99 }
100 return result;
101}
102
Florent Castelli892acf02018-10-01 22:47:20 +0200103} // namespace
104
Seth Hampson2d2c8882018-05-16 16:02:32 -0700105// Returns true if any RtpParameters member that isn't implemented contains a
106// value.
107bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
Florent Castelli87b3c512018-07-18 16:00:28 +0200108 if (!parameters.mid.empty()) {
Seth Hampson2d2c8882018-05-16 16:02:32 -0700109 return true;
110 }
111 for (size_t i = 0; i < parameters.encodings.size(); ++i) {
112 if (UnimplementedRtpEncodingParameterHasValue(parameters.encodings[i])) {
113 return true;
114 }
115 // Encoding parameters that are per-sender should only contain value at
116 // index 0.
117 if (i != 0 &&
118 PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
119 return true;
120 }
121 }
122 return false;
123}
124
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200125RtpSenderBase::RtpSenderBase(rtc::Thread* worker_thread,
126 const std::string& id,
127 SetStreamsObserver* set_streams_observer)
128 : worker_thread_(worker_thread),
129 id_(id),
130 set_streams_observer_(set_streams_observer) {
Steve Anton47136dd2018-01-12 10:49:35 -0800131 RTC_DCHECK(worker_thread);
Florent Castelli892acf02018-10-01 22:47:20 +0200132 init_parameters_.encodings.emplace_back();
deadbeef20cb0c12017-02-01 20:27:00 -0800133}
deadbeeffac06552015-11-25 11:26:01 -0800134
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800135void RtpSenderBase::SetFrameEncryptor(
Benjamin Wrightd81ac952018-08-29 17:02:10 -0700136 rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
137 frame_encryptor_ = std::move(frame_encryptor);
Benjamin Wright6cc9cca2018-10-09 17:29:54 -0700138 // Special Case: Set the frame encryptor to any value on any existing channel.
Benjamin Wrightc462a6e2018-10-26 13:16:16 -0700139 if (media_channel_ && ssrc_ && !stopped_) {
Benjamin Wright6cc9cca2018-10-09 17:29:54 -0700140 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
141 media_channel_->SetFrameEncryptor(ssrc_, frame_encryptor_);
142 });
143 }
Benjamin Wrightd81ac952018-08-29 17:02:10 -0700144}
145
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800146void RtpSenderBase::SetMediaChannel(cricket::MediaChannel* media_channel) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800147 RTC_DCHECK(media_channel == nullptr ||
148 media_channel->media_type() == media_type());
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800149 media_channel_ = media_channel;
Benjamin Wrightbfd412e2018-09-10 14:06:02 -0700150}
151
Amit Hilbuch619b2942019-02-26 15:55:19 -0800152RtpParameters RtpSenderBase::GetParametersInternal() const {
Florent Castelli892acf02018-10-01 22:47:20 +0200153 if (stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700154 return RtpParameters();
155 }
Amit Hilbuchaa584152019-02-06 17:09:52 -0800156 if (!media_channel_ || !ssrc_) {
Amit Hilbuch619b2942019-02-26 15:55:19 -0800157 return init_parameters_;
Florent Castelli892acf02018-10-01 22:47:20 +0200158 }
Steve Anton47136dd2018-01-12 10:49:35 -0800159 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200160 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
Amit Hilbuch2297d332019-02-19 12:49:22 -0800161 RemoveEncodingLayers(disabled_rids_, &result.encodings);
Florent Castellicebf50f2018-05-03 15:31:53 +0200162 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800163 });
deadbeefa601f5c2016-06-06 14:27:39 -0700164}
165
Amit Hilbuch619b2942019-02-26 15:55:19 -0800166RtpParameters RtpSenderBase::GetParameters() const {
167 RtpParameters result = GetParametersInternal();
168 last_transaction_id_ = rtc::CreateRandomUuid();
169 result.transaction_id = last_transaction_id_.value();
170 return result;
171}
172
173RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
174 RTC_DCHECK(!stopped_);
Florent Castellicebf50f2018-05-03 15:31:53 +0200175
Seth Hampson2d2c8882018-05-16 16:02:32 -0700176 if (UnimplementedRtpParameterHasValue(parameters)) {
177 LOG_AND_RETURN_ERROR(
178 RTCErrorType::UNSUPPORTED_PARAMETER,
179 "Attempted to set an unimplemented parameter of RtpParameters.");
180 }
Amit Hilbuchaa584152019-02-06 17:09:52 -0800181 if (!media_channel_ || !ssrc_) {
Florent Castellic1a0bcb2019-01-29 14:26:48 +0100182 auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
183 init_parameters_, parameters);
Florent Castelli892acf02018-10-01 22:47:20 +0200184 if (result.ok()) {
185 init_parameters_ = parameters;
186 }
187 return result;
188 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800189 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Amit Hilbuch2297d332019-02-19 12:49:22 -0800190 RtpParameters rtp_parameters = parameters;
191 if (!disabled_rids_.empty()) {
192 // Need to add the inactive layers.
193 RtpParameters old_parameters =
194 media_channel_->GetRtpSendParameters(ssrc_);
195 rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
196 old_parameters.encodings);
197 }
Amit Hilbuch619b2942019-02-26 15:55:19 -0800198 return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
Steve Anton47136dd2018-01-12 10:49:35 -0800199 });
deadbeefa601f5c2016-06-06 14:27:39 -0700200}
201
Amit Hilbuch619b2942019-02-26 15:55:19 -0800202RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
203 TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
204 if (stopped_) {
205 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
206 "Cannot set parameters on a stopped sender.");
207 }
208 if (!last_transaction_id_) {
209 LOG_AND_RETURN_ERROR(
210 RTCErrorType::INVALID_STATE,
211 "Failed to set parameters since getParameters() has never been called"
212 " on this sender");
213 }
214 if (last_transaction_id_ != parameters.transaction_id) {
215 LOG_AND_RETURN_ERROR(
216 RTCErrorType::INVALID_MODIFICATION,
217 "Failed to set parameters since the transaction_id doesn't match"
218 " the last value returned from getParameters()");
219 }
220
221 RTCError result = SetParametersInternal(parameters);
222 last_transaction_id_.reset();
223 return result;
224}
225
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200226void RtpSenderBase::SetStreams(const std::vector<std::string>& stream_ids) {
227 set_stream_ids(stream_ids);
228 if (set_streams_observer_)
229 set_streams_observer_->OnSetStreams();
230}
231
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800232bool RtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
233 TRACE_EVENT0("webrtc", "RtpSenderBase::SetTrack");
234 if (stopped_) {
235 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
236 return false;
Benjamin Wright6cc9cca2018-10-09 17:29:54 -0700237 }
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800238 if (track && track->kind() != track_kind()) {
239 RTC_LOG(LS_ERROR) << "SetTrack with " << track->kind()
240 << " called on RtpSender with " << track_kind()
241 << " track.";
242 return false;
243 }
244
245 // Detach from old track.
246 if (track_) {
247 DetachTrack();
248 track_->UnregisterObserver(this);
249 RemoveTrackFromStats();
250 }
251
252 // Attach to new track.
253 bool prev_can_send_track = can_send_track();
254 // Keep a reference to the old track to keep it alive until we call SetSend.
255 rtc::scoped_refptr<MediaStreamTrackInterface> old_track = track_;
256 track_ = track;
257 if (track_) {
258 track_->RegisterObserver(this);
259 AttachTrack();
260 }
261
262 // Update channel.
263 if (can_send_track()) {
264 SetSend();
265 AddTrackToStats();
266 } else if (prev_can_send_track) {
267 ClearSend();
268 }
269 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
270 return true;
Benjamin Wrightd81ac952018-08-29 17:02:10 -0700271}
272
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800273void RtpSenderBase::SetSsrc(uint32_t ssrc) {
274 TRACE_EVENT0("webrtc", "RtpSenderBase::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800275 if (stopped_ || ssrc == ssrc_) {
276 return;
277 }
278 // If we are already sending with a particular SSRC, stop sending.
279 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800280 ClearSend();
281 RemoveTrackFromStats();
deadbeeffac06552015-11-25 11:26:01 -0800282 }
283 ssrc_ = ssrc;
284 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800285 SetSend();
286 AddTrackToStats();
deadbeeffac06552015-11-25 11:26:01 -0800287 }
Florent Castelli892acf02018-10-01 22:47:20 +0200288 if (!init_parameters_.encodings.empty()) {
289 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
290 RTC_DCHECK(media_channel_);
291 // Get the current parameters, which are constructed from the SDP.
292 // The number of layers in the SDP is currently authoritative to support
293 // SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
294 // lines as described in RFC 5576.
295 // All fields should be default constructed and the SSRC field set, which
296 // we need to copy.
297 RtpParameters current_parameters =
298 media_channel_->GetRtpSendParameters(ssrc_);
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800299 RTC_DCHECK_GE(current_parameters.encodings.size(),
300 init_parameters_.encodings.size());
Florent Castelli892acf02018-10-01 22:47:20 +0200301 for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
302 init_parameters_.encodings[i].ssrc =
303 current_parameters.encodings[i].ssrc;
Amit Hilbuch2297d332019-02-19 12:49:22 -0800304 init_parameters_.encodings[i].rid = current_parameters.encodings[i].rid;
Florent Castelli892acf02018-10-01 22:47:20 +0200305 current_parameters.encodings[i] = init_parameters_.encodings[i];
306 }
307 current_parameters.degradation_preference =
308 init_parameters_.degradation_preference;
309 media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
310 init_parameters_.encodings.clear();
311 });
312 }
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800313 // Attempt to attach the frame decryptor to the current media channel.
314 if (frame_encryptor_) {
315 SetFrameEncryptor(frame_encryptor_);
316 }
deadbeeffac06552015-11-25 11:26:01 -0800317}
318
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800319void RtpSenderBase::Stop() {
320 TRACE_EVENT0("webrtc", "RtpSenderBase::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700321 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800322 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700323 return;
324 }
deadbeeffac06552015-11-25 11:26:01 -0800325 if (track_) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800326 DetachTrack();
deadbeeffac06552015-11-25 11:26:01 -0800327 track_->UnregisterObserver(this);
328 }
329 if (can_send_track()) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800330 ClearSend();
331 RemoveTrackFromStats();
deadbeeffac06552015-11-25 11:26:01 -0800332 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100333 media_channel_ = nullptr;
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200334 set_streams_observer_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800335 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700336}
337
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800338RTCError RtpSenderBase::DisableEncodingLayers(
Amit Hilbuch2297d332019-02-19 12:49:22 -0800339 const std::vector<std::string>& rids) {
340 if (stopped_) {
Amit Hilbuch619b2942019-02-26 15:55:19 -0800341 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
342 "Cannot disable encodings on a stopped sender.");
Amit Hilbuch2297d332019-02-19 12:49:22 -0800343 }
344
Amit Hilbuch619b2942019-02-26 15:55:19 -0800345 if (rids.empty()) {
Amit Hilbuch2297d332019-02-19 12:49:22 -0800346 return RTCError::OK();
347 }
348
349 // Check that all the specified layers exist and disable them in the channel.
Amit Hilbuch619b2942019-02-26 15:55:19 -0800350 RtpParameters parameters = GetParametersInternal();
Amit Hilbuch2297d332019-02-19 12:49:22 -0800351 for (const std::string& rid : rids) {
Amit Hilbuch619b2942019-02-26 15:55:19 -0800352 if (absl::c_none_of(parameters.encodings,
353 [&rid](const RtpEncodingParameters& encoding) {
354 return encoding.rid == rid;
355 })) {
356 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
357 "RID: " + rid + " does not refer to a valid layer.");
Amit Hilbuch2297d332019-02-19 12:49:22 -0800358 }
Amit Hilbuch2297d332019-02-19 12:49:22 -0800359 }
360
Amit Hilbuch619b2942019-02-26 15:55:19 -0800361 if (!media_channel_ || !ssrc_) {
362 RemoveEncodingLayers(rids, &init_parameters_.encodings);
363 // Invalidate any transaction upon success.
364 last_transaction_id_.reset();
365 return RTCError::OK();
366 }
367
368 for (RtpEncodingParameters& encoding : parameters.encodings) {
369 // Remain active if not in the disable list.
370 encoding.active &= absl::c_none_of(
371 rids,
372 [&encoding](const std::string& rid) { return encoding.rid == rid; });
373 }
374
375 RTCError result = SetParametersInternal(parameters);
Amit Hilbuch2297d332019-02-19 12:49:22 -0800376 if (result.ok()) {
377 disabled_rids_.insert(disabled_rids_.end(), rids.begin(), rids.end());
Amit Hilbuch619b2942019-02-26 15:55:19 -0800378 // Invalidate any transaction upon success.
379 last_transaction_id_.reset();
Amit Hilbuch2297d332019-02-19 12:49:22 -0800380 }
381 return result;
382}
383
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800384LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
385
386LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
387 rtc::CritScope lock(&lock_);
388 if (sink_)
389 sink_->OnClose();
390}
391
392void LocalAudioSinkAdapter::OnData(const void* audio_data,
393 int bits_per_sample,
394 int sample_rate,
395 size_t number_of_channels,
396 size_t number_of_frames) {
397 rtc::CritScope lock(&lock_);
398 if (sink_) {
399 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
400 number_of_frames);
401 }
402}
403
404void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
405 rtc::CritScope lock(&lock_);
406 RTC_DCHECK(!sink || !sink_);
407 sink_ = sink;
408}
409
410rtc::scoped_refptr<AudioRtpSender> AudioRtpSender::Create(
411 rtc::Thread* worker_thread,
412 const std::string& id,
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200413 StatsCollector* stats,
414 SetStreamsObserver* set_streams_observer) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800415 return rtc::scoped_refptr<AudioRtpSender>(
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200416 new rtc::RefCountedObject<AudioRtpSender>(worker_thread, id, stats,
417 set_streams_observer));
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800418}
419
420AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
421 const std::string& id,
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200422 StatsCollector* stats,
423 SetStreamsObserver* set_streams_observer)
424 : RtpSenderBase(worker_thread, id, set_streams_observer),
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800425 stats_(stats),
426 dtmf_sender_proxy_(DtmfSenderProxy::Create(
427 rtc::Thread::Current(),
428 DtmfSender::Create(rtc::Thread::Current(), this))),
429 sink_adapter_(new LocalAudioSinkAdapter()) {}
430
431AudioRtpSender::~AudioRtpSender() {
432 // For DtmfSender.
433 SignalDestroyed();
434 Stop();
435}
436
437bool AudioRtpSender::CanInsertDtmf() {
438 if (!media_channel_) {
439 RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
440 return false;
441 }
442 // Check that this RTP sender is active (description has been applied that
443 // matches an SSRC to its ID).
444 if (!ssrc_) {
445 RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
446 return false;
447 }
448 return worker_thread_->Invoke<bool>(
449 RTC_FROM_HERE, [&] { return voice_media_channel()->CanInsertDtmf(); });
450}
451
452bool AudioRtpSender::InsertDtmf(int code, int duration) {
453 if (!media_channel_) {
454 RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
455 return false;
456 }
457 if (!ssrc_) {
458 RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
459 return false;
460 }
461 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
462 return voice_media_channel()->InsertDtmf(ssrc_, code, duration);
463 });
464 if (!success) {
465 RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
466 }
467 return success;
468}
469
470sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
471 return &SignalDestroyed;
472}
473
474void AudioRtpSender::OnChanged() {
475 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
476 RTC_DCHECK(!stopped_);
477 if (cached_track_enabled_ != track_->enabled()) {
478 cached_track_enabled_ = track_->enabled();
479 if (can_send_track()) {
480 SetSend();
481 }
482 }
483}
484
485void AudioRtpSender::DetachTrack() {
486 RTC_DCHECK(track_);
487 audio_track()->RemoveSink(sink_adapter_.get());
488}
489
490void AudioRtpSender::AttachTrack() {
491 RTC_DCHECK(track_);
492 cached_track_enabled_ = track_->enabled();
493 audio_track()->AddSink(sink_adapter_.get());
494}
495
496void AudioRtpSender::AddTrackToStats() {
497 if (can_send_track() && stats_) {
498 stats_->AddLocalAudioTrack(audio_track().get(), ssrc_);
499 }
500}
501
502void AudioRtpSender::RemoveTrackFromStats() {
503 if (can_send_track() && stats_) {
504 stats_->RemoveLocalAudioTrack(audio_track().get(), ssrc_);
505 }
506}
507
508rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
509 return dtmf_sender_proxy_;
510}
511
512void AudioRtpSender::SetSend() {
513 RTC_DCHECK(!stopped_);
514 RTC_DCHECK(can_send_track());
515 if (!media_channel_) {
516 RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
517 return;
518 }
519 cricket::AudioOptions options;
520#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
521 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
522 // PeerConnection. This is a bit of a strange way to apply local audio
523 // options since it is also applied to all streams/channels, local or remote.
524 if (track_->enabled() && audio_track()->GetSource() &&
525 !audio_track()->GetSource()->remote()) {
526 options = audio_track()->GetSource()->options();
527 }
528#endif
529
530 // |track_->enabled()| hops to the signaling thread, so call it before we hop
531 // to the worker thread or else it will deadlock.
532 bool track_enabled = track_->enabled();
533 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
534 return voice_media_channel()->SetAudioSend(ssrc_, track_enabled, &options,
535 sink_adapter_.get());
536 });
537 if (!success) {
538 RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
539 }
540}
541
542void AudioRtpSender::ClearSend() {
543 RTC_DCHECK(ssrc_ != 0);
544 RTC_DCHECK(!stopped_);
545 if (!media_channel_) {
546 RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
547 return;
548 }
549 cricket::AudioOptions options;
550 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
551 return voice_media_channel()->SetAudioSend(ssrc_, false, &options, nullptr);
552 });
553 if (!success) {
554 RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
555 }
556}
557
558rtc::scoped_refptr<VideoRtpSender> VideoRtpSender::Create(
559 rtc::Thread* worker_thread,
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200560 const std::string& id,
561 SetStreamsObserver* set_streams_observer) {
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800562 return rtc::scoped_refptr<VideoRtpSender>(
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200563 new rtc::RefCountedObject<VideoRtpSender>(worker_thread, id,
564 set_streams_observer));
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800565}
566
567VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
Guido Urdaneta1ff16c82019-05-20 19:31:53 +0200568 const std::string& id,
569 SetStreamsObserver* set_streams_observer)
570 : RtpSenderBase(worker_thread, id, set_streams_observer) {}
Amit Hilbuchea7ef2a2019-02-19 15:20:21 -0800571
572VideoRtpSender::~VideoRtpSender() {
573 Stop();
574}
575
576void VideoRtpSender::OnChanged() {
577 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
578 RTC_DCHECK(!stopped_);
579 if (cached_track_content_hint_ != video_track()->content_hint()) {
580 cached_track_content_hint_ = video_track()->content_hint();
581 if (can_send_track()) {
582 SetSend();
583 }
584 }
585}
586
587void VideoRtpSender::AttachTrack() {
588 RTC_DCHECK(track_);
589 cached_track_content_hint_ = video_track()->content_hint();
590}
591
592rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
593 RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
594 return nullptr;
595}
596
597void VideoRtpSender::SetSend() {
598 RTC_DCHECK(!stopped_);
599 RTC_DCHECK(can_send_track());
600 if (!media_channel_) {
601 RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
602 return;
603 }
604 cricket::VideoOptions options;
605 VideoTrackSourceInterface* source = video_track()->GetSource();
606 if (source) {
607 options.is_screencast = source->is_screencast();
608 options.video_noise_reduction = source->needs_denoising();
609 }
610 switch (cached_track_content_hint_) {
611 case VideoTrackInterface::ContentHint::kNone:
612 break;
613 case VideoTrackInterface::ContentHint::kFluid:
614 options.is_screencast = false;
615 break;
616 case VideoTrackInterface::ContentHint::kDetailed:
617 case VideoTrackInterface::ContentHint::kText:
618 options.is_screencast = true;
619 break;
620 }
621 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
622 return video_media_channel()->SetVideoSend(ssrc_, &options, video_track());
623 });
624 RTC_DCHECK(success);
625}
626
627void VideoRtpSender::ClearSend() {
628 RTC_DCHECK(ssrc_ != 0);
629 RTC_DCHECK(!stopped_);
630 if (!media_channel_) {
631 RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
632 return;
633 }
634 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
635 // This the normal case when the underlying media channel has already been
636 // deleted.
637 worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
638 return video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr);
639 });
640}
641
deadbeef70ab1a12015-09-28 16:53:55 -0700642} // namespace webrtc