Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1729)

Side by Side Diff: talk/app/webrtc/rtpsender.cc

Issue 1413713003: Adding the ability to create an RtpSender without a track. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Adding some unit tests for new methods on the sender. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2015 Google Inc. 3 * Copyright 2015 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 11 matching lines...) Expand all
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 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 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 #include "talk/app/webrtc/rtpsender.h" 28 #include "talk/app/webrtc/rtpsender.h"
29 29
30 #include "talk/app/webrtc/localaudiosource.h" 30 #include "talk/app/webrtc/localaudiosource.h"
31 #include "talk/app/webrtc/videosourceinterface.h" 31 #include "talk/app/webrtc/videosourceinterface.h"
32 #include "webrtc/base/helpers.h"
32 33
33 namespace webrtc { 34 namespace webrtc {
34 35
35 LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {} 36 LocalAudioSinkAdapter::LocalAudioSinkAdapter() : sink_(nullptr) {}
36 37
37 LocalAudioSinkAdapter::~LocalAudioSinkAdapter() { 38 LocalAudioSinkAdapter::~LocalAudioSinkAdapter() {
38 rtc::CritScope lock(&lock_); 39 rtc::CritScope lock(&lock_);
39 if (sink_) 40 if (sink_)
40 sink_->OnClose(); 41 sink_->OnClose();
41 } 42 }
(...skipping 10 matching lines...) Expand all
52 } 53 }
53 } 54 }
54 55
55 void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) { 56 void LocalAudioSinkAdapter::SetSink(cricket::AudioRenderer::Sink* sink) {
56 rtc::CritScope lock(&lock_); 57 rtc::CritScope lock(&lock_);
57 ASSERT(!sink || !sink_); 58 ASSERT(!sink || !sink_);
58 sink_ = sink; 59 sink_ = sink;
59 } 60 }
60 61
61 AudioRtpSender::AudioRtpSender(AudioTrackInterface* track, 62 AudioRtpSender::AudioRtpSender(AudioTrackInterface* track,
62 uint32_t ssrc, 63 const std::string& stream_id,
63 AudioProviderInterface* provider) 64 AudioProviderInterface* provider,
65 StatsCollector* stats)
64 : id_(track->id()), 66 : id_(track->id()),
67 stream_id_(stream_id),
68 provider_(provider),
69 stats_(stats),
65 track_(track), 70 track_(track),
66 ssrc_(ssrc),
67 provider_(provider),
68 cached_track_enabled_(track->enabled()), 71 cached_track_enabled_(track->enabled()),
69 sink_adapter_(new LocalAudioSinkAdapter()) { 72 sink_adapter_(new LocalAudioSinkAdapter()) {
73 RTC_DCHECK(provider != nullptr);
70 track_->RegisterObserver(this); 74 track_->RegisterObserver(this);
71 track_->AddSink(sink_adapter_.get()); 75 track_->AddSink(sink_adapter_.get());
72 Reconfigure();
73 } 76 }
74 77
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
75 AudioRtpSender::~AudioRtpSender() { 86 AudioRtpSender::~AudioRtpSender() {
76 track_->RemoveSink(sink_adapter_.get());
77 track_->UnregisterObserver(this);
78 Stop(); 87 Stop();
79 } 88 }
80 89
81 void AudioRtpSender::OnChanged() { 90 void AudioRtpSender::OnChanged() {
91 RTC_DCHECK(!stopped_);
82 if (cached_track_enabled_ != track_->enabled()) { 92 if (cached_track_enabled_ != track_->enabled()) {
83 cached_track_enabled_ = track_->enabled(); 93 cached_track_enabled_ = track_->enabled();
84 Reconfigure(); 94 if (ssrc_) {
95 SetAudioSend();
96 }
85 } 97 }
86 } 98 }
87 99
88 bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) { 100 bool AudioRtpSender::SetTrack(MediaStreamTrackInterface* track) {
101 if (stopped_) {
102 LOG(LS_ERROR) << "SetTrack can't be called on stopped RtpSender.";
pthatcher1 2015/10/20 17:42:49 on stopped => on a stopped
Taylor Brandstetter 2015/10/21 00:22:08 Done.
103 return false;
104 }
105 if (!track) {
106 LOG(LS_ERROR) << "SetTrack can't be called with NULL.";
107 return false;
pthatcher1 2015/10/20 17:42:49 Can we not support this? Why not just have it cau
Taylor Brandstetter 2015/10/21 00:22:08 I thought we weren't supposed to support this, but
108 }
89 if (track->kind() != "audio") { 109 if (track->kind() != "audio") {
90 LOG(LS_ERROR) << "SetTrack called on audio RtpSender with " << track->kind() 110 LOG(LS_ERROR) << "SetTrack called on audio RtpSender with " << track->kind()
91 << " track."; 111 << " track.";
92 return false; 112 return false;
93 } 113 }
94 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track); 114 AudioTrackInterface* audio_track = static_cast<AudioTrackInterface*>(track);
95 115
96 // Detach from old track. 116 // Detach from old track.
97 track_->RemoveSink(sink_adapter_.get()); 117 if (track_) {
98 track_->UnregisterObserver(this); 118 track_->RemoveSink(sink_adapter_.get());
119 track_->UnregisterObserver(this);
120 if (ssrc_) {
121 if (stats_) {
122 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
123 }
124 }
125 }
99 126
100 // Attach to new track. 127 // Attach to new track.
101 track_ = audio_track; 128 track_ = audio_track;
102 cached_track_enabled_ = track_->enabled(); 129 cached_track_enabled_ = track_->enabled();
103 track_->RegisterObserver(this); 130 track_->RegisterObserver(this);
104 track_->AddSink(sink_adapter_.get()); 131 track_->AddSink(sink_adapter_.get());
105 Reconfigure(); 132
133 if (ssrc_) {
134 SetAudioSend();
135 if (stats_) {
136 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
137 }
138 }
106 return true; 139 return true;
107 } 140 }
108 141
142 void AudioRtpSender::SetSsrc(uint32_t ssrc) {
pthatcher1 2015/10/20 17:42:49 Do we support changing SSRCs for a given sender?
Taylor Brandstetter 2015/10/21 00:22:08 We talked about this a bit; basically, it was bein
143 if (stopped_ || ssrc == ssrc_) {
144 return;
145 }
146 // If we are already sending with a particular SSRC, stop sending.
147 if (track_ && ssrc_) {
148 cricket::AudioOptions options;
149 provider_->SetAudioSend(ssrc_, false, options, nullptr);
150 if (stats_) {
151 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
152 }
153 }
154 ssrc_ = ssrc;
155 if (track_ && ssrc_) {
156 SetAudioSend();
157 if (stats_) {
158 stats_->AddLocalAudioTrack(track_.get(), ssrc_);
159 }
pthatcher1 2015/10/20 17:42:49 Do we support stats_ to be null? Would it be easi
Taylor Brandstetter 2015/10/21 00:22:08 Yes, it's for unit tests, mainly.
160 }
161 }
162
109 void AudioRtpSender::Stop() { 163 void AudioRtpSender::Stop() {
110 // TODO(deadbeef): Need to do more here to fully stop sending packets. 164 // TODO(deadbeef): Need to do more here to fully stop sending packets.
111 if (!provider_) { 165 if (stopped_) {
112 return; 166 return;
113 } 167 }
114 cricket::AudioOptions options; 168 if (track_) {
115 provider_->SetAudioSend(ssrc_, false, options, nullptr); 169 track_->RemoveSink(sink_adapter_.get());
116 provider_ = nullptr; 170 track_->UnregisterObserver(this);
171 if (ssrc_) {
172 cricket::AudioOptions options;
173 provider_->SetAudioSend(ssrc_, false, options, nullptr);
174 if (stats_) {
175 stats_->RemoveLocalAudioTrack(track_.get(), ssrc_);
176 }
177 }
178 }
179 stopped_ = true;
117 } 180 }
118 181
119 void AudioRtpSender::Reconfigure() { 182 void AudioRtpSender::SetAudioSend() {
120 if (!provider_) { 183 RTC_DCHECK(!stopped_ && track_ && ssrc_);
pthatcher1 2015/10/20 17:42:49 Would it be easier to just do the check for stoppe
Taylor Brandstetter 2015/10/21 00:22:08 Maybe, but it would only save a few lines of code,
pthatcher1 2015/10/22 07:34:14 This does look good.
121 return;
122 }
123 cricket::AudioOptions options; 184 cricket::AudioOptions options;
124 if (track_->enabled() && track_->GetSource()) { 185 if (track_->enabled() && track_->GetSource()) {
125 // TODO(xians): Remove this static_cast since we should be able to connect 186 // TODO(xians): Remove this static_cast since we should be able to connect
126 // a remote audio track to peer connection. 187 // a remote audio track to a peer connection.
127 options = static_cast<LocalAudioSource*>(track_->GetSource())->options(); 188 options = static_cast<LocalAudioSource*>(track_->GetSource())->options();
128 } 189 }
129 190
130 // Use the renderer if the audio track has one, otherwise use the sink 191 // Use the renderer if the audio track has one, otherwise use the sink
131 // adapter owned by this class. 192 // adapter owned by this class.
132 cricket::AudioRenderer* renderer = 193 cricket::AudioRenderer* renderer =
133 track_->GetRenderer() ? track_->GetRenderer() : sink_adapter_.get(); 194 track_->GetRenderer() ? track_->GetRenderer() : sink_adapter_.get();
134 ASSERT(renderer != nullptr); 195 ASSERT(renderer != nullptr);
135 provider_->SetAudioSend(ssrc_, track_->enabled(), options, renderer); 196 provider_->SetAudioSend(ssrc_, track_->enabled(), options, renderer);
136 } 197 }
137 198
138 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track, 199 VideoRtpSender::VideoRtpSender(VideoTrackInterface* track,
139 uint32_t ssrc, 200 const std::string& stream_id,
140 VideoProviderInterface* provider) 201 VideoProviderInterface* provider)
141 : id_(track->id()), 202 : id_(track->id()),
203 stream_id_(stream_id),
204 provider_(provider),
142 track_(track), 205 track_(track),
143 ssrc_(ssrc),
144 provider_(provider),
145 cached_track_enabled_(track->enabled()) { 206 cached_track_enabled_(track->enabled()) {
207 RTC_DCHECK(provider != nullptr);
146 track_->RegisterObserver(this); 208 track_->RegisterObserver(this);
147 VideoSourceInterface* source = track_->GetSource();
148 if (source) {
149 provider_->SetCaptureDevice(ssrc_, source->GetVideoCapturer());
150 }
151 Reconfigure();
152 } 209 }
153 210
211 VideoRtpSender::VideoRtpSender(VideoProviderInterface* provider)
212 : id_(rtc::CreateRandomUuid()),
213 stream_id_(rtc::CreateRandomUuid()),
214 provider_(provider) {}
215
154 VideoRtpSender::~VideoRtpSender() { 216 VideoRtpSender::~VideoRtpSender() {
155 track_->UnregisterObserver(this);
156 Stop(); 217 Stop();
157 } 218 }
158 219
159 void VideoRtpSender::OnChanged() { 220 void VideoRtpSender::OnChanged() {
221 RTC_DCHECK(!stopped_);
160 if (cached_track_enabled_ != track_->enabled()) { 222 if (cached_track_enabled_ != track_->enabled()) {
161 cached_track_enabled_ = track_->enabled(); 223 cached_track_enabled_ = track_->enabled();
162 Reconfigure(); 224 if (ssrc_) {
225 SetVideoSend();
226 }
163 } 227 }
164 } 228 }
165 229
166 bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) { 230 bool VideoRtpSender::SetTrack(MediaStreamTrackInterface* track) {
231 if (stopped_) {
232 LOG(LS_ERROR) << "SetTrack can't be called on stopped RtpSender.";
233 return false;
234 }
235 if (!track) {
236 LOG(LS_ERROR) << "SetTrack can't be called with NULL.";
237 return false;
238 }
pthatcher1 2015/10/20 17:42:49 Similarly as with audio: can we support this?
Taylor Brandstetter 2015/10/21 00:22:08 Done.
167 if (track->kind() != "video") { 239 if (track->kind() != "video") {
168 LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind() 240 LOG(LS_ERROR) << "SetTrack called on video RtpSender with " << track->kind()
169 << " track."; 241 << " track.";
170 return false; 242 return false;
171 } 243 }
172 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track); 244 VideoTrackInterface* video_track = static_cast<VideoTrackInterface*>(track);
173 245
174 // Detach from old track. 246 // Detach from old track.
175 track_->UnregisterObserver(this); 247 if (track_) {
248 track_->UnregisterObserver(this);
249 }
176 250
177 // Attach to new track. 251 // Attach to new track.
178 track_ = video_track; 252 track_ = video_track;
179 cached_track_enabled_ = track_->enabled(); 253 cached_track_enabled_ = track_->enabled();
180 track_->RegisterObserver(this); 254 track_->RegisterObserver(this);
181 Reconfigure(); 255
256 if (ssrc_) {
257 VideoSourceInterface* source = track_->GetSource();
258 // TODO(deadbeef): If SetTrack is called with a disabled track, and the
259 // previous track was enabled, this could cause a frame from the new track
260 // to slip out. Really, what we need is for SetCaptureDevice and
261 // SetVideoSend
262 // to be combined into one atomic operation, all the way down to
263 // WebRtcVideoSendStream.
264 provider_->SetCaptureDevice(ssrc_,
265 source ? source->GetVideoCapturer() : nullptr);
266 SetVideoSend();
267 }
182 return true; 268 return true;
183 } 269 }
184 270
271 void VideoRtpSender::SetSsrc(uint32_t ssrc) {
pthatcher1 2015/10/20 17:42:49 Similarly as with audio: would it simplify things
272 if (stopped_ || ssrc == ssrc_) {
273 return;
274 }
275 // If we are already sending with a particular SSRC, stop sending.
276 if (track_ && ssrc_) {
277 provider_->SetCaptureDevice(ssrc_, nullptr);
278 provider_->SetVideoSend(ssrc_, false, nullptr);
279 }
280 ssrc_ = ssrc;
281 if (track_ && ssrc_) {
282 VideoSourceInterface* source = track_->GetSource();
283 provider_->SetCaptureDevice(ssrc_,
284 source ? source->GetVideoCapturer() : nullptr);
285 SetVideoSend();
286 }
287 }
288
185 void VideoRtpSender::Stop() { 289 void VideoRtpSender::Stop() {
186 // TODO(deadbeef): Need to do more here to fully stop sending packets. 290 // TODO(deadbeef): Need to do more here to fully stop sending packets.
187 if (!provider_) { 291 if (stopped_) {
188 return; 292 return;
189 } 293 }
190 provider_->SetCaptureDevice(ssrc_, nullptr); 294 if (track_) {
191 provider_->SetVideoSend(ssrc_, false, nullptr); 295 track_->UnregisterObserver(this);
192 provider_ = nullptr; 296 if (ssrc_) {
297 provider_->SetCaptureDevice(ssrc_, nullptr);
298 provider_->SetVideoSend(ssrc_, false, nullptr);
299 }
pthatcher1 2015/10/20 17:42:49 What if we have an ssrc_ but no track_? Would we
Taylor Brandstetter 2015/10/21 00:22:08 This is inside "if (track_)" so it's safe. I rearr
pthatcher1 2015/10/22 07:34:14 Looks much better.
300 }
301 stopped_ = true;
193 } 302 }
194 303
195 void VideoRtpSender::Reconfigure() { 304 void VideoRtpSender::SetVideoSend() {
196 if (!provider_) { 305 RTC_DCHECK(!stopped_);
197 return;
198 }
199 const cricket::VideoOptions* options = nullptr; 306 const cricket::VideoOptions* options = nullptr;
200 VideoSourceInterface* source = track_->GetSource(); 307 VideoSourceInterface* source = track_->GetSource();
201 if (track_->enabled() && source) { 308 if (track_->enabled() && source) {
202 options = source->options(); 309 options = source->options();
203 } 310 }
204 provider_->SetVideoSend(ssrc_, track_->enabled(), options); 311 provider_->SetVideoSend(ssrc_, track_->enabled(), options);
205 } 312 }
206 313
207 } // namespace webrtc 314 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698