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