blob: 91708fa225ce55703293a8de7b0f75dd69e941f2 [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() ||
40 encoding_params.max_framerate.has_value() ||
41 !encoding_params.rid.empty() ||
42 encoding_params.scale_resolution_down_by.has_value() ||
43 encoding_params.scale_framerate_down_by.has_value() ||
44 !encoding_params.dependency_rids.empty()) {
45 return true;
46 }
47 return false;
48}
49
50// Returns true if a "per-sender" encoding parameter contains a value that isn't
51// its default. Currently max_bitrate_bps and bitrate_priority both are
52// implemented "per-sender," meaning that these encoding parameters
53// are used for the RtpSender as a whole, not for a specific encoding layer.
54// This is done by setting these encoding parameters at index 0 of
55// RtpParameters.encodings. This function can be used to check if these
56// parameters are set at any index other than 0 of RtpParameters.encodings,
57// because they are currently unimplemented to be used for a specific encoding
58// layer.
59bool PerSenderRtpEncodingParameterHasValue(
60 const RtpEncodingParameters& encoding_params) {
Åsa Persson55659812018-06-18 17:51:32 +020061 if (encoding_params.bitrate_priority != kDefaultBitratePriority) {
Seth Hampson2d2c8882018-05-16 16:02:32 -070062 return true;
63 }
64 return false;
65}
66
67// Returns true if any RtpParameters member that isn't implemented contains a
68// value.
69bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
Florent Castelli87b3c512018-07-18 16:00:28 +020070 if (!parameters.mid.empty()) {
Seth Hampson2d2c8882018-05-16 16:02:32 -070071 return true;
72 }
73 for (size_t i = 0; i < parameters.encodings.size(); ++i) {
74 if (UnimplementedRtpEncodingParameterHasValue(parameters.encodings[i])) {
75 return true;
76 }
77 // Encoding parameters that are per-sender should only contain value at
78 // index 0.
79 if (i != 0 &&
80 PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
81 return true;
82 }
83 }
84 return false;
85}
86
Harald Alvestrandc72af932018-01-11 17:18:19 +010087} // namespace
88
deadbeef70ab1a12015-09-28 16:53:55 -070089LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
90
91LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
92 rtc::CritScope lock(&lock_);
93 if (sink_)
94 sink_->OnClose();
95}
96
97void LocalAudioSinkAdapter::OnData(const void* audio_data,
98 int bits_per_sample,
99 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800100 size_t number_of_channels,
deadbeef70ab1a12015-09-28 16:53:55 -0700101 size_t number_of_frames) {
102 rtc::CritScope lock(&lock_);
103 if (sink_) {
104 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
105 number_of_frames);
106 }
107}
108
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800109void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
deadbeef70ab1a12015-09-28 16:53:55 -0700110 rtc::CritScope lock(&lock_);
nisseede5da42017-01-12 05:15:36 -0800111 RTC_DCHECK(!sink || !sink_);
deadbeef70ab1a12015-09-28 16:53:55 -0700112 sink_ = sink;
113}
114
Steve Anton47136dd2018-01-12 10:49:35 -0800115AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
Steve Anton111fdfd2018-06-25 13:03:36 -0700116 const std::string& id,
deadbeefe1f9d832016-01-14 15:35:42 -0800117 StatsCollector* stats)
Steve Anton47136dd2018-01-12 10:49:35 -0800118 : worker_thread_(worker_thread),
Steve Anton111fdfd2018-06-25 13:03:36 -0700119 id_(id),
deadbeefe1f9d832016-01-14 15:35:42 -0800120 stats_(stats),
Steve Anton02ee47c2018-01-10 16:26:06 -0800121 dtmf_sender_proxy_(DtmfSenderProxy::Create(
122 rtc::Thread::Current(),
Steve Antonb983bae2018-06-20 11:16:53 -0700123 DtmfSender::Create(rtc::Thread::Current(), this))),
Steve Anton111fdfd2018-06-25 13:03:36 -0700124 sink_adapter_(new LocalAudioSinkAdapter()) {
Steve Anton47136dd2018-01-12 10:49:35 -0800125 RTC_DCHECK(worker_thread);
deadbeef20cb0c12017-02-01 20:27:00 -0800126}
deadbeeffac06552015-11-25 11:26:01 -0800127
deadbeef70ab1a12015-09-28 16:53:55 -0700128AudioRtpSender::~AudioRtpSender() {
deadbeef20cb0c12017-02-01 20:27:00 -0800129 // For DtmfSender.
130 SignalDestroyed();
deadbeef70ab1a12015-09-28 16:53:55 -0700131 Stop();
132}
133
deadbeef20cb0c12017-02-01 20:27:00 -0800134bool AudioRtpSender::CanInsertDtmf() {
Steve Anton47136dd2018-01-12 10:49:35 -0800135 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100136 RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
deadbeef20cb0c12017-02-01 20:27:00 -0800137 return false;
138 }
139 // Check that this RTP sender is active (description has been applied that
140 // matches an SSRC to its ID).
141 if (!ssrc_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100142 RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
deadbeef20cb0c12017-02-01 20:27:00 -0800143 return false;
144 }
Steve Anton47136dd2018-01-12 10:49:35 -0800145 return worker_thread_->Invoke<bool>(
146 RTC_FROM_HERE, [&] { return media_channel_->CanInsertDtmf(); });
deadbeef20cb0c12017-02-01 20:27:00 -0800147}
148
149bool AudioRtpSender::InsertDtmf(int code, int duration) {
Steve Anton47136dd2018-01-12 10:49:35 -0800150 if (!media_channel_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100151 RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
deadbeef20cb0c12017-02-01 20:27:00 -0800152 return false;
153 }
154 if (!ssrc_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100155 RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
deadbeef20cb0c12017-02-01 20:27:00 -0800156 return false;
157 }
Steve Anton47136dd2018-01-12 10:49:35 -0800158 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
159 return media_channel_->InsertDtmf(ssrc_, code, duration);
160 });
161 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100162 RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
deadbeef20cb0c12017-02-01 20:27:00 -0800163 }
Steve Anton47136dd2018-01-12 10:49:35 -0800164 return success;
deadbeef20cb0c12017-02-01 20:27:00 -0800165}
166
167sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
168 return &SignalDestroyed;
169}
170
deadbeef70ab1a12015-09-28 16:53:55 -0700171void AudioRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200172 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800173 RTC_DCHECK(!stopped_);
deadbeef70ab1a12015-09-28 16:53:55 -0700174 if (cached_track_enabled_ != track_->enabled()) {
175 cached_track_enabled_ = track_->enabled();
deadbeeffac06552015-11-25 11:26:01 -0800176 if (can_send_track()) {
177 SetAudioSend();
178 }
deadbeef70ab1a12015-09-28 16:53:55 -0700179 }
180}
181
182bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200183 TRACE_EVENT0("webrtc", "AudioRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800184 if (stopped_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100185 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
deadbeeffac06552015-11-25 11:26:01 -0800186 return false;
187 }
188 if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100189 RTC_LOG(LS_ERROR) << "SetTrack called on audio RtpSender with "
190 << track->kind() << " track.";
deadbeef70ab1a12015-09-28 16:53:55 -0700191 return false;
192 }
193 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track);
194
195 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800196 if (track_) {
197 track_->RemoveSink(sink_adapter_.get());
198 track_->UnregisterObserver(this);
199 }
200
201 if (can_send_track() && stats_) {
202 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
203 }
deadbeef70ab1a12015-09-28 16:53:55 -0700204
205 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800206 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700207 // Keep a reference to the old track to keep it alive until we call
208 // SetAudioSend.
209 rtc::scoped_refptr<AudioTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700210 track_ = audio_track;
deadbeeffac06552015-11-25 11:26:01 -0800211 if (track_) {
212 cached_track_enabled_ = track_->enabled();
213 track_->RegisterObserver(this);
214 track_->AddSink(sink_adapter_.get());
215 }
216
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700217 // Update audio channel.
deadbeeffac06552015-11-25 11:26:01 -0800218 if (can_send_track()) {
219 SetAudioSend();
220 if (stats_) {
221 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
222 }
223 } else if (prev_can_send_track) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700224 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800225 }
Steve Anton111fdfd2018-06-25 13:03:36 -0700226 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
deadbeef70ab1a12015-09-28 16:53:55 -0700227 return true;
228}
229
Florent Castellicebf50f2018-05-03 15:31:53 +0200230RtpParameters AudioRtpSender::GetParameters() {
Steve Anton47136dd2018-01-12 10:49:35 -0800231 if (!media_channel_ || stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700232 return RtpParameters();
233 }
Steve Anton47136dd2018-01-12 10:49:35 -0800234 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200235 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
236 last_transaction_id_ = rtc::CreateRandomUuid();
237 result.transaction_id = last_transaction_id_.value();
238 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800239 });
deadbeefa601f5c2016-06-06 14:27:39 -0700240}
241
Zach Steinba37b4b2018-01-23 15:02:36 -0800242RTCError AudioRtpSender::SetParameters(const RtpParameters& parameters) {
deadbeefa601f5c2016-06-06 14:27:39 -0700243 TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
Steve Anton47136dd2018-01-12 10:49:35 -0800244 if (!media_channel_ || stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800245 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700246 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200247 if (!last_transaction_id_) {
248 LOG_AND_RETURN_ERROR(
249 RTCErrorType::INVALID_STATE,
250 "Failed to set parameters since getParameters() has never been called"
251 " on this sender");
252 }
253 if (last_transaction_id_ != parameters.transaction_id) {
254 LOG_AND_RETURN_ERROR(
255 RTCErrorType::INVALID_MODIFICATION,
256 "Failed to set parameters since the transaction_id doesn't match"
257 " the last value returned from getParameters()");
258 }
259
Seth Hampson2d2c8882018-05-16 16:02:32 -0700260 if (UnimplementedRtpParameterHasValue(parameters)) {
261 LOG_AND_RETURN_ERROR(
262 RTCErrorType::UNSUPPORTED_PARAMETER,
263 "Attempted to set an unimplemented parameter of RtpParameters.");
264 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800265 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200266 RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
267 last_transaction_id_.reset();
268 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800269 });
deadbeefa601f5c2016-06-06 14:27:39 -0700270}
271
deadbeef20cb0c12017-02-01 20:27:00 -0800272rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
273 return dtmf_sender_proxy_;
274}
275
deadbeeffac06552015-11-25 11:26:01 -0800276void AudioRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200277 TRACE_EVENT0("webrtc", "AudioRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800278 if (stopped_ || ssrc == ssrc_) {
279 return;
280 }
281 // If we are already sending with a particular SSRC, stop sending.
282 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700283 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800284 if (stats_) {
285 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
286 }
287 }
288 ssrc_ = ssrc;
289 if (can_send_track()) {
290 SetAudioSend();
291 if (stats_) {
292 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
293 }
294 }
295}
296
deadbeef70ab1a12015-09-28 16:53:55 -0700297void AudioRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200298 TRACE_EVENT0("webrtc", "AudioRtpSender::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_) {
304 track_->RemoveSink(sink_adapter_.get());
305 track_->UnregisterObserver(this);
306 }
307 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700308 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800309 if (stats_) {
310 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
311 }
312 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100313 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800314 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700315}
316
deadbeeffac06552015-11-25 11:26:01 -0800317void AudioRtpSender::SetAudioSend() {
kwibergee89e782017-08-09 17:22:01 -0700318 RTC_DCHECK(!stopped_);
319 RTC_DCHECK(can_send_track());
Steve Anton47136dd2018-01-12 10:49:35 -0800320 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100321 RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700322 return;
323 }
deadbeef70ab1a12015-09-28 16:53:55 -0700324 cricket::AudioOptions options;
agouaillardb11fb252017-02-03 06:37:05 -0800325#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
Tommi3c169782016-01-21 16:12:17 +0100326 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
327 // PeerConnection. This is a bit of a strange way to apply local audio
328 // options since it is also applied to all streams/channels, local or remote.
tommi6eca7e32015-12-15 04:27:11 -0800329 if (track_->enabled() && track_->GetSource() &&
330 !track_->GetSource()->remote()) {
deadbeef70ab1a12015-09-28 16:53:55 -0700331 // TODO(xians): Remove this static_cast since we should be able to connect
deadbeeffac06552015-11-25 11:26:01 -0800332 // a remote audio track to a peer connection.
deadbeef70ab1a12015-09-28 16:53:55 -0700333 options = static_cast<LocalAudioSource*>(track_->GetSource())->options();
334 }
Tommi3c169782016-01-21 16:12:17 +0100335#endif
deadbeef70ab1a12015-09-28 16:53:55 -0700336
Steve Anton47136dd2018-01-12 10:49:35 -0800337 // |track_->enabled()| hops to the signaling thread, so call it before we hop
338 // to the worker thread or else it will deadlock.
339 bool track_enabled = track_->enabled();
340 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
341 return media_channel_->SetAudioSend(ssrc_, track_enabled, &options,
342 sink_adapter_.get());
343 });
344 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100345 RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700346 }
347}
348
349void AudioRtpSender::ClearAudioSend() {
350 RTC_DCHECK(ssrc_ != 0);
351 RTC_DCHECK(!stopped_);
Steve Anton47136dd2018-01-12 10:49:35 -0800352 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100353 RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700354 return;
355 }
356 cricket::AudioOptions options;
Steve Anton47136dd2018-01-12 10:49:35 -0800357 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
358 return media_channel_->SetAudioSend(ssrc_, false, &options, nullptr);
359 });
360 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100361 RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700362 }
deadbeef70ab1a12015-09-28 16:53:55 -0700363}
364
Steve Anton47136dd2018-01-12 10:49:35 -0800365VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
Steve Anton111fdfd2018-06-25 13:03:36 -0700366 const std::string& id)
367 : worker_thread_(worker_thread), id_(id) {
Steve Anton47136dd2018-01-12 10:49:35 -0800368 RTC_DCHECK(worker_thread);
deadbeef20cb0c12017-02-01 20:27:00 -0800369}
370
deadbeef70ab1a12015-09-28 16:53:55 -0700371VideoRtpSender::~VideoRtpSender() {
deadbeef70ab1a12015-09-28 16:53:55 -0700372 Stop();
373}
374
375void VideoRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200376 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800377 RTC_DCHECK(!stopped_);
Niels Möllerff40b142018-04-09 08:49:14 +0200378 if (cached_track_content_hint_ != track_->content_hint()) {
pbos5214a0a2016-12-16 15:39:11 -0800379 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800380 if (can_send_track()) {
381 SetVideoSend();
382 }
deadbeef70ab1a12015-09-28 16:53:55 -0700383 }
384}
385
386bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200387 TRACE_EVENT0("webrtc", "VideoRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800388 if (stopped_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100389 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
deadbeeffac06552015-11-25 11:26:01 -0800390 return false;
391 }
392 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100393 RTC_LOG(LS_ERROR) << "SetTrack called on video RtpSender with "
394 << track->kind() << " track.";
deadbeef70ab1a12015-09-28 16:53:55 -0700395 return false;
396 }
397 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track);
398
399 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800400 if (track_) {
401 track_->UnregisterObserver(this);
402 }
deadbeef70ab1a12015-09-28 16:53:55 -0700403
404 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800405 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700406 // Keep a reference to the old track to keep it alive until we call
deadbeef5a4a75a2016-06-02 16:23:38 -0700407 // SetVideoSend.
deadbeef5dd42fd2016-05-02 16:20:01 -0700408 rtc::scoped_refptr<VideoTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700409 track_ = video_track;
deadbeeffac06552015-11-25 11:26:01 -0800410 if (track_) {
pbos5214a0a2016-12-16 15:39:11 -0800411 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800412 track_->RegisterObserver(this);
413 }
414
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700415 // Update video channel.
deadbeeffac06552015-11-25 11:26:01 -0800416 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800417 SetVideoSend();
418 } else if (prev_can_send_track) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700419 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800420 }
Steve Anton111fdfd2018-06-25 13:03:36 -0700421 attachment_id_ = (track_ ? GenerateUniqueId() : 0);
deadbeef70ab1a12015-09-28 16:53:55 -0700422 return true;
423}
424
Florent Castellicebf50f2018-05-03 15:31:53 +0200425RtpParameters VideoRtpSender::GetParameters() {
Steve Anton47136dd2018-01-12 10:49:35 -0800426 if (!media_channel_ || stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700427 return RtpParameters();
428 }
Steve Anton47136dd2018-01-12 10:49:35 -0800429 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200430 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
431 last_transaction_id_ = rtc::CreateRandomUuid();
432 result.transaction_id = last_transaction_id_.value();
433 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800434 });
deadbeefa601f5c2016-06-06 14:27:39 -0700435}
436
Zach Steinba37b4b2018-01-23 15:02:36 -0800437RTCError VideoRtpSender::SetParameters(const RtpParameters& parameters) {
deadbeefa601f5c2016-06-06 14:27:39 -0700438 TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
Steve Anton47136dd2018-01-12 10:49:35 -0800439 if (!media_channel_ || stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800440 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700441 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200442 if (!last_transaction_id_) {
443 LOG_AND_RETURN_ERROR(
444 RTCErrorType::INVALID_STATE,
445 "Failed to set parameters since getParameters() has never been called"
446 " on this sender");
447 }
448 if (last_transaction_id_ != parameters.transaction_id) {
449 LOG_AND_RETURN_ERROR(
450 RTCErrorType::INVALID_MODIFICATION,
451 "Failed to set parameters since the transaction_id doesn't match"
452 " the last value returned from getParameters()");
453 }
454
Seth Hampson2d2c8882018-05-16 16:02:32 -0700455 if (UnimplementedRtpParameterHasValue(parameters)) {
456 LOG_AND_RETURN_ERROR(
457 RTCErrorType::UNSUPPORTED_PARAMETER,
458 "Attempted to set an unimplemented parameter of RtpParameters.");
459 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800460 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200461 RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
462 last_transaction_id_.reset();
463 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800464 });
deadbeefa601f5c2016-06-06 14:27:39 -0700465}
466
deadbeef20cb0c12017-02-01 20:27:00 -0800467rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100468 RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
deadbeef20cb0c12017-02-01 20:27:00 -0800469 return nullptr;
470}
471
deadbeeffac06552015-11-25 11:26:01 -0800472void VideoRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200473 TRACE_EVENT0("webrtc", "VideoRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800474 if (stopped_ || ssrc == ssrc_) {
475 return;
476 }
477 // If we are already sending with a particular SSRC, stop sending.
478 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700479 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800480 }
481 ssrc_ = ssrc;
482 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800483 SetVideoSend();
484 }
485}
486
deadbeef70ab1a12015-09-28 16:53:55 -0700487void VideoRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200488 TRACE_EVENT0("webrtc", "VideoRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700489 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800490 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700491 return;
492 }
deadbeeffac06552015-11-25 11:26:01 -0800493 if (track_) {
494 track_->UnregisterObserver(this);
495 }
496 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700497 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800498 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100499 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800500 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700501}
502
deadbeeffac06552015-11-25 11:26:01 -0800503void VideoRtpSender::SetVideoSend() {
kwibergee89e782017-08-09 17:22:01 -0700504 RTC_DCHECK(!stopped_);
505 RTC_DCHECK(can_send_track());
Steve Anton47136dd2018-01-12 10:49:35 -0800506 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100507 RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700508 return;
509 }
perkj0d3eef22016-03-09 02:39:17 +0100510 cricket::VideoOptions options;
perkja3ede6c2016-03-08 01:27:48 +0100511 VideoTrackSourceInterface* source = track_->GetSource();
perkj0d3eef22016-03-09 02:39:17 +0100512 if (source) {
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100513 options.is_screencast = source->is_screencast();
Perc0d31e92016-03-31 17:23:39 +0200514 options.video_noise_reduction = source->needs_denoising();
deadbeef70ab1a12015-09-28 16:53:55 -0700515 }
pbos5214a0a2016-12-16 15:39:11 -0800516 switch (cached_track_content_hint_) {
517 case VideoTrackInterface::ContentHint::kNone:
518 break;
519 case VideoTrackInterface::ContentHint::kFluid:
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100520 options.is_screencast = false;
pbos5214a0a2016-12-16 15:39:11 -0800521 break;
522 case VideoTrackInterface::ContentHint::kDetailed:
Harald Alvestrandc19ab072018-06-18 08:53:10 +0200523 case VideoTrackInterface::ContentHint::kText:
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100524 options.is_screencast = true;
pbos5214a0a2016-12-16 15:39:11 -0800525 break;
526 }
Steve Anton47136dd2018-01-12 10:49:35 -0800527 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Yves Gerey665174f2018-06-19 15:03:05 +0200528 return media_channel_->SetVideoSend(ssrc_, &options, track_);
Steve Anton47136dd2018-01-12 10:49:35 -0800529 });
530 RTC_DCHECK(success);
deadbeef5a4a75a2016-06-02 16:23:38 -0700531}
532
533void VideoRtpSender::ClearVideoSend() {
534 RTC_DCHECK(ssrc_ != 0);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700535 RTC_DCHECK(!stopped_);
Steve Anton47136dd2018-01-12 10:49:35 -0800536 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100537 RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700538 return;
539 }
540 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
541 // This the normal case when the underlying media channel has already been
542 // deleted.
Steve Anton47136dd2018-01-12 10:49:35 -0800543 worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Niels Möllerff40b142018-04-09 08:49:14 +0200544 return media_channel_->SetVideoSend(ssrc_, nullptr, nullptr);
Steve Anton47136dd2018-01-12 10:49:35 -0800545 });
deadbeef70ab1a12015-09-28 16:53:55 -0700546}
547
548} // namespace webrtc