blob: bb5526a497be68c77a4608643e0570178d3cfd9d [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
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/rtpsender.h"
deadbeef6979b022015-09-24 16:47:53 -070012
Henrik Kjellander15583c12016-02-10 10:53:12 +010013#include "webrtc/api/localaudiosource.h"
perkj9e083d22016-03-20 09:38:40 -070014#include "webrtc/api/mediastreaminterface.h"
deadbeeffac06552015-11-25 11:26:01 -080015#include "webrtc/base/helpers.h"
Peter Boströmdabc9442016-04-11 11:45:14 +020016#include "webrtc/base/trace_event.h"
deadbeef70ab1a12015-09-28 16:53:55 -070017
18namespace webrtc {
19
20LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
21
22LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
23 rtc::CritScope lock(&lock_);
24 if (sink_)
25 sink_->OnClose();
26}
27
28void LocalAudioSinkAdapter::OnData(const void* audio_data,
29 int bits_per_sample,
30 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -080031 size_t number_of_channels,
deadbeef70ab1a12015-09-28 16:53:55 -070032 size_t number_of_frames) {
33 rtc::CritScope lock(&lock_);
34 if (sink_) {
35 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
36 number_of_frames);
37 }
38}
39
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -080040void LocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
deadbeef70ab1a12015-09-28 16:53:55 -070041 rtc::CritScope lock(&lock_);
42 ASSERT(!sink || !sink_);
43 sink_ = sink;
44}
45
46AudioRtpSender::AudioRtpSender(AudioTrackInterface* track,
deadbeeffac06552015-11-25 11:26:01 -080047 const std::string& stream_id,
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -070048 cricket::VoiceChannel* channel,
deadbeeffac06552015-11-25 11:26:01 -080049 StatsCollector* stats)
deadbeef70ab1a12015-09-28 16:53:55 -070050 : id_(track->id()),
deadbeeffac06552015-11-25 11:26:01 -080051 stream_id_(stream_id),
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -070052 channel_(channel),
deadbeeffac06552015-11-25 11:26:01 -080053 stats_(stats),
54 track_(track),
deadbeef70ab1a12015-09-28 16:53:55 -070055 cached_track_enabled_(track->enabled()),
56 sink_adapter_(new LocalAudioSinkAdapter()) {
57 track_->RegisterObserver(this);
58 track_->AddSink(sink_adapter_.get());
deadbeef70ab1a12015-09-28 16:53:55 -070059}
60
deadbeefe1f9d832016-01-14 15:35:42 -080061AudioRtpSender::AudioRtpSender(AudioTrackInterface* track,
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -070062 cricket::VoiceChannel* channel,
deadbeefe1f9d832016-01-14 15:35:42 -080063 StatsCollector* stats)
64 : id_(track->id()),
65 stream_id_(rtc::CreateRandomUuid()),
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -070066 channel_(channel),
deadbeefe1f9d832016-01-14 15:35:42 -080067 stats_(stats),
68 track_(track),
69 cached_track_enabled_(track->enabled()),
70 sink_adapter_(new LocalAudioSinkAdapter()) {
deadbeefe1f9d832016-01-14 15:35:42 -080071 track_->RegisterObserver(this);
72 track_->AddSink(sink_adapter_.get());
73}
74
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -070075AudioRtpSender::AudioRtpSender(cricket::VoiceChannel* channel,
deadbeeffac06552015-11-25 11:26:01 -080076 StatsCollector* stats)
77 : id_(rtc::CreateRandomUuid()),
78 stream_id_(rtc::CreateRandomUuid()),
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -070079 channel_(channel),
deadbeeffac06552015-11-25 11:26:01 -080080 stats_(stats),
81 sink_adapter_(new LocalAudioSinkAdapter()) {}
82
deadbeef70ab1a12015-09-28 16:53:55 -070083AudioRtpSender::~AudioRtpSender() {
deadbeef70ab1a12015-09-28 16:53:55 -070084 Stop();
85}
86
87void AudioRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +020088 TRACE_EVENT0("webrtc", "AudioRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -080089 RTC_DCHECK(!stopped_);
deadbeef70ab1a12015-09-28 16:53:55 -070090 if (cached_track_enabled_ != track_->enabled()) {
91 cached_track_enabled_ = track_->enabled();
deadbeeffac06552015-11-25 11:26:01 -080092 if (can_send_track()) {
93 SetAudioSend();
94 }
deadbeef70ab1a12015-09-28 16:53:55 -070095 }
96}
97
98bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +020099 TRACE_EVENT0("webrtc", "AudioRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800100 if (stopped_) {
101 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
102 return false;
103 }
104 if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) {
deadbeef70ab1a12015-09-28 16:53:55 -0700105 LOG(LS_ERROR) << "SetTrack called on audio RtpSender with " << track->kind()
106 << " track.";
107 return false;
108 }
109 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track);
110
111 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800112 if (track_) {
113 track_->RemoveSink(sink_adapter_.get());
114 track_->UnregisterObserver(this);
115 }
116
117 if (can_send_track() && stats_) {
118 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
119 }
deadbeef70ab1a12015-09-28 16:53:55 -0700120
121 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800122 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700123 // Keep a reference to the old track to keep it alive until we call
124 // SetAudioSend.
125 rtc::scoped_refptr<AudioTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700126 track_ = audio_track;
deadbeeffac06552015-11-25 11:26:01 -0800127 if (track_) {
128 cached_track_enabled_ = track_->enabled();
129 track_->RegisterObserver(this);
130 track_->AddSink(sink_adapter_.get());
131 }
132
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700133 // Update audio channel.
deadbeeffac06552015-11-25 11:26:01 -0800134 if (can_send_track()) {
135 SetAudioSend();
136 if (stats_) {
137 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
138 }
139 } else if (prev_can_send_track) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700140 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800141 }
deadbeef70ab1a12015-09-28 16:53:55 -0700142 return true;
143}
144
deadbeefa601f5c2016-06-06 14:27:39 -0700145RtpParameters AudioRtpSender::GetParameters() const {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700146 if (!channel_ || stopped_) {
147 return RtpParameters();
148 }
149 return channel_->GetRtpSendParameters(ssrc_);
deadbeefa601f5c2016-06-06 14:27:39 -0700150}
151
152bool AudioRtpSender::SetParameters(const RtpParameters& parameters) {
153 TRACE_EVENT0("webrtc", "AudioRtpSender::SetParameters");
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700154 if (!channel_ || stopped_) {
155 return false;
156 }
157 return channel_->SetRtpSendParameters(ssrc_, parameters);
deadbeefa601f5c2016-06-06 14:27:39 -0700158}
159
deadbeeffac06552015-11-25 11:26:01 -0800160void AudioRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200161 TRACE_EVENT0("webrtc", "AudioRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800162 if (stopped_ || ssrc == ssrc_) {
163 return;
164 }
165 // If we are already sending with a particular SSRC, stop sending.
166 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700167 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800168 if (stats_) {
169 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
170 }
171 }
172 ssrc_ = ssrc;
173 if (can_send_track()) {
174 SetAudioSend();
175 if (stats_) {
176 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
177 }
178 }
179}
180
deadbeef70ab1a12015-09-28 16:53:55 -0700181void AudioRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200182 TRACE_EVENT0("webrtc", "AudioRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700183 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800184 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700185 return;
186 }
deadbeeffac06552015-11-25 11:26:01 -0800187 if (track_) {
188 track_->RemoveSink(sink_adapter_.get());
189 track_->UnregisterObserver(this);
190 }
191 if (can_send_track()) {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700192 ClearAudioSend();
deadbeeffac06552015-11-25 11:26:01 -0800193 if (stats_) {
194 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
195 }
196 }
197 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700198}
199
deadbeeffac06552015-11-25 11:26:01 -0800200void AudioRtpSender::SetAudioSend() {
201 RTC_DCHECK(!stopped_ && can_send_track());
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700202 if (!channel_) {
203 LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
204 return;
205 }
deadbeef70ab1a12015-09-28 16:53:55 -0700206 cricket::AudioOptions options;
Tommi3c169782016-01-21 16:12:17 +0100207#if !defined(WEBRTC_CHROMIUM_BUILD)
208 // TODO(tommi): Remove this hack when we move CreateAudioSource out of
209 // PeerConnection. This is a bit of a strange way to apply local audio
210 // options since it is also applied to all streams/channels, local or remote.
tommi6eca7e32015-12-15 04:27:11 -0800211 if (track_->enabled() && track_->GetSource() &&
212 !track_->GetSource()->remote()) {
deadbeef70ab1a12015-09-28 16:53:55 -0700213 // TODO(xians): Remove this static_cast since we should be able to connect
deadbeeffac06552015-11-25 11:26:01 -0800214 // a remote audio track to a peer connection.
deadbeef70ab1a12015-09-28 16:53:55 -0700215 options = static_cast<LocalAudioSource*>(track_->GetSource())->options();
216 }
Tommi3c169782016-01-21 16:12:17 +0100217#endif
deadbeef70ab1a12015-09-28 16:53:55 -0700218
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800219 cricket::AudioSource* source = sink_adapter_.get();
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700220 RTC_DCHECK(source != nullptr);
221 if (!channel_->SetAudioSend(ssrc_, track_->enabled(), &options, source)) {
222 LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
223 }
224}
225
226void AudioRtpSender::ClearAudioSend() {
227 RTC_DCHECK(ssrc_ != 0);
228 RTC_DCHECK(!stopped_);
229 if (!channel_) {
230 LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
231 return;
232 }
233 cricket::AudioOptions options;
234 if (!channel_->SetAudioSend(ssrc_, false, &options, nullptr)) {
235 LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
236 }
deadbeef70ab1a12015-09-28 16:53:55 -0700237}
238
239VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
deadbeeffac06552015-11-25 11:26:01 -0800240 const std::string& stream_id,
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700241 cricket::VideoChannel* channel)
deadbeef70ab1a12015-09-28 16:53:55 -0700242 : id_(track->id()),
deadbeeffac06552015-11-25 11:26:01 -0800243 stream_id_(stream_id),
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700244 channel_(channel),
deadbeeffac06552015-11-25 11:26:01 -0800245 track_(track),
pbos5214a0a2016-12-16 15:39:11 -0800246 cached_track_enabled_(track->enabled()),
247 cached_track_content_hint_(track->content_hint()) {
deadbeef70ab1a12015-09-28 16:53:55 -0700248 track_->RegisterObserver(this);
deadbeef70ab1a12015-09-28 16:53:55 -0700249}
250
deadbeefe1f9d832016-01-14 15:35:42 -0800251VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700252 cricket::VideoChannel* channel)
deadbeefe1f9d832016-01-14 15:35:42 -0800253 : id_(track->id()),
254 stream_id_(rtc::CreateRandomUuid()),
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700255 channel_(channel),
deadbeefe1f9d832016-01-14 15:35:42 -0800256 track_(track),
pbos5214a0a2016-12-16 15:39:11 -0800257 cached_track_enabled_(track->enabled()),
258 cached_track_content_hint_(track->content_hint()) {
deadbeefe1f9d832016-01-14 15:35:42 -0800259 track_->RegisterObserver(this);
260}
261
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700262VideoRtpSender::VideoRtpSender(cricket::VideoChannel* channel)
deadbeeffac06552015-11-25 11:26:01 -0800263 : id_(rtc::CreateRandomUuid()),
264 stream_id_(rtc::CreateRandomUuid()),
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700265 channel_(channel) {}
deadbeeffac06552015-11-25 11:26:01 -0800266
deadbeef70ab1a12015-09-28 16:53:55 -0700267VideoRtpSender::~VideoRtpSender() {
deadbeef70ab1a12015-09-28 16:53:55 -0700268 Stop();
269}
270
271void VideoRtpSender::OnChanged() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200272 TRACE_EVENT0("webrtc", "VideoRtpSender::OnChanged");
deadbeeffac06552015-11-25 11:26:01 -0800273 RTC_DCHECK(!stopped_);
pbos5214a0a2016-12-16 15:39:11 -0800274 if (cached_track_enabled_ != track_->enabled() ||
275 cached_track_content_hint_ != track_->content_hint()) {
deadbeef70ab1a12015-09-28 16:53:55 -0700276 cached_track_enabled_ = track_->enabled();
pbos5214a0a2016-12-16 15:39:11 -0800277 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800278 if (can_send_track()) {
279 SetVideoSend();
280 }
deadbeef70ab1a12015-09-28 16:53:55 -0700281 }
282}
283
284bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200285 TRACE_EVENT0("webrtc", "VideoRtpSender::SetTrack");
deadbeeffac06552015-11-25 11:26:01 -0800286 if (stopped_) {
287 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
288 return false;
289 }
290 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) {
deadbeef70ab1a12015-09-28 16:53:55 -0700291 LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind()
292 << " track.";
293 return false;
294 }
295 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track);
296
297 // Detach from old track.
deadbeeffac06552015-11-25 11:26:01 -0800298 if (track_) {
299 track_->UnregisterObserver(this);
300 }
deadbeef70ab1a12015-09-28 16:53:55 -0700301
302 // Attach to new track.
deadbeeffac06552015-11-25 11:26:01 -0800303 bool prev_can_send_track = can_send_track();
deadbeef5dd42fd2016-05-02 16:20:01 -0700304 // Keep a reference to the old track to keep it alive until we call
deadbeef5a4a75a2016-06-02 16:23:38 -0700305 // SetVideoSend.
deadbeef5dd42fd2016-05-02 16:20:01 -0700306 rtc::scoped_refptr<VideoTrackInterface> old_track = track_;
deadbeef70ab1a12015-09-28 16:53:55 -0700307 track_ = video_track;
deadbeeffac06552015-11-25 11:26:01 -0800308 if (track_) {
309 cached_track_enabled_ = track_->enabled();
pbos5214a0a2016-12-16 15:39:11 -0800310 cached_track_content_hint_ = track_->content_hint();
deadbeeffac06552015-11-25 11:26:01 -0800311 track_->RegisterObserver(this);
312 }
313
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700314 // Update video channel.
deadbeeffac06552015-11-25 11:26:01 -0800315 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800316 SetVideoSend();
317 } else if (prev_can_send_track) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700318 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800319 }
deadbeef70ab1a12015-09-28 16:53:55 -0700320 return true;
321}
322
deadbeefa601f5c2016-06-06 14:27:39 -0700323RtpParameters VideoRtpSender::GetParameters() const {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700324 if (!channel_ || stopped_) {
325 return RtpParameters();
326 }
327 return channel_->GetRtpSendParameters(ssrc_);
deadbeefa601f5c2016-06-06 14:27:39 -0700328}
329
330bool VideoRtpSender::SetParameters(const RtpParameters& parameters) {
331 TRACE_EVENT0("webrtc", "VideoRtpSender::SetParameters");
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700332 if (!channel_ || stopped_) {
333 return false;
334 }
335 return channel_->SetRtpSendParameters(ssrc_, parameters);
deadbeefa601f5c2016-06-06 14:27:39 -0700336}
337
deadbeeffac06552015-11-25 11:26:01 -0800338void VideoRtpSender::SetSsrc(uint32_t ssrc) {
Peter Boströmdabc9442016-04-11 11:45:14 +0200339 TRACE_EVENT0("webrtc", "VideoRtpSender::SetSsrc");
deadbeeffac06552015-11-25 11:26:01 -0800340 if (stopped_ || ssrc == ssrc_) {
341 return;
342 }
343 // If we are already sending with a particular SSRC, stop sending.
344 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700345 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800346 }
347 ssrc_ = ssrc;
348 if (can_send_track()) {
deadbeeffac06552015-11-25 11:26:01 -0800349 SetVideoSend();
350 }
351}
352
deadbeef70ab1a12015-09-28 16:53:55 -0700353void VideoRtpSender::Stop() {
Peter Boströmdabc9442016-04-11 11:45:14 +0200354 TRACE_EVENT0("webrtc", "VideoRtpSender::Stop");
deadbeef70ab1a12015-09-28 16:53:55 -0700355 // TODO(deadbeef): Need to do more here to fully stop sending packets.
deadbeeffac06552015-11-25 11:26:01 -0800356 if (stopped_) {
deadbeef70ab1a12015-09-28 16:53:55 -0700357 return;
358 }
deadbeeffac06552015-11-25 11:26:01 -0800359 if (track_) {
360 track_->UnregisterObserver(this);
361 }
362 if (can_send_track()) {
deadbeef5a4a75a2016-06-02 16:23:38 -0700363 ClearVideoSend();
deadbeeffac06552015-11-25 11:26:01 -0800364 }
365 stopped_ = true;
deadbeef70ab1a12015-09-28 16:53:55 -0700366}
367
deadbeeffac06552015-11-25 11:26:01 -0800368void VideoRtpSender::SetVideoSend() {
369 RTC_DCHECK(!stopped_ && can_send_track());
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700370 if (!channel_) {
371 LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
372 return;
373 }
perkj0d3eef22016-03-09 02:39:17 +0100374 cricket::VideoOptions options;
perkja3ede6c2016-03-08 01:27:48 +0100375 VideoTrackSourceInterface* source = track_->GetSource();
perkj0d3eef22016-03-09 02:39:17 +0100376 if (source) {
377 options.is_screencast = rtc::Optional<bool>(source->is_screencast());
Perc0d31e92016-03-31 17:23:39 +0200378 options.video_noise_reduction = source->needs_denoising();
deadbeef70ab1a12015-09-28 16:53:55 -0700379 }
pbos5214a0a2016-12-16 15:39:11 -0800380 switch (cached_track_content_hint_) {
381 case VideoTrackInterface::ContentHint::kNone:
382 break;
383 case VideoTrackInterface::ContentHint::kFluid:
384 options.is_screencast = rtc::Optional<bool>(false);
385 break;
386 case VideoTrackInterface::ContentHint::kDetailed:
387 options.is_screencast = rtc::Optional<bool>(true);
388 break;
389 }
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700390 if (!channel_->SetVideoSend(ssrc_, track_->enabled(), &options, track_)) {
nisseeb4ca4e2017-01-12 02:24:27 -0800391 RTC_NOTREACHED();
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700392 }
deadbeef5a4a75a2016-06-02 16:23:38 -0700393}
394
395void VideoRtpSender::ClearVideoSend() {
396 RTC_DCHECK(ssrc_ != 0);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700397 RTC_DCHECK(!stopped_);
398 if (!channel_) {
399 LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
400 return;
401 }
402 // Allow SetVideoSend to fail since |enable| is false and |source| is null.
403 // This the normal case when the underlying media channel has already been
404 // deleted.
405 channel_->SetVideoSend(ssrc_, false, nullptr, nullptr);
deadbeef70ab1a12015-09-28 16:53:55 -0700406}
407
408} // namespace webrtc