| OLD | NEW |
| (Empty) |
| 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 | |
| 34 namespace webrtc { | |
| 35 | |
| 36 LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {} | |
| 37 | |
| 38 LocalAudioSinkAdapter::~LocalAudioSinkAdapter() { | |
| 39 rtc::CritScope lock(&lock_); | |
| 40 if (sink_) | |
| 41 sink_->OnClose(); | |
| 42 } | |
| 43 | |
| 44 void 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 | |
| 56 void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) { | |
| 57 rtc::CritScope lock(&lock_); | |
| 58 ASSERT(!sink || !sink_); | |
| 59 sink_ = sink; | |
| 60 } | |
| 61 | |
| 62 AudioRtpSender::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 | |
| 78 AudioRtpSender::AudioRtpSender(AudioTrackInterface* track, | |
| 79 AudioProviderInterface* provider, | |
| 80 StatsCollector* stats) | |
| 81 : id_(track->id()), | |
| 82 stream_id_(rtc::CreateRandomUuid()), | |
| 83 provider_(provider), | |
| 84 stats_(stats), | |
| 85 track_(track), | |
| 86 cached_track_enabled_(track->enabled()), | |
| 87 sink_adapter_(new LocalAudioSinkAdapter()) { | |
| 88 RTC_DCHECK(provider != nullptr); | |
| 89 track_->RegisterObserver(this); | |
| 90 track_->AddSink(sink_adapter_.get()); | |
| 91 } | |
| 92 | |
| 93 AudioRtpSender::AudioRtpSender(AudioProviderInterface* provider, | |
| 94 StatsCollector* stats) | |
| 95 : id_(rtc::CreateRandomUuid()), | |
| 96 stream_id_(rtc::CreateRandomUuid()), | |
| 97 provider_(provider), | |
| 98 stats_(stats), | |
| 99 sink_adapter_(new LocalAudioSinkAdapter()) {} | |
| 100 | |
| 101 AudioRtpSender::~AudioRtpSender() { | |
| 102 Stop(); | |
| 103 } | |
| 104 | |
| 105 void AudioRtpSender::OnChanged() { | |
| 106 RTC_DCHECK(!stopped_); | |
| 107 if (cached_track_enabled_ != track_->enabled()) { | |
| 108 cached_track_enabled_ = track_->enabled(); | |
| 109 if (can_send_track()) { | |
| 110 SetAudioSend(); | |
| 111 } | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) { | |
| 116 if (stopped_) { | |
| 117 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; | |
| 118 return false; | |
| 119 } | |
| 120 if (track && track->kind() != MediaStreamTrackInterface::kAudioKind) { | |
| 121 LOG(LS_ERROR) << "SetTrack called on audio RtpSender with " << track->kind() | |
| 122 << " track."; | |
| 123 return false; | |
| 124 } | |
| 125 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track); | |
| 126 | |
| 127 // Detach from old track. | |
| 128 if (track_) { | |
| 129 track_->RemoveSink(sink_adapter_.get()); | |
| 130 track_->UnregisterObserver(this); | |
| 131 } | |
| 132 | |
| 133 if (can_send_track() && stats_) { | |
| 134 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); | |
| 135 } | |
| 136 | |
| 137 // Attach to new track. | |
| 138 bool prev_can_send_track = can_send_track(); | |
| 139 track_ = audio_track; | |
| 140 if (track_) { | |
| 141 cached_track_enabled_ = track_->enabled(); | |
| 142 track_->RegisterObserver(this); | |
| 143 track_->AddSink(sink_adapter_.get()); | |
| 144 } | |
| 145 | |
| 146 // Update audio provider. | |
| 147 if (can_send_track()) { | |
| 148 SetAudioSend(); | |
| 149 if (stats_) { | |
| 150 stats_->AddLocalAudioTrack(track_.get(), ssrc_); | |
| 151 } | |
| 152 } else if (prev_can_send_track) { | |
| 153 cricket::AudioOptions options; | |
| 154 provider_->SetAudioSend(ssrc_, false, options, nullptr); | |
| 155 } | |
| 156 return true; | |
| 157 } | |
| 158 | |
| 159 void AudioRtpSender::SetSsrc(uint32_t ssrc) { | |
| 160 if (stopped_ || ssrc == ssrc_) { | |
| 161 return; | |
| 162 } | |
| 163 // If we are already sending with a particular SSRC, stop sending. | |
| 164 if (can_send_track()) { | |
| 165 cricket::AudioOptions options; | |
| 166 provider_->SetAudioSend(ssrc_, false, options, nullptr); | |
| 167 if (stats_) { | |
| 168 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); | |
| 169 } | |
| 170 } | |
| 171 ssrc_ = ssrc; | |
| 172 if (can_send_track()) { | |
| 173 SetAudioSend(); | |
| 174 if (stats_) { | |
| 175 stats_->AddLocalAudioTrack(track_.get(), ssrc_); | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 void AudioRtpSender::Stop() { | |
| 181 // TODO(deadbeef): Need to do more here to fully stop sending packets. | |
| 182 if (stopped_) { | |
| 183 return; | |
| 184 } | |
| 185 if (track_) { | |
| 186 track_->RemoveSink(sink_adapter_.get()); | |
| 187 track_->UnregisterObserver(this); | |
| 188 } | |
| 189 if (can_send_track()) { | |
| 190 cricket::AudioOptions options; | |
| 191 provider_->SetAudioSend(ssrc_, false, options, nullptr); | |
| 192 if (stats_) { | |
| 193 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_); | |
| 194 } | |
| 195 } | |
| 196 stopped_ = true; | |
| 197 } | |
| 198 | |
| 199 void AudioRtpSender::SetAudioSend() { | |
| 200 RTC_DCHECK(!stopped_ && can_send_track()); | |
| 201 cricket::AudioOptions options; | |
| 202 #if !defined(WEBRTC_CHROMIUM_BUILD) | |
| 203 // TODO(tommi): Remove this hack when we move CreateAudioSource out of | |
| 204 // PeerConnection. This is a bit of a strange way to apply local audio | |
| 205 // options since it is also applied to all streams/channels, local or remote. | |
| 206 if (track_->enabled() && track_->GetSource() && | |
| 207 !track_->GetSource()->remote()) { | |
| 208 // TODO(xians): Remove this static_cast since we should be able to connect | |
| 209 // a remote audio track to a peer connection. | |
| 210 options = static_cast<LocalAudioSource*>(track_->GetSource())->options(); | |
| 211 } | |
| 212 #endif | |
| 213 | |
| 214 // Use the renderer if the audio track has one, otherwise use the sink | |
| 215 // adapter owned by this class. | |
| 216 cricket::AudioRenderer* renderer = | |
| 217 track_->GetRenderer() ? track_->GetRenderer() : sink_adapter_.get(); | |
| 218 ASSERT(renderer != nullptr); | |
| 219 provider_->SetAudioSend(ssrc_, track_->enabled(), options, renderer); | |
| 220 } | |
| 221 | |
| 222 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, | |
| 223 const std::string& stream_id, | |
| 224 VideoProviderInterface* provider) | |
| 225 : id_(track->id()), | |
| 226 stream_id_(stream_id), | |
| 227 provider_(provider), | |
| 228 track_(track), | |
| 229 cached_track_enabled_(track->enabled()) { | |
| 230 RTC_DCHECK(provider != nullptr); | |
| 231 track_->RegisterObserver(this); | |
| 232 } | |
| 233 | |
| 234 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, | |
| 235 VideoProviderInterface* provider) | |
| 236 : id_(track->id()), | |
| 237 stream_id_(rtc::CreateRandomUuid()), | |
| 238 provider_(provider), | |
| 239 track_(track), | |
| 240 cached_track_enabled_(track->enabled()) { | |
| 241 RTC_DCHECK(provider != nullptr); | |
| 242 track_->RegisterObserver(this); | |
| 243 } | |
| 244 | |
| 245 VideoRtpSender::VideoRtpSender(VideoProviderInterface* provider) | |
| 246 : id_(rtc::CreateRandomUuid()), | |
| 247 stream_id_(rtc::CreateRandomUuid()), | |
| 248 provider_(provider) {} | |
| 249 | |
| 250 VideoRtpSender::~VideoRtpSender() { | |
| 251 Stop(); | |
| 252 } | |
| 253 | |
| 254 void VideoRtpSender::OnChanged() { | |
| 255 RTC_DCHECK(!stopped_); | |
| 256 if (cached_track_enabled_ != track_->enabled()) { | |
| 257 cached_track_enabled_ = track_->enabled(); | |
| 258 if (can_send_track()) { | |
| 259 SetVideoSend(); | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) { | |
| 265 if (stopped_) { | |
| 266 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; | |
| 267 return false; | |
| 268 } | |
| 269 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) { | |
| 270 LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind() | |
| 271 << " track."; | |
| 272 return false; | |
| 273 } | |
| 274 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track); | |
| 275 | |
| 276 // Detach from old track. | |
| 277 if (track_) { | |
| 278 track_->UnregisterObserver(this); | |
| 279 } | |
| 280 | |
| 281 // Attach to new track. | |
| 282 bool prev_can_send_track = can_send_track(); | |
| 283 track_ = video_track; | |
| 284 if (track_) { | |
| 285 cached_track_enabled_ = track_->enabled(); | |
| 286 track_->RegisterObserver(this); | |
| 287 } | |
| 288 | |
| 289 // Update video provider. | |
| 290 if (can_send_track()) { | |
| 291 VideoSourceInterface* source = track_->GetSource(); | |
| 292 // TODO(deadbeef): If SetTrack is called with a disabled track, and the | |
| 293 // previous track was enabled, this could cause a frame from the new track | |
| 294 // to slip out. Really, what we need is for SetCaptureDevice and | |
| 295 // SetVideoSend | |
| 296 // to be combined into one atomic operation, all the way down to | |
| 297 // WebRtcVideoSendStream. | |
| 298 provider_->SetCaptureDevice(ssrc_, | |
| 299 source ? source->GetVideoCapturer() : nullptr); | |
| 300 SetVideoSend(); | |
| 301 } else if (prev_can_send_track) { | |
| 302 provider_->SetCaptureDevice(ssrc_, nullptr); | |
| 303 provider_->SetVideoSend(ssrc_, false, nullptr); | |
| 304 } | |
| 305 return true; | |
| 306 } | |
| 307 | |
| 308 void VideoRtpSender::SetSsrc(uint32_t ssrc) { | |
| 309 if (stopped_ || ssrc == ssrc_) { | |
| 310 return; | |
| 311 } | |
| 312 // If we are already sending with a particular SSRC, stop sending. | |
| 313 if (can_send_track()) { | |
| 314 provider_->SetCaptureDevice(ssrc_, nullptr); | |
| 315 provider_->SetVideoSend(ssrc_, false, nullptr); | |
| 316 } | |
| 317 ssrc_ = ssrc; | |
| 318 if (can_send_track()) { | |
| 319 VideoSourceInterface* source = track_->GetSource(); | |
| 320 provider_->SetCaptureDevice(ssrc_, | |
| 321 source ? source->GetVideoCapturer() : nullptr); | |
| 322 SetVideoSend(); | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 void VideoRtpSender::Stop() { | |
| 327 // TODO(deadbeef): Need to do more here to fully stop sending packets. | |
| 328 if (stopped_) { | |
| 329 return; | |
| 330 } | |
| 331 if (track_) { | |
| 332 track_->UnregisterObserver(this); | |
| 333 } | |
| 334 if (can_send_track()) { | |
| 335 provider_->SetCaptureDevice(ssrc_, nullptr); | |
| 336 provider_->SetVideoSend(ssrc_, false, nullptr); | |
| 337 } | |
| 338 stopped_ = true; | |
| 339 } | |
| 340 | |
| 341 void VideoRtpSender::SetVideoSend() { | |
| 342 RTC_DCHECK(!stopped_ && can_send_track()); | |
| 343 const cricket::VideoOptions* options = nullptr; | |
| 344 VideoSourceInterface* source = track_->GetSource(); | |
| 345 if (track_->enabled() && source) { | |
| 346 options = source->options(); | |
| 347 } | |
| 348 provider_->SetVideoSend(ssrc_, track_->enabled(), options); | |
| 349 } | |
| 350 | |
| 351 } // namespace webrtc | |
| OLD | NEW |