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 |