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