blob: fa1705671a012e35f40d581cf232d41725edfbf5 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/rtpsender.h"
deadbeef6979b022015-09-24 16:47:53 -070012
Steve Anton36b29d12017-10-30 09:57:42 -070013#include <vector>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/mediastreaminterface.h"
16#include "pc/localaudiosource.h"
Steve Anton2d8609c2018-01-23 16:38:46 -080017#include "pc/statscollector.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
19#include "rtc_base/helpers.h"
20#include "rtc_base/trace_event.h"
deadbeef70ab1a12015-09-28 16:53:55 -070021
22namespace webrtc {
23
Harald Alvestrandc72af932018-01-11 17:18:19 +010024namespace {
25
26// This function is only expected to be called on the signalling thread.
27int GenerateUniqueId() {
28 static int g_unique_id = 0;
29
30 return ++g_unique_id;
31}
32
Seth Hampson2d2c8882018-05-16 16:02:32 -070033// Returns an true if any RtpEncodingParameters member that isn't implemented
34// contains a value.
35bool UnimplementedRtpEncodingParameterHasValue(
36 const RtpEncodingParameters& encoding_params) {
37 if (encoding_params.codec_payload_type.has_value() ||
38 encoding_params.fec.has_value() || encoding_params.rtx.has_value() ||
39 encoding_params.dtx.has_value() || encoding_params.ptime.has_value() ||
Seth Hampson2d2c8882018-05-16 16:02:32 -070040 !encoding_params.rid.empty() ||
41 encoding_params.scale_resolution_down_by.has_value() ||
42 encoding_params.scale_framerate_down_by.has_value() ||
43 !encoding_params.dependency_rids.empty()) {
44 return true;
45 }
46 return false;
47}
48
49// Returns true if a "per-sender" encoding parameter contains a value that isn't
50// its default. Currently max_bitrate_bps and bitrate_priority both are
51// implemented "per-sender," meaning that these encoding parameters
52// are used for the RtpSender as a whole, not for a specific encoding layer.
53// This is done by setting these encoding parameters at index 0 of
54// RtpParameters.encodings. This function can be used to check if these
55// parameters are set at any index other than 0 of RtpParameters.encodings,
56// because they are currently unimplemented to be used for a specific encoding
57// layer.
58bool PerSenderRtpEncodingParameterHasValue(
59 const RtpEncodingParameters& encoding_params) {
Åsa Persson55659812018-06-18 17:51:32 +020060 if (encoding_params.bitrate_priority != kDefaultBitratePriority) {
Seth Hampson2d2c8882018-05-16 16:02:32 -070061 return true;
62 }
63 return false;
64}
65
66// Returns true if any RtpParameters member that isn't implemented contains a
67// value.
68bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
Florent Castelli87b3c512018-07-18 16:00:28 +020069 if (!parameters.mid.empty()) {
Seth Hampson2d2c8882018-05-16 16:02:32 -070070 return true;
71 }
72 for (size_t i = 0; i < parameters.encodings.size(); ++i) {
73 if (UnimplementedRtpEncodingParameterHasValue(parameters.encodings[i])) {
74 return true;
75 }
76 // Encoding parameters that are per-sender should only contain value at
77 // index 0.
78 if (i != 0 &&
79 PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
80 return true;
81 }
82 }
83 return false;
84}
85
Harald Alvestrandc72af932018-01-11 17:18:19 +010086} // namespace
87
deadbeef70ab1a12015-09-28 16:53:55 -070088LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
89
90LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
91 rtc::CritScope lock(&lock_);
92 if (sink_)
93 sink_->OnClose();
94}
95
96void LocalAudioSinkAdapter::OnData(const void* audio_data,
97 int bits_per_sample,
98 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -080099 size_t number_of_channels,
deadbeef70ab1a12015-09-28 16:53:55 -0700100 size_t number_of_frames) {
101 rtc::CritScope lock(&lock_);
102 if (sink_) {
103 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
104 number_of_frames);
105 }
106}
107
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800108void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
deadbeef70ab1a12015-09-28 16:53:55 -0700109 rtc::CritScope lock(&lock_);
nisseede5da42017-01-12 05:15:36 -0800110 RTC_DCHECK(!sink || !sink_);
deadbeef70ab1a12015-09-28 16:53:55 -0700111 sink_ = sink;
112}
113
Steve Anton47136dd2018-01-12 10:49:35 -0800114AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
Steve Anton111fdfd2018-06-25 13:03:36 -0700115 const std::string& id,
deadbeefe1f9d832016-01-14 15:35:42 -0800116 StatsCollector* stats)
Steve Anton47136dd2018-01-12 10:49:35 -0800117 : worker_thread_(worker_thread),
Steve Anton111fdfd2018-06-25 13:03:36 -0700118 id_(id),
deadbeefe1f9d832016-01-14 15:35:42 -0800119 stats_(stats),
Steve Anton02ee47c2018-01-10 16:26:06 -0800120 dtmf_sender_proxy_(DtmfSenderProxy::Create(
121 rtc::Thread::Current(),
Steve Antonb983bae2018-06-20 11:16:53 -0700122 DtmfSender::Create(rtc::Thread::Current(), this))),
Steve Anton111fdfd2018-06-25 13:03:36 -0700123 sink_adapter_(new LocalAudioSinkAdapter()) {
Steve Anton47136dd2018-01-12 10:49:35 -0800124 RTC_DCHECK(worker_thread);
deadbeef20cb0c12017-02-01 20:27:00 -0800125}
deadbeeffac06552015-11-25 11:26:01 -0800126
deadbeef70ab1a12015-09-28 16:53:55 -0700127AudioRtpSender::~AudioRtpSender() {
deadbeef20cb0c12017-02-01 20:27:00 -0800128 // For DtmfSender.
129 SignalDestroyed();
deadbeef70ab1a12015-09-28 16:53:55 -0700130 Stop();
131}
132
deadbeef20cb0c12017-02-01 20:27:00 -0800133bool AudioRtpSender::CanInsertDtmf() {
Steve Anton47136dd2018-01-12 10:49:35 -0800134 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100135 RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
deadbeef20cb0c12017-02-01 20:27:00 -0800136 return false;
137 }
138 // Check that this RTP sender is active (description has been applied that
139 // matches an SSRC to its ID).
140 if (!ssrc_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100141 RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
deadbeef20cb0c12017-02-01 20:27:00 -0800142 return false;
143 }
Steve Anton47136dd2018-01-12 10:49:35 -0800144 return worker_thread_->Invoke<bool>(
145 RTC_FROM_HERE, [&] { return media_channel_->CanInsertDtmf(); });
deadbeef20cb0c12017-02-01 20:27:00 -0800146}
147
148bool AudioRtpSender::InsertDtmf(int code, int duration) {
Steve Anton47136dd2018-01-12 10:49:35 -0800149 if (!media_channel_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100150 RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
deadbeef20cb0c12017-02-01 20:27:00 -0800151 return false;
152 }
153 if (!ssrc_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100154 RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
deadbeef20cb0c12017-02-01 20:27:00 -0800155 return false;
156 }
Steve Anton47136dd2018-01-12 10:49:35 -0800157 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
158 return media_channel_->InsertDtmf(ssrc_, code, duration);
159 });
160 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100161 RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
deadbeef20cb0c12017-02-01 20:27:00 -0800162 }
Steve Anton47136dd2018-01-12 10:49:35 -0800163 return success;
deadbeef20cb0c12017-02-01 20:27:00 -0800164}
165
166sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
167 return &SignalDestroyed;
168}
169
deadbeef70ab1a12015-09-28 16:53:55 -0700170void AudioRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200171 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800172 RTC_DCHECK(!stopped_);
deadbeef70ab1a12015-09-28 16:53:55 -0700173 if (cached_track_enabled_ != track_->enabled()) {
174 cached_track_enabled_ = track_->enabled();
deadbeeffac06552015-11-25 11:26:01 -0800175 if (can_send_track()) {
176 SetAudioSend();
177 }
deadbeef70ab1a12015-09-28 16:53:55 -0700178 }
179}
180
181bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200182 TRACE_EVENT0("webrtc", "AudioRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800183 if (stopped_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100184 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
deadbeeffac06552015-11-25 11:26:01 -0800185 return false;
186 }
187 if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100188 RTC_LOG(LS_ERROR) << "SetTrack called on audio RtpSender with "
189 << track->kind() << " track.";
deadbeef70ab1a12015-09-28 16:53:55 -0700190 return false;
191 }
192 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track);
193
194 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800195 if (track_) {
196 track_->RemoveSink(sink_adapter_.get());
197 track_->UnregisterObserver(this);
198 }
199
200 if (can_send_track() && stats_) {
201 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
202 }
deadbeef70ab1a12015-09-28 16:53:55 -0700203
204 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800205 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700206 // Keep a reference to the old track to keep it alive until we call
207 // SetAudioSend.
208 rtc::scoped_refptr<AudioTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700209 track_ = audio_track;
deadbeeffac06552015-11-25 11:26:01 -0800210 if (track_) {
211 cached_track_enabled_ = track_->enabled();
212 track_->RegisterObserver(this);
213 track_->AddSink(sink_adapter_.get());
214 }
215
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700216 // Update audio channel.
deadbeeffac06552015-11-25 11:26:01 -0800217 if (can_send_track()) {
218 SetAudioSend();
219 if (stats_) {
220 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
221 }
222 } else if (prev_can_send_track) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700223 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800224 }
Steve Anton111fdfd2018-06-25 13:03:36 -0700225 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
deadbeef70ab1a12015-09-28 16:53:55 -0700226 return true;
227}
228
Florent Castellicebf50f2018-05-03 15:31:53 +0200229RtpParameters AudioRtpSender::GetParameters() {
Steve Anton47136dd2018-01-12 10:49:35 -0800230 if (!media_channel_ || stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700231 return RtpParameters();
232 }
Steve Anton47136dd2018-01-12 10:49:35 -0800233 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200234 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
235 last_transaction_id_ = rtc::CreateRandomUuid();
236 result.transaction_id = last_transaction_id_.value();
237 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800238 });
deadbeefa601f5c2016-06-06 14:27:39 -0700239}
240
Zach Steinba37b4b2018-01-23 15:02:36 -0800241RTCError AudioRtpSender::SetParameters(const RtpParameters& parameters) {
deadbeefa601f5c2016-06-06 14:27:39 -0700242 TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
Steve Anton47136dd2018-01-12 10:49:35 -0800243 if (!media_channel_ || stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800244 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700245 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200246 if (!last_transaction_id_) {
247 LOG_AND_RETURN_ERROR(
248 RTCErrorType::INVALID_STATE,
249 "Failed to set parameters since getParameters() has never been called"
250 " on this sender");
251 }
252 if (last_transaction_id_ != parameters.transaction_id) {
253 LOG_AND_RETURN_ERROR(
254 RTCErrorType::INVALID_MODIFICATION,
255 "Failed to set parameters since the transaction_id doesn't match"
256 " the last value returned from getParameters()");
257 }
258
Seth Hampson2d2c8882018-05-16 16:02:32 -0700259 if (UnimplementedRtpParameterHasValue(parameters)) {
260 LOG_AND_RETURN_ERROR(
261 RTCErrorType::UNSUPPORTED_PARAMETER,
262 "Attempted to set an unimplemented parameter of RtpParameters.");
263 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800264 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200265 RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
266 last_transaction_id_.reset();
267 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800268 });
deadbeefa601f5c2016-06-06 14:27:39 -0700269}
270
deadbeef20cb0c12017-02-01 20:27:00 -0800271rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
272 return dtmf_sender_proxy_;
273}
274
deadbeeffac06552015-11-25 11:26:01 -0800275void AudioRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200276 TRACE_EVENT0("webrtc", "AudioRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800277 if (stopped_ || ssrc == ssrc_) {
278 return;
279 }
280 // If we are already sending with a particular SSRC, stop sending.
281 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700282 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800283 if (stats_) {
284 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
285 }
286 }
287 ssrc_ = ssrc;
288 if (can_send_track()) {
289 SetAudioSend();
290 if (stats_) {
291 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
292 }
293 }
294}
295
deadbeef70ab1a12015-09-28 16:53:55 -0700296void AudioRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200297 TRACE_EVENT0("webrtc", "AudioRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700298 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800299 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700300 return;
301 }
deadbeeffac06552015-11-25 11:26:01 -0800302 if (track_) {
303 track_->RemoveSink(sink_adapter_.get());
304 track_->UnregisterObserver(this);
305 }
306 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700307 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800308 if (stats_) {
309 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
310 }
311 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100312 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800313 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700314}
315
deadbeeffac06552015-11-25 11:26:01 -0800316void AudioRtpSender::SetAudioSend() {
kwibergee89e782017-08-09 17:22:01 -0700317 RTC_DCHECK(!stopped_);
318 RTC_DCHECK(can_send_track());
Steve Anton47136dd2018-01-12 10:49:35 -0800319 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100320 RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700321 return;
322 }
deadbeef70ab1a12015-09-28 16:53:55 -0700323 cricket::AudioOptions options;
agouaillardb11fb252017-02-03 06:37:05 -0800324#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
Tommi3c169782016-01-21 16:12:17 +0100325 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
326 // PeerConnection. This is a bit of a strange way to apply local audio
327 // options since it is also applied to all streams/channels, local or remote.
tommi6eca7e32015-12-15 04:27:11 -0800328 if (track_->enabled() && track_->GetSource() &&
329 !track_->GetSource()->remote()) {
deadbeef70ab1a12015-09-28 16:53:55 -0700330 // TODO(xians): Remove this static_cast since we should be able to connect
deadbeeffac06552015-11-25 11:26:01 -0800331 // a remote audio track to a peer connection.
deadbeef70ab1a12015-09-28 16:53:55 -0700332 options = static_cast<LocalAudioSource*>(track_->GetSource())->options();
333 }
Tommi3c169782016-01-21 16:12:17 +0100334#endif
deadbeef70ab1a12015-09-28 16:53:55 -0700335
Steve Anton47136dd2018-01-12 10:49:35 -0800336 // |track_->enabled()| hops to the signaling thread, so call it before we hop
337 // to the worker thread or else it will deadlock.
338 bool track_enabled = track_->enabled();
339 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
340 return media_channel_->SetAudioSend(ssrc_, track_enabled, &options,
341 sink_adapter_.get());
342 });
343 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100344 RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700345 }
346}
347
348void AudioRtpSender::ClearAudioSend() {
349 RTC_DCHECK(ssrc_ != 0);
350 RTC_DCHECK(!stopped_);
Steve Anton47136dd2018-01-12 10:49:35 -0800351 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100352 RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700353 return;
354 }
355 cricket::AudioOptions options;
Steve Anton47136dd2018-01-12 10:49:35 -0800356 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
357 return media_channel_->SetAudioSend(ssrc_, false, &options, nullptr);
358 });
359 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100360 RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700361 }
deadbeef70ab1a12015-09-28 16:53:55 -0700362}
363
Steve Anton47136dd2018-01-12 10:49:35 -0800364VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
Steve Anton111fdfd2018-06-25 13:03:36 -0700365 const std::string& id)
366 : worker_thread_(worker_thread), id_(id) {
Steve Anton47136dd2018-01-12 10:49:35 -0800367 RTC_DCHECK(worker_thread);
deadbeef20cb0c12017-02-01 20:27:00 -0800368}
369
deadbeef70ab1a12015-09-28 16:53:55 -0700370VideoRtpSender::~VideoRtpSender() {
deadbeef70ab1a12015-09-28 16:53:55 -0700371 Stop();
372}
373
374void VideoRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200375 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800376 RTC_DCHECK(!stopped_);
Niels Möllerff40b142018-04-09 08:49:14 +0200377 if (cached_track_content_hint_ != track_->content_hint()) {
pbos5214a0a2016-12-16 15:39:11 -0800378 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800379 if (can_send_track()) {
380 SetVideoSend();
381 }
deadbeef70ab1a12015-09-28 16:53:55 -0700382 }
383}
384
385bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200386 TRACE_EVENT0("webrtc", "VideoRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800387 if (stopped_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100388 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
deadbeeffac06552015-11-25 11:26:01 -0800389 return false;
390 }
391 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100392 RTC_LOG(LS_ERROR) << "SetTrack called on video RtpSender with "
393 << track->kind() << " track.";
deadbeef70ab1a12015-09-28 16:53:55 -0700394 return false;
395 }
396 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track);
397
398 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800399 if (track_) {
400 track_->UnregisterObserver(this);
401 }
deadbeef70ab1a12015-09-28 16:53:55 -0700402
403 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800404 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700405 // Keep a reference to the old track to keep it alive until we call
deadbeef5a4a75a2016-06-02 16:23:38 -0700406 // SetVideoSend.
deadbeef5dd42fd2016-05-02 16:20:01 -0700407 rtc::scoped_refptr<VideoTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700408 track_ = video_track;
deadbeeffac06552015-11-25 11:26:01 -0800409 if (track_) {
pbos5214a0a2016-12-16 15:39:11 -0800410 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800411 track_->RegisterObserver(this);
412 }
413
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700414 // Update video channel.
deadbeeffac06552015-11-25 11:26:01 -0800415 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800416 SetVideoSend();
417 } else if (prev_can_send_track) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700418 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800419 }
Steve Anton111fdfd2018-06-25 13:03:36 -0700420 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
deadbeef70ab1a12015-09-28 16:53:55 -0700421 return true;
422}
423
Florent Castellicebf50f2018-05-03 15:31:53 +0200424RtpParameters VideoRtpSender::GetParameters() {
Steve Anton47136dd2018-01-12 10:49:35 -0800425 if (!media_channel_ || stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700426 return RtpParameters();
427 }
Steve Anton47136dd2018-01-12 10:49:35 -0800428 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200429 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
430 last_transaction_id_ = rtc::CreateRandomUuid();
431 result.transaction_id = last_transaction_id_.value();
432 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800433 });
deadbeefa601f5c2016-06-06 14:27:39 -0700434}
435
Zach Steinba37b4b2018-01-23 15:02:36 -0800436RTCError VideoRtpSender::SetParameters(const RtpParameters& parameters) {
deadbeefa601f5c2016-06-06 14:27:39 -0700437 TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
Steve Anton47136dd2018-01-12 10:49:35 -0800438 if (!media_channel_ || stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800439 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700440 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200441 if (!last_transaction_id_) {
442 LOG_AND_RETURN_ERROR(
443 RTCErrorType::INVALID_STATE,
444 "Failed to set parameters since getParameters() has never been called"
445 " on this sender");
446 }
447 if (last_transaction_id_ != parameters.transaction_id) {
448 LOG_AND_RETURN_ERROR(
449 RTCErrorType::INVALID_MODIFICATION,
450 "Failed to set parameters since the transaction_id doesn't match"
451 " the last value returned from getParameters()");
452 }
453
Seth Hampson2d2c8882018-05-16 16:02:32 -0700454 if (UnimplementedRtpParameterHasValue(parameters)) {
455 LOG_AND_RETURN_ERROR(
456 RTCErrorType::UNSUPPORTED_PARAMETER,
457 "Attempted to set an unimplemented parameter of RtpParameters.");
458 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800459 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200460 RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
461 last_transaction_id_.reset();
462 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800463 });
deadbeefa601f5c2016-06-06 14:27:39 -0700464}
465
deadbeef20cb0c12017-02-01 20:27:00 -0800466rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100467 RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
deadbeef20cb0c12017-02-01 20:27:00 -0800468 return nullptr;
469}
470
deadbeeffac06552015-11-25 11:26:01 -0800471void VideoRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200472 TRACE_EVENT0("webrtc", "VideoRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800473 if (stopped_ || ssrc == ssrc_) {
474 return;
475 }
476 // If we are already sending with a particular SSRC, stop sending.
477 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700478 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800479 }
480 ssrc_ = ssrc;
481 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800482 SetVideoSend();
483 }
484}
485
deadbeef70ab1a12015-09-28 16:53:55 -0700486void VideoRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200487 TRACE_EVENT0("webrtc", "VideoRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700488 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800489 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700490 return;
491 }
deadbeeffac06552015-11-25 11:26:01 -0800492 if (track_) {
493 track_->UnregisterObserver(this);
494 }
495 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700496 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800497 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100498 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800499 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700500}
501
deadbeeffac06552015-11-25 11:26:01 -0800502void VideoRtpSender::SetVideoSend() {
kwibergee89e782017-08-09 17:22:01 -0700503 RTC_DCHECK(!stopped_);
504 RTC_DCHECK(can_send_track());
Steve Anton47136dd2018-01-12 10:49:35 -0800505 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100506 RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700507 return;
508 }
perkj0d3eef22016-03-09 02:39:17 +0100509 cricket::VideoOptions options;
perkja3ede6c2016-03-08 01:27:48 +0100510 VideoTrackSourceInterface* source = track_->GetSource();
perkj0d3eef22016-03-09 02:39:17 +0100511 if (source) {
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100512 options.is_screencast = source->is_screencast();
Perc0d31e92016-03-31 17:23:39 +0200513 options.video_noise_reduction = source->needs_denoising();
deadbeef70ab1a12015-09-28 16:53:55 -0700514 }
pbos5214a0a2016-12-16 15:39:11 -0800515 switch (cached_track_content_hint_) {
516 case VideoTrackInterface::ContentHint::kNone:
517 break;
518 case VideoTrackInterface::ContentHint::kFluid:
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100519 options.is_screencast = false;
pbos5214a0a2016-12-16 15:39:11 -0800520 break;
521 case VideoTrackInterface::ContentHint::kDetailed:
Harald Alvestrandc19ab072018-06-18 08:53:10 +0200522 case VideoTrackInterface::ContentHint::kText:
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100523 options.is_screencast = true;
pbos5214a0a2016-12-16 15:39:11 -0800524 break;
525 }
Steve Anton47136dd2018-01-12 10:49:35 -0800526 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Yves Gerey665174f2018-06-19 15:03:05 +0200527 return media_channel_->SetVideoSend(ssrc_, &options, track_);
Steve Anton47136dd2018-01-12 10:49:35 -0800528 });
529 RTC_DCHECK(success);
deadbeef5a4a75a2016-06-02 16:23:38 -0700530}
531
532void VideoRtpSender::ClearVideoSend() {
533 RTC_DCHECK(ssrc_ != 0);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700534 RTC_DCHECK(!stopped_);
Steve Anton47136dd2018-01-12 10:49:35 -0800535 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100536 RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700537 return;
538 }
539 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
540 // This the normal case when the underlying media channel has already been
541 // deleted.
Steve Anton47136dd2018-01-12 10:49:35 -0800542 worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Niels Möllerff40b142018-04-09 08:49:14 +0200543 return media_channel_->SetVideoSend(ssrc_, nullptr, nullptr);
Steve Anton47136dd2018-01-12 10:49:35 -0800544 });
deadbeef70ab1a12015-09-28 16:53:55 -0700545}
546
547} // namespace webrtc