1/* 2 * libjingle 3 * Copyright 2015 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/app/webrtc/rtpsender.h" 29 30#include "talk/app/webrtc/localaudiosource.h" 31#include "talk/app/webrtc/videosourceinterface.h" 32#include "webrtc/base/helpers.h" 33 34namespace webrtc { 35 36LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {} 37 38LocalAudioSinkAdapter::~LocalAudioSinkAdapter() { 39 rtc::CritScope lock(&lock_); 40 if (sink_) 41 sink_->OnClose(); 42} 43 44void LocalAudioSinkAdapter::OnData(const void* audio_data, 45 int bits_per_sample, 46 int sample_rate, 47 size_t number_of_channels, 48 size_t number_of_frames) { 49 rtc::CritScope lock(&lock_); 50 if (sink_) { 51 sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels, 52 number_of_frames); 53 } 54} 55 56void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) { 57 rtc::CritScope lock(&lock_); 58 ASSERT(!sink || !sink_); 59 sink_ = sink; 60} 61 62AudioRtpSender::AudioRtpSender(AudioTrackInterface* track, 63 const std::string& stream_id, 64 AudioProviderInterface* provider, 65 StatsCollector* stats) 66 : id_(track->id()), 67 stream_id_(stream_id), 68 provider_(provider), 69 stats_(stats), 70 track_(track), 71 cached_track_enabled_(track->enabled()), 72 sink_adapter_(new LocalAudioSinkAdapter()) { 73 RTC_DCHECK(provider != nullptr); 74 track_->RegisterObserver(this); 75 track_->AddSink(sink_adapter_.get()); 76} 77 78AudioRtpSender::AudioRtpSender(AudioProviderInterface* provider, 79 StatsCollector* stats) 80 : id_(rtc::CreateRandomUuid()), 81 stream_id_(rtc::CreateRandomUuid()), 82 provider_(provider), 83 stats_(stats), 84 sink_adapter_(new LocalAudioSinkAdapter()) {} 85 86AudioRtpSender::~AudioRtpSender() { 87 Stop(); 88} 89 90void AudioRtpSender::OnChanged() { 91 RTC_DCHECK(!stopped_); 92 if (cached_track_enabled_ != track_->enabled()) { 93 cached_track_enabled_ = track_->enabled(); 94 if (can_send_track()) { 95 SetAudioSend(); 96 } 97 } 98} 99 100bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) { 101 if (stopped_) { 102 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; 103 return false; 104 } 105 if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) { 106 LOG(LS_ERROR) << "SetTrack called on audio RtpSender with " << track->kind() 107 << " track."; 108 return false; 109 } 110 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track); 111 112 // Detach from old track. 113 if (track_) { 114 track_->RemoveSink(sink_adapter_.get()); 115 track_->UnregisterObserver(this); 116 } 117 118 if (can_send_track() && stats_) { 119 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); 120 } 121 122 // Attach to new track. 123 bool prev_can_send_track = can_send_track(); 124 track_ = audio_track; 125 if (track_) { 126 cached_track_enabled_ = track_->enabled(); 127 track_->RegisterObserver(this); 128 track_->AddSink(sink_adapter_.get()); 129 } 130 131 // Update audio provider. 132 if (can_send_track()) { 133 SetAudioSend(); 134 if (stats_) { 135 stats_->AddLocalAudioTrack(track_.get(), ssrc_); 136 } 137 } else if (prev_can_send_track) { 138 cricket::AudioOptions options; 139 provider_->SetAudioSend(ssrc_, false, options, nullptr); 140 } 141 return true; 142} 143 144void AudioRtpSender::SetSsrc(uint32_t ssrc) { 145 if (stopped_ || ssrc == ssrc_) { 146 return; 147 } 148 // If we are already sending with a particular SSRC, stop sending. 149 if (can_send_track()) { 150 cricket::AudioOptions options; 151 provider_->SetAudioSend(ssrc_, false, options, nullptr); 152 if (stats_) { 153 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); 154 } 155 } 156 ssrc_ = ssrc; 157 if (can_send_track()) { 158 SetAudioSend(); 159 if (stats_) { 160 stats_->AddLocalAudioTrack(track_.get(), ssrc_); 161 } 162 } 163} 164 165void AudioRtpSender::Stop() { 166 // TODO(deadbeef): Need to do more here to fully stop sending packets. 167 if (stopped_) { 168 return; 169 } 170 if (track_) { 171 track_->RemoveSink(sink_adapter_.get()); 172 track_->UnregisterObserver(this); 173 } 174 if (can_send_track()) { 175 cricket::AudioOptions options; 176 provider_->SetAudioSend(ssrc_, false, options, nullptr); 177 if (stats_) { 178 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); 179 } 180 } 181 stopped_ = true; 182} 183 184void AudioRtpSender::SetAudioSend() { 185 RTC_DCHECK(!stopped_ && can_send_track()); 186 cricket::AudioOptions options; 187 if (track_->enabled() && track_->GetSource() && 188 !track_->GetSource()->remote()) { 189 // TODO(xians): Remove this static_cast since we should be able to connect 190 // a remote audio track to a peer connection. 191 options = static_cast<LocalAudioSource*>(track_->GetSource())->options(); 192 } 193 194 // Use the renderer if the audio track has one, otherwise use the sink 195 // adapter owned by this class. 196 cricket::AudioRenderer* renderer = 197 track_->GetRenderer() ? track_->GetRenderer() : sink_adapter_.get(); 198 ASSERT(renderer != nullptr); 199 provider_->SetAudioSend(ssrc_, track_->enabled(), options, renderer); 200} 201 202VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, 203 const std::string& stream_id, 204 VideoProviderInterface* provider) 205 : id_(track->id()), 206 stream_id_(stream_id), 207 provider_(provider), 208 track_(track), 209 cached_track_enabled_(track->enabled()) { 210 RTC_DCHECK(provider != nullptr); 211 track_->RegisterObserver(this); 212} 213 214VideoRtpSender::VideoRtpSender(VideoProviderInterface* provider) 215 : id_(rtc::CreateRandomUuid()), 216 stream_id_(rtc::CreateRandomUuid()), 217 provider_(provider) {} 218 219VideoRtpSender::~VideoRtpSender() { 220 Stop(); 221} 222 223void VideoRtpSender::OnChanged() { 224 RTC_DCHECK(!stopped_); 225 if (cached_track_enabled_ != track_->enabled()) { 226 cached_track_enabled_ = track_->enabled(); 227 if (can_send_track()) { 228 SetVideoSend(); 229 } 230 } 231} 232 233bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) { 234 if (stopped_) { 235 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; 236 return false; 237 } 238 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) { 239 LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind() 240 << " track."; 241 return false; 242 } 243 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track); 244 245 // Detach from old track. 246 if (track_) { 247 track_->UnregisterObserver(this); 248 } 249 250 // Attach to new track. 251 bool prev_can_send_track = can_send_track(); 252 track_ = video_track; 253 if (track_) { 254 cached_track_enabled_ = track_->enabled(); 255 track_->RegisterObserver(this); 256 } 257 258 // Update video provider. 259 if (can_send_track()) { 260 VideoSourceInterface* source = track_->GetSource(); 261 // TODO(deadbeef): If SetTrack is called with a disabled track, and the 262 // previous track was enabled, this could cause a frame from the new track 263 // to slip out. Really, what we need is for SetCaptureDevice and 264 // SetVideoSend 265 // to be combined into one atomic operation, all the way down to 266 // WebRtcVideoSendStream. 267 provider_->SetCaptureDevice(ssrc_, 268 source ? source->GetVideoCapturer() : nullptr); 269 SetVideoSend(); 270 } else if (prev_can_send_track) { 271 provider_->SetCaptureDevice(ssrc_, nullptr); 272 provider_->SetVideoSend(ssrc_, false, nullptr); 273 } 274 return true; 275} 276 277void VideoRtpSender::SetSsrc(uint32_t ssrc) { 278 if (stopped_ || ssrc == ssrc_) { 279 return; 280 } 281 // If we are already sending with a particular SSRC, stop sending. 282 if (can_send_track()) { 283 provider_->SetCaptureDevice(ssrc_, nullptr); 284 provider_->SetVideoSend(ssrc_, false, nullptr); 285 } 286 ssrc_ = ssrc; 287 if (can_send_track()) { 288 VideoSourceInterface* source = track_->GetSource(); 289 provider_->SetCaptureDevice(ssrc_, 290 source ? source->GetVideoCapturer() : nullptr); 291 SetVideoSend(); 292 } 293} 294 295void VideoRtpSender::Stop() { 296 // TODO(deadbeef): Need to do more here to fully stop sending packets. 297 if (stopped_) { 298 return; 299 } 300 if (track_) { 301 track_->UnregisterObserver(this); 302 } 303 if (can_send_track()) { 304 provider_->SetCaptureDevice(ssrc_, nullptr); 305 provider_->SetVideoSend(ssrc_, false, nullptr); 306 } 307 stopped_ = true; 308} 309 310void VideoRtpSender::SetVideoSend() { 311 RTC_DCHECK(!stopped_ && can_send_track()); 312 const cricket::VideoOptions* options = nullptr; 313 VideoSourceInterface* source = track_->GetSource(); 314 if (track_->enabled() && source) { 315 options = source->options(); 316 } 317 provider_->SetVideoSend(ssrc_, track_->enabled(), options); 318} 319 320} // namespace webrtc 321