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 cricket::AudioRenderer* renderer = sink_adapter_.get(); | |
215 ASSERT(renderer != nullptr); | |
216 provider_->SetAudioSend(ssrc_, track_->enabled(), options, renderer); | |
217 } | |
218 | |
219 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, | |
220 const std::string& stream_id, | |
221 VideoProviderInterface* provider) | |
222 : id_(track->id()), | |
223 stream_id_(stream_id), | |
224 provider_(provider), | |
225 track_(track), | |
226 cached_track_enabled_(track->enabled()) { | |
227 RTC_DCHECK(provider != nullptr); | |
228 track_->RegisterObserver(this); | |
229 } | |
230 | |
231 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, | |
232 VideoProviderInterface* provider) | |
233 : id_(track->id()), | |
234 stream_id_(rtc::CreateRandomUuid()), | |
235 provider_(provider), | |
236 track_(track), | |
237 cached_track_enabled_(track->enabled()) { | |
238 RTC_DCHECK(provider != nullptr); | |
239 track_->RegisterObserver(this); | |
240 } | |
241 | |
242 VideoRtpSender::VideoRtpSender(VideoProviderInterface* provider) | |
243 : id_(rtc::CreateRandomUuid()), | |
244 stream_id_(rtc::CreateRandomUuid()), | |
245 provider_(provider) {} | |
246 | |
247 VideoRtpSender::~VideoRtpSender() { | |
248 Stop(); | |
249 } | |
250 | |
251 void VideoRtpSender::OnChanged() { | |
252 RTC_DCHECK(!stopped_); | |
253 if (cached_track_enabled_ != track_->enabled()) { | |
254 cached_track_enabled_ = track_->enabled(); | |
255 if (can_send_track()) { | |
256 SetVideoSend(); | |
257 } | |
258 } | |
259 } | |
260 | |
261 bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) { | |
262 if (stopped_) { | |
263 LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender."; | |
264 return false; | |
265 } | |
266 if (track && track->kind() != MediaStreamTrackInterface::kVideoKind) { | |
267 LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind() | |
268 << " track."; | |
269 return false; | |
270 } | |
271 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track); | |
272 | |
273 // Detach from old track. | |
274 if (track_) { | |
275 track_->UnregisterObserver(this); | |
276 } | |
277 | |
278 // Attach to new track. | |
279 bool prev_can_send_track = can_send_track(); | |
280 track_ = video_track; | |
281 if (track_) { | |
282 cached_track_enabled_ = track_->enabled(); | |
283 track_->RegisterObserver(this); | |
284 } | |
285 | |
286 // Update video provider. | |
287 if (can_send_track()) { | |
288 VideoSourceInterface* source = track_->GetSource(); | |
289 // TODO(deadbeef): If SetTrack is called with a disabled track, and the | |
290 // previous track was enabled, this could cause a frame from the new track | |
291 // to slip out. Really, what we need is for SetCaptureDevice and | |
292 // SetVideoSend | |
293 // to be combined into one atomic operation, all the way down to | |
294 // WebRtcVideoSendStream. | |
295 provider_->SetCaptureDevice(ssrc_, | |
296 source ? source->GetVideoCapturer() : nullptr); | |
297 SetVideoSend(); | |
298 } else if (prev_can_send_track) { | |
299 provider_->SetCaptureDevice(ssrc_, nullptr); | |
300 provider_->SetVideoSend(ssrc_, false, nullptr); | |
301 } | |
302 return true; | |
303 } | |
304 | |
305 void VideoRtpSender::SetSsrc(uint32_t ssrc) { | |
306 if (stopped_ || ssrc == ssrc_) { | |
307 return; | |
308 } | |
309 // If we are already sending with a particular SSRC, stop sending. | |
310 if (can_send_track()) { | |
311 provider_->SetCaptureDevice(ssrc_, nullptr); | |
312 provider_->SetVideoSend(ssrc_, false, nullptr); | |
313 } | |
314 ssrc_ = ssrc; | |
315 if (can_send_track()) { | |
316 VideoSourceInterface* source = track_->GetSource(); | |
317 provider_->SetCaptureDevice(ssrc_, | |
318 source ? source->GetVideoCapturer() : nullptr); | |
319 SetVideoSend(); | |
320 } | |
321 } | |
322 | |
323 void VideoRtpSender::Stop() { | |
324 // TODO(deadbeef): Need to do more here to fully stop sending packets. | |
325 if (stopped_) { | |
326 return; | |
327 } | |
328 if (track_) { | |
329 track_->UnregisterObserver(this); | |
330 } | |
331 if (can_send_track()) { | |
332 provider_->SetCaptureDevice(ssrc_, nullptr); | |
333 provider_->SetVideoSend(ssrc_, false, nullptr); | |
334 } | |
335 stopped_ = true; | |
336 } | |
337 | |
338 void VideoRtpSender::SetVideoSend() { | |
339 RTC_DCHECK(!stopped_ && can_send_track()); | |
340 const cricket::VideoOptions* options = nullptr; | |
341 VideoSourceInterface* source = track_->GetSource(); | |
342 if (track_->enabled() && source) { | |
343 options = source->options(); | |
344 } | |
345 provider_->SetVideoSend(ssrc_, track_->enabled(), options); | |
346 } | |
347 | |
348 } // namespace webrtc | |
OLD | NEW |