blob: c7fe83f1b2f8211df88f2a61a8cf5b7cceeb4689 [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) {
61 if (encoding_params.max_bitrate_bps.has_value() ||
62 encoding_params.bitrate_priority != kDefaultBitratePriority) {
63 return true;
64 }
65 return false;
66}
67
68// Returns true if any RtpParameters member that isn't implemented contains a
69// value.
70bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
Florent Castelliabe301f2018-06-12 18:33:49 +020071 if (!parameters.mid.empty() ||
Seth Hampson2d2c8882018-05-16 16:02:32 -070072 parameters.degradation_preference != DegradationPreference::BALANCED) {
73 return true;
74 }
75 for (size_t i = 0; i < parameters.encodings.size(); ++i) {
76 if (UnimplementedRtpEncodingParameterHasValue(parameters.encodings[i])) {
77 return true;
78 }
79 // Encoding parameters that are per-sender should only contain value at
80 // index 0.
81 if (i != 0 &&
82 PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
83 return true;
84 }
85 }
86 return false;
87}
88
Harald Alvestrandc72af932018-01-11 17:18:19 +010089} // namespace
90
deadbeef70ab1a12015-09-28 16:53:55 -070091LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
92
93LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
94 rtc::CritScope lock(&lock_);
95 if (sink_)
96 sink_->OnClose();
97}
98
99void LocalAudioSinkAdapter::OnData(const void* audio_data,
100 int bits_per_sample,
101 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800102 size_t number_of_channels,
deadbeef70ab1a12015-09-28 16:53:55 -0700103 size_t number_of_frames) {
104 rtc::CritScope lock(&lock_);
105 if (sink_) {
106 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
107 number_of_frames);
108 }
109}
110
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800111void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
deadbeef70ab1a12015-09-28 16:53:55 -0700112 rtc::CritScope lock(&lock_);
nisseede5da42017-01-12 05:15:36 -0800113 RTC_DCHECK(!sink || !sink_);
deadbeef70ab1a12015-09-28 16:53:55 -0700114 sink_ = sink;
115}
116
Steve Anton47136dd2018-01-12 10:49:35 -0800117AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
118 StatsCollector* stats)
119 : AudioRtpSender(worker_thread, nullptr, {rtc::CreateRandomUuid()}, stats) {
120}
deadbeef70ab1a12015-09-28 16:53:55 -0700121
Steve Anton47136dd2018-01-12 10:49:35 -0800122AudioRtpSender::AudioRtpSender(rtc::Thread* worker_thread,
123 rtc::scoped_refptr<AudioTrackInterface> track,
Seth Hampson845e8782018-03-02 11:34:10 -0800124 const std::vector<std::string>& stream_ids,
deadbeefe1f9d832016-01-14 15:35:42 -0800125 StatsCollector* stats)
Steve Anton47136dd2018-01-12 10:49:35 -0800126 : worker_thread_(worker_thread),
127 id_(track ? track->id() : rtc::CreateRandomUuid()),
Seth Hampson845e8782018-03-02 11:34:10 -0800128 stream_ids_(stream_ids),
deadbeefe1f9d832016-01-14 15:35:42 -0800129 stats_(stats),
130 track_(track),
Steve Anton02ee47c2018-01-10 16:26:06 -0800131 dtmf_sender_proxy_(DtmfSenderProxy::Create(
132 rtc::Thread::Current(),
133 DtmfSender::Create(track_, rtc::Thread::Current(), this))),
134 cached_track_enabled_(track ? track->enabled() : false),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100135 sink_adapter_(new LocalAudioSinkAdapter()),
136 attachment_id_(track ? GenerateUniqueId() : 0) {
Steve Anton47136dd2018-01-12 10:49:35 -0800137 RTC_DCHECK(worker_thread);
Steve Anton02ee47c2018-01-10 16:26:06 -0800138 if (track_) {
139 track_->RegisterObserver(this);
140 track_->AddSink(sink_adapter_.get());
141 }
deadbeef20cb0c12017-02-01 20:27:00 -0800142}
deadbeeffac06552015-11-25 11:26:01 -0800143
deadbeef70ab1a12015-09-28 16:53:55 -0700144AudioRtpSender::~AudioRtpSender() {
deadbeef20cb0c12017-02-01 20:27:00 -0800145 // For DtmfSender.
146 SignalDestroyed();
deadbeef70ab1a12015-09-28 16:53:55 -0700147 Stop();
148}
149
deadbeef20cb0c12017-02-01 20:27:00 -0800150bool AudioRtpSender::CanInsertDtmf() {
Steve Anton47136dd2018-01-12 10:49:35 -0800151 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100152 RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
deadbeef20cb0c12017-02-01 20:27:00 -0800153 return false;
154 }
155 // Check that this RTP sender is active (description has been applied that
156 // matches an SSRC to its ID).
157 if (!ssrc_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100158 RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
deadbeef20cb0c12017-02-01 20:27:00 -0800159 return false;
160 }
Steve Anton47136dd2018-01-12 10:49:35 -0800161 return worker_thread_->Invoke<bool>(
162 RTC_FROM_HERE, [&] { return media_channel_->CanInsertDtmf(); });
deadbeef20cb0c12017-02-01 20:27:00 -0800163}
164
165bool AudioRtpSender::InsertDtmf(int code, int duration) {
Steve Anton47136dd2018-01-12 10:49:35 -0800166 if (!media_channel_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100167 RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
deadbeef20cb0c12017-02-01 20:27:00 -0800168 return false;
169 }
170 if (!ssrc_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100171 RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
deadbeef20cb0c12017-02-01 20:27:00 -0800172 return false;
173 }
Steve Anton47136dd2018-01-12 10:49:35 -0800174 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
175 return media_channel_->InsertDtmf(ssrc_, code, duration);
176 });
177 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100178 RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
deadbeef20cb0c12017-02-01 20:27:00 -0800179 }
Steve Anton47136dd2018-01-12 10:49:35 -0800180 return success;
deadbeef20cb0c12017-02-01 20:27:00 -0800181}
182
183sigslot::signal0<>* AudioRtpSender::GetOnDestroyedSignal() {
184 return &SignalDestroyed;
185}
186
deadbeef70ab1a12015-09-28 16:53:55 -0700187void AudioRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200188 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800189 RTC_DCHECK(!stopped_);
deadbeef70ab1a12015-09-28 16:53:55 -0700190 if (cached_track_enabled_ != track_->enabled()) {
191 cached_track_enabled_ = track_->enabled();
deadbeeffac06552015-11-25 11:26:01 -0800192 if (can_send_track()) {
193 SetAudioSend();
194 }
deadbeef70ab1a12015-09-28 16:53:55 -0700195 }
196}
197
198bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200199 TRACE_EVENT0("webrtc", "AudioRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800200 if (stopped_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100201 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
deadbeeffac06552015-11-25 11:26:01 -0800202 return false;
203 }
204 if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100205 RTC_LOG(LS_ERROR) << "SetTrack called on audio RtpSender with "
206 << track->kind() << " track.";
deadbeef70ab1a12015-09-28 16:53:55 -0700207 return false;
208 }
209 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track);
210
211 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800212 if (track_) {
213 track_->RemoveSink(sink_adapter_.get());
214 track_->UnregisterObserver(this);
215 }
216
217 if (can_send_track() && stats_) {
218 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
219 }
deadbeef70ab1a12015-09-28 16:53:55 -0700220
221 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800222 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700223 // Keep a reference to the old track to keep it alive until we call
224 // SetAudioSend.
225 rtc::scoped_refptr<AudioTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700226 track_ = audio_track;
deadbeeffac06552015-11-25 11:26:01 -0800227 if (track_) {
228 cached_track_enabled_ = track_->enabled();
229 track_->RegisterObserver(this);
230 track_->AddSink(sink_adapter_.get());
231 }
232
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700233 // Update audio channel.
deadbeeffac06552015-11-25 11:26:01 -0800234 if (can_send_track()) {
235 SetAudioSend();
236 if (stats_) {
237 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
238 }
239 } else if (prev_can_send_track) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700240 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800241 }
Harald Alvestrandc72af932018-01-11 17:18:19 +0100242 attachment_id_ = GenerateUniqueId();
deadbeef70ab1a12015-09-28 16:53:55 -0700243 return true;
244}
245
Florent Castellicebf50f2018-05-03 15:31:53 +0200246RtpParameters AudioRtpSender::GetParameters() {
Steve Anton47136dd2018-01-12 10:49:35 -0800247 if (!media_channel_ || stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700248 return RtpParameters();
249 }
Steve Anton47136dd2018-01-12 10:49:35 -0800250 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200251 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
252 last_transaction_id_ = rtc::CreateRandomUuid();
253 result.transaction_id = last_transaction_id_.value();
254 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800255 });
deadbeefa601f5c2016-06-06 14:27:39 -0700256}
257
Zach Steinba37b4b2018-01-23 15:02:36 -0800258RTCError AudioRtpSender::SetParameters(const RtpParameters& parameters) {
deadbeefa601f5c2016-06-06 14:27:39 -0700259 TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
Steve Anton47136dd2018-01-12 10:49:35 -0800260 if (!media_channel_ || stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800261 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700262 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200263 if (!last_transaction_id_) {
264 LOG_AND_RETURN_ERROR(
265 RTCErrorType::INVALID_STATE,
266 "Failed to set parameters since getParameters() has never been called"
267 " on this sender");
268 }
269 if (last_transaction_id_ != parameters.transaction_id) {
270 LOG_AND_RETURN_ERROR(
271 RTCErrorType::INVALID_MODIFICATION,
272 "Failed to set parameters since the transaction_id doesn't match"
273 " the last value returned from getParameters()");
274 }
275
Seth Hampson2d2c8882018-05-16 16:02:32 -0700276 if (UnimplementedRtpParameterHasValue(parameters)) {
277 LOG_AND_RETURN_ERROR(
278 RTCErrorType::UNSUPPORTED_PARAMETER,
279 "Attempted to set an unimplemented parameter of RtpParameters.");
280 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800281 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200282 RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
283 last_transaction_id_.reset();
284 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800285 });
deadbeefa601f5c2016-06-06 14:27:39 -0700286}
287
deadbeef20cb0c12017-02-01 20:27:00 -0800288rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
289 return dtmf_sender_proxy_;
290}
291
deadbeeffac06552015-11-25 11:26:01 -0800292void AudioRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200293 TRACE_EVENT0("webrtc", "AudioRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800294 if (stopped_ || ssrc == ssrc_) {
295 return;
296 }
297 // If we are already sending with a particular SSRC, stop sending.
298 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700299 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800300 if (stats_) {
301 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
302 }
303 }
304 ssrc_ = ssrc;
305 if (can_send_track()) {
306 SetAudioSend();
307 if (stats_) {
308 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
309 }
310 }
311}
312
deadbeef70ab1a12015-09-28 16:53:55 -0700313void AudioRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200314 TRACE_EVENT0("webrtc", "AudioRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700315 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800316 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700317 return;
318 }
deadbeeffac06552015-11-25 11:26:01 -0800319 if (track_) {
320 track_->RemoveSink(sink_adapter_.get());
321 track_->UnregisterObserver(this);
322 }
323 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700324 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800325 if (stats_) {
326 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
327 }
328 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100329 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800330 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700331}
332
deadbeeffac06552015-11-25 11:26:01 -0800333void AudioRtpSender::SetAudioSend() {
kwibergee89e782017-08-09 17:22:01 -0700334 RTC_DCHECK(!stopped_);
335 RTC_DCHECK(can_send_track());
Steve Anton47136dd2018-01-12 10:49:35 -0800336 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100337 RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700338 return;
339 }
deadbeef70ab1a12015-09-28 16:53:55 -0700340 cricket::AudioOptions options;
agouaillardb11fb252017-02-03 06:37:05 -0800341#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
Tommi3c169782016-01-21 16:12:17 +0100342 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
343 // PeerConnection. This is a bit of a strange way to apply local audio
344 // options since it is also applied to all streams/channels, local or remote.
tommi6eca7e32015-12-15 04:27:11 -0800345 if (track_->enabled() && track_->GetSource() &&
346 !track_->GetSource()->remote()) {
deadbeef70ab1a12015-09-28 16:53:55 -0700347 // TODO(xians): Remove this static_cast since we should be able to connect
deadbeeffac06552015-11-25 11:26:01 -0800348 // a remote audio track to a peer connection.
deadbeef70ab1a12015-09-28 16:53:55 -0700349 options = static_cast<LocalAudioSource*>(track_->GetSource())->options();
350 }
Tommi3c169782016-01-21 16:12:17 +0100351#endif
deadbeef70ab1a12015-09-28 16:53:55 -0700352
Steve Anton47136dd2018-01-12 10:49:35 -0800353 // |track_->enabled()| hops to the signaling thread, so call it before we hop
354 // to the worker thread or else it will deadlock.
355 bool track_enabled = track_->enabled();
356 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
357 return media_channel_->SetAudioSend(ssrc_, track_enabled, &options,
358 sink_adapter_.get());
359 });
360 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100361 RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700362 }
363}
364
365void AudioRtpSender::ClearAudioSend() {
366 RTC_DCHECK(ssrc_ != 0);
367 RTC_DCHECK(!stopped_);
Steve Anton47136dd2018-01-12 10:49:35 -0800368 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100369 RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700370 return;
371 }
372 cricket::AudioOptions options;
Steve Anton47136dd2018-01-12 10:49:35 -0800373 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
374 return media_channel_->SetAudioSend(ssrc_, false, &options, nullptr);
375 });
376 if (!success) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100377 RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700378 }
deadbeef70ab1a12015-09-28 16:53:55 -0700379}
380
Steve Anton47136dd2018-01-12 10:49:35 -0800381VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread)
382 : VideoRtpSender(worker_thread, nullptr, {rtc::CreateRandomUuid()}) {}
Steve Anton02ee47c2018-01-10 16:26:06 -0800383
Steve Anton47136dd2018-01-12 10:49:35 -0800384VideoRtpSender::VideoRtpSender(rtc::Thread* worker_thread,
385 rtc::scoped_refptr<VideoTrackInterface> track,
Seth Hampson845e8782018-03-02 11:34:10 -0800386 const std::vector<std::string>& stream_ids)
Steve Anton47136dd2018-01-12 10:49:35 -0800387 : worker_thread_(worker_thread),
388 id_(track ? track->id() : rtc::CreateRandomUuid()),
Seth Hampson845e8782018-03-02 11:34:10 -0800389 stream_ids_(stream_ids),
Steve Anton02ee47c2018-01-10 16:26:06 -0800390 track_(track),
Seth Hampson845e8782018-03-02 11:34:10 -0800391 cached_track_content_hint_(track
392 ? track->content_hint()
393 : VideoTrackInterface::ContentHint::kNone),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100394 attachment_id_(track ? GenerateUniqueId() : 0) {
Steve Anton47136dd2018-01-12 10:49:35 -0800395 RTC_DCHECK(worker_thread);
Steve Anton02ee47c2018-01-10 16:26:06 -0800396 if (track_) {
397 track_->RegisterObserver(this);
deadbeef20cb0c12017-02-01 20:27:00 -0800398 }
deadbeef20cb0c12017-02-01 20:27:00 -0800399}
400
deadbeef70ab1a12015-09-28 16:53:55 -0700401VideoRtpSender::~VideoRtpSender() {
deadbeef70ab1a12015-09-28 16:53:55 -0700402 Stop();
403}
404
405void VideoRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200406 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800407 RTC_DCHECK(!stopped_);
Niels Möllerff40b142018-04-09 08:49:14 +0200408 if (cached_track_content_hint_ != track_->content_hint()) {
pbos5214a0a2016-12-16 15:39:11 -0800409 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800410 if (can_send_track()) {
411 SetVideoSend();
412 }
deadbeef70ab1a12015-09-28 16:53:55 -0700413 }
414}
415
416bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200417 TRACE_EVENT0("webrtc", "VideoRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800418 if (stopped_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100419 RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
deadbeeffac06552015-11-25 11:26:01 -0800420 return false;
421 }
422 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100423 RTC_LOG(LS_ERROR) << "SetTrack called on video RtpSender with "
424 << track->kind() << " track.";
deadbeef70ab1a12015-09-28 16:53:55 -0700425 return false;
426 }
427 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track);
428
429 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800430 if (track_) {
431 track_->UnregisterObserver(this);
432 }
deadbeef70ab1a12015-09-28 16:53:55 -0700433
434 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800435 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700436 // Keep a reference to the old track to keep it alive until we call
deadbeef5a4a75a2016-06-02 16:23:38 -0700437 // SetVideoSend.
deadbeef5dd42fd2016-05-02 16:20:01 -0700438 rtc::scoped_refptr<VideoTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700439 track_ = video_track;
deadbeeffac06552015-11-25 11:26:01 -0800440 if (track_) {
pbos5214a0a2016-12-16 15:39:11 -0800441 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800442 track_->RegisterObserver(this);
443 }
444
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700445 // Update video channel.
deadbeeffac06552015-11-25 11:26:01 -0800446 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800447 SetVideoSend();
448 } else if (prev_can_send_track) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700449 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800450 }
Harald Alvestrandc72af932018-01-11 17:18:19 +0100451 attachment_id_ = GenerateUniqueId();
deadbeef70ab1a12015-09-28 16:53:55 -0700452 return true;
453}
454
Florent Castellicebf50f2018-05-03 15:31:53 +0200455RtpParameters VideoRtpSender::GetParameters() {
Steve Anton47136dd2018-01-12 10:49:35 -0800456 if (!media_channel_ || stopped_) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700457 return RtpParameters();
458 }
Steve Anton47136dd2018-01-12 10:49:35 -0800459 return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200460 RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
461 last_transaction_id_ = rtc::CreateRandomUuid();
462 result.transaction_id = last_transaction_id_.value();
463 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800464 });
deadbeefa601f5c2016-06-06 14:27:39 -0700465}
466
Zach Steinba37b4b2018-01-23 15:02:36 -0800467RTCError VideoRtpSender::SetParameters(const RtpParameters& parameters) {
deadbeefa601f5c2016-06-06 14:27:39 -0700468 TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
Steve Anton47136dd2018-01-12 10:49:35 -0800469 if (!media_channel_ || stopped_) {
Zach Steinba37b4b2018-01-23 15:02:36 -0800470 return RTCError(RTCErrorType::INVALID_STATE);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700471 }
Florent Castellicebf50f2018-05-03 15:31:53 +0200472 if (!last_transaction_id_) {
473 LOG_AND_RETURN_ERROR(
474 RTCErrorType::INVALID_STATE,
475 "Failed to set parameters since getParameters() has never been called"
476 " on this sender");
477 }
478 if (last_transaction_id_ != parameters.transaction_id) {
479 LOG_AND_RETURN_ERROR(
480 RTCErrorType::INVALID_MODIFICATION,
481 "Failed to set parameters since the transaction_id doesn't match"
482 " the last value returned from getParameters()");
483 }
484
Seth Hampson2d2c8882018-05-16 16:02:32 -0700485 if (UnimplementedRtpParameterHasValue(parameters)) {
486 LOG_AND_RETURN_ERROR(
487 RTCErrorType::UNSUPPORTED_PARAMETER,
488 "Attempted to set an unimplemented parameter of RtpParameters.");
489 }
Zach Steinba37b4b2018-01-23 15:02:36 -0800490 return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
Florent Castellicebf50f2018-05-03 15:31:53 +0200491 RTCError result = media_channel_->SetRtpSendParameters(ssrc_, parameters);
492 last_transaction_id_.reset();
493 return result;
Steve Anton47136dd2018-01-12 10:49:35 -0800494 });
deadbeefa601f5c2016-06-06 14:27:39 -0700495}
496
deadbeef20cb0c12017-02-01 20:27:00 -0800497rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100498 RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
deadbeef20cb0c12017-02-01 20:27:00 -0800499 return nullptr;
500}
501
deadbeeffac06552015-11-25 11:26:01 -0800502void VideoRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200503 TRACE_EVENT0("webrtc", "VideoRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800504 if (stopped_ || ssrc == ssrc_) {
505 return;
506 }
507 // If we are already sending with a particular SSRC, stop sending.
508 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700509 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800510 }
511 ssrc_ = ssrc;
512 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800513 SetVideoSend();
514 }
515}
516
deadbeef70ab1a12015-09-28 16:53:55 -0700517void VideoRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200518 TRACE_EVENT0("webrtc", "VideoRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700519 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800520 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700521 return;
522 }
deadbeeffac06552015-11-25 11:26:01 -0800523 if (track_) {
524 track_->UnregisterObserver(this);
525 }
526 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700527 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800528 }
Harald Alvestrand3d976f62018-03-19 19:05:06 +0100529 media_channel_ = nullptr;
deadbeeffac06552015-11-25 11:26:01 -0800530 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700531}
532
deadbeeffac06552015-11-25 11:26:01 -0800533void VideoRtpSender::SetVideoSend() {
kwibergee89e782017-08-09 17:22:01 -0700534 RTC_DCHECK(!stopped_);
535 RTC_DCHECK(can_send_track());
Steve Anton47136dd2018-01-12 10:49:35 -0800536 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100537 RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700538 return;
539 }
perkj0d3eef22016-03-09 02:39:17 +0100540 cricket::VideoOptions options;
perkja3ede6c2016-03-08 01:27:48 +0100541 VideoTrackSourceInterface* source = track_->GetSource();
perkj0d3eef22016-03-09 02:39:17 +0100542 if (source) {
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100543 options.is_screencast = source->is_screencast();
Perc0d31e92016-03-31 17:23:39 +0200544 options.video_noise_reduction = source->needs_denoising();
deadbeef70ab1a12015-09-28 16:53:55 -0700545 }
pbos5214a0a2016-12-16 15:39:11 -0800546 switch (cached_track_content_hint_) {
547 case VideoTrackInterface::ContentHint::kNone:
548 break;
549 case VideoTrackInterface::ContentHint::kFluid:
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100550 options.is_screencast = false;
pbos5214a0a2016-12-16 15:39:11 -0800551 break;
552 case VideoTrackInterface::ContentHint::kDetailed:
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100553 options.is_screencast = true;
pbos5214a0a2016-12-16 15:39:11 -0800554 break;
555 }
Steve Anton47136dd2018-01-12 10:49:35 -0800556 bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Niels Möllerff40b142018-04-09 08:49:14 +0200557 return media_channel_->SetVideoSend(ssrc_, &options, track_);
Steve Anton47136dd2018-01-12 10:49:35 -0800558 });
559 RTC_DCHECK(success);
deadbeef5a4a75a2016-06-02 16:23:38 -0700560}
561
562void VideoRtpSender::ClearVideoSend() {
563 RTC_DCHECK(ssrc_ != 0);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700564 RTC_DCHECK(!stopped_);
Steve Anton47136dd2018-01-12 10:49:35 -0800565 if (!media_channel_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100566 RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700567 return;
568 }
569 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
570 // This the normal case when the underlying media channel has already been
571 // deleted.
Steve Anton47136dd2018-01-12 10:49:35 -0800572 worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
Niels Möllerff40b142018-04-09 08:49:14 +0200573 return media_channel_->SetVideoSend(ssrc_, nullptr, nullptr);
Steve Anton47136dd2018-01-12 10:49:35 -0800574 });
deadbeef70ab1a12015-09-28 16:53:55 -0700575}
576
577} // namespace webrtc