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 
LocalAudioSinkAdapter()36 LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
37 
~LocalAudioSinkAdapter()38 LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
39   rtc::CritScope lock(&lock_);
40   if (sink_)
41     sink_->OnClose();
42 }
43 
OnData(const void * audio_data,int bits_per_sample,int sample_rate,size_t number_of_channels,size_t number_of_frames)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 
SetSink(cricket::AudioRenderer::Sink * sink)56 void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) {
57   rtc::CritScope lock(&lock_);
58   ASSERT(!sink || !sink_);
59   sink_ = sink;
60 }
61 
AudioRtpSender(AudioTrackInterface * track,const std::string & stream_id,AudioProviderInterface * provider,StatsCollector * stats)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 
AudioRtpSender(AudioProviderInterface * provider,StatsCollector * stats)78 AudioRtpSender::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 
~AudioRtpSender()86 AudioRtpSender::~AudioRtpSender() {
87   Stop();
88 }
89 
OnChanged()90 void 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 
SetTrack(MediaStreamTrackInterface * track)100 bool 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 
SetSsrc(uint32_t ssrc)144 void 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 
Stop()165 void 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 
SetAudioSend()184 void 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 
VideoRtpSender(VideoTrackInterface * track,const std::string & stream_id,VideoProviderInterface * provider)202 VideoRtpSender::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 
VideoRtpSender(VideoProviderInterface * provider)214 VideoRtpSender::VideoRtpSender(VideoProviderInterface* provider)
215     : id_(rtc::CreateRandomUuid()),
216       stream_id_(rtc::CreateRandomUuid()),
217       provider_(provider) {}
218 
~VideoRtpSender()219 VideoRtpSender::~VideoRtpSender() {
220   Stop();
221 }
222 
OnChanged()223 void 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 
SetTrack(MediaStreamTrackInterface * track)233 bool 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 
SetSsrc(uint32_t ssrc)277 void 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 
Stop()295 void 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 
SetVideoSend()310 void 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