OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2012 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 <utility> | |
29 #include <vector> | |
30 | |
31 #include "talk/app/webrtc/audiotrack.h" | |
32 #include "talk/app/webrtc/fakemediacontroller.h" | |
33 #include "talk/app/webrtc/fakemetricsobserver.h" | |
34 #include "talk/app/webrtc/jsepicecandidate.h" | |
35 #include "talk/app/webrtc/jsepsessiondescription.h" | |
36 #include "talk/app/webrtc/peerconnection.h" | |
37 #include "talk/app/webrtc/sctputils.h" | |
38 #include "talk/app/webrtc/streamcollection.h" | |
39 #include "talk/app/webrtc/streamcollection.h" | |
40 #include "talk/app/webrtc/test/fakeconstraints.h" | |
41 #include "talk/app/webrtc/test/fakedtlsidentitystore.h" | |
42 #include "talk/app/webrtc/videotrack.h" | |
43 #include "talk/app/webrtc/webrtcsession.h" | |
44 #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" | |
45 #include "talk/session/media/channelmanager.h" | |
46 #include "talk/session/media/mediasession.h" | |
47 #include "webrtc/base/fakenetwork.h" | |
48 #include "webrtc/base/firewallsocketserver.h" | |
49 #include "webrtc/base/gunit.h" | |
50 #include "webrtc/base/logging.h" | |
51 #include "webrtc/base/network.h" | |
52 #include "webrtc/base/physicalsocketserver.h" | |
53 #include "webrtc/base/ssladapter.h" | |
54 #include "webrtc/base/sslidentity.h" | |
55 #include "webrtc/base/sslstreamadapter.h" | |
56 #include "webrtc/base/stringutils.h" | |
57 #include "webrtc/base/thread.h" | |
58 #include "webrtc/base/virtualsocketserver.h" | |
59 #include "webrtc/media/base/fakemediaengine.h" | |
60 #include "webrtc/media/base/fakevideorenderer.h" | |
61 #include "webrtc/media/base/mediachannel.h" | |
62 #include "webrtc/media/webrtc/fakewebrtccall.h" | |
63 #include "webrtc/p2p/base/stunserver.h" | |
64 #include "webrtc/p2p/base/teststunserver.h" | |
65 #include "webrtc/p2p/base/testturnserver.h" | |
66 #include "webrtc/p2p/base/transportchannel.h" | |
67 #include "webrtc/p2p/client/basicportallocator.h" | |
68 | |
69 #define MAYBE_SKIP_TEST(feature) \ | |
70 if (!(feature())) { \ | |
71 LOG(LS_INFO) << "Feature disabled... skipping"; \ | |
72 return; \ | |
73 } | |
74 | |
75 using cricket::FakeVoiceMediaChannel; | |
76 using cricket::TransportInfo; | |
77 using rtc::SocketAddress; | |
78 using rtc::scoped_ptr; | |
79 using rtc::Thread; | |
80 using webrtc::CreateSessionDescription; | |
81 using webrtc::CreateSessionDescriptionObserver; | |
82 using webrtc::CreateSessionDescriptionRequest; | |
83 using webrtc::DataChannel; | |
84 using webrtc::DtlsIdentityStoreInterface; | |
85 using webrtc::FakeConstraints; | |
86 using webrtc::FakeMetricsObserver; | |
87 using webrtc::IceCandidateCollection; | |
88 using webrtc::InternalDataChannelInit; | |
89 using webrtc::JsepIceCandidate; | |
90 using webrtc::JsepSessionDescription; | |
91 using webrtc::PeerConnectionFactoryInterface; | |
92 using webrtc::PeerConnectionInterface; | |
93 using webrtc::SessionDescriptionInterface; | |
94 using webrtc::SessionStats; | |
95 using webrtc::StreamCollection; | |
96 using webrtc::WebRtcSession; | |
97 using webrtc::kBundleWithoutRtcpMux; | |
98 using webrtc::kCreateChannelFailed; | |
99 using webrtc::kInvalidSdp; | |
100 using webrtc::kMlineMismatch; | |
101 using webrtc::kPushDownTDFailed; | |
102 using webrtc::kSdpWithoutIceUfragPwd; | |
103 using webrtc::kSdpWithoutDtlsFingerprint; | |
104 using webrtc::kSdpWithoutSdesCrypto; | |
105 using webrtc::kSessionError; | |
106 using webrtc::kSessionErrorDesc; | |
107 using webrtc::kMaxUnsignalledRecvStreams; | |
108 | |
109 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions; | |
110 | |
111 static const int kClientAddrPort = 0; | |
112 static const char kClientAddrHost1[] = "11.11.11.11"; | |
113 static const char kClientIPv6AddrHost1[] = | |
114 "2620:0:aaaa:bbbb:cccc:dddd:eeee:ffff"; | |
115 static const char kClientAddrHost2[] = "22.22.22.22"; | |
116 static const char kStunAddrHost[] = "99.99.99.1"; | |
117 static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478); | |
118 static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0); | |
119 static const char kTurnUsername[] = "test"; | |
120 static const char kTurnPassword[] = "test"; | |
121 | |
122 static const char kSessionVersion[] = "1"; | |
123 | |
124 // Media index of candidates belonging to the first media content. | |
125 static const int kMediaContentIndex0 = 0; | |
126 static const char kMediaContentName0[] = "audio"; | |
127 | |
128 // Media index of candidates belonging to the second media content. | |
129 static const int kMediaContentIndex1 = 1; | |
130 static const char kMediaContentName1[] = "video"; | |
131 | |
132 static const int kIceCandidatesTimeout = 10000; | |
133 | |
134 static const char kFakeDtlsFingerprint[] = | |
135 "BB:CD:72:F7:2F:D0:BA:43:F3:68:B1:0C:23:72:B6:4A:" | |
136 "0F:DE:34:06:BC:E0:FE:01:BC:73:C8:6D:F4:65:D5:24"; | |
137 | |
138 static const char kTooLongIceUfragPwd[] = | |
139 "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag" | |
140 "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag" | |
141 "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag" | |
142 "IceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfragIceUfrag"; | |
143 | |
144 static const char kSdpWithRtx[] = | |
145 "v=0\r\n" | |
146 "o=- 4104004319237231850 2 IN IP4 127.0.0.1\r\n" | |
147 "s=-\r\n" | |
148 "t=0 0\r\n" | |
149 "a=msid-semantic: WMS stream1\r\n" | |
150 "m=video 9 RTP/SAVPF 0 96\r\n" | |
151 "c=IN IP4 0.0.0.0\r\n" | |
152 "a=rtcp:9 IN IP4 0.0.0.0\r\n" | |
153 "a=ice-ufrag:CerjGp19G7wpXwl7\r\n" | |
154 "a=ice-pwd:cMvOlFvQ6ochez1ZOoC2uBEC\r\n" | |
155 "a=mid:video\r\n" | |
156 "a=sendrecv\r\n" | |
157 "a=rtcp-mux\r\n" | |
158 "a=crypto:1 AES_CM_128_HMAC_SHA1_80 " | |
159 "inline:5/4N5CDvMiyDArHtBByUM71VIkguH17ZNoX60GrA\r\n" | |
160 "a=rtpmap:0 fake_video_codec/90000\r\n" | |
161 "a=rtpmap:96 rtx/90000\r\n" | |
162 "a=fmtp:96 apt=0\r\n"; | |
163 | |
164 static const char kStream1[] = "stream1"; | |
165 static const char kVideoTrack1[] = "video1"; | |
166 static const char kAudioTrack1[] = "audio1"; | |
167 | |
168 static const char kStream2[] = "stream2"; | |
169 static const char kVideoTrack2[] = "video2"; | |
170 static const char kAudioTrack2[] = "audio2"; | |
171 | |
172 enum RTCCertificateGenerationMethod { ALREADY_GENERATED, DTLS_IDENTITY_STORE }; | |
173 | |
174 class MockIceObserver : public webrtc::IceObserver { | |
175 public: | |
176 MockIceObserver() | |
177 : oncandidatesready_(false), | |
178 ice_connection_state_(PeerConnectionInterface::kIceConnectionNew), | |
179 ice_gathering_state_(PeerConnectionInterface::kIceGatheringNew) { | |
180 } | |
181 | |
182 void OnIceConnectionChange( | |
183 PeerConnectionInterface::IceConnectionState new_state) override { | |
184 ice_connection_state_ = new_state; | |
185 } | |
186 void OnIceGatheringChange( | |
187 PeerConnectionInterface::IceGatheringState new_state) override { | |
188 // We can never transition back to "new". | |
189 EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, new_state); | |
190 ice_gathering_state_ = new_state; | |
191 oncandidatesready_ = | |
192 new_state == PeerConnectionInterface::kIceGatheringComplete; | |
193 } | |
194 | |
195 // Found a new candidate. | |
196 void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override { | |
197 switch (candidate->sdp_mline_index()) { | |
198 case kMediaContentIndex0: | |
199 mline_0_candidates_.push_back(candidate->candidate()); | |
200 break; | |
201 case kMediaContentIndex1: | |
202 mline_1_candidates_.push_back(candidate->candidate()); | |
203 break; | |
204 default: | |
205 ASSERT(false); | |
206 } | |
207 | |
208 // The ICE gathering state should always be Gathering when a candidate is | |
209 // received (or possibly Completed in the case of the final candidate). | |
210 EXPECT_NE(PeerConnectionInterface::kIceGatheringNew, ice_gathering_state_); | |
211 } | |
212 | |
213 bool oncandidatesready_; | |
214 std::vector<cricket::Candidate> mline_0_candidates_; | |
215 std::vector<cricket::Candidate> mline_1_candidates_; | |
216 PeerConnectionInterface::IceConnectionState ice_connection_state_; | |
217 PeerConnectionInterface::IceGatheringState ice_gathering_state_; | |
218 }; | |
219 | |
220 class WebRtcSessionForTest : public webrtc::WebRtcSession { | |
221 public: | |
222 WebRtcSessionForTest(webrtc::MediaControllerInterface* media_controller, | |
223 rtc::Thread* signaling_thread, | |
224 rtc::Thread* worker_thread, | |
225 cricket::PortAllocator* port_allocator, | |
226 webrtc::IceObserver* ice_observer) | |
227 : WebRtcSession(media_controller, | |
228 signaling_thread, | |
229 worker_thread, | |
230 port_allocator) { | |
231 RegisterIceObserver(ice_observer); | |
232 } | |
233 virtual ~WebRtcSessionForTest() {} | |
234 | |
235 // Note that these methods are only safe to use if the signaling thread | |
236 // is the same as the worker thread | |
237 cricket::TransportChannel* voice_rtp_transport_channel() { | |
238 return rtp_transport_channel(voice_channel()); | |
239 } | |
240 | |
241 cricket::TransportChannel* voice_rtcp_transport_channel() { | |
242 return rtcp_transport_channel(voice_channel()); | |
243 } | |
244 | |
245 cricket::TransportChannel* video_rtp_transport_channel() { | |
246 return rtp_transport_channel(video_channel()); | |
247 } | |
248 | |
249 cricket::TransportChannel* video_rtcp_transport_channel() { | |
250 return rtcp_transport_channel(video_channel()); | |
251 } | |
252 | |
253 cricket::TransportChannel* data_rtp_transport_channel() { | |
254 return rtp_transport_channel(data_channel()); | |
255 } | |
256 | |
257 cricket::TransportChannel* data_rtcp_transport_channel() { | |
258 return rtcp_transport_channel(data_channel()); | |
259 } | |
260 | |
261 using webrtc::WebRtcSession::SetAudioPlayout; | |
262 using webrtc::WebRtcSession::SetAudioSend; | |
263 using webrtc::WebRtcSession::SetCaptureDevice; | |
264 using webrtc::WebRtcSession::SetVideoPlayout; | |
265 using webrtc::WebRtcSession::SetVideoSend; | |
266 | |
267 private: | |
268 cricket::TransportChannel* rtp_transport_channel(cricket::BaseChannel* ch) { | |
269 if (!ch) { | |
270 return nullptr; | |
271 } | |
272 return ch->transport_channel(); | |
273 } | |
274 | |
275 cricket::TransportChannel* rtcp_transport_channel(cricket::BaseChannel* ch) { | |
276 if (!ch) { | |
277 return nullptr; | |
278 } | |
279 return ch->rtcp_transport_channel(); | |
280 } | |
281 }; | |
282 | |
283 class WebRtcSessionCreateSDPObserverForTest | |
284 : public rtc::RefCountedObject<CreateSessionDescriptionObserver> { | |
285 public: | |
286 enum State { | |
287 kInit, | |
288 kFailed, | |
289 kSucceeded, | |
290 }; | |
291 WebRtcSessionCreateSDPObserverForTest() : state_(kInit) {} | |
292 | |
293 // CreateSessionDescriptionObserver implementation. | |
294 virtual void OnSuccess(SessionDescriptionInterface* desc) { | |
295 description_.reset(desc); | |
296 state_ = kSucceeded; | |
297 } | |
298 virtual void OnFailure(const std::string& error) { | |
299 state_ = kFailed; | |
300 } | |
301 | |
302 SessionDescriptionInterface* description() { return description_.get(); } | |
303 | |
304 SessionDescriptionInterface* ReleaseDescription() { | |
305 return description_.release(); | |
306 } | |
307 | |
308 State state() const { return state_; } | |
309 | |
310 protected: | |
311 ~WebRtcSessionCreateSDPObserverForTest() {} | |
312 | |
313 private: | |
314 rtc::scoped_ptr<SessionDescriptionInterface> description_; | |
315 State state_; | |
316 }; | |
317 | |
318 class FakeAudioRenderer : public cricket::AudioRenderer { | |
319 public: | |
320 FakeAudioRenderer() : sink_(NULL) {} | |
321 virtual ~FakeAudioRenderer() { | |
322 if (sink_) | |
323 sink_->OnClose(); | |
324 } | |
325 | |
326 void SetSink(Sink* sink) override { sink_ = sink; } | |
327 | |
328 cricket::AudioRenderer::Sink* sink() const { return sink_; } | |
329 private: | |
330 cricket::AudioRenderer::Sink* sink_; | |
331 }; | |
332 | |
333 class WebRtcSessionTest | |
334 : public testing::TestWithParam<RTCCertificateGenerationMethod>, | |
335 public sigslot::has_slots<> { | |
336 protected: | |
337 // TODO Investigate why ChannelManager crashes, if it's created | |
338 // after stun_server. | |
339 WebRtcSessionTest() | |
340 : media_engine_(new cricket::FakeMediaEngine()), | |
341 data_engine_(new cricket::FakeDataEngine()), | |
342 channel_manager_( | |
343 new cricket::ChannelManager(media_engine_, | |
344 data_engine_, | |
345 new cricket::CaptureManager(), | |
346 rtc::Thread::Current())), | |
347 fake_call_(webrtc::Call::Config()), | |
348 media_controller_( | |
349 webrtc::MediaControllerInterface::Create(rtc::Thread::Current(), | |
350 channel_manager_.get())), | |
351 tdesc_factory_(new cricket::TransportDescriptionFactory()), | |
352 desc_factory_( | |
353 new cricket::MediaSessionDescriptionFactory(channel_manager_.get(), | |
354 tdesc_factory_.get())), | |
355 pss_(new rtc::PhysicalSocketServer), | |
356 vss_(new rtc::VirtualSocketServer(pss_.get())), | |
357 fss_(new rtc::FirewallSocketServer(vss_.get())), | |
358 ss_scope_(fss_.get()), | |
359 stun_socket_addr_( | |
360 rtc::SocketAddress(kStunAddrHost, cricket::STUN_SERVER_PORT)), | |
361 stun_server_(cricket::TestStunServer::Create(Thread::Current(), | |
362 stun_socket_addr_)), | |
363 turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr), | |
364 metrics_observer_(new rtc::RefCountedObject<FakeMetricsObserver>()) { | |
365 cricket::ServerAddresses stun_servers; | |
366 stun_servers.insert(stun_socket_addr_); | |
367 allocator_.reset(new cricket::BasicPortAllocator( | |
368 &network_manager_, | |
369 stun_servers, | |
370 SocketAddress(), SocketAddress(), SocketAddress())); | |
371 allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | | |
372 cricket::PORTALLOCATOR_DISABLE_RELAY); | |
373 EXPECT_TRUE(channel_manager_->Init()); | |
374 desc_factory_->set_add_legacy_streams(false); | |
375 allocator_->set_step_delay(cricket::kMinimumStepDelay); | |
376 } | |
377 | |
378 void AddInterface(const SocketAddress& addr) { | |
379 network_manager_.AddInterface(addr); | |
380 } | |
381 | |
382 // If |dtls_identity_store| != null or |rtc_configuration| contains | |
383 // |certificates| then DTLS will be enabled unless explicitly disabled by | |
384 // |rtc_configuration| options. When DTLS is enabled a certificate will be | |
385 // used if provided, otherwise one will be generated using the | |
386 // |dtls_identity_store|. | |
387 void Init( | |
388 rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store, | |
389 const PeerConnectionInterface::RTCConfiguration& rtc_configuration) { | |
390 ASSERT_TRUE(session_.get() == NULL); | |
391 session_.reset(new WebRtcSessionForTest( | |
392 media_controller_.get(), rtc::Thread::Current(), rtc::Thread::Current(), | |
393 allocator_.get(), &observer_)); | |
394 session_->SignalDataChannelOpenMessage.connect( | |
395 this, &WebRtcSessionTest::OnDataChannelOpenMessage); | |
396 session_->GetOnDestroyedSignal()->connect( | |
397 this, &WebRtcSessionTest::OnSessionDestroyed); | |
398 | |
399 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew, | |
400 observer_.ice_connection_state_); | |
401 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew, | |
402 observer_.ice_gathering_state_); | |
403 | |
404 EXPECT_TRUE(session_->Initialize(options_, constraints_.get(), | |
405 std::move(dtls_identity_store), | |
406 rtc_configuration)); | |
407 session_->set_metrics_observer(metrics_observer_); | |
408 } | |
409 | |
410 void OnDataChannelOpenMessage(const std::string& label, | |
411 const InternalDataChannelInit& config) { | |
412 last_data_channel_label_ = label; | |
413 last_data_channel_config_ = config; | |
414 } | |
415 | |
416 void OnSessionDestroyed() { session_destroyed_ = true; } | |
417 | |
418 void Init() { | |
419 PeerConnectionInterface::RTCConfiguration configuration; | |
420 Init(nullptr, configuration); | |
421 } | |
422 | |
423 void InitWithIceTransport( | |
424 PeerConnectionInterface::IceTransportsType ice_transport_type) { | |
425 PeerConnectionInterface::RTCConfiguration configuration; | |
426 configuration.type = ice_transport_type; | |
427 Init(nullptr, configuration); | |
428 } | |
429 | |
430 void InitWithBundlePolicy( | |
431 PeerConnectionInterface::BundlePolicy bundle_policy) { | |
432 PeerConnectionInterface::RTCConfiguration configuration; | |
433 configuration.bundle_policy = bundle_policy; | |
434 Init(nullptr, configuration); | |
435 } | |
436 | |
437 void InitWithRtcpMuxPolicy( | |
438 PeerConnectionInterface::RtcpMuxPolicy rtcp_mux_policy) { | |
439 PeerConnectionInterface::RTCConfiguration configuration; | |
440 configuration.rtcp_mux_policy = rtcp_mux_policy; | |
441 Init(nullptr, configuration); | |
442 } | |
443 | |
444 // Successfully init with DTLS; with a certificate generated and supplied or | |
445 // with a store that generates it for us. | |
446 void InitWithDtls(RTCCertificateGenerationMethod cert_gen_method) { | |
447 rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store; | |
448 PeerConnectionInterface::RTCConfiguration configuration; | |
449 if (cert_gen_method == ALREADY_GENERATED) { | |
450 configuration.certificates.push_back( | |
451 FakeDtlsIdentityStore::GenerateCertificate()); | |
452 } else if (cert_gen_method == DTLS_IDENTITY_STORE) { | |
453 dtls_identity_store.reset(new FakeDtlsIdentityStore()); | |
454 dtls_identity_store->set_should_fail(false); | |
455 } else { | |
456 RTC_CHECK(false); | |
457 } | |
458 Init(std::move(dtls_identity_store), configuration); | |
459 } | |
460 | |
461 // Init with DTLS with a store that will fail to generate a certificate. | |
462 void InitWithDtlsIdentityGenFail() { | |
463 rtc::scoped_ptr<FakeDtlsIdentityStore> dtls_identity_store( | |
464 new FakeDtlsIdentityStore()); | |
465 dtls_identity_store->set_should_fail(true); | |
466 PeerConnectionInterface::RTCConfiguration configuration; | |
467 Init(std::move(dtls_identity_store), configuration); | |
468 } | |
469 | |
470 void InitWithDtmfCodec() { | |
471 // Add kTelephoneEventCodec for dtmf test. | |
472 const cricket::AudioCodec kTelephoneEventCodec( | |
473 106, "telephone-event", 8000, 0, 1, 0); | |
474 std::vector<cricket::AudioCodec> codecs; | |
475 codecs.push_back(kTelephoneEventCodec); | |
476 media_engine_->SetAudioCodecs(codecs); | |
477 desc_factory_->set_audio_codecs(codecs); | |
478 Init(); | |
479 } | |
480 | |
481 void SendAudioVideoStream1() { | |
482 send_stream_1_ = true; | |
483 send_stream_2_ = false; | |
484 send_audio_ = true; | |
485 send_video_ = true; | |
486 } | |
487 | |
488 void SendAudioVideoStream2() { | |
489 send_stream_1_ = false; | |
490 send_stream_2_ = true; | |
491 send_audio_ = true; | |
492 send_video_ = true; | |
493 } | |
494 | |
495 void SendAudioVideoStream1And2() { | |
496 send_stream_1_ = true; | |
497 send_stream_2_ = true; | |
498 send_audio_ = true; | |
499 send_video_ = true; | |
500 } | |
501 | |
502 void SendNothing() { | |
503 send_stream_1_ = false; | |
504 send_stream_2_ = false; | |
505 send_audio_ = false; | |
506 send_video_ = false; | |
507 } | |
508 | |
509 void SendAudioOnlyStream2() { | |
510 send_stream_1_ = false; | |
511 send_stream_2_ = true; | |
512 send_audio_ = true; | |
513 send_video_ = false; | |
514 } | |
515 | |
516 void SendVideoOnlyStream2() { | |
517 send_stream_1_ = false; | |
518 send_stream_2_ = true; | |
519 send_audio_ = false; | |
520 send_video_ = true; | |
521 } | |
522 | |
523 void AddStreamsToOptions(cricket::MediaSessionOptions* session_options) { | |
524 if (send_stream_1_ && send_audio_) { | |
525 session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack1, | |
526 kStream1); | |
527 } | |
528 if (send_stream_1_ && send_video_) { | |
529 session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack1, | |
530 kStream1); | |
531 } | |
532 if (send_stream_2_ && send_audio_) { | |
533 session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, kAudioTrack2, | |
534 kStream2); | |
535 } | |
536 if (send_stream_2_ && send_video_) { | |
537 session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, kVideoTrack2, | |
538 kStream2); | |
539 } | |
540 if (data_channel_ && session_->data_channel_type() == cricket::DCT_RTP) { | |
541 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, | |
542 data_channel_->label(), | |
543 data_channel_->label()); | |
544 } | |
545 } | |
546 | |
547 void GetOptionsForOffer( | |
548 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options, | |
549 cricket::MediaSessionOptions* session_options) { | |
550 ASSERT_TRUE(ConvertRtcOptionsForOffer(rtc_options, session_options)); | |
551 | |
552 AddStreamsToOptions(session_options); | |
553 if (rtc_options.offer_to_receive_audio == | |
554 RTCOfferAnswerOptions::kUndefined) { | |
555 session_options->recv_audio = | |
556 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO); | |
557 } | |
558 if (rtc_options.offer_to_receive_video == | |
559 RTCOfferAnswerOptions::kUndefined) { | |
560 session_options->recv_video = | |
561 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO); | |
562 } | |
563 session_options->bundle_enabled = | |
564 session_options->bundle_enabled && | |
565 (session_options->has_audio() || session_options->has_video() || | |
566 session_options->has_data()); | |
567 | |
568 if (session_->data_channel_type() == cricket::DCT_SCTP && data_channel_) { | |
569 session_options->data_channel_type = cricket::DCT_SCTP; | |
570 } | |
571 } | |
572 | |
573 void GetOptionsForAnswer(const webrtc::MediaConstraintsInterface* constraints, | |
574 cricket::MediaSessionOptions* session_options) { | |
575 session_options->recv_audio = false; | |
576 session_options->recv_video = false; | |
577 ASSERT_TRUE(ParseConstraintsForAnswer(constraints, session_options)); | |
578 | |
579 AddStreamsToOptions(session_options); | |
580 session_options->bundle_enabled = | |
581 session_options->bundle_enabled && | |
582 (session_options->has_audio() || session_options->has_video() || | |
583 session_options->has_data()); | |
584 | |
585 if (session_->data_channel_type() == cricket::DCT_SCTP) { | |
586 session_options->data_channel_type = cricket::DCT_SCTP; | |
587 } | |
588 } | |
589 | |
590 // Creates a local offer and applies it. Starts ICE. | |
591 // Call SendAudioVideoStreamX() before this function | |
592 // to decide which streams to create. | |
593 void InitiateCall() { | |
594 SessionDescriptionInterface* offer = CreateOffer(); | |
595 SetLocalDescriptionWithoutError(offer); | |
596 EXPECT_TRUE_WAIT(PeerConnectionInterface::kIceGatheringNew != | |
597 observer_.ice_gathering_state_, | |
598 kIceCandidatesTimeout); | |
599 } | |
600 | |
601 SessionDescriptionInterface* CreateOffer() { | |
602 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
603 options.offer_to_receive_audio = | |
604 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; | |
605 | |
606 return CreateOffer(options); | |
607 } | |
608 | |
609 SessionDescriptionInterface* CreateOffer( | |
610 const PeerConnectionInterface::RTCOfferAnswerOptions& options) { | |
611 rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> | |
612 observer = new WebRtcSessionCreateSDPObserverForTest(); | |
613 cricket::MediaSessionOptions session_options; | |
614 GetOptionsForOffer(options, &session_options); | |
615 session_->CreateOffer(observer, options, session_options); | |
616 EXPECT_TRUE_WAIT( | |
617 observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit, | |
618 2000); | |
619 return observer->ReleaseDescription(); | |
620 } | |
621 | |
622 SessionDescriptionInterface* CreateAnswer( | |
623 const webrtc::MediaConstraintsInterface* constraints) { | |
624 rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> observer | |
625 = new WebRtcSessionCreateSDPObserverForTest(); | |
626 cricket::MediaSessionOptions session_options; | |
627 GetOptionsForAnswer(constraints, &session_options); | |
628 session_->CreateAnswer(observer, constraints, session_options); | |
629 EXPECT_TRUE_WAIT( | |
630 observer->state() != WebRtcSessionCreateSDPObserverForTest::kInit, | |
631 2000); | |
632 return observer->ReleaseDescription(); | |
633 } | |
634 | |
635 bool ChannelsExist() const { | |
636 return (session_->voice_channel() != NULL && | |
637 session_->video_channel() != NULL); | |
638 } | |
639 | |
640 void VerifyCryptoParams(const cricket::SessionDescription* sdp) { | |
641 ASSERT_TRUE(session_.get() != NULL); | |
642 const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp); | |
643 ASSERT_TRUE(content != NULL); | |
644 const cricket::AudioContentDescription* audio_content = | |
645 static_cast<const cricket::AudioContentDescription*>( | |
646 content->description); | |
647 ASSERT_TRUE(audio_content != NULL); | |
648 ASSERT_EQ(1U, audio_content->cryptos().size()); | |
649 ASSERT_EQ(47U, audio_content->cryptos()[0].key_params.size()); | |
650 ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", | |
651 audio_content->cryptos()[0].cipher_suite); | |
652 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), | |
653 audio_content->protocol()); | |
654 | |
655 content = cricket::GetFirstVideoContent(sdp); | |
656 ASSERT_TRUE(content != NULL); | |
657 const cricket::VideoContentDescription* video_content = | |
658 static_cast<const cricket::VideoContentDescription*>( | |
659 content->description); | |
660 ASSERT_TRUE(video_content != NULL); | |
661 ASSERT_EQ(1U, video_content->cryptos().size()); | |
662 ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", | |
663 video_content->cryptos()[0].cipher_suite); | |
664 ASSERT_EQ(47U, video_content->cryptos()[0].key_params.size()); | |
665 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), | |
666 video_content->protocol()); | |
667 } | |
668 | |
669 void VerifyNoCryptoParams(const cricket::SessionDescription* sdp, bool dtls) { | |
670 const cricket::ContentInfo* content = cricket::GetFirstAudioContent(sdp); | |
671 ASSERT_TRUE(content != NULL); | |
672 const cricket::AudioContentDescription* audio_content = | |
673 static_cast<const cricket::AudioContentDescription*>( | |
674 content->description); | |
675 ASSERT_TRUE(audio_content != NULL); | |
676 ASSERT_EQ(0U, audio_content->cryptos().size()); | |
677 | |
678 content = cricket::GetFirstVideoContent(sdp); | |
679 ASSERT_TRUE(content != NULL); | |
680 const cricket::VideoContentDescription* video_content = | |
681 static_cast<const cricket::VideoContentDescription*>( | |
682 content->description); | |
683 ASSERT_TRUE(video_content != NULL); | |
684 ASSERT_EQ(0U, video_content->cryptos().size()); | |
685 | |
686 if (dtls) { | |
687 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf), | |
688 audio_content->protocol()); | |
689 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf), | |
690 video_content->protocol()); | |
691 } else { | |
692 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), | |
693 audio_content->protocol()); | |
694 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), | |
695 video_content->protocol()); | |
696 } | |
697 } | |
698 | |
699 // Set the internal fake description factories to do DTLS-SRTP. | |
700 void SetFactoryDtlsSrtp() { | |
701 desc_factory_->set_secure(cricket::SEC_DISABLED); | |
702 std::string identity_name = "WebRTC" + | |
703 rtc::ToString(rtc::CreateRandomId()); | |
704 // Confirmed to work with KT_RSA and KT_ECDSA. | |
705 tdesc_factory_->set_certificate( | |
706 rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>( | |
707 rtc::SSLIdentity::Generate(identity_name, rtc::KT_DEFAULT)))); | |
708 tdesc_factory_->set_secure(cricket::SEC_REQUIRED); | |
709 } | |
710 | |
711 void VerifyFingerprintStatus(const cricket::SessionDescription* sdp, | |
712 bool expected) { | |
713 const TransportInfo* audio = sdp->GetTransportInfoByName("audio"); | |
714 ASSERT_TRUE(audio != NULL); | |
715 ASSERT_EQ(expected, audio->description.identity_fingerprint.get() != NULL); | |
716 const TransportInfo* video = sdp->GetTransportInfoByName("video"); | |
717 ASSERT_TRUE(video != NULL); | |
718 ASSERT_EQ(expected, video->description.identity_fingerprint.get() != NULL); | |
719 } | |
720 | |
721 void VerifyAnswerFromNonCryptoOffer() { | |
722 // Create an SDP without Crypto. | |
723 cricket::MediaSessionOptions options; | |
724 options.recv_video = true; | |
725 JsepSessionDescription* offer( | |
726 CreateRemoteOffer(options, cricket::SEC_DISABLED)); | |
727 ASSERT_TRUE(offer != NULL); | |
728 VerifyNoCryptoParams(offer->description(), false); | |
729 SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, | |
730 offer); | |
731 const webrtc::SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
732 // Answer should be NULL as no crypto params in offer. | |
733 ASSERT_TRUE(answer == NULL); | |
734 } | |
735 | |
736 void VerifyAnswerFromCryptoOffer() { | |
737 cricket::MediaSessionOptions options; | |
738 options.recv_video = true; | |
739 options.bundle_enabled = true; | |
740 scoped_ptr<JsepSessionDescription> offer( | |
741 CreateRemoteOffer(options, cricket::SEC_REQUIRED)); | |
742 ASSERT_TRUE(offer.get() != NULL); | |
743 VerifyCryptoParams(offer->description()); | |
744 SetRemoteDescriptionWithoutError(offer.release()); | |
745 scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); | |
746 ASSERT_TRUE(answer.get() != NULL); | |
747 VerifyCryptoParams(answer->description()); | |
748 } | |
749 | |
750 void CompareIceUfragAndPassword(const cricket::SessionDescription* desc1, | |
751 const cricket::SessionDescription* desc2, | |
752 bool expect_equal) { | |
753 if (desc1->contents().size() != desc2->contents().size()) { | |
754 EXPECT_FALSE(expect_equal); | |
755 return; | |
756 } | |
757 | |
758 const cricket::ContentInfos& contents = desc1->contents(); | |
759 cricket::ContentInfos::const_iterator it = contents.begin(); | |
760 | |
761 for (; it != contents.end(); ++it) { | |
762 const cricket::TransportDescription* transport_desc1 = | |
763 desc1->GetTransportDescriptionByName(it->name); | |
764 const cricket::TransportDescription* transport_desc2 = | |
765 desc2->GetTransportDescriptionByName(it->name); | |
766 if (!transport_desc1 || !transport_desc2) { | |
767 EXPECT_FALSE(expect_equal); | |
768 return; | |
769 } | |
770 if (transport_desc1->ice_pwd != transport_desc2->ice_pwd || | |
771 transport_desc1->ice_ufrag != transport_desc2->ice_ufrag) { | |
772 EXPECT_FALSE(expect_equal); | |
773 return; | |
774 } | |
775 } | |
776 EXPECT_TRUE(expect_equal); | |
777 } | |
778 | |
779 void RemoveIceUfragPwdLines(const SessionDescriptionInterface* current_desc, | |
780 std::string *sdp) { | |
781 const cricket::SessionDescription* desc = current_desc->description(); | |
782 EXPECT_TRUE(current_desc->ToString(sdp)); | |
783 | |
784 const cricket::ContentInfos& contents = desc->contents(); | |
785 cricket::ContentInfos::const_iterator it = contents.begin(); | |
786 // Replace ufrag and pwd lines with empty strings. | |
787 for (; it != contents.end(); ++it) { | |
788 const cricket::TransportDescription* transport_desc = | |
789 desc->GetTransportDescriptionByName(it->name); | |
790 std::string ufrag_line = "a=ice-ufrag:" + transport_desc->ice_ufrag | |
791 + "\r\n"; | |
792 std::string pwd_line = "a=ice-pwd:" + transport_desc->ice_pwd | |
793 + "\r\n"; | |
794 rtc::replace_substrs(ufrag_line.c_str(), ufrag_line.length(), | |
795 "", 0, | |
796 sdp); | |
797 rtc::replace_substrs(pwd_line.c_str(), pwd_line.length(), | |
798 "", 0, | |
799 sdp); | |
800 } | |
801 } | |
802 | |
803 void ModifyIceUfragPwdLines(const SessionDescriptionInterface* current_desc, | |
804 const std::string& modified_ice_ufrag, | |
805 const std::string& modified_ice_pwd, | |
806 std::string* sdp) { | |
807 const cricket::SessionDescription* desc = current_desc->description(); | |
808 EXPECT_TRUE(current_desc->ToString(sdp)); | |
809 | |
810 const cricket::ContentInfos& contents = desc->contents(); | |
811 cricket::ContentInfos::const_iterator it = contents.begin(); | |
812 // Replace ufrag and pwd lines with |modified_ice_ufrag| and | |
813 // |modified_ice_pwd| strings. | |
814 for (; it != contents.end(); ++it) { | |
815 const cricket::TransportDescription* transport_desc = | |
816 desc->GetTransportDescriptionByName(it->name); | |
817 std::string ufrag_line = "a=ice-ufrag:" + transport_desc->ice_ufrag | |
818 + "\r\n"; | |
819 std::string pwd_line = "a=ice-pwd:" + transport_desc->ice_pwd | |
820 + "\r\n"; | |
821 std::string mod_ufrag = "a=ice-ufrag:" + modified_ice_ufrag + "\r\n"; | |
822 std::string mod_pwd = "a=ice-pwd:" + modified_ice_pwd + "\r\n"; | |
823 rtc::replace_substrs(ufrag_line.c_str(), ufrag_line.length(), | |
824 mod_ufrag.c_str(), mod_ufrag.length(), | |
825 sdp); | |
826 rtc::replace_substrs(pwd_line.c_str(), pwd_line.length(), | |
827 mod_pwd.c_str(), mod_pwd.length(), | |
828 sdp); | |
829 } | |
830 } | |
831 | |
832 // Creates a remote offer and and applies it as a remote description, | |
833 // creates a local answer and applies is as a local description. | |
834 // Call SendAudioVideoStreamX() before this function | |
835 // to decide which local and remote streams to create. | |
836 void CreateAndSetRemoteOfferAndLocalAnswer() { | |
837 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
838 SetRemoteDescriptionWithoutError(offer); | |
839 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
840 SetLocalDescriptionWithoutError(answer); | |
841 } | |
842 void SetLocalDescriptionWithoutError(SessionDescriptionInterface* desc) { | |
843 EXPECT_TRUE(session_->SetLocalDescription(desc, NULL)); | |
844 session_->MaybeStartGathering(); | |
845 } | |
846 void SetLocalDescriptionExpectState(SessionDescriptionInterface* desc, | |
847 WebRtcSession::State expected_state) { | |
848 SetLocalDescriptionWithoutError(desc); | |
849 EXPECT_EQ(expected_state, session_->state()); | |
850 } | |
851 void SetLocalDescriptionExpectError(const std::string& action, | |
852 const std::string& expected_error, | |
853 SessionDescriptionInterface* desc) { | |
854 std::string error; | |
855 EXPECT_FALSE(session_->SetLocalDescription(desc, &error)); | |
856 std::string sdp_type = "local "; | |
857 sdp_type.append(action); | |
858 EXPECT_NE(std::string::npos, error.find(sdp_type)); | |
859 EXPECT_NE(std::string::npos, error.find(expected_error)); | |
860 } | |
861 void SetLocalDescriptionOfferExpectError(const std::string& expected_error, | |
862 SessionDescriptionInterface* desc) { | |
863 SetLocalDescriptionExpectError(SessionDescriptionInterface::kOffer, | |
864 expected_error, desc); | |
865 } | |
866 void SetLocalDescriptionAnswerExpectError(const std::string& expected_error, | |
867 SessionDescriptionInterface* desc) { | |
868 SetLocalDescriptionExpectError(SessionDescriptionInterface::kAnswer, | |
869 expected_error, desc); | |
870 } | |
871 void SetRemoteDescriptionWithoutError(SessionDescriptionInterface* desc) { | |
872 EXPECT_TRUE(session_->SetRemoteDescription(desc, NULL)); | |
873 } | |
874 void SetRemoteDescriptionExpectState(SessionDescriptionInterface* desc, | |
875 WebRtcSession::State expected_state) { | |
876 SetRemoteDescriptionWithoutError(desc); | |
877 EXPECT_EQ(expected_state, session_->state()); | |
878 } | |
879 void SetRemoteDescriptionExpectError(const std::string& action, | |
880 const std::string& expected_error, | |
881 SessionDescriptionInterface* desc) { | |
882 std::string error; | |
883 EXPECT_FALSE(session_->SetRemoteDescription(desc, &error)); | |
884 std::string sdp_type = "remote "; | |
885 sdp_type.append(action); | |
886 EXPECT_NE(std::string::npos, error.find(sdp_type)); | |
887 EXPECT_NE(std::string::npos, error.find(expected_error)); | |
888 } | |
889 void SetRemoteDescriptionOfferExpectError( | |
890 const std::string& expected_error, SessionDescriptionInterface* desc) { | |
891 SetRemoteDescriptionExpectError(SessionDescriptionInterface::kOffer, | |
892 expected_error, desc); | |
893 } | |
894 void SetRemoteDescriptionPranswerExpectError( | |
895 const std::string& expected_error, SessionDescriptionInterface* desc) { | |
896 SetRemoteDescriptionExpectError(SessionDescriptionInterface::kPrAnswer, | |
897 expected_error, desc); | |
898 } | |
899 void SetRemoteDescriptionAnswerExpectError( | |
900 const std::string& expected_error, SessionDescriptionInterface* desc) { | |
901 SetRemoteDescriptionExpectError(SessionDescriptionInterface::kAnswer, | |
902 expected_error, desc); | |
903 } | |
904 | |
905 void CreateCryptoOfferAndNonCryptoAnswer(SessionDescriptionInterface** offer, | |
906 SessionDescriptionInterface** nocrypto_answer) { | |
907 // Create a SDP without Crypto. | |
908 cricket::MediaSessionOptions options; | |
909 options.recv_video = true; | |
910 options.bundle_enabled = true; | |
911 *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED); | |
912 ASSERT_TRUE(*offer != NULL); | |
913 VerifyCryptoParams((*offer)->description()); | |
914 | |
915 *nocrypto_answer = CreateRemoteAnswer(*offer, options, | |
916 cricket::SEC_DISABLED); | |
917 EXPECT_TRUE(*nocrypto_answer != NULL); | |
918 } | |
919 | |
920 void CreateDtlsOfferAndNonDtlsAnswer(SessionDescriptionInterface** offer, | |
921 SessionDescriptionInterface** nodtls_answer) { | |
922 cricket::MediaSessionOptions options; | |
923 options.recv_video = true; | |
924 options.bundle_enabled = true; | |
925 | |
926 rtc::scoped_ptr<SessionDescriptionInterface> temp_offer( | |
927 CreateRemoteOffer(options, cricket::SEC_ENABLED)); | |
928 | |
929 *nodtls_answer = | |
930 CreateRemoteAnswer(temp_offer.get(), options, cricket::SEC_ENABLED); | |
931 EXPECT_TRUE(*nodtls_answer != NULL); | |
932 VerifyFingerprintStatus((*nodtls_answer)->description(), false); | |
933 VerifyCryptoParams((*nodtls_answer)->description()); | |
934 | |
935 SetFactoryDtlsSrtp(); | |
936 *offer = CreateRemoteOffer(options, cricket::SEC_ENABLED); | |
937 ASSERT_TRUE(*offer != NULL); | |
938 VerifyFingerprintStatus((*offer)->description(), true); | |
939 VerifyCryptoParams((*offer)->description()); | |
940 } | |
941 | |
942 JsepSessionDescription* CreateRemoteOfferWithVersion( | |
943 cricket::MediaSessionOptions options, | |
944 cricket::SecurePolicy secure_policy, | |
945 const std::string& session_version, | |
946 const SessionDescriptionInterface* current_desc) { | |
947 std::string session_id = rtc::ToString(rtc::CreateRandomId64()); | |
948 const cricket::SessionDescription* cricket_desc = NULL; | |
949 if (current_desc) { | |
950 cricket_desc = current_desc->description(); | |
951 session_id = current_desc->session_id(); | |
952 } | |
953 | |
954 desc_factory_->set_secure(secure_policy); | |
955 JsepSessionDescription* offer( | |
956 new JsepSessionDescription(JsepSessionDescription::kOffer)); | |
957 if (!offer->Initialize(desc_factory_->CreateOffer(options, cricket_desc), | |
958 session_id, session_version)) { | |
959 delete offer; | |
960 offer = NULL; | |
961 } | |
962 return offer; | |
963 } | |
964 JsepSessionDescription* CreateRemoteOffer( | |
965 cricket::MediaSessionOptions options) { | |
966 return CreateRemoteOfferWithVersion(options, cricket::SEC_ENABLED, | |
967 kSessionVersion, NULL); | |
968 } | |
969 JsepSessionDescription* CreateRemoteOffer( | |
970 cricket::MediaSessionOptions options, cricket::SecurePolicy sdes_policy) { | |
971 return CreateRemoteOfferWithVersion( | |
972 options, sdes_policy, kSessionVersion, NULL); | |
973 } | |
974 JsepSessionDescription* CreateRemoteOffer( | |
975 cricket::MediaSessionOptions options, | |
976 const SessionDescriptionInterface* current_desc) { | |
977 return CreateRemoteOfferWithVersion(options, cricket::SEC_ENABLED, | |
978 kSessionVersion, current_desc); | |
979 } | |
980 | |
981 JsepSessionDescription* CreateRemoteOfferWithSctpPort( | |
982 const char* sctp_stream_name, int new_port, | |
983 cricket::MediaSessionOptions options) { | |
984 options.data_channel_type = cricket::DCT_SCTP; | |
985 options.AddSendStream(cricket::MEDIA_TYPE_DATA, "datachannel", | |
986 sctp_stream_name); | |
987 return ChangeSDPSctpPort(new_port, CreateRemoteOffer(options)); | |
988 } | |
989 | |
990 // Takes ownership of offer_basis (and deletes it). | |
991 JsepSessionDescription* ChangeSDPSctpPort( | |
992 int new_port, webrtc::SessionDescriptionInterface *offer_basis) { | |
993 // Stringify the input SDP, swap the 5000 for 'new_port' and create a new | |
994 // SessionDescription from the mutated string. | |
995 const char* default_port_str = "5000"; | |
996 char new_port_str[16]; | |
997 rtc::sprintfn(new_port_str, sizeof(new_port_str), "%d", new_port); | |
998 std::string offer_str; | |
999 offer_basis->ToString(&offer_str); | |
1000 rtc::replace_substrs(default_port_str, strlen(default_port_str), | |
1001 new_port_str, strlen(new_port_str), | |
1002 &offer_str); | |
1003 JsepSessionDescription* offer = new JsepSessionDescription( | |
1004 offer_basis->type()); | |
1005 delete offer_basis; | |
1006 offer->Initialize(offer_str, NULL); | |
1007 return offer; | |
1008 } | |
1009 | |
1010 // Create a remote offer. Call SendAudioVideoStreamX() | |
1011 // before this function to decide which streams to create. | |
1012 JsepSessionDescription* CreateRemoteOffer() { | |
1013 cricket::MediaSessionOptions options; | |
1014 GetOptionsForAnswer(NULL, &options); | |
1015 return CreateRemoteOffer(options, session_->remote_description()); | |
1016 } | |
1017 | |
1018 JsepSessionDescription* CreateRemoteAnswer( | |
1019 const SessionDescriptionInterface* offer, | |
1020 cricket::MediaSessionOptions options, | |
1021 cricket::SecurePolicy policy) { | |
1022 desc_factory_->set_secure(policy); | |
1023 const std::string session_id = | |
1024 rtc::ToString(rtc::CreateRandomId64()); | |
1025 JsepSessionDescription* answer( | |
1026 new JsepSessionDescription(JsepSessionDescription::kAnswer)); | |
1027 if (!answer->Initialize(desc_factory_->CreateAnswer(offer->description(), | |
1028 options, NULL), | |
1029 session_id, kSessionVersion)) { | |
1030 delete answer; | |
1031 answer = NULL; | |
1032 } | |
1033 return answer; | |
1034 } | |
1035 | |
1036 JsepSessionDescription* CreateRemoteAnswer( | |
1037 const SessionDescriptionInterface* offer, | |
1038 cricket::MediaSessionOptions options) { | |
1039 return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED); | |
1040 } | |
1041 | |
1042 // Creates an answer session description. | |
1043 // Call SendAudioVideoStreamX() before this function | |
1044 // to decide which streams to create. | |
1045 JsepSessionDescription* CreateRemoteAnswer( | |
1046 const SessionDescriptionInterface* offer) { | |
1047 cricket::MediaSessionOptions options; | |
1048 GetOptionsForAnswer(NULL, &options); | |
1049 return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED); | |
1050 } | |
1051 | |
1052 void TestSessionCandidatesWithBundleRtcpMux(bool bundle, bool rtcp_mux) { | |
1053 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1054 Init(); | |
1055 SendAudioVideoStream1(); | |
1056 | |
1057 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
1058 options.use_rtp_mux = bundle; | |
1059 | |
1060 SessionDescriptionInterface* offer = CreateOffer(options); | |
1061 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer | |
1062 // and answer. | |
1063 SetLocalDescriptionWithoutError(offer); | |
1064 | |
1065 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
1066 CreateRemoteAnswer(session_->local_description())); | |
1067 std::string sdp; | |
1068 EXPECT_TRUE(answer->ToString(&sdp)); | |
1069 | |
1070 size_t expected_candidate_num = 2; | |
1071 if (!rtcp_mux) { | |
1072 // If rtcp_mux is enabled we should expect 4 candidates - host and srflex | |
1073 // for rtp and rtcp. | |
1074 expected_candidate_num = 4; | |
1075 // Disable rtcp-mux from the answer | |
1076 const std::string kRtcpMux = "a=rtcp-mux"; | |
1077 const std::string kXRtcpMux = "a=xrtcp-mux"; | |
1078 rtc::replace_substrs(kRtcpMux.c_str(), kRtcpMux.length(), | |
1079 kXRtcpMux.c_str(), kXRtcpMux.length(), | |
1080 &sdp); | |
1081 } | |
1082 | |
1083 SessionDescriptionInterface* new_answer = CreateSessionDescription( | |
1084 JsepSessionDescription::kAnswer, sdp, NULL); | |
1085 | |
1086 // SetRemoteDescription to enable rtcp mux. | |
1087 SetRemoteDescriptionWithoutError(new_answer); | |
1088 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1089 EXPECT_EQ(expected_candidate_num, observer_.mline_0_candidates_.size()); | |
1090 if (bundle) { | |
1091 EXPECT_EQ(0, observer_.mline_1_candidates_.size()); | |
1092 } else { | |
1093 EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size()); | |
1094 } | |
1095 } | |
1096 // Tests that we can only send DTMF when the dtmf codec is supported. | |
1097 void TestCanInsertDtmf(bool can) { | |
1098 if (can) { | |
1099 InitWithDtmfCodec(); | |
1100 } else { | |
1101 Init(); | |
1102 } | |
1103 SendAudioVideoStream1(); | |
1104 CreateAndSetRemoteOfferAndLocalAnswer(); | |
1105 EXPECT_FALSE(session_->CanInsertDtmf("")); | |
1106 EXPECT_EQ(can, session_->CanInsertDtmf(kAudioTrack1)); | |
1107 } | |
1108 | |
1109 // Helper class to configure loopback network and verify Best | |
1110 // Connection using right IP protocol for TestLoopbackCall | |
1111 // method. LoopbackNetworkManager applies firewall rules to block | |
1112 // all ping traffic once ICE completed, and remove them to observe | |
1113 // ICE reconnected again. This LoopbackNetworkConfiguration struct | |
1114 // verifies the best connection is using the right IP protocol after | |
1115 // initial ICE convergences. | |
1116 | |
1117 class LoopbackNetworkConfiguration { | |
1118 public: | |
1119 LoopbackNetworkConfiguration() | |
1120 : test_ipv6_network_(false), | |
1121 test_extra_ipv4_network_(false), | |
1122 best_connection_after_initial_ice_converged_(1, 0) {} | |
1123 | |
1124 // Used to track the expected best connection count in each IP protocol. | |
1125 struct ExpectedBestConnection { | |
1126 ExpectedBestConnection(int ipv4_count, int ipv6_count) | |
1127 : ipv4_count_(ipv4_count), | |
1128 ipv6_count_(ipv6_count) {} | |
1129 | |
1130 int ipv4_count_; | |
1131 int ipv6_count_; | |
1132 }; | |
1133 | |
1134 bool test_ipv6_network_; | |
1135 bool test_extra_ipv4_network_; | |
1136 ExpectedBestConnection best_connection_after_initial_ice_converged_; | |
1137 | |
1138 void VerifyBestConnectionAfterIceConverge( | |
1139 const rtc::scoped_refptr<FakeMetricsObserver> metrics_observer) const { | |
1140 Verify(metrics_observer, best_connection_after_initial_ice_converged_); | |
1141 } | |
1142 | |
1143 private: | |
1144 void Verify(const rtc::scoped_refptr<FakeMetricsObserver> metrics_observer, | |
1145 const ExpectedBestConnection& expected) const { | |
1146 EXPECT_EQ( | |
1147 metrics_observer->GetEnumCounter(webrtc::kEnumCounterAddressFamily, | |
1148 webrtc::kBestConnections_IPv4), | |
1149 expected.ipv4_count_); | |
1150 EXPECT_EQ( | |
1151 metrics_observer->GetEnumCounter(webrtc::kEnumCounterAddressFamily, | |
1152 webrtc::kBestConnections_IPv6), | |
1153 expected.ipv6_count_); | |
1154 // This is used in the loopback call so there is only single host to host | |
1155 // candidate pair. | |
1156 EXPECT_EQ(metrics_observer->GetEnumCounter( | |
1157 webrtc::kEnumCounterIceCandidatePairTypeUdp, | |
1158 webrtc::kIceCandidatePairHostHost), | |
1159 0); | |
1160 EXPECT_EQ(metrics_observer->GetEnumCounter( | |
1161 webrtc::kEnumCounterIceCandidatePairTypeUdp, | |
1162 webrtc::kIceCandidatePairHostPublicHostPublic), | |
1163 1); | |
1164 } | |
1165 }; | |
1166 | |
1167 class LoopbackNetworkManager { | |
1168 public: | |
1169 LoopbackNetworkManager(WebRtcSessionTest* session, | |
1170 const LoopbackNetworkConfiguration& config) | |
1171 : config_(config) { | |
1172 session->AddInterface( | |
1173 rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1174 if (config_.test_extra_ipv4_network_) { | |
1175 session->AddInterface( | |
1176 rtc::SocketAddress(kClientAddrHost2, kClientAddrPort)); | |
1177 } | |
1178 if (config_.test_ipv6_network_) { | |
1179 session->AddInterface( | |
1180 rtc::SocketAddress(kClientIPv6AddrHost1, kClientAddrPort)); | |
1181 } | |
1182 } | |
1183 | |
1184 void ApplyFirewallRules(rtc::FirewallSocketServer* fss) { | |
1185 fss->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, | |
1186 rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1187 if (config_.test_extra_ipv4_network_) { | |
1188 fss->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, | |
1189 rtc::SocketAddress(kClientAddrHost2, kClientAddrPort)); | |
1190 } | |
1191 if (config_.test_ipv6_network_) { | |
1192 fss->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, | |
1193 rtc::SocketAddress(kClientIPv6AddrHost1, kClientAddrPort)); | |
1194 } | |
1195 } | |
1196 | |
1197 void ClearRules(rtc::FirewallSocketServer* fss) { fss->ClearRules(); } | |
1198 | |
1199 private: | |
1200 LoopbackNetworkConfiguration config_; | |
1201 }; | |
1202 | |
1203 // The method sets up a call from the session to itself, in a loopback | |
1204 // arrangement. It also uses a firewall rule to create a temporary | |
1205 // disconnection, and then a permanent disconnection. | |
1206 // This code is placed in a method so that it can be invoked | |
1207 // by multiple tests with different allocators (e.g. with and without BUNDLE). | |
1208 // While running the call, this method also checks if the session goes through | |
1209 // the correct sequence of ICE states when a connection is established, | |
1210 // broken, and re-established. | |
1211 // The Connection state should go: | |
1212 // New -> Checking -> (Connected) -> Completed -> Disconnected -> Completed | |
1213 // -> Failed. | |
1214 // The Gathering state should go: New -> Gathering -> Completed. | |
1215 | |
1216 void SetupLoopbackCall() { | |
1217 Init(); | |
1218 SendAudioVideoStream1(); | |
1219 SessionDescriptionInterface* offer = CreateOffer(); | |
1220 | |
1221 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew, | |
1222 observer_.ice_gathering_state_); | |
1223 SetLocalDescriptionWithoutError(offer); | |
1224 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew, | |
1225 observer_.ice_connection_state_); | |
1226 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringGathering, | |
1227 observer_.ice_gathering_state_, kIceCandidatesTimeout); | |
1228 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1229 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete, | |
1230 observer_.ice_gathering_state_, kIceCandidatesTimeout); | |
1231 | |
1232 std::string sdp; | |
1233 offer->ToString(&sdp); | |
1234 SessionDescriptionInterface* desc = webrtc::CreateSessionDescription( | |
1235 JsepSessionDescription::kAnswer, sdp, nullptr); | |
1236 ASSERT_TRUE(desc != NULL); | |
1237 SetRemoteDescriptionWithoutError(desc); | |
1238 | |
1239 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking, | |
1240 observer_.ice_connection_state_, kIceCandidatesTimeout); | |
1241 | |
1242 // The ice connection state is "Connected" too briefly to catch in a test. | |
1243 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted, | |
1244 observer_.ice_connection_state_, kIceCandidatesTimeout); | |
1245 } | |
1246 | |
1247 void TestLoopbackCall(const LoopbackNetworkConfiguration& config) { | |
1248 LoopbackNetworkManager loopback_network_manager(this, config); | |
1249 SetupLoopbackCall(); | |
1250 config.VerifyBestConnectionAfterIceConverge(metrics_observer_); | |
1251 // Adding firewall rule to block ping requests, which should cause | |
1252 // transport channel failure. | |
1253 | |
1254 loopback_network_manager.ApplyFirewallRules(fss_.get()); | |
1255 | |
1256 LOG(LS_INFO) << "Firewall Rules applied"; | |
1257 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected, | |
1258 observer_.ice_connection_state_, | |
1259 kIceCandidatesTimeout); | |
1260 | |
1261 metrics_observer_->Reset(); | |
1262 | |
1263 // Clearing the rules, session should move back to completed state. | |
1264 loopback_network_manager.ClearRules(fss_.get()); | |
1265 | |
1266 LOG(LS_INFO) << "Firewall Rules cleared"; | |
1267 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted, | |
1268 observer_.ice_connection_state_, | |
1269 kIceCandidatesTimeout); | |
1270 | |
1271 // Now we block ping requests and wait until the ICE connection transitions | |
1272 // to the Failed state. This will take at least 30 seconds because it must | |
1273 // wait for the Port to timeout. | |
1274 int port_timeout = 30000; | |
1275 | |
1276 loopback_network_manager.ApplyFirewallRules(fss_.get()); | |
1277 LOG(LS_INFO) << "Firewall Rules applied again"; | |
1278 EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected, | |
1279 observer_.ice_connection_state_, | |
1280 kIceCandidatesTimeout + port_timeout); | |
1281 } | |
1282 | |
1283 void TestLoopbackCall() { | |
1284 LoopbackNetworkConfiguration config; | |
1285 TestLoopbackCall(config); | |
1286 } | |
1287 | |
1288 void TestPacketOptions() { | |
1289 media_controller_.reset( | |
1290 new cricket::FakeMediaController(channel_manager_.get(), &fake_call_)); | |
1291 LoopbackNetworkConfiguration config; | |
1292 LoopbackNetworkManager loopback_network_manager(this, config); | |
1293 | |
1294 SetupLoopbackCall(); | |
1295 | |
1296 uint8_t test_packet[15] = {0}; | |
1297 rtc::PacketOptions options; | |
1298 options.packet_id = 10; | |
1299 media_engine_->GetVideoChannel(0) | |
1300 ->SendRtp(test_packet, sizeof(test_packet), options); | |
1301 | |
1302 const int kPacketTimeout = 2000; | |
1303 EXPECT_EQ_WAIT(fake_call_.last_sent_packet().packet_id, 10, kPacketTimeout); | |
1304 EXPECT_GT(fake_call_.last_sent_packet().send_time_ms, -1); | |
1305 } | |
1306 | |
1307 // Adds CN codecs to FakeMediaEngine and MediaDescriptionFactory. | |
1308 void AddCNCodecs() { | |
1309 const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1, 0); | |
1310 const cricket::AudioCodec kCNCodec2(103, "CN", 16000, 0, 1, 0); | |
1311 | |
1312 // Add kCNCodec for dtmf test. | |
1313 std::vector<cricket::AudioCodec> codecs = media_engine_->audio_codecs();; | |
1314 codecs.push_back(kCNCodec1); | |
1315 codecs.push_back(kCNCodec2); | |
1316 media_engine_->SetAudioCodecs(codecs); | |
1317 desc_factory_->set_audio_codecs(codecs); | |
1318 } | |
1319 | |
1320 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) { | |
1321 const cricket::ContentDescription* description = content->description; | |
1322 ASSERT(description != NULL); | |
1323 const cricket::AudioContentDescription* audio_content_desc = | |
1324 static_cast<const cricket::AudioContentDescription*>(description); | |
1325 ASSERT(audio_content_desc != NULL); | |
1326 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) { | |
1327 if (audio_content_desc->codecs()[i].name == "CN") | |
1328 return false; | |
1329 } | |
1330 return true; | |
1331 } | |
1332 | |
1333 void CreateDataChannel() { | |
1334 webrtc::InternalDataChannelInit dci; | |
1335 dci.reliable = session_->data_channel_type() == cricket::DCT_SCTP; | |
1336 data_channel_ = DataChannel::Create( | |
1337 session_.get(), session_->data_channel_type(), "datachannel", dci); | |
1338 } | |
1339 | |
1340 void SetLocalDescriptionWithDataChannel() { | |
1341 CreateDataChannel(); | |
1342 SessionDescriptionInterface* offer = CreateOffer(); | |
1343 SetLocalDescriptionWithoutError(offer); | |
1344 } | |
1345 | |
1346 void VerifyMultipleAsyncCreateDescription( | |
1347 RTCCertificateGenerationMethod cert_gen_method, | |
1348 CreateSessionDescriptionRequest::Type type) { | |
1349 InitWithDtls(cert_gen_method); | |
1350 VerifyMultipleAsyncCreateDescriptionAfterInit(true, type); | |
1351 } | |
1352 | |
1353 void VerifyMultipleAsyncCreateDescriptionIdentityGenFailure( | |
1354 CreateSessionDescriptionRequest::Type type) { | |
1355 InitWithDtlsIdentityGenFail(); | |
1356 VerifyMultipleAsyncCreateDescriptionAfterInit(false, type); | |
1357 } | |
1358 | |
1359 void VerifyMultipleAsyncCreateDescriptionAfterInit( | |
1360 bool success, CreateSessionDescriptionRequest::Type type) { | |
1361 RTC_CHECK(session_); | |
1362 SetFactoryDtlsSrtp(); | |
1363 if (type == CreateSessionDescriptionRequest::kAnswer) { | |
1364 cricket::MediaSessionOptions options; | |
1365 scoped_ptr<JsepSessionDescription> offer( | |
1366 CreateRemoteOffer(options, cricket::SEC_DISABLED)); | |
1367 ASSERT_TRUE(offer.get() != NULL); | |
1368 SetRemoteDescriptionWithoutError(offer.release()); | |
1369 } | |
1370 | |
1371 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
1372 cricket::MediaSessionOptions session_options; | |
1373 const int kNumber = 3; | |
1374 rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> | |
1375 observers[kNumber]; | |
1376 for (int i = 0; i < kNumber; ++i) { | |
1377 observers[i] = new WebRtcSessionCreateSDPObserverForTest(); | |
1378 if (type == CreateSessionDescriptionRequest::kOffer) { | |
1379 session_->CreateOffer(observers[i], options, session_options); | |
1380 } else { | |
1381 session_->CreateAnswer(observers[i], nullptr, session_options); | |
1382 } | |
1383 } | |
1384 | |
1385 WebRtcSessionCreateSDPObserverForTest::State expected_state = | |
1386 success ? WebRtcSessionCreateSDPObserverForTest::kSucceeded : | |
1387 WebRtcSessionCreateSDPObserverForTest::kFailed; | |
1388 | |
1389 for (int i = 0; i < kNumber; ++i) { | |
1390 EXPECT_EQ_WAIT(expected_state, observers[i]->state(), 1000); | |
1391 if (success) { | |
1392 EXPECT_TRUE(observers[i]->description() != NULL); | |
1393 } else { | |
1394 EXPECT_TRUE(observers[i]->description() == NULL); | |
1395 } | |
1396 } | |
1397 } | |
1398 | |
1399 void ConfigureAllocatorWithTurn() { | |
1400 cricket::RelayServerConfig turn_server(cricket::RELAY_TURN); | |
1401 cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); | |
1402 turn_server.credentials = credentials; | |
1403 turn_server.ports.push_back( | |
1404 cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP, false)); | |
1405 allocator_->AddTurnServer(turn_server); | |
1406 allocator_->set_step_delay(cricket::kMinimumStepDelay); | |
1407 allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP); | |
1408 } | |
1409 | |
1410 cricket::FakeMediaEngine* media_engine_; | |
1411 cricket::FakeDataEngine* data_engine_; | |
1412 rtc::scoped_ptr<cricket::ChannelManager> channel_manager_; | |
1413 cricket::FakeCall fake_call_; | |
1414 rtc::scoped_ptr<webrtc::MediaControllerInterface> media_controller_; | |
1415 rtc::scoped_ptr<cricket::TransportDescriptionFactory> tdesc_factory_; | |
1416 rtc::scoped_ptr<cricket::MediaSessionDescriptionFactory> desc_factory_; | |
1417 rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; | |
1418 rtc::scoped_ptr<rtc::VirtualSocketServer> vss_; | |
1419 rtc::scoped_ptr<rtc::FirewallSocketServer> fss_; | |
1420 rtc::SocketServerScope ss_scope_; | |
1421 rtc::SocketAddress stun_socket_addr_; | |
1422 rtc::scoped_ptr<cricket::TestStunServer> stun_server_; | |
1423 cricket::TestTurnServer turn_server_; | |
1424 rtc::FakeNetworkManager network_manager_; | |
1425 rtc::scoped_ptr<cricket::BasicPortAllocator> allocator_; | |
1426 PeerConnectionFactoryInterface::Options options_; | |
1427 rtc::scoped_ptr<FakeConstraints> constraints_; | |
1428 rtc::scoped_ptr<WebRtcSessionForTest> session_; | |
1429 MockIceObserver observer_; | |
1430 cricket::FakeVideoMediaChannel* video_channel_; | |
1431 cricket::FakeVoiceMediaChannel* voice_channel_; | |
1432 rtc::scoped_refptr<FakeMetricsObserver> metrics_observer_; | |
1433 // The following flags affect options created for CreateOffer/CreateAnswer. | |
1434 bool send_stream_1_ = false; | |
1435 bool send_stream_2_ = false; | |
1436 bool send_audio_ = false; | |
1437 bool send_video_ = false; | |
1438 rtc::scoped_refptr<DataChannel> data_channel_; | |
1439 // Last values received from data channel creation signal. | |
1440 std::string last_data_channel_label_; | |
1441 InternalDataChannelInit last_data_channel_config_; | |
1442 bool session_destroyed_ = false; | |
1443 }; | |
1444 | |
1445 TEST_P(WebRtcSessionTest, TestInitializeWithDtls) { | |
1446 InitWithDtls(GetParam()); | |
1447 // SDES is disabled when DTLS is on. | |
1448 EXPECT_EQ(cricket::SEC_DISABLED, session_->SdesPolicy()); | |
1449 } | |
1450 | |
1451 TEST_F(WebRtcSessionTest, TestInitializeWithoutDtls) { | |
1452 Init(); | |
1453 // SDES is required if DTLS is off. | |
1454 EXPECT_EQ(cricket::SEC_REQUIRED, session_->SdesPolicy()); | |
1455 } | |
1456 | |
1457 TEST_F(WebRtcSessionTest, TestSessionCandidates) { | |
1458 TestSessionCandidatesWithBundleRtcpMux(false, false); | |
1459 } | |
1460 | |
1461 // Below test cases (TestSessionCandidatesWith*) verify the candidates gathered | |
1462 // with rtcp-mux and/or bundle. | |
1463 TEST_F(WebRtcSessionTest, TestSessionCandidatesWithRtcpMux) { | |
1464 TestSessionCandidatesWithBundleRtcpMux(false, true); | |
1465 } | |
1466 | |
1467 TEST_F(WebRtcSessionTest, TestSessionCandidatesWithBundleRtcpMux) { | |
1468 TestSessionCandidatesWithBundleRtcpMux(true, true); | |
1469 } | |
1470 | |
1471 TEST_F(WebRtcSessionTest, TestMultihomeCandidates) { | |
1472 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1473 AddInterface(rtc::SocketAddress(kClientAddrHost2, kClientAddrPort)); | |
1474 Init(); | |
1475 SendAudioVideoStream1(); | |
1476 InitiateCall(); | |
1477 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1478 EXPECT_EQ(8u, observer_.mline_0_candidates_.size()); | |
1479 EXPECT_EQ(8u, observer_.mline_1_candidates_.size()); | |
1480 } | |
1481 | |
1482 // Crashes on Win only. See webrtc:5411. | |
1483 #if defined(WEBRTC_WIN) | |
1484 #define MAYBE_TestStunError DISABLED_TestStunError | |
1485 #else | |
1486 #define MAYBE_TestStunError TestStunError | |
1487 #endif | |
1488 TEST_F(WebRtcSessionTest, MAYBE_TestStunError) { | |
1489 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1490 AddInterface(rtc::SocketAddress(kClientAddrHost2, kClientAddrPort)); | |
1491 fss_->AddRule(false, | |
1492 rtc::FP_UDP, | |
1493 rtc::FD_ANY, | |
1494 rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1495 Init(); | |
1496 SendAudioVideoStream1(); | |
1497 InitiateCall(); | |
1498 // Since kClientAddrHost1 is blocked, not expecting stun candidates for it. | |
1499 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1500 EXPECT_EQ(6u, observer_.mline_0_candidates_.size()); | |
1501 EXPECT_EQ(6u, observer_.mline_1_candidates_.size()); | |
1502 } | |
1503 | |
1504 // Test session delivers no candidates gathered when constraint set to "none". | |
1505 TEST_F(WebRtcSessionTest, TestIceTransportsNone) { | |
1506 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1507 InitWithIceTransport(PeerConnectionInterface::kNone); | |
1508 SendAudioVideoStream1(); | |
1509 InitiateCall(); | |
1510 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1511 EXPECT_EQ(0u, observer_.mline_0_candidates_.size()); | |
1512 EXPECT_EQ(0u, observer_.mline_1_candidates_.size()); | |
1513 } | |
1514 | |
1515 // Test session delivers only relay candidates gathered when constaint set to | |
1516 // "relay". | |
1517 TEST_F(WebRtcSessionTest, TestIceTransportsRelay) { | |
1518 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1519 ConfigureAllocatorWithTurn(); | |
1520 InitWithIceTransport(PeerConnectionInterface::kRelay); | |
1521 SendAudioVideoStream1(); | |
1522 InitiateCall(); | |
1523 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1524 EXPECT_EQ(2u, observer_.mline_0_candidates_.size()); | |
1525 EXPECT_EQ(2u, observer_.mline_1_candidates_.size()); | |
1526 for (size_t i = 0; i < observer_.mline_0_candidates_.size(); ++i) { | |
1527 EXPECT_EQ(cricket::RELAY_PORT_TYPE, | |
1528 observer_.mline_0_candidates_[i].type()); | |
1529 } | |
1530 for (size_t i = 0; i < observer_.mline_1_candidates_.size(); ++i) { | |
1531 EXPECT_EQ(cricket::RELAY_PORT_TYPE, | |
1532 observer_.mline_1_candidates_[i].type()); | |
1533 } | |
1534 } | |
1535 | |
1536 // Test session delivers all candidates gathered when constaint set to "all". | |
1537 TEST_F(WebRtcSessionTest, TestIceTransportsAll) { | |
1538 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
1539 InitWithIceTransport(PeerConnectionInterface::kAll); | |
1540 SendAudioVideoStream1(); | |
1541 InitiateCall(); | |
1542 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
1543 // Host + STUN. By default allocator is disabled to gather relay candidates. | |
1544 EXPECT_EQ(4u, observer_.mline_0_candidates_.size()); | |
1545 EXPECT_EQ(4u, observer_.mline_1_candidates_.size()); | |
1546 } | |
1547 | |
1548 TEST_F(WebRtcSessionTest, SetSdpFailedOnInvalidSdp) { | |
1549 Init(); | |
1550 SessionDescriptionInterface* offer = NULL; | |
1551 // Since |offer| is NULL, there's no way to tell if it's an offer or answer. | |
1552 std::string unknown_action; | |
1553 SetLocalDescriptionExpectError(unknown_action, kInvalidSdp, offer); | |
1554 SetRemoteDescriptionExpectError(unknown_action, kInvalidSdp, offer); | |
1555 } | |
1556 | |
1557 // Test creating offers and receive answers and make sure the | |
1558 // media engine creates the expected send and receive streams. | |
1559 TEST_F(WebRtcSessionTest, TestCreateSdesOfferReceiveSdesAnswer) { | |
1560 Init(); | |
1561 SendAudioVideoStream1(); | |
1562 SessionDescriptionInterface* offer = CreateOffer(); | |
1563 const std::string session_id_orig = offer->session_id(); | |
1564 const std::string session_version_orig = offer->session_version(); | |
1565 SetLocalDescriptionWithoutError(offer); | |
1566 | |
1567 SendAudioVideoStream2(); | |
1568 SessionDescriptionInterface* answer = | |
1569 CreateRemoteAnswer(session_->local_description()); | |
1570 SetRemoteDescriptionWithoutError(answer); | |
1571 | |
1572 video_channel_ = media_engine_->GetVideoChannel(0); | |
1573 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
1574 | |
1575 ASSERT_EQ(1u, video_channel_->recv_streams().size()); | |
1576 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); | |
1577 | |
1578 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); | |
1579 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); | |
1580 | |
1581 ASSERT_EQ(1u, video_channel_->send_streams().size()); | |
1582 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id); | |
1583 ASSERT_EQ(1u, voice_channel_->send_streams().size()); | |
1584 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id); | |
1585 | |
1586 // Create new offer without send streams. | |
1587 SendNothing(); | |
1588 offer = CreateOffer(); | |
1589 | |
1590 // Verify the session id is the same and the session version is | |
1591 // increased. | |
1592 EXPECT_EQ(session_id_orig, offer->session_id()); | |
1593 EXPECT_LT(rtc::FromString<uint64_t>(session_version_orig), | |
1594 rtc::FromString<uint64_t>(offer->session_version())); | |
1595 | |
1596 SetLocalDescriptionWithoutError(offer); | |
1597 EXPECT_EQ(0u, video_channel_->send_streams().size()); | |
1598 EXPECT_EQ(0u, voice_channel_->send_streams().size()); | |
1599 | |
1600 SendAudioVideoStream2(); | |
1601 answer = CreateRemoteAnswer(session_->local_description()); | |
1602 SetRemoteDescriptionWithoutError(answer); | |
1603 | |
1604 // Make sure the receive streams have not changed. | |
1605 ASSERT_EQ(1u, video_channel_->recv_streams().size()); | |
1606 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); | |
1607 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); | |
1608 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); | |
1609 } | |
1610 | |
1611 // Test receiving offers and creating answers and make sure the | |
1612 // media engine creates the expected send and receive streams. | |
1613 TEST_F(WebRtcSessionTest, TestReceiveSdesOfferCreateSdesAnswer) { | |
1614 Init(); | |
1615 SendAudioVideoStream2(); | |
1616 SessionDescriptionInterface* offer = CreateOffer(); | |
1617 VerifyCryptoParams(offer->description()); | |
1618 SetRemoteDescriptionWithoutError(offer); | |
1619 | |
1620 SendAudioVideoStream1(); | |
1621 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
1622 VerifyCryptoParams(answer->description()); | |
1623 SetLocalDescriptionWithoutError(answer); | |
1624 | |
1625 const std::string session_id_orig = answer->session_id(); | |
1626 const std::string session_version_orig = answer->session_version(); | |
1627 | |
1628 video_channel_ = media_engine_->GetVideoChannel(0); | |
1629 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
1630 | |
1631 ASSERT_EQ(1u, video_channel_->recv_streams().size()); | |
1632 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id); | |
1633 | |
1634 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); | |
1635 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id); | |
1636 | |
1637 ASSERT_EQ(1u, video_channel_->send_streams().size()); | |
1638 EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id); | |
1639 ASSERT_EQ(1u, voice_channel_->send_streams().size()); | |
1640 EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id); | |
1641 | |
1642 SendAudioVideoStream1And2(); | |
1643 offer = CreateOffer(); | |
1644 SetRemoteDescriptionWithoutError(offer); | |
1645 | |
1646 // Answer by turning off all send streams. | |
1647 SendNothing(); | |
1648 answer = CreateAnswer(NULL); | |
1649 | |
1650 // Verify the session id is the same and the session version is | |
1651 // increased. | |
1652 EXPECT_EQ(session_id_orig, answer->session_id()); | |
1653 EXPECT_LT(rtc::FromString<uint64_t>(session_version_orig), | |
1654 rtc::FromString<uint64_t>(answer->session_version())); | |
1655 SetLocalDescriptionWithoutError(answer); | |
1656 | |
1657 ASSERT_EQ(2u, video_channel_->recv_streams().size()); | |
1658 EXPECT_TRUE(kVideoTrack1 == video_channel_->recv_streams()[0].id); | |
1659 EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[1].id); | |
1660 ASSERT_EQ(2u, voice_channel_->recv_streams().size()); | |
1661 EXPECT_TRUE(kAudioTrack1 == voice_channel_->recv_streams()[0].id); | |
1662 EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[1].id); | |
1663 | |
1664 // Make sure we have no send streams. | |
1665 EXPECT_EQ(0u, video_channel_->send_streams().size()); | |
1666 EXPECT_EQ(0u, voice_channel_->send_streams().size()); | |
1667 } | |
1668 | |
1669 TEST_F(WebRtcSessionTest, SetLocalSdpFailedOnCreateChannel) { | |
1670 Init(); | |
1671 media_engine_->set_fail_create_channel(true); | |
1672 | |
1673 SessionDescriptionInterface* offer = CreateOffer(); | |
1674 ASSERT_TRUE(offer != NULL); | |
1675 // SetRemoteDescription and SetLocalDescription will take the ownership of | |
1676 // the offer. | |
1677 SetRemoteDescriptionOfferExpectError(kCreateChannelFailed, offer); | |
1678 offer = CreateOffer(); | |
1679 ASSERT_TRUE(offer != NULL); | |
1680 SetLocalDescriptionOfferExpectError(kCreateChannelFailed, offer); | |
1681 } | |
1682 | |
1683 // | |
1684 // Tests for creating/setting SDP under different SDES/DTLS polices: | |
1685 // | |
1686 // --DTLS off and SDES on | |
1687 // TestCreateSdesOfferReceiveSdesAnswer/TestReceiveSdesOfferCreateSdesAnswer: | |
1688 // set local/remote offer/answer with crypto --> success | |
1689 // TestSetNonSdesOfferWhenSdesOn: set local/remote offer without crypto ---> | |
1690 // failure | |
1691 // TestSetLocalNonSdesAnswerWhenSdesOn: set local answer without crypto --> | |
1692 // failure | |
1693 // TestSetRemoteNonSdesAnswerWhenSdesOn: set remote answer without crypto --> | |
1694 // failure | |
1695 // | |
1696 // --DTLS on and SDES off | |
1697 // TestCreateDtlsOfferReceiveDtlsAnswer/TestReceiveDtlsOfferCreateDtlsAnswer: | |
1698 // set local/remote offer/answer with DTLS fingerprint --> success | |
1699 // TestReceiveNonDtlsOfferWhenDtlsOn: set local/remote offer without DTLS | |
1700 // fingerprint --> failure | |
1701 // TestSetLocalNonDtlsAnswerWhenDtlsOn: set local answer without fingerprint | |
1702 // --> failure | |
1703 // TestSetRemoteNonDtlsAnswerWhenDtlsOn: set remote answer without fingerprint | |
1704 // --> failure | |
1705 // | |
1706 // --Encryption disabled: DTLS off and SDES off | |
1707 // TestCreateOfferReceiveAnswerWithoutEncryption: set local offer and remote | |
1708 // answer without SDES or DTLS --> success | |
1709 // TestCreateAnswerReceiveOfferWithoutEncryption: set remote offer and local | |
1710 // answer without SDES or DTLS --> success | |
1711 // | |
1712 | |
1713 // Test that we return a failure when applying a remote/local offer that doesn't | |
1714 // have cryptos enabled when DTLS is off. | |
1715 TEST_F(WebRtcSessionTest, TestSetNonSdesOfferWhenSdesOn) { | |
1716 Init(); | |
1717 cricket::MediaSessionOptions options; | |
1718 options.recv_video = true; | |
1719 JsepSessionDescription* offer = CreateRemoteOffer( | |
1720 options, cricket::SEC_DISABLED); | |
1721 ASSERT_TRUE(offer != NULL); | |
1722 VerifyNoCryptoParams(offer->description(), false); | |
1723 // SetRemoteDescription and SetLocalDescription will take the ownership of | |
1724 // the offer. | |
1725 SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer); | |
1726 offer = CreateRemoteOffer(options, cricket::SEC_DISABLED); | |
1727 ASSERT_TRUE(offer != NULL); | |
1728 SetLocalDescriptionOfferExpectError(kSdpWithoutSdesCrypto, offer); | |
1729 } | |
1730 | |
1731 // Test that we return a failure when applying a local answer that doesn't have | |
1732 // cryptos enabled when DTLS is off. | |
1733 TEST_F(WebRtcSessionTest, TestSetLocalNonSdesAnswerWhenSdesOn) { | |
1734 Init(); | |
1735 SessionDescriptionInterface* offer = NULL; | |
1736 SessionDescriptionInterface* answer = NULL; | |
1737 CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer); | |
1738 // SetRemoteDescription and SetLocalDescription will take the ownership of | |
1739 // the offer. | |
1740 SetRemoteDescriptionWithoutError(offer); | |
1741 SetLocalDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer); | |
1742 } | |
1743 | |
1744 // Test we will return fail when apply an remote answer that doesn't have | |
1745 // crypto enabled when DTLS is off. | |
1746 TEST_F(WebRtcSessionTest, TestSetRemoteNonSdesAnswerWhenSdesOn) { | |
1747 Init(); | |
1748 SessionDescriptionInterface* offer = NULL; | |
1749 SessionDescriptionInterface* answer = NULL; | |
1750 CreateCryptoOfferAndNonCryptoAnswer(&offer, &answer); | |
1751 // SetRemoteDescription and SetLocalDescription will take the ownership of | |
1752 // the offer. | |
1753 SetLocalDescriptionWithoutError(offer); | |
1754 SetRemoteDescriptionAnswerExpectError(kSdpWithoutSdesCrypto, answer); | |
1755 } | |
1756 | |
1757 // Test that we accept an offer with a DTLS fingerprint when DTLS is on | |
1758 // and that we return an answer with a DTLS fingerprint. | |
1759 TEST_P(WebRtcSessionTest, TestReceiveDtlsOfferCreateDtlsAnswer) { | |
1760 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
1761 SendAudioVideoStream1(); | |
1762 InitWithDtls(GetParam()); | |
1763 SetFactoryDtlsSrtp(); | |
1764 cricket::MediaSessionOptions options; | |
1765 options.recv_video = true; | |
1766 JsepSessionDescription* offer = | |
1767 CreateRemoteOffer(options, cricket::SEC_DISABLED); | |
1768 ASSERT_TRUE(offer != NULL); | |
1769 VerifyFingerprintStatus(offer->description(), true); | |
1770 VerifyNoCryptoParams(offer->description(), true); | |
1771 | |
1772 // SetRemoteDescription will take the ownership of the offer. | |
1773 SetRemoteDescriptionWithoutError(offer); | |
1774 | |
1775 // Verify that we get a crypto fingerprint in the answer. | |
1776 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
1777 ASSERT_TRUE(answer != NULL); | |
1778 VerifyFingerprintStatus(answer->description(), true); | |
1779 // Check that we don't have an a=crypto line in the answer. | |
1780 VerifyNoCryptoParams(answer->description(), true); | |
1781 | |
1782 // Now set the local description, which should work, even without a=crypto. | |
1783 SetLocalDescriptionWithoutError(answer); | |
1784 } | |
1785 | |
1786 // Test that we set a local offer with a DTLS fingerprint when DTLS is on | |
1787 // and then we accept a remote answer with a DTLS fingerprint successfully. | |
1788 TEST_P(WebRtcSessionTest, TestCreateDtlsOfferReceiveDtlsAnswer) { | |
1789 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
1790 SendAudioVideoStream1(); | |
1791 InitWithDtls(GetParam()); | |
1792 SetFactoryDtlsSrtp(); | |
1793 | |
1794 // Verify that we get a crypto fingerprint in the answer. | |
1795 SessionDescriptionInterface* offer = CreateOffer(); | |
1796 ASSERT_TRUE(offer != NULL); | |
1797 VerifyFingerprintStatus(offer->description(), true); | |
1798 // Check that we don't have an a=crypto line in the offer. | |
1799 VerifyNoCryptoParams(offer->description(), true); | |
1800 | |
1801 // Now set the local description, which should work, even without a=crypto. | |
1802 SetLocalDescriptionWithoutError(offer); | |
1803 | |
1804 cricket::MediaSessionOptions options; | |
1805 options.recv_video = true; | |
1806 JsepSessionDescription* answer = | |
1807 CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); | |
1808 ASSERT_TRUE(answer != NULL); | |
1809 VerifyFingerprintStatus(answer->description(), true); | |
1810 VerifyNoCryptoParams(answer->description(), true); | |
1811 | |
1812 // SetRemoteDescription will take the ownership of the answer. | |
1813 SetRemoteDescriptionWithoutError(answer); | |
1814 } | |
1815 | |
1816 // Test that if we support DTLS and the other side didn't offer a fingerprint, | |
1817 // we will fail to set the remote description. | |
1818 TEST_P(WebRtcSessionTest, TestReceiveNonDtlsOfferWhenDtlsOn) { | |
1819 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
1820 InitWithDtls(GetParam()); | |
1821 cricket::MediaSessionOptions options; | |
1822 options.recv_video = true; | |
1823 options.bundle_enabled = true; | |
1824 JsepSessionDescription* offer = CreateRemoteOffer( | |
1825 options, cricket::SEC_REQUIRED); | |
1826 ASSERT_TRUE(offer != NULL); | |
1827 VerifyFingerprintStatus(offer->description(), false); | |
1828 VerifyCryptoParams(offer->description()); | |
1829 | |
1830 // SetRemoteDescription will take the ownership of the offer. | |
1831 SetRemoteDescriptionOfferExpectError( | |
1832 kSdpWithoutDtlsFingerprint, offer); | |
1833 | |
1834 offer = CreateRemoteOffer(options, cricket::SEC_REQUIRED); | |
1835 // SetLocalDescription will take the ownership of the offer. | |
1836 SetLocalDescriptionOfferExpectError( | |
1837 kSdpWithoutDtlsFingerprint, offer); | |
1838 } | |
1839 | |
1840 // Test that we return a failure when applying a local answer that doesn't have | |
1841 // a DTLS fingerprint when DTLS is required. | |
1842 TEST_P(WebRtcSessionTest, TestSetLocalNonDtlsAnswerWhenDtlsOn) { | |
1843 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
1844 InitWithDtls(GetParam()); | |
1845 SessionDescriptionInterface* offer = NULL; | |
1846 SessionDescriptionInterface* answer = NULL; | |
1847 CreateDtlsOfferAndNonDtlsAnswer(&offer, &answer); | |
1848 | |
1849 // SetRemoteDescription and SetLocalDescription will take the ownership of | |
1850 // the offer and answer. | |
1851 SetRemoteDescriptionWithoutError(offer); | |
1852 SetLocalDescriptionAnswerExpectError( | |
1853 kSdpWithoutDtlsFingerprint, answer); | |
1854 } | |
1855 | |
1856 // Test that we return a failure when applying a remote answer that doesn't have | |
1857 // a DTLS fingerprint when DTLS is required. | |
1858 TEST_P(WebRtcSessionTest, TestSetRemoteNonDtlsAnswerWhenDtlsOn) { | |
1859 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
1860 InitWithDtls(GetParam()); | |
1861 SessionDescriptionInterface* offer = CreateOffer(); | |
1862 cricket::MediaSessionOptions options; | |
1863 options.recv_video = true; | |
1864 rtc::scoped_ptr<SessionDescriptionInterface> temp_offer( | |
1865 CreateRemoteOffer(options, cricket::SEC_ENABLED)); | |
1866 JsepSessionDescription* answer = | |
1867 CreateRemoteAnswer(temp_offer.get(), options, cricket::SEC_ENABLED); | |
1868 | |
1869 // SetRemoteDescription and SetLocalDescription will take the ownership of | |
1870 // the offer and answer. | |
1871 SetLocalDescriptionWithoutError(offer); | |
1872 SetRemoteDescriptionAnswerExpectError( | |
1873 kSdpWithoutDtlsFingerprint, answer); | |
1874 } | |
1875 | |
1876 // Test that we create a local offer without SDES or DTLS and accept a remote | |
1877 // answer without SDES or DTLS when encryption is disabled. | |
1878 TEST_P(WebRtcSessionTest, TestCreateOfferReceiveAnswerWithoutEncryption) { | |
1879 SendAudioVideoStream1(); | |
1880 options_.disable_encryption = true; | |
1881 InitWithDtls(GetParam()); | |
1882 | |
1883 // Verify that we get a crypto fingerprint in the answer. | |
1884 SessionDescriptionInterface* offer = CreateOffer(); | |
1885 ASSERT_TRUE(offer != NULL); | |
1886 VerifyFingerprintStatus(offer->description(), false); | |
1887 // Check that we don't have an a=crypto line in the offer. | |
1888 VerifyNoCryptoParams(offer->description(), false); | |
1889 | |
1890 // Now set the local description, which should work, even without a=crypto. | |
1891 SetLocalDescriptionWithoutError(offer); | |
1892 | |
1893 cricket::MediaSessionOptions options; | |
1894 options.recv_video = true; | |
1895 JsepSessionDescription* answer = | |
1896 CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); | |
1897 ASSERT_TRUE(answer != NULL); | |
1898 VerifyFingerprintStatus(answer->description(), false); | |
1899 VerifyNoCryptoParams(answer->description(), false); | |
1900 | |
1901 // SetRemoteDescription will take the ownership of the answer. | |
1902 SetRemoteDescriptionWithoutError(answer); | |
1903 } | |
1904 | |
1905 // Test that we create a local answer without SDES or DTLS and accept a remote | |
1906 // offer without SDES or DTLS when encryption is disabled. | |
1907 TEST_P(WebRtcSessionTest, TestCreateAnswerReceiveOfferWithoutEncryption) { | |
1908 options_.disable_encryption = true; | |
1909 InitWithDtls(GetParam()); | |
1910 | |
1911 cricket::MediaSessionOptions options; | |
1912 options.recv_video = true; | |
1913 JsepSessionDescription* offer = | |
1914 CreateRemoteOffer(options, cricket::SEC_DISABLED); | |
1915 ASSERT_TRUE(offer != NULL); | |
1916 VerifyFingerprintStatus(offer->description(), false); | |
1917 VerifyNoCryptoParams(offer->description(), false); | |
1918 | |
1919 // SetRemoteDescription will take the ownership of the offer. | |
1920 SetRemoteDescriptionWithoutError(offer); | |
1921 | |
1922 // Verify that we get a crypto fingerprint in the answer. | |
1923 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
1924 ASSERT_TRUE(answer != NULL); | |
1925 VerifyFingerprintStatus(answer->description(), false); | |
1926 // Check that we don't have an a=crypto line in the answer. | |
1927 VerifyNoCryptoParams(answer->description(), false); | |
1928 | |
1929 // Now set the local description, which should work, even without a=crypto. | |
1930 SetLocalDescriptionWithoutError(answer); | |
1931 } | |
1932 | |
1933 // Test that we can create and set an answer correctly when different | |
1934 // SSL roles have been negotiated for different transports. | |
1935 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525 | |
1936 TEST_P(WebRtcSessionTest, TestCreateAnswerWithDifferentSslRoles) { | |
1937 SendAudioVideoStream1(); | |
1938 InitWithDtls(GetParam()); | |
1939 SetFactoryDtlsSrtp(); | |
1940 | |
1941 SessionDescriptionInterface* offer = CreateOffer(); | |
1942 SetLocalDescriptionWithoutError(offer); | |
1943 | |
1944 cricket::MediaSessionOptions options; | |
1945 options.recv_video = true; | |
1946 | |
1947 // First, negotiate different SSL roles. | |
1948 SessionDescriptionInterface* answer = | |
1949 CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); | |
1950 TransportInfo* audio_transport_info = | |
1951 answer->description()->GetTransportInfoByName("audio"); | |
1952 audio_transport_info->description.connection_role = | |
1953 cricket::CONNECTIONROLE_ACTIVE; | |
1954 TransportInfo* video_transport_info = | |
1955 answer->description()->GetTransportInfoByName("video"); | |
1956 video_transport_info->description.connection_role = | |
1957 cricket::CONNECTIONROLE_PASSIVE; | |
1958 SetRemoteDescriptionWithoutError(answer); | |
1959 | |
1960 // Now create an offer in the reverse direction, and ensure the initial | |
1961 // offerer responds with an answer with correct SSL roles. | |
1962 offer = CreateRemoteOfferWithVersion(options, cricket::SEC_DISABLED, | |
1963 kSessionVersion, | |
1964 session_->remote_description()); | |
1965 SetRemoteDescriptionWithoutError(offer); | |
1966 | |
1967 answer = CreateAnswer(nullptr); | |
1968 audio_transport_info = answer->description()->GetTransportInfoByName("audio"); | |
1969 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE, | |
1970 audio_transport_info->description.connection_role); | |
1971 video_transport_info = answer->description()->GetTransportInfoByName("video"); | |
1972 EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE, | |
1973 video_transport_info->description.connection_role); | |
1974 SetLocalDescriptionWithoutError(answer); | |
1975 | |
1976 // Lastly, start BUNDLE-ing on "audio", expecting that the "passive" role of | |
1977 // audio is transferred over to video in the answer that completes the BUNDLE | |
1978 // negotiation. | |
1979 options.bundle_enabled = true; | |
1980 offer = CreateRemoteOfferWithVersion(options, cricket::SEC_DISABLED, | |
1981 kSessionVersion, | |
1982 session_->remote_description()); | |
1983 SetRemoteDescriptionWithoutError(offer); | |
1984 answer = CreateAnswer(nullptr); | |
1985 audio_transport_info = answer->description()->GetTransportInfoByName("audio"); | |
1986 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE, | |
1987 audio_transport_info->description.connection_role); | |
1988 video_transport_info = answer->description()->GetTransportInfoByName("video"); | |
1989 EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE, | |
1990 video_transport_info->description.connection_role); | |
1991 SetLocalDescriptionWithoutError(answer); | |
1992 } | |
1993 | |
1994 TEST_F(WebRtcSessionTest, TestSetLocalOfferTwice) { | |
1995 Init(); | |
1996 SendNothing(); | |
1997 // SetLocalDescription take ownership of offer. | |
1998 SessionDescriptionInterface* offer = CreateOffer(); | |
1999 SetLocalDescriptionWithoutError(offer); | |
2000 | |
2001 // SetLocalDescription take ownership of offer. | |
2002 SessionDescriptionInterface* offer2 = CreateOffer(); | |
2003 SetLocalDescriptionWithoutError(offer2); | |
2004 } | |
2005 | |
2006 TEST_F(WebRtcSessionTest, TestSetRemoteOfferTwice) { | |
2007 Init(); | |
2008 SendNothing(); | |
2009 // SetLocalDescription take ownership of offer. | |
2010 SessionDescriptionInterface* offer = CreateOffer(); | |
2011 SetRemoteDescriptionWithoutError(offer); | |
2012 | |
2013 SessionDescriptionInterface* offer2 = CreateOffer(); | |
2014 SetRemoteDescriptionWithoutError(offer2); | |
2015 } | |
2016 | |
2017 TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteOffer) { | |
2018 Init(); | |
2019 SendNothing(); | |
2020 SessionDescriptionInterface* offer = CreateOffer(); | |
2021 SetLocalDescriptionWithoutError(offer); | |
2022 offer = CreateOffer(); | |
2023 SetRemoteDescriptionOfferExpectError("Called in wrong state: STATE_SENTOFFER", | |
2024 offer); | |
2025 } | |
2026 | |
2027 TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) { | |
2028 Init(); | |
2029 SendNothing(); | |
2030 SessionDescriptionInterface* offer = CreateOffer(); | |
2031 SetRemoteDescriptionWithoutError(offer); | |
2032 offer = CreateOffer(); | |
2033 SetLocalDescriptionOfferExpectError( | |
2034 "Called in wrong state: STATE_RECEIVEDOFFER", offer); | |
2035 } | |
2036 | |
2037 TEST_F(WebRtcSessionTest, TestSetLocalPrAnswer) { | |
2038 Init(); | |
2039 SendNothing(); | |
2040 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
2041 SetRemoteDescriptionExpectState(offer, WebRtcSession::STATE_RECEIVEDOFFER); | |
2042 | |
2043 JsepSessionDescription* pranswer = static_cast<JsepSessionDescription*>( | |
2044 CreateAnswer(NULL)); | |
2045 pranswer->set_type(SessionDescriptionInterface::kPrAnswer); | |
2046 SetLocalDescriptionExpectState(pranswer, WebRtcSession::STATE_SENTPRANSWER); | |
2047 | |
2048 SendAudioVideoStream1(); | |
2049 JsepSessionDescription* pranswer2 = static_cast<JsepSessionDescription*>( | |
2050 CreateAnswer(NULL)); | |
2051 pranswer2->set_type(SessionDescriptionInterface::kPrAnswer); | |
2052 | |
2053 SetLocalDescriptionExpectState(pranswer2, WebRtcSession::STATE_SENTPRANSWER); | |
2054 | |
2055 SendAudioVideoStream2(); | |
2056 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
2057 SetLocalDescriptionExpectState(answer, WebRtcSession::STATE_INPROGRESS); | |
2058 } | |
2059 | |
2060 TEST_F(WebRtcSessionTest, TestSetRemotePrAnswer) { | |
2061 Init(); | |
2062 SendNothing(); | |
2063 SessionDescriptionInterface* offer = CreateOffer(); | |
2064 SetLocalDescriptionExpectState(offer, WebRtcSession::STATE_SENTOFFER); | |
2065 | |
2066 JsepSessionDescription* pranswer = | |
2067 CreateRemoteAnswer(session_->local_description()); | |
2068 pranswer->set_type(SessionDescriptionInterface::kPrAnswer); | |
2069 | |
2070 SetRemoteDescriptionExpectState(pranswer, | |
2071 WebRtcSession::STATE_RECEIVEDPRANSWER); | |
2072 | |
2073 SendAudioVideoStream1(); | |
2074 JsepSessionDescription* pranswer2 = | |
2075 CreateRemoteAnswer(session_->local_description()); | |
2076 pranswer2->set_type(SessionDescriptionInterface::kPrAnswer); | |
2077 | |
2078 SetRemoteDescriptionExpectState(pranswer2, | |
2079 WebRtcSession::STATE_RECEIVEDPRANSWER); | |
2080 | |
2081 SendAudioVideoStream2(); | |
2082 SessionDescriptionInterface* answer = | |
2083 CreateRemoteAnswer(session_->local_description()); | |
2084 SetRemoteDescriptionExpectState(answer, WebRtcSession::STATE_INPROGRESS); | |
2085 } | |
2086 | |
2087 TEST_F(WebRtcSessionTest, TestSetLocalAnswerWithoutOffer) { | |
2088 Init(); | |
2089 SendNothing(); | |
2090 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2091 | |
2092 SessionDescriptionInterface* answer = | |
2093 CreateRemoteAnswer(offer.get()); | |
2094 SetLocalDescriptionAnswerExpectError("Called in wrong state: STATE_INIT", | |
2095 answer); | |
2096 } | |
2097 | |
2098 TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) { | |
2099 Init(); | |
2100 SendNothing(); | |
2101 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2102 | |
2103 SessionDescriptionInterface* answer = | |
2104 CreateRemoteAnswer(offer.get()); | |
2105 SetRemoteDescriptionAnswerExpectError( | |
2106 "Called in wrong state: STATE_INIT", answer); | |
2107 } | |
2108 | |
2109 TEST_F(WebRtcSessionTest, TestAddRemoteCandidate) { | |
2110 Init(); | |
2111 SendAudioVideoStream1(); | |
2112 | |
2113 cricket::Candidate candidate; | |
2114 candidate.set_component(1); | |
2115 JsepIceCandidate ice_candidate1(kMediaContentName0, 0, candidate); | |
2116 | |
2117 // Fail since we have not set a remote description. | |
2118 EXPECT_FALSE(session_->ProcessIceMessage(&ice_candidate1)); | |
2119 | |
2120 SessionDescriptionInterface* offer = CreateOffer(); | |
2121 SetLocalDescriptionWithoutError(offer); | |
2122 | |
2123 // Fail since we have not set a remote description. | |
2124 EXPECT_FALSE(session_->ProcessIceMessage(&ice_candidate1)); | |
2125 | |
2126 SessionDescriptionInterface* answer = CreateRemoteAnswer( | |
2127 session_->local_description()); | |
2128 SetRemoteDescriptionWithoutError(answer); | |
2129 | |
2130 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1)); | |
2131 candidate.set_component(2); | |
2132 JsepIceCandidate ice_candidate2(kMediaContentName0, 0, candidate); | |
2133 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2)); | |
2134 | |
2135 // Verifying the candidates are copied properly from internal vector. | |
2136 const SessionDescriptionInterface* remote_desc = | |
2137 session_->remote_description(); | |
2138 ASSERT_TRUE(remote_desc != NULL); | |
2139 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); | |
2140 const IceCandidateCollection* candidates = | |
2141 remote_desc->candidates(kMediaContentIndex0); | |
2142 ASSERT_EQ(2u, candidates->count()); | |
2143 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); | |
2144 EXPECT_EQ(kMediaContentName0, candidates->at(0)->sdp_mid()); | |
2145 EXPECT_EQ(1, candidates->at(0)->candidate().component()); | |
2146 EXPECT_EQ(2, candidates->at(1)->candidate().component()); | |
2147 | |
2148 // |ice_candidate3| is identical to |ice_candidate2|. It can be added | |
2149 // successfully, but the total count of candidates will not increase. | |
2150 candidate.set_component(2); | |
2151 JsepIceCandidate ice_candidate3(kMediaContentName0, 0, candidate); | |
2152 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate3)); | |
2153 ASSERT_EQ(2u, candidates->count()); | |
2154 | |
2155 JsepIceCandidate bad_ice_candidate("bad content name", 99, candidate); | |
2156 EXPECT_FALSE(session_->ProcessIceMessage(&bad_ice_candidate)); | |
2157 } | |
2158 | |
2159 // Test that a remote candidate is added to the remote session description and | |
2160 // that it is retained if the remote session description is changed. | |
2161 TEST_F(WebRtcSessionTest, TestRemoteCandidatesAddedToSessionDescription) { | |
2162 Init(); | |
2163 cricket::Candidate candidate1; | |
2164 candidate1.set_component(1); | |
2165 JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0, | |
2166 candidate1); | |
2167 SendAudioVideoStream1(); | |
2168 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2169 | |
2170 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1)); | |
2171 const SessionDescriptionInterface* remote_desc = | |
2172 session_->remote_description(); | |
2173 ASSERT_TRUE(remote_desc != NULL); | |
2174 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); | |
2175 const IceCandidateCollection* candidates = | |
2176 remote_desc->candidates(kMediaContentIndex0); | |
2177 ASSERT_EQ(1u, candidates->count()); | |
2178 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); | |
2179 | |
2180 // Update the RemoteSessionDescription with a new session description and | |
2181 // a candidate and check that the new remote session description contains both | |
2182 // candidates. | |
2183 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
2184 cricket::Candidate candidate2; | |
2185 JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0, | |
2186 candidate2); | |
2187 EXPECT_TRUE(offer->AddCandidate(&ice_candidate2)); | |
2188 SetRemoteDescriptionWithoutError(offer); | |
2189 | |
2190 remote_desc = session_->remote_description(); | |
2191 ASSERT_TRUE(remote_desc != NULL); | |
2192 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); | |
2193 candidates = remote_desc->candidates(kMediaContentIndex0); | |
2194 ASSERT_EQ(2u, candidates->count()); | |
2195 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); | |
2196 // Username and password have be updated with the TransportInfo of the | |
2197 // SessionDescription, won't be equal to the original one. | |
2198 candidate2.set_username(candidates->at(0)->candidate().username()); | |
2199 candidate2.set_password(candidates->at(0)->candidate().password()); | |
2200 EXPECT_TRUE(candidate2.IsEquivalent(candidates->at(0)->candidate())); | |
2201 EXPECT_EQ(kMediaContentIndex0, candidates->at(1)->sdp_mline_index()); | |
2202 // No need to verify the username and password. | |
2203 candidate1.set_username(candidates->at(1)->candidate().username()); | |
2204 candidate1.set_password(candidates->at(1)->candidate().password()); | |
2205 EXPECT_TRUE(candidate1.IsEquivalent(candidates->at(1)->candidate())); | |
2206 | |
2207 // Test that the candidate is ignored if we can add the same candidate again. | |
2208 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2)); | |
2209 } | |
2210 | |
2211 // Test that local candidates are added to the local session description and | |
2212 // that they are retained if the local session description is changed. | |
2213 TEST_F(WebRtcSessionTest, TestLocalCandidatesAddedToSessionDescription) { | |
2214 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
2215 Init(); | |
2216 SendAudioVideoStream1(); | |
2217 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2218 | |
2219 const SessionDescriptionInterface* local_desc = session_->local_description(); | |
2220 const IceCandidateCollection* candidates = | |
2221 local_desc->candidates(kMediaContentIndex0); | |
2222 ASSERT_TRUE(candidates != NULL); | |
2223 EXPECT_EQ(0u, candidates->count()); | |
2224 | |
2225 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
2226 | |
2227 local_desc = session_->local_description(); | |
2228 candidates = local_desc->candidates(kMediaContentIndex0); | |
2229 ASSERT_TRUE(candidates != NULL); | |
2230 EXPECT_LT(0u, candidates->count()); | |
2231 candidates = local_desc->candidates(1); | |
2232 ASSERT_TRUE(candidates != NULL); | |
2233 EXPECT_EQ(0u, candidates->count()); | |
2234 | |
2235 // Update the session descriptions. | |
2236 SendAudioVideoStream1(); | |
2237 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2238 | |
2239 local_desc = session_->local_description(); | |
2240 candidates = local_desc->candidates(kMediaContentIndex0); | |
2241 ASSERT_TRUE(candidates != NULL); | |
2242 EXPECT_LT(0u, candidates->count()); | |
2243 candidates = local_desc->candidates(1); | |
2244 ASSERT_TRUE(candidates != NULL); | |
2245 EXPECT_EQ(0u, candidates->count()); | |
2246 } | |
2247 | |
2248 // Test that we can set a remote session description with remote candidates. | |
2249 TEST_F(WebRtcSessionTest, TestSetRemoteSessionDescriptionWithCandidates) { | |
2250 Init(); | |
2251 | |
2252 cricket::Candidate candidate1; | |
2253 candidate1.set_component(1); | |
2254 JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0, | |
2255 candidate1); | |
2256 SendAudioVideoStream1(); | |
2257 SessionDescriptionInterface* offer = CreateOffer(); | |
2258 | |
2259 EXPECT_TRUE(offer->AddCandidate(&ice_candidate)); | |
2260 SetRemoteDescriptionWithoutError(offer); | |
2261 | |
2262 const SessionDescriptionInterface* remote_desc = | |
2263 session_->remote_description(); | |
2264 ASSERT_TRUE(remote_desc != NULL); | |
2265 ASSERT_EQ(2u, remote_desc->number_of_mediasections()); | |
2266 const IceCandidateCollection* candidates = | |
2267 remote_desc->candidates(kMediaContentIndex0); | |
2268 ASSERT_EQ(1u, candidates->count()); | |
2269 EXPECT_EQ(kMediaContentIndex0, candidates->at(0)->sdp_mline_index()); | |
2270 | |
2271 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
2272 SetLocalDescriptionWithoutError(answer); | |
2273 } | |
2274 | |
2275 // Test that offers and answers contains ice candidates when Ice candidates have | |
2276 // been gathered. | |
2277 TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteDescriptionWithCandidates) { | |
2278 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
2279 Init(); | |
2280 SendAudioVideoStream1(); | |
2281 // Ice is started but candidates are not provided until SetLocalDescription | |
2282 // is called. | |
2283 EXPECT_EQ(0u, observer_.mline_0_candidates_.size()); | |
2284 EXPECT_EQ(0u, observer_.mline_1_candidates_.size()); | |
2285 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2286 // Wait until at least one local candidate has been collected. | |
2287 EXPECT_TRUE_WAIT(0u < observer_.mline_0_candidates_.size(), | |
2288 kIceCandidatesTimeout); | |
2289 | |
2290 rtc::scoped_ptr<SessionDescriptionInterface> local_offer(CreateOffer()); | |
2291 | |
2292 ASSERT_TRUE(local_offer->candidates(kMediaContentIndex0) != NULL); | |
2293 EXPECT_LT(0u, local_offer->candidates(kMediaContentIndex0)->count()); | |
2294 | |
2295 SessionDescriptionInterface* remote_offer(CreateRemoteOffer()); | |
2296 SetRemoteDescriptionWithoutError(remote_offer); | |
2297 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
2298 ASSERT_TRUE(answer->candidates(kMediaContentIndex0) != NULL); | |
2299 EXPECT_LT(0u, answer->candidates(kMediaContentIndex0)->count()); | |
2300 SetLocalDescriptionWithoutError(answer); | |
2301 } | |
2302 | |
2303 // Verifies TransportProxy and media channels are created with content names | |
2304 // present in the SessionDescription. | |
2305 TEST_F(WebRtcSessionTest, TestChannelCreationsWithContentNames) { | |
2306 Init(); | |
2307 SendAudioVideoStream1(); | |
2308 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2309 | |
2310 // CreateOffer creates session description with the content names "audio" and | |
2311 // "video". Goal is to modify these content names and verify transport | |
2312 // channels | |
2313 // in the WebRtcSession, as channels are created with the content names | |
2314 // present in SDP. | |
2315 std::string sdp; | |
2316 EXPECT_TRUE(offer->ToString(&sdp)); | |
2317 const std::string kAudioMid = "a=mid:audio"; | |
2318 const std::string kAudioMidReplaceStr = "a=mid:audio_content_name"; | |
2319 const std::string kVideoMid = "a=mid:video"; | |
2320 const std::string kVideoMidReplaceStr = "a=mid:video_content_name"; | |
2321 | |
2322 // Replacing |audio| with |audio_content_name|. | |
2323 rtc::replace_substrs(kAudioMid.c_str(), kAudioMid.length(), | |
2324 kAudioMidReplaceStr.c_str(), | |
2325 kAudioMidReplaceStr.length(), | |
2326 &sdp); | |
2327 // Replacing |video| with |video_content_name|. | |
2328 rtc::replace_substrs(kVideoMid.c_str(), kVideoMid.length(), | |
2329 kVideoMidReplaceStr.c_str(), | |
2330 kVideoMidReplaceStr.length(), | |
2331 &sdp); | |
2332 | |
2333 SessionDescriptionInterface* modified_offer = | |
2334 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2335 | |
2336 SetRemoteDescriptionWithoutError(modified_offer); | |
2337 | |
2338 SessionDescriptionInterface* answer = | |
2339 CreateAnswer(NULL); | |
2340 SetLocalDescriptionWithoutError(answer); | |
2341 | |
2342 cricket::TransportChannel* voice_transport_channel = | |
2343 session_->voice_rtp_transport_channel(); | |
2344 EXPECT_TRUE(voice_transport_channel != NULL); | |
2345 EXPECT_EQ(voice_transport_channel->transport_name(), "audio_content_name"); | |
2346 cricket::TransportChannel* video_transport_channel = | |
2347 session_->video_rtp_transport_channel(); | |
2348 EXPECT_TRUE(video_transport_channel != NULL); | |
2349 EXPECT_EQ(video_transport_channel->transport_name(), "video_content_name"); | |
2350 EXPECT_TRUE((video_channel_ = media_engine_->GetVideoChannel(0)) != NULL); | |
2351 EXPECT_TRUE((voice_channel_ = media_engine_->GetVoiceChannel(0)) != NULL); | |
2352 } | |
2353 | |
2354 // Test that an offer contains the correct media content descriptions based on | |
2355 // the send streams when no constraints have been set. | |
2356 TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraintsOrStreams) { | |
2357 Init(); | |
2358 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2359 | |
2360 ASSERT_TRUE(offer != NULL); | |
2361 const cricket::ContentInfo* content = | |
2362 cricket::GetFirstAudioContent(offer->description()); | |
2363 EXPECT_TRUE(content != NULL); | |
2364 content = cricket::GetFirstVideoContent(offer->description()); | |
2365 EXPECT_TRUE(content == NULL); | |
2366 } | |
2367 | |
2368 // Test that an offer contains the correct media content descriptions based on | |
2369 // the send streams when no constraints have been set. | |
2370 TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraints) { | |
2371 Init(); | |
2372 // Test Audio only offer. | |
2373 SendAudioOnlyStream2(); | |
2374 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2375 | |
2376 const cricket::ContentInfo* content = | |
2377 cricket::GetFirstAudioContent(offer->description()); | |
2378 EXPECT_TRUE(content != NULL); | |
2379 content = cricket::GetFirstVideoContent(offer->description()); | |
2380 EXPECT_TRUE(content == NULL); | |
2381 | |
2382 // Test Audio / Video offer. | |
2383 SendAudioVideoStream1(); | |
2384 offer.reset(CreateOffer()); | |
2385 content = cricket::GetFirstAudioContent(offer->description()); | |
2386 EXPECT_TRUE(content != NULL); | |
2387 content = cricket::GetFirstVideoContent(offer->description()); | |
2388 EXPECT_TRUE(content != NULL); | |
2389 } | |
2390 | |
2391 // Test that an offer contains no media content descriptions if | |
2392 // kOfferToReceiveVideo and kOfferToReceiveAudio constraints are set to false. | |
2393 TEST_F(WebRtcSessionTest, CreateOfferWithConstraintsWithoutStreams) { | |
2394 Init(); | |
2395 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
2396 options.offer_to_receive_audio = 0; | |
2397 options.offer_to_receive_video = 0; | |
2398 | |
2399 rtc::scoped_ptr<SessionDescriptionInterface> offer( | |
2400 CreateOffer(options)); | |
2401 | |
2402 ASSERT_TRUE(offer != NULL); | |
2403 const cricket::ContentInfo* content = | |
2404 cricket::GetFirstAudioContent(offer->description()); | |
2405 EXPECT_TRUE(content == NULL); | |
2406 content = cricket::GetFirstVideoContent(offer->description()); | |
2407 EXPECT_TRUE(content == NULL); | |
2408 } | |
2409 | |
2410 // Test that an offer contains only audio media content descriptions if | |
2411 // kOfferToReceiveAudio constraints are set to true. | |
2412 TEST_F(WebRtcSessionTest, CreateAudioOnlyOfferWithConstraints) { | |
2413 Init(); | |
2414 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
2415 options.offer_to_receive_audio = | |
2416 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; | |
2417 | |
2418 rtc::scoped_ptr<SessionDescriptionInterface> offer( | |
2419 CreateOffer(options)); | |
2420 | |
2421 const cricket::ContentInfo* content = | |
2422 cricket::GetFirstAudioContent(offer->description()); | |
2423 EXPECT_TRUE(content != NULL); | |
2424 content = cricket::GetFirstVideoContent(offer->description()); | |
2425 EXPECT_TRUE(content == NULL); | |
2426 } | |
2427 | |
2428 // Test that an offer contains audio and video media content descriptions if | |
2429 // kOfferToReceiveAudio and kOfferToReceiveVideo constraints are set to true. | |
2430 TEST_F(WebRtcSessionTest, CreateOfferWithConstraints) { | |
2431 Init(); | |
2432 // Test Audio / Video offer. | |
2433 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
2434 options.offer_to_receive_audio = | |
2435 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; | |
2436 options.offer_to_receive_video = | |
2437 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; | |
2438 | |
2439 rtc::scoped_ptr<SessionDescriptionInterface> offer( | |
2440 CreateOffer(options)); | |
2441 | |
2442 const cricket::ContentInfo* content = | |
2443 cricket::GetFirstAudioContent(offer->description()); | |
2444 EXPECT_TRUE(content != NULL); | |
2445 | |
2446 content = cricket::GetFirstVideoContent(offer->description()); | |
2447 EXPECT_TRUE(content != NULL); | |
2448 | |
2449 // Sets constraints to false and verifies that audio/video contents are | |
2450 // removed. | |
2451 options.offer_to_receive_audio = 0; | |
2452 options.offer_to_receive_video = 0; | |
2453 offer.reset(CreateOffer(options)); | |
2454 | |
2455 content = cricket::GetFirstAudioContent(offer->description()); | |
2456 EXPECT_TRUE(content == NULL); | |
2457 content = cricket::GetFirstVideoContent(offer->description()); | |
2458 EXPECT_TRUE(content == NULL); | |
2459 } | |
2460 | |
2461 // Test that an answer can not be created if the last remote description is not | |
2462 // an offer. | |
2463 TEST_F(WebRtcSessionTest, CreateAnswerWithoutAnOffer) { | |
2464 Init(); | |
2465 SessionDescriptionInterface* offer = CreateOffer(); | |
2466 SetLocalDescriptionWithoutError(offer); | |
2467 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); | |
2468 SetRemoteDescriptionWithoutError(answer); | |
2469 EXPECT_TRUE(CreateAnswer(NULL) == NULL); | |
2470 } | |
2471 | |
2472 // Test that an answer contains the correct media content descriptions when no | |
2473 // constraints have been set. | |
2474 TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraintsOrStreams) { | |
2475 Init(); | |
2476 // Create a remote offer with audio and video content. | |
2477 rtc::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); | |
2478 SetRemoteDescriptionWithoutError(offer.release()); | |
2479 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
2480 CreateAnswer(NULL)); | |
2481 const cricket::ContentInfo* content = | |
2482 cricket::GetFirstAudioContent(answer->description()); | |
2483 ASSERT_TRUE(content != NULL); | |
2484 EXPECT_FALSE(content->rejected); | |
2485 | |
2486 content = cricket::GetFirstVideoContent(answer->description()); | |
2487 ASSERT_TRUE(content != NULL); | |
2488 EXPECT_FALSE(content->rejected); | |
2489 } | |
2490 | |
2491 // Test that an answer contains the correct media content descriptions when no | |
2492 // constraints have been set and the offer only contain audio. | |
2493 TEST_F(WebRtcSessionTest, CreateAudioAnswerWithoutConstraintsOrStreams) { | |
2494 Init(); | |
2495 // Create a remote offer with audio only. | |
2496 cricket::MediaSessionOptions options; | |
2497 | |
2498 rtc::scoped_ptr<JsepSessionDescription> offer( | |
2499 CreateRemoteOffer(options)); | |
2500 ASSERT_TRUE(cricket::GetFirstVideoContent(offer->description()) == NULL); | |
2501 ASSERT_TRUE(cricket::GetFirstAudioContent(offer->description()) != NULL); | |
2502 | |
2503 SetRemoteDescriptionWithoutError(offer.release()); | |
2504 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
2505 CreateAnswer(NULL)); | |
2506 const cricket::ContentInfo* content = | |
2507 cricket::GetFirstAudioContent(answer->description()); | |
2508 ASSERT_TRUE(content != NULL); | |
2509 EXPECT_FALSE(content->rejected); | |
2510 | |
2511 EXPECT_TRUE(cricket::GetFirstVideoContent(answer->description()) == NULL); | |
2512 } | |
2513 | |
2514 // Test that an answer contains the correct media content descriptions when no | |
2515 // constraints have been set. | |
2516 TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraints) { | |
2517 Init(); | |
2518 // Create a remote offer with audio and video content. | |
2519 rtc::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); | |
2520 SetRemoteDescriptionWithoutError(offer.release()); | |
2521 // Test with a stream with tracks. | |
2522 SendAudioVideoStream1(); | |
2523 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
2524 CreateAnswer(NULL)); | |
2525 const cricket::ContentInfo* content = | |
2526 cricket::GetFirstAudioContent(answer->description()); | |
2527 ASSERT_TRUE(content != NULL); | |
2528 EXPECT_FALSE(content->rejected); | |
2529 | |
2530 content = cricket::GetFirstVideoContent(answer->description()); | |
2531 ASSERT_TRUE(content != NULL); | |
2532 EXPECT_FALSE(content->rejected); | |
2533 } | |
2534 | |
2535 // Test that an answer contains the correct media content descriptions when | |
2536 // constraints have been set but no stream is sent. | |
2537 TEST_F(WebRtcSessionTest, CreateAnswerWithConstraintsWithoutStreams) { | |
2538 Init(); | |
2539 // Create a remote offer with audio and video content. | |
2540 rtc::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); | |
2541 SetRemoteDescriptionWithoutError(offer.release()); | |
2542 | |
2543 webrtc::FakeConstraints constraints_no_receive; | |
2544 constraints_no_receive.SetMandatoryReceiveAudio(false); | |
2545 constraints_no_receive.SetMandatoryReceiveVideo(false); | |
2546 | |
2547 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
2548 CreateAnswer(&constraints_no_receive)); | |
2549 const cricket::ContentInfo* content = | |
2550 cricket::GetFirstAudioContent(answer->description()); | |
2551 ASSERT_TRUE(content != NULL); | |
2552 EXPECT_TRUE(content->rejected); | |
2553 | |
2554 content = cricket::GetFirstVideoContent(answer->description()); | |
2555 ASSERT_TRUE(content != NULL); | |
2556 EXPECT_TRUE(content->rejected); | |
2557 } | |
2558 | |
2559 // Test that an answer contains the correct media content descriptions when | |
2560 // constraints have been set and streams are sent. | |
2561 TEST_F(WebRtcSessionTest, CreateAnswerWithConstraints) { | |
2562 Init(); | |
2563 // Create a remote offer with audio and video content. | |
2564 rtc::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); | |
2565 SetRemoteDescriptionWithoutError(offer.release()); | |
2566 | |
2567 webrtc::FakeConstraints constraints_no_receive; | |
2568 constraints_no_receive.SetMandatoryReceiveAudio(false); | |
2569 constraints_no_receive.SetMandatoryReceiveVideo(false); | |
2570 | |
2571 // Test with a stream with tracks. | |
2572 SendAudioVideoStream1(); | |
2573 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
2574 CreateAnswer(&constraints_no_receive)); | |
2575 | |
2576 // TODO(perkj): Should the direction be set to SEND_ONLY? | |
2577 const cricket::ContentInfo* content = | |
2578 cricket::GetFirstAudioContent(answer->description()); | |
2579 ASSERT_TRUE(content != NULL); | |
2580 EXPECT_FALSE(content->rejected); | |
2581 | |
2582 // TODO(perkj): Should the direction be set to SEND_ONLY? | |
2583 content = cricket::GetFirstVideoContent(answer->description()); | |
2584 ASSERT_TRUE(content != NULL); | |
2585 EXPECT_FALSE(content->rejected); | |
2586 } | |
2587 | |
2588 TEST_F(WebRtcSessionTest, CreateOfferWithoutCNCodecs) { | |
2589 AddCNCodecs(); | |
2590 Init(); | |
2591 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
2592 options.offer_to_receive_audio = | |
2593 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; | |
2594 options.voice_activity_detection = false; | |
2595 | |
2596 rtc::scoped_ptr<SessionDescriptionInterface> offer( | |
2597 CreateOffer(options)); | |
2598 | |
2599 const cricket::ContentInfo* content = | |
2600 cricket::GetFirstAudioContent(offer->description()); | |
2601 EXPECT_TRUE(content != NULL); | |
2602 EXPECT_TRUE(VerifyNoCNCodecs(content)); | |
2603 } | |
2604 | |
2605 TEST_F(WebRtcSessionTest, CreateAnswerWithoutCNCodecs) { | |
2606 AddCNCodecs(); | |
2607 Init(); | |
2608 // Create a remote offer with audio and video content. | |
2609 rtc::scoped_ptr<JsepSessionDescription> offer(CreateRemoteOffer()); | |
2610 SetRemoteDescriptionWithoutError(offer.release()); | |
2611 | |
2612 webrtc::FakeConstraints constraints; | |
2613 constraints.SetOptionalVAD(false); | |
2614 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
2615 CreateAnswer(&constraints)); | |
2616 const cricket::ContentInfo* content = | |
2617 cricket::GetFirstAudioContent(answer->description()); | |
2618 ASSERT_TRUE(content != NULL); | |
2619 EXPECT_TRUE(VerifyNoCNCodecs(content)); | |
2620 } | |
2621 | |
2622 // This test verifies the call setup when remote answer with audio only and | |
2623 // later updates with video. | |
2624 TEST_F(WebRtcSessionTest, TestAVOfferWithAudioOnlyAnswer) { | |
2625 Init(); | |
2626 EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL); | |
2627 EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL); | |
2628 | |
2629 SendAudioVideoStream1(); | |
2630 SessionDescriptionInterface* offer = CreateOffer(); | |
2631 | |
2632 cricket::MediaSessionOptions options; | |
2633 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer, options); | |
2634 | |
2635 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer | |
2636 // and answer; | |
2637 SetLocalDescriptionWithoutError(offer); | |
2638 SetRemoteDescriptionWithoutError(answer); | |
2639 | |
2640 video_channel_ = media_engine_->GetVideoChannel(0); | |
2641 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
2642 | |
2643 ASSERT_TRUE(video_channel_ == NULL); | |
2644 | |
2645 ASSERT_EQ(0u, voice_channel_->recv_streams().size()); | |
2646 ASSERT_EQ(1u, voice_channel_->send_streams().size()); | |
2647 EXPECT_EQ(kAudioTrack1, voice_channel_->send_streams()[0].id); | |
2648 | |
2649 // Let the remote end update the session descriptions, with Audio and Video. | |
2650 SendAudioVideoStream2(); | |
2651 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2652 | |
2653 video_channel_ = media_engine_->GetVideoChannel(0); | |
2654 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
2655 | |
2656 ASSERT_TRUE(video_channel_ != NULL); | |
2657 ASSERT_TRUE(voice_channel_ != NULL); | |
2658 | |
2659 ASSERT_EQ(1u, video_channel_->recv_streams().size()); | |
2660 ASSERT_EQ(1u, video_channel_->send_streams().size()); | |
2661 EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id); | |
2662 EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id); | |
2663 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); | |
2664 ASSERT_EQ(1u, voice_channel_->send_streams().size()); | |
2665 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id); | |
2666 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id); | |
2667 | |
2668 // Change session back to audio only. | |
2669 SendAudioOnlyStream2(); | |
2670 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2671 | |
2672 EXPECT_EQ(0u, video_channel_->recv_streams().size()); | |
2673 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); | |
2674 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id); | |
2675 ASSERT_EQ(1u, voice_channel_->send_streams().size()); | |
2676 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id); | |
2677 } | |
2678 | |
2679 // This test verifies the call setup when remote answer with video only and | |
2680 // later updates with audio. | |
2681 TEST_F(WebRtcSessionTest, TestAVOfferWithVideoOnlyAnswer) { | |
2682 Init(); | |
2683 EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL); | |
2684 EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL); | |
2685 SendAudioVideoStream1(); | |
2686 SessionDescriptionInterface* offer = CreateOffer(); | |
2687 | |
2688 cricket::MediaSessionOptions options; | |
2689 options.recv_audio = false; | |
2690 options.recv_video = true; | |
2691 SessionDescriptionInterface* answer = CreateRemoteAnswer( | |
2692 offer, options, cricket::SEC_ENABLED); | |
2693 | |
2694 // SetLocalDescription and SetRemoteDescriptions takes ownership of offer | |
2695 // and answer. | |
2696 SetLocalDescriptionWithoutError(offer); | |
2697 SetRemoteDescriptionWithoutError(answer); | |
2698 | |
2699 video_channel_ = media_engine_->GetVideoChannel(0); | |
2700 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
2701 | |
2702 ASSERT_TRUE(voice_channel_ == NULL); | |
2703 ASSERT_TRUE(video_channel_ != NULL); | |
2704 | |
2705 EXPECT_EQ(0u, video_channel_->recv_streams().size()); | |
2706 ASSERT_EQ(1u, video_channel_->send_streams().size()); | |
2707 EXPECT_EQ(kVideoTrack1, video_channel_->send_streams()[0].id); | |
2708 | |
2709 // Update the session descriptions, with Audio and Video. | |
2710 SendAudioVideoStream2(); | |
2711 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2712 | |
2713 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
2714 ASSERT_TRUE(voice_channel_ != NULL); | |
2715 | |
2716 ASSERT_EQ(1u, voice_channel_->recv_streams().size()); | |
2717 ASSERT_EQ(1u, voice_channel_->send_streams().size()); | |
2718 EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id); | |
2719 EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id); | |
2720 | |
2721 // Change session back to video only. | |
2722 SendVideoOnlyStream2(); | |
2723 CreateAndSetRemoteOfferAndLocalAnswer(); | |
2724 | |
2725 video_channel_ = media_engine_->GetVideoChannel(0); | |
2726 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
2727 | |
2728 ASSERT_EQ(1u, video_channel_->recv_streams().size()); | |
2729 EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id); | |
2730 ASSERT_EQ(1u, video_channel_->send_streams().size()); | |
2731 EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id); | |
2732 } | |
2733 | |
2734 TEST_F(WebRtcSessionTest, VerifyCryptoParamsInSDP) { | |
2735 Init(); | |
2736 SendAudioVideoStream1(); | |
2737 scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2738 VerifyCryptoParams(offer->description()); | |
2739 SetRemoteDescriptionWithoutError(offer.release()); | |
2740 scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); | |
2741 VerifyCryptoParams(answer->description()); | |
2742 } | |
2743 | |
2744 TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) { | |
2745 options_.disable_encryption = true; | |
2746 Init(); | |
2747 SendAudioVideoStream1(); | |
2748 scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2749 VerifyNoCryptoParams(offer->description(), false); | |
2750 } | |
2751 | |
2752 TEST_F(WebRtcSessionTest, VerifyAnswerFromNonCryptoOffer) { | |
2753 Init(); | |
2754 VerifyAnswerFromNonCryptoOffer(); | |
2755 } | |
2756 | |
2757 TEST_F(WebRtcSessionTest, VerifyAnswerFromCryptoOffer) { | |
2758 Init(); | |
2759 VerifyAnswerFromCryptoOffer(); | |
2760 } | |
2761 | |
2762 // This test verifies that setLocalDescription fails if | |
2763 // no a=ice-ufrag and a=ice-pwd lines are present in the SDP. | |
2764 TEST_F(WebRtcSessionTest, TestSetLocalDescriptionWithoutIce) { | |
2765 Init(); | |
2766 SendAudioVideoStream1(); | |
2767 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2768 | |
2769 std::string sdp; | |
2770 RemoveIceUfragPwdLines(offer.get(), &sdp); | |
2771 SessionDescriptionInterface* modified_offer = | |
2772 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2773 SetLocalDescriptionOfferExpectError(kSdpWithoutIceUfragPwd, modified_offer); | |
2774 } | |
2775 | |
2776 // This test verifies that setRemoteDescription fails if | |
2777 // no a=ice-ufrag and a=ice-pwd lines are present in the SDP. | |
2778 TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionWithoutIce) { | |
2779 Init(); | |
2780 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer()); | |
2781 std::string sdp; | |
2782 RemoveIceUfragPwdLines(offer.get(), &sdp); | |
2783 SessionDescriptionInterface* modified_offer = | |
2784 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2785 SetRemoteDescriptionOfferExpectError(kSdpWithoutIceUfragPwd, modified_offer); | |
2786 } | |
2787 | |
2788 // This test verifies that setLocalDescription fails if local offer has | |
2789 // too short ice ufrag and pwd strings. | |
2790 TEST_F(WebRtcSessionTest, TestSetLocalDescriptionInvalidIceCredentials) { | |
2791 Init(); | |
2792 SendAudioVideoStream1(); | |
2793 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
2794 | |
2795 std::string sdp; | |
2796 // Modifying ice ufrag and pwd in local offer with strings smaller than the | |
2797 // recommended values of 4 and 22 bytes respectively. | |
2798 ModifyIceUfragPwdLines(offer.get(), "ice", "icepwd", &sdp); | |
2799 SessionDescriptionInterface* modified_offer = | |
2800 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2801 std::string error; | |
2802 EXPECT_FALSE(session_->SetLocalDescription(modified_offer, &error)); | |
2803 | |
2804 // Test with string greater than 256. | |
2805 sdp.clear(); | |
2806 ModifyIceUfragPwdLines(offer.get(), kTooLongIceUfragPwd, kTooLongIceUfragPwd, | |
2807 &sdp); | |
2808 modified_offer = CreateSessionDescription(JsepSessionDescription::kOffer, sdp, | |
2809 NULL); | |
2810 EXPECT_FALSE(session_->SetLocalDescription(modified_offer, &error)); | |
2811 } | |
2812 | |
2813 // This test verifies that setRemoteDescription fails if remote offer has | |
2814 // too short ice ufrag and pwd strings. | |
2815 TEST_F(WebRtcSessionTest, TestSetRemoteDescriptionInvalidIceCredentials) { | |
2816 Init(); | |
2817 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer()); | |
2818 std::string sdp; | |
2819 // Modifying ice ufrag and pwd in remote offer with strings smaller than the | |
2820 // recommended values of 4 and 22 bytes respectively. | |
2821 ModifyIceUfragPwdLines(offer.get(), "ice", "icepwd", &sdp); | |
2822 SessionDescriptionInterface* modified_offer = | |
2823 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2824 std::string error; | |
2825 EXPECT_FALSE(session_->SetRemoteDescription(modified_offer, &error)); | |
2826 | |
2827 sdp.clear(); | |
2828 ModifyIceUfragPwdLines(offer.get(), kTooLongIceUfragPwd, kTooLongIceUfragPwd, | |
2829 &sdp); | |
2830 modified_offer = CreateSessionDescription(JsepSessionDescription::kOffer, sdp, | |
2831 NULL); | |
2832 EXPECT_FALSE(session_->SetRemoteDescription(modified_offer, &error)); | |
2833 } | |
2834 | |
2835 // Test that if the remote offer indicates the peer requested ICE restart (via | |
2836 // a new ufrag or pwd), the old ICE candidates are not copied, and vice versa. | |
2837 TEST_F(WebRtcSessionTest, TestSetRemoteOfferWithIceRestart) { | |
2838 Init(); | |
2839 scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer()); | |
2840 | |
2841 // Create the first offer. | |
2842 std::string sdp; | |
2843 ModifyIceUfragPwdLines(offer.get(), "0123456789012345", | |
2844 "abcdefghijklmnopqrstuvwx", &sdp); | |
2845 SessionDescriptionInterface* offer1 = | |
2846 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2847 cricket::Candidate candidate1(1, "udp", rtc::SocketAddress("1.1.1.1", 5000), | |
2848 0, "", "", "relay", 0, ""); | |
2849 JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0, | |
2850 candidate1); | |
2851 EXPECT_TRUE(offer1->AddCandidate(&ice_candidate1)); | |
2852 SetRemoteDescriptionWithoutError(offer1); | |
2853 EXPECT_EQ(1, session_->remote_description()->candidates(0)->count()); | |
2854 | |
2855 // The second offer has the same ufrag and pwd but different address. | |
2856 sdp.clear(); | |
2857 ModifyIceUfragPwdLines(offer.get(), "0123456789012345", | |
2858 "abcdefghijklmnopqrstuvwx", &sdp); | |
2859 SessionDescriptionInterface* offer2 = | |
2860 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2861 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 6000)); | |
2862 JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0, | |
2863 candidate1); | |
2864 EXPECT_TRUE(offer2->AddCandidate(&ice_candidate2)); | |
2865 SetRemoteDescriptionWithoutError(offer2); | |
2866 EXPECT_EQ(2, session_->remote_description()->candidates(0)->count()); | |
2867 | |
2868 // The third offer has a different ufrag and different address. | |
2869 sdp.clear(); | |
2870 ModifyIceUfragPwdLines(offer.get(), "0123456789012333", | |
2871 "abcdefghijklmnopqrstuvwx", &sdp); | |
2872 SessionDescriptionInterface* offer3 = | |
2873 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2874 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 7000)); | |
2875 JsepIceCandidate ice_candidate3(kMediaContentName0, kMediaContentIndex0, | |
2876 candidate1); | |
2877 EXPECT_TRUE(offer3->AddCandidate(&ice_candidate3)); | |
2878 SetRemoteDescriptionWithoutError(offer3); | |
2879 EXPECT_EQ(1, session_->remote_description()->candidates(0)->count()); | |
2880 | |
2881 // The fourth offer has no candidate but a different ufrag/pwd. | |
2882 sdp.clear(); | |
2883 ModifyIceUfragPwdLines(offer.get(), "0123456789012444", | |
2884 "abcdefghijklmnopqrstuvyz", &sdp); | |
2885 SessionDescriptionInterface* offer4 = | |
2886 CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL); | |
2887 SetRemoteDescriptionWithoutError(offer4); | |
2888 EXPECT_EQ(0, session_->remote_description()->candidates(0)->count()); | |
2889 } | |
2890 | |
2891 // Test that if the remote answer indicates the peer requested ICE restart (via | |
2892 // a new ufrag or pwd), the old ICE candidates are not copied, and vice versa. | |
2893 TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithIceRestart) { | |
2894 Init(); | |
2895 SessionDescriptionInterface* offer = CreateOffer(); | |
2896 SetLocalDescriptionWithoutError(offer); | |
2897 scoped_ptr<SessionDescriptionInterface> answer(CreateRemoteAnswer(offer)); | |
2898 | |
2899 // Create the first answer. | |
2900 std::string sdp; | |
2901 ModifyIceUfragPwdLines(answer.get(), "0123456789012345", | |
2902 "abcdefghijklmnopqrstuvwx", &sdp); | |
2903 SessionDescriptionInterface* answer1 = | |
2904 CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); | |
2905 cricket::Candidate candidate1(1, "udp", rtc::SocketAddress("1.1.1.1", 5000), | |
2906 0, "", "", "relay", 0, ""); | |
2907 JsepIceCandidate ice_candidate1(kMediaContentName0, kMediaContentIndex0, | |
2908 candidate1); | |
2909 EXPECT_TRUE(answer1->AddCandidate(&ice_candidate1)); | |
2910 SetRemoteDescriptionWithoutError(answer1); | |
2911 EXPECT_EQ(1, session_->remote_description()->candidates(0)->count()); | |
2912 | |
2913 // The second answer has the same ufrag and pwd but different address. | |
2914 sdp.clear(); | |
2915 ModifyIceUfragPwdLines(answer.get(), "0123456789012345", | |
2916 "abcdefghijklmnopqrstuvwx", &sdp); | |
2917 SessionDescriptionInterface* answer2 = | |
2918 CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); | |
2919 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 6000)); | |
2920 JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0, | |
2921 candidate1); | |
2922 EXPECT_TRUE(answer2->AddCandidate(&ice_candidate2)); | |
2923 SetRemoteDescriptionWithoutError(answer2); | |
2924 EXPECT_EQ(2, session_->remote_description()->candidates(0)->count()); | |
2925 | |
2926 // The third answer has a different ufrag and different address. | |
2927 sdp.clear(); | |
2928 ModifyIceUfragPwdLines(answer.get(), "0123456789012333", | |
2929 "abcdefghijklmnopqrstuvwx", &sdp); | |
2930 SessionDescriptionInterface* answer3 = | |
2931 CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); | |
2932 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 7000)); | |
2933 JsepIceCandidate ice_candidate3(kMediaContentName0, kMediaContentIndex0, | |
2934 candidate1); | |
2935 EXPECT_TRUE(answer3->AddCandidate(&ice_candidate3)); | |
2936 SetRemoteDescriptionWithoutError(answer3); | |
2937 EXPECT_EQ(1, session_->remote_description()->candidates(0)->count()); | |
2938 | |
2939 // The fourth answer has no candidate but a different ufrag/pwd. | |
2940 sdp.clear(); | |
2941 ModifyIceUfragPwdLines(answer.get(), "0123456789012444", | |
2942 "abcdefghijklmnopqrstuvyz", &sdp); | |
2943 SessionDescriptionInterface* offer4 = | |
2944 CreateSessionDescription(JsepSessionDescription::kPrAnswer, sdp, NULL); | |
2945 SetRemoteDescriptionWithoutError(offer4); | |
2946 EXPECT_EQ(0, session_->remote_description()->candidates(0)->count()); | |
2947 } | |
2948 | |
2949 // Test that candidates sent to the "video" transport do not get pushed down to | |
2950 // the "audio" transport channel when bundling. | |
2951 TEST_F(WebRtcSessionTest, TestIgnoreCandidatesForUnusedTransportWhenBundling) { | |
2952 AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort)); | |
2953 | |
2954 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced); | |
2955 SendAudioVideoStream1(); | |
2956 | |
2957 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
2958 options.use_rtp_mux = true; | |
2959 | |
2960 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
2961 SetRemoteDescriptionWithoutError(offer); | |
2962 | |
2963 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
2964 SetLocalDescriptionWithoutError(answer); | |
2965 | |
2966 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
2967 session_->video_rtp_transport_channel()); | |
2968 | |
2969 cricket::BaseChannel* voice_channel = session_->voice_channel(); | |
2970 ASSERT(voice_channel != NULL); | |
2971 | |
2972 // Checks if one of the transport channels contains a connection using a given | |
2973 // port. | |
2974 auto connection_with_remote_port = [this, voice_channel](int port) { | |
2975 SessionStats stats; | |
2976 session_->GetChannelTransportStats(voice_channel, &stats); | |
2977 for (auto& kv : stats.transport_stats) { | |
2978 for (auto& chan_stat : kv.second.channel_stats) { | |
2979 for (auto& conn_info : chan_stat.connection_infos) { | |
2980 if (conn_info.remote_candidate.address().port() == port) { | |
2981 return true; | |
2982 } | |
2983 } | |
2984 } | |
2985 } | |
2986 return false; | |
2987 }; | |
2988 | |
2989 EXPECT_FALSE(connection_with_remote_port(5000)); | |
2990 EXPECT_FALSE(connection_with_remote_port(5001)); | |
2991 EXPECT_FALSE(connection_with_remote_port(6000)); | |
2992 | |
2993 // The way the *_WAIT checks work is they only wait if the condition fails, | |
2994 // which does not help in the case where state is not changing. This is | |
2995 // problematic in this test since we want to verify that adding a video | |
2996 // candidate does _not_ change state. So we interleave candidates and assume | |
2997 // that messages are executed in the order they were posted. | |
2998 | |
2999 // First audio candidate. | |
3000 cricket::Candidate candidate0; | |
3001 candidate0.set_address(rtc::SocketAddress("1.1.1.1", 5000)); | |
3002 candidate0.set_component(1); | |
3003 candidate0.set_protocol("udp"); | |
3004 JsepIceCandidate ice_candidate0(kMediaContentName0, kMediaContentIndex0, | |
3005 candidate0); | |
3006 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate0)); | |
3007 | |
3008 // Video candidate. | |
3009 cricket::Candidate candidate1; | |
3010 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 6000)); | |
3011 candidate1.set_component(1); | |
3012 candidate1.set_protocol("udp"); | |
3013 JsepIceCandidate ice_candidate1(kMediaContentName1, kMediaContentIndex1, | |
3014 candidate1); | |
3015 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1)); | |
3016 | |
3017 // Second audio candidate. | |
3018 cricket::Candidate candidate2; | |
3019 candidate2.set_address(rtc::SocketAddress("1.1.1.1", 5001)); | |
3020 candidate2.set_component(1); | |
3021 candidate2.set_protocol("udp"); | |
3022 JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0, | |
3023 candidate2); | |
3024 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2)); | |
3025 | |
3026 EXPECT_TRUE_WAIT(connection_with_remote_port(5000), 1000); | |
3027 EXPECT_TRUE_WAIT(connection_with_remote_port(5001), 1000); | |
3028 | |
3029 // No need here for a _WAIT check since we are checking that state hasn't | |
3030 // changed: if this is false we would be doing waits for nothing and if this | |
3031 // is true then there will be no messages processed anyways. | |
3032 EXPECT_FALSE(connection_with_remote_port(6000)); | |
3033 } | |
3034 | |
3035 // kBundlePolicyBalanced BUNDLE policy and answer contains BUNDLE. | |
3036 TEST_F(WebRtcSessionTest, TestBalancedBundleInAnswer) { | |
3037 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced); | |
3038 SendAudioVideoStream1(); | |
3039 | |
3040 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3041 options.use_rtp_mux = true; | |
3042 | |
3043 SessionDescriptionInterface* offer = CreateOffer(options); | |
3044 SetLocalDescriptionWithoutError(offer); | |
3045 | |
3046 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
3047 session_->video_rtp_transport_channel()); | |
3048 | |
3049 SendAudioVideoStream2(); | |
3050 SessionDescriptionInterface* answer = | |
3051 CreateRemoteAnswer(session_->local_description()); | |
3052 SetRemoteDescriptionWithoutError(answer); | |
3053 | |
3054 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3055 session_->video_rtp_transport_channel()); | |
3056 } | |
3057 | |
3058 // kBundlePolicyBalanced BUNDLE policy but no BUNDLE in the answer. | |
3059 TEST_F(WebRtcSessionTest, TestBalancedNoBundleInAnswer) { | |
3060 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced); | |
3061 SendAudioVideoStream1(); | |
3062 | |
3063 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3064 options.use_rtp_mux = true; | |
3065 | |
3066 SessionDescriptionInterface* offer = CreateOffer(options); | |
3067 SetLocalDescriptionWithoutError(offer); | |
3068 | |
3069 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
3070 session_->video_rtp_transport_channel()); | |
3071 | |
3072 SendAudioVideoStream2(); | |
3073 | |
3074 // Remove BUNDLE from the answer. | |
3075 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
3076 CreateRemoteAnswer(session_->local_description())); | |
3077 cricket::SessionDescription* answer_copy = answer->description()->Copy(); | |
3078 answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); | |
3079 JsepSessionDescription* modified_answer = | |
3080 new JsepSessionDescription(JsepSessionDescription::kAnswer); | |
3081 modified_answer->Initialize(answer_copy, "1", "1"); | |
3082 SetRemoteDescriptionWithoutError(modified_answer); // | |
3083 | |
3084 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
3085 session_->video_rtp_transport_channel()); | |
3086 } | |
3087 | |
3088 // kBundlePolicyMaxBundle policy with BUNDLE in the answer. | |
3089 TEST_F(WebRtcSessionTest, TestMaxBundleBundleInAnswer) { | |
3090 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle); | |
3091 SendAudioVideoStream1(); | |
3092 | |
3093 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3094 options.use_rtp_mux = true; | |
3095 | |
3096 SessionDescriptionInterface* offer = CreateOffer(options); | |
3097 SetLocalDescriptionWithoutError(offer); | |
3098 | |
3099 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3100 session_->video_rtp_transport_channel()); | |
3101 | |
3102 SendAudioVideoStream2(); | |
3103 SessionDescriptionInterface* answer = | |
3104 CreateRemoteAnswer(session_->local_description()); | |
3105 SetRemoteDescriptionWithoutError(answer); | |
3106 | |
3107 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3108 session_->video_rtp_transport_channel()); | |
3109 } | |
3110 | |
3111 // kBundlePolicyMaxBundle policy with BUNDLE in the answer, but no | |
3112 // audio content in the answer. | |
3113 TEST_F(WebRtcSessionTest, TestMaxBundleRejectAudio) { | |
3114 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle); | |
3115 SendAudioVideoStream1(); | |
3116 | |
3117 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3118 options.use_rtp_mux = true; | |
3119 | |
3120 SessionDescriptionInterface* offer = CreateOffer(options); | |
3121 SetLocalDescriptionWithoutError(offer); | |
3122 | |
3123 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3124 session_->video_rtp_transport_channel()); | |
3125 | |
3126 SendAudioVideoStream2(); | |
3127 cricket::MediaSessionOptions recv_options; | |
3128 recv_options.recv_audio = false; | |
3129 recv_options.recv_video = true; | |
3130 SessionDescriptionInterface* answer = | |
3131 CreateRemoteAnswer(session_->local_description(), recv_options); | |
3132 SetRemoteDescriptionWithoutError(answer); | |
3133 | |
3134 EXPECT_TRUE(nullptr == session_->voice_channel()); | |
3135 EXPECT_TRUE(nullptr != session_->video_rtp_transport_channel()); | |
3136 | |
3137 session_->Close(); | |
3138 EXPECT_TRUE(nullptr == session_->voice_rtp_transport_channel()); | |
3139 EXPECT_TRUE(nullptr == session_->voice_rtcp_transport_channel()); | |
3140 EXPECT_TRUE(nullptr == session_->video_rtp_transport_channel()); | |
3141 EXPECT_TRUE(nullptr == session_->video_rtcp_transport_channel()); | |
3142 } | |
3143 | |
3144 // kBundlePolicyMaxBundle policy but no BUNDLE in the answer. | |
3145 TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInAnswer) { | |
3146 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle); | |
3147 SendAudioVideoStream1(); | |
3148 | |
3149 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3150 options.use_rtp_mux = true; | |
3151 | |
3152 SessionDescriptionInterface* offer = CreateOffer(options); | |
3153 SetLocalDescriptionWithoutError(offer); | |
3154 | |
3155 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3156 session_->video_rtp_transport_channel()); | |
3157 | |
3158 SendAudioVideoStream2(); | |
3159 | |
3160 // Remove BUNDLE from the answer. | |
3161 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
3162 CreateRemoteAnswer(session_->local_description())); | |
3163 cricket::SessionDescription* answer_copy = answer->description()->Copy(); | |
3164 answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); | |
3165 JsepSessionDescription* modified_answer = | |
3166 new JsepSessionDescription(JsepSessionDescription::kAnswer); | |
3167 modified_answer->Initialize(answer_copy, "1", "1"); | |
3168 SetRemoteDescriptionWithoutError(modified_answer); | |
3169 | |
3170 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3171 session_->video_rtp_transport_channel()); | |
3172 } | |
3173 | |
3174 // kBundlePolicyMaxBundle policy with BUNDLE in the remote offer. | |
3175 TEST_F(WebRtcSessionTest, TestMaxBundleBundleInRemoteOffer) { | |
3176 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle); | |
3177 SendAudioVideoStream1(); | |
3178 | |
3179 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
3180 SetRemoteDescriptionWithoutError(offer); | |
3181 | |
3182 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3183 session_->video_rtp_transport_channel()); | |
3184 | |
3185 SendAudioVideoStream2(); | |
3186 SessionDescriptionInterface* answer = CreateAnswer(nullptr); | |
3187 SetLocalDescriptionWithoutError(answer); | |
3188 | |
3189 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3190 session_->video_rtp_transport_channel()); | |
3191 } | |
3192 | |
3193 // kBundlePolicyMaxBundle policy but no BUNDLE in the remote offer. | |
3194 TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInRemoteOffer) { | |
3195 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle); | |
3196 SendAudioVideoStream1(); | |
3197 | |
3198 // Remove BUNDLE from the offer. | |
3199 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer()); | |
3200 cricket::SessionDescription* offer_copy = offer->description()->Copy(); | |
3201 offer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); | |
3202 JsepSessionDescription* modified_offer = | |
3203 new JsepSessionDescription(JsepSessionDescription::kOffer); | |
3204 modified_offer->Initialize(offer_copy, "1", "1"); | |
3205 | |
3206 // Expect an error when applying the remote description | |
3207 SetRemoteDescriptionExpectError(JsepSessionDescription::kOffer, | |
3208 kCreateChannelFailed, modified_offer); | |
3209 } | |
3210 | |
3211 // kBundlePolicyMaxCompat bundle policy and answer contains BUNDLE. | |
3212 TEST_F(WebRtcSessionTest, TestMaxCompatBundleInAnswer) { | |
3213 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat); | |
3214 SendAudioVideoStream1(); | |
3215 | |
3216 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3217 options.use_rtp_mux = true; | |
3218 | |
3219 SessionDescriptionInterface* offer = CreateOffer(options); | |
3220 SetLocalDescriptionWithoutError(offer); | |
3221 | |
3222 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
3223 session_->video_rtp_transport_channel()); | |
3224 | |
3225 SendAudioVideoStream2(); | |
3226 SessionDescriptionInterface* answer = | |
3227 CreateRemoteAnswer(session_->local_description()); | |
3228 SetRemoteDescriptionWithoutError(answer); | |
3229 | |
3230 // This should lead to an audio-only call but isn't implemented | |
3231 // correctly yet. | |
3232 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3233 session_->video_rtp_transport_channel()); | |
3234 } | |
3235 | |
3236 // kBundlePolicyMaxCompat BUNDLE policy but no BUNDLE in the answer. | |
3237 TEST_F(WebRtcSessionTest, TestMaxCompatNoBundleInAnswer) { | |
3238 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat); | |
3239 SendAudioVideoStream1(); | |
3240 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3241 options.use_rtp_mux = true; | |
3242 | |
3243 SessionDescriptionInterface* offer = CreateOffer(options); | |
3244 SetLocalDescriptionWithoutError(offer); | |
3245 | |
3246 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
3247 session_->video_rtp_transport_channel()); | |
3248 | |
3249 SendAudioVideoStream2(); | |
3250 | |
3251 // Remove BUNDLE from the answer. | |
3252 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
3253 CreateRemoteAnswer(session_->local_description())); | |
3254 cricket::SessionDescription* answer_copy = answer->description()->Copy(); | |
3255 answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE); | |
3256 JsepSessionDescription* modified_answer = | |
3257 new JsepSessionDescription(JsepSessionDescription::kAnswer); | |
3258 modified_answer->Initialize(answer_copy, "1", "1"); | |
3259 SetRemoteDescriptionWithoutError(modified_answer); // | |
3260 | |
3261 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
3262 session_->video_rtp_transport_channel()); | |
3263 } | |
3264 | |
3265 // kBundlePolicyMaxbundle and then we call SetRemoteDescription first. | |
3266 TEST_F(WebRtcSessionTest, TestMaxBundleWithSetRemoteDescriptionFirst) { | |
3267 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle); | |
3268 SendAudioVideoStream1(); | |
3269 | |
3270 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3271 options.use_rtp_mux = true; | |
3272 | |
3273 SessionDescriptionInterface* offer = CreateOffer(options); | |
3274 SetRemoteDescriptionWithoutError(offer); | |
3275 | |
3276 EXPECT_EQ(session_->voice_rtp_transport_channel(), | |
3277 session_->video_rtp_transport_channel()); | |
3278 } | |
3279 | |
3280 TEST_F(WebRtcSessionTest, TestRequireRtcpMux) { | |
3281 InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyRequire); | |
3282 SendAudioVideoStream1(); | |
3283 | |
3284 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3285 SessionDescriptionInterface* offer = CreateOffer(options); | |
3286 SetLocalDescriptionWithoutError(offer); | |
3287 | |
3288 EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL); | |
3289 EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL); | |
3290 | |
3291 SendAudioVideoStream2(); | |
3292 SessionDescriptionInterface* answer = | |
3293 CreateRemoteAnswer(session_->local_description()); | |
3294 SetRemoteDescriptionWithoutError(answer); | |
3295 | |
3296 EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL); | |
3297 EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL); | |
3298 } | |
3299 | |
3300 TEST_F(WebRtcSessionTest, TestNegotiateRtcpMux) { | |
3301 InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyNegotiate); | |
3302 SendAudioVideoStream1(); | |
3303 | |
3304 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3305 SessionDescriptionInterface* offer = CreateOffer(options); | |
3306 SetLocalDescriptionWithoutError(offer); | |
3307 | |
3308 EXPECT_TRUE(session_->voice_rtcp_transport_channel() != NULL); | |
3309 EXPECT_TRUE(session_->video_rtcp_transport_channel() != NULL); | |
3310 | |
3311 SendAudioVideoStream2(); | |
3312 SessionDescriptionInterface* answer = | |
3313 CreateRemoteAnswer(session_->local_description()); | |
3314 SetRemoteDescriptionWithoutError(answer); | |
3315 | |
3316 EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL); | |
3317 EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL); | |
3318 } | |
3319 | |
3320 // This test verifies that SetLocalDescription and SetRemoteDescription fails | |
3321 // if BUNDLE is enabled but rtcp-mux is disabled in m-lines. | |
3322 TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) { | |
3323 Init(); | |
3324 SendAudioVideoStream1(); | |
3325 | |
3326 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
3327 options.use_rtp_mux = true; | |
3328 | |
3329 SessionDescriptionInterface* offer = CreateOffer(options); | |
3330 std::string offer_str; | |
3331 offer->ToString(&offer_str); | |
3332 // Disable rtcp-mux | |
3333 const std::string rtcp_mux = "rtcp-mux"; | |
3334 const std::string xrtcp_mux = "xrtcp-mux"; | |
3335 rtc::replace_substrs(rtcp_mux.c_str(), rtcp_mux.length(), | |
3336 xrtcp_mux.c_str(), xrtcp_mux.length(), | |
3337 &offer_str); | |
3338 JsepSessionDescription* local_offer = | |
3339 new JsepSessionDescription(JsepSessionDescription::kOffer); | |
3340 EXPECT_TRUE((local_offer)->Initialize(offer_str, NULL)); | |
3341 SetLocalDescriptionOfferExpectError(kBundleWithoutRtcpMux, local_offer); | |
3342 JsepSessionDescription* remote_offer = | |
3343 new JsepSessionDescription(JsepSessionDescription::kOffer); | |
3344 EXPECT_TRUE((remote_offer)->Initialize(offer_str, NULL)); | |
3345 SetRemoteDescriptionOfferExpectError(kBundleWithoutRtcpMux, remote_offer); | |
3346 // Trying unmodified SDP. | |
3347 SetLocalDescriptionWithoutError(offer); | |
3348 } | |
3349 | |
3350 TEST_F(WebRtcSessionTest, SetAudioPlayout) { | |
3351 Init(); | |
3352 SendAudioVideoStream1(); | |
3353 CreateAndSetRemoteOfferAndLocalAnswer(); | |
3354 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); | |
3355 ASSERT_TRUE(channel != NULL); | |
3356 ASSERT_EQ(1u, channel->recv_streams().size()); | |
3357 uint32_t receive_ssrc = channel->recv_streams()[0].first_ssrc(); | |
3358 double volume; | |
3359 EXPECT_TRUE(channel->GetOutputVolume(receive_ssrc, &volume)); | |
3360 EXPECT_EQ(1, volume); | |
3361 session_->SetAudioPlayout(receive_ssrc, false); | |
3362 EXPECT_TRUE(channel->GetOutputVolume(receive_ssrc, &volume)); | |
3363 EXPECT_EQ(0, volume); | |
3364 session_->SetAudioPlayout(receive_ssrc, true); | |
3365 EXPECT_TRUE(channel->GetOutputVolume(receive_ssrc, &volume)); | |
3366 EXPECT_EQ(1, volume); | |
3367 } | |
3368 | |
3369 TEST_F(WebRtcSessionTest, SetAudioSend) { | |
3370 Init(); | |
3371 SendAudioVideoStream1(); | |
3372 CreateAndSetRemoteOfferAndLocalAnswer(); | |
3373 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); | |
3374 ASSERT_TRUE(channel != NULL); | |
3375 ASSERT_EQ(1u, channel->send_streams().size()); | |
3376 uint32_t send_ssrc = channel->send_streams()[0].first_ssrc(); | |
3377 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); | |
3378 | |
3379 cricket::AudioOptions options; | |
3380 options.echo_cancellation = rtc::Optional<bool>(true); | |
3381 | |
3382 rtc::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer()); | |
3383 session_->SetAudioSend(send_ssrc, false, options, renderer.get()); | |
3384 EXPECT_TRUE(channel->IsStreamMuted(send_ssrc)); | |
3385 EXPECT_EQ(rtc::Optional<bool>(), channel->options().echo_cancellation); | |
3386 EXPECT_TRUE(renderer->sink() != NULL); | |
3387 | |
3388 // This will trigger SetSink(NULL) to the |renderer|. | |
3389 session_->SetAudioSend(send_ssrc, true, options, NULL); | |
3390 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); | |
3391 EXPECT_EQ(rtc::Optional<bool>(true), channel->options().echo_cancellation); | |
3392 EXPECT_TRUE(renderer->sink() == NULL); | |
3393 } | |
3394 | |
3395 TEST_F(WebRtcSessionTest, AudioRendererForLocalStream) { | |
3396 Init(); | |
3397 SendAudioVideoStream1(); | |
3398 CreateAndSetRemoteOfferAndLocalAnswer(); | |
3399 cricket::FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); | |
3400 ASSERT_TRUE(channel != NULL); | |
3401 ASSERT_EQ(1u, channel->send_streams().size()); | |
3402 uint32_t send_ssrc = channel->send_streams()[0].first_ssrc(); | |
3403 | |
3404 rtc::scoped_ptr<FakeAudioRenderer> renderer(new FakeAudioRenderer()); | |
3405 cricket::AudioOptions options; | |
3406 session_->SetAudioSend(send_ssrc, true, options, renderer.get()); | |
3407 EXPECT_TRUE(renderer->sink() != NULL); | |
3408 | |
3409 // Delete the |renderer| and it will trigger OnClose() to the sink, and this | |
3410 // will invalidate the |renderer_| pointer in the sink and prevent getting a | |
3411 // SetSink(NULL) callback afterwards. | |
3412 renderer.reset(); | |
3413 | |
3414 // This will trigger SetSink(NULL) if no OnClose() callback. | |
3415 session_->SetAudioSend(send_ssrc, true, options, NULL); | |
3416 } | |
3417 | |
3418 TEST_F(WebRtcSessionTest, SetVideoPlayout) { | |
3419 Init(); | |
3420 SendAudioVideoStream1(); | |
3421 CreateAndSetRemoteOfferAndLocalAnswer(); | |
3422 cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0); | |
3423 ASSERT_TRUE(channel != NULL); | |
3424 ASSERT_LT(0u, channel->sinks().size()); | |
3425 EXPECT_TRUE(channel->sinks().begin()->second == NULL); | |
3426 ASSERT_EQ(1u, channel->recv_streams().size()); | |
3427 uint32_t receive_ssrc = channel->recv_streams()[0].first_ssrc(); | |
3428 cricket::FakeVideoRenderer renderer; | |
3429 session_->SetVideoPlayout(receive_ssrc, true, &renderer); | |
3430 EXPECT_TRUE(channel->sinks().begin()->second == &renderer); | |
3431 session_->SetVideoPlayout(receive_ssrc, false, &renderer); | |
3432 EXPECT_TRUE(channel->sinks().begin()->second == NULL); | |
3433 } | |
3434 | |
3435 TEST_F(WebRtcSessionTest, SetVideoSend) { | |
3436 Init(); | |
3437 SendAudioVideoStream1(); | |
3438 CreateAndSetRemoteOfferAndLocalAnswer(); | |
3439 cricket::FakeVideoMediaChannel* channel = media_engine_->GetVideoChannel(0); | |
3440 ASSERT_TRUE(channel != NULL); | |
3441 ASSERT_EQ(1u, channel->send_streams().size()); | |
3442 uint32_t send_ssrc = channel->send_streams()[0].first_ssrc(); | |
3443 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); | |
3444 cricket::VideoOptions* options = NULL; | |
3445 session_->SetVideoSend(send_ssrc, false, options); | |
3446 EXPECT_TRUE(channel->IsStreamMuted(send_ssrc)); | |
3447 session_->SetVideoSend(send_ssrc, true, options); | |
3448 EXPECT_FALSE(channel->IsStreamMuted(send_ssrc)); | |
3449 } | |
3450 | |
3451 TEST_F(WebRtcSessionTest, CanNotInsertDtmf) { | |
3452 TestCanInsertDtmf(false); | |
3453 } | |
3454 | |
3455 TEST_F(WebRtcSessionTest, CanInsertDtmf) { | |
3456 TestCanInsertDtmf(true); | |
3457 } | |
3458 | |
3459 TEST_F(WebRtcSessionTest, InsertDtmf) { | |
3460 // Setup | |
3461 Init(); | |
3462 SendAudioVideoStream1(); | |
3463 CreateAndSetRemoteOfferAndLocalAnswer(); | |
3464 FakeVoiceMediaChannel* channel = media_engine_->GetVoiceChannel(0); | |
3465 EXPECT_EQ(0U, channel->dtmf_info_queue().size()); | |
3466 | |
3467 // Insert DTMF | |
3468 const int expected_duration = 90; | |
3469 session_->InsertDtmf(kAudioTrack1, 0, expected_duration); | |
3470 session_->InsertDtmf(kAudioTrack1, 1, expected_duration); | |
3471 session_->InsertDtmf(kAudioTrack1, 2, expected_duration); | |
3472 | |
3473 // Verify | |
3474 ASSERT_EQ(3U, channel->dtmf_info_queue().size()); | |
3475 const uint32_t send_ssrc = channel->send_streams()[0].first_ssrc(); | |
3476 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[0], send_ssrc, 0, | |
3477 expected_duration)); | |
3478 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[1], send_ssrc, 1, | |
3479 expected_duration)); | |
3480 EXPECT_TRUE(CompareDtmfInfo(channel->dtmf_info_queue()[2], send_ssrc, 2, | |
3481 expected_duration)); | |
3482 } | |
3483 | |
3484 // This test verifies the |initial_offerer| flag when session initiates the | |
3485 // call. | |
3486 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsOriginator) { | |
3487 Init(); | |
3488 EXPECT_FALSE(session_->initial_offerer()); | |
3489 SessionDescriptionInterface* offer = CreateOffer(); | |
3490 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); | |
3491 SetLocalDescriptionWithoutError(offer); | |
3492 EXPECT_TRUE(session_->initial_offerer()); | |
3493 SetRemoteDescriptionWithoutError(answer); | |
3494 EXPECT_TRUE(session_->initial_offerer()); | |
3495 } | |
3496 | |
3497 // This test verifies the |initial_offerer| flag when session receives the call. | |
3498 TEST_F(WebRtcSessionTest, TestInitiatorFlagAsReceiver) { | |
3499 Init(); | |
3500 EXPECT_FALSE(session_->initial_offerer()); | |
3501 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
3502 SetRemoteDescriptionWithoutError(offer); | |
3503 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
3504 | |
3505 EXPECT_FALSE(session_->initial_offerer()); | |
3506 SetLocalDescriptionWithoutError(answer); | |
3507 EXPECT_FALSE(session_->initial_offerer()); | |
3508 } | |
3509 | |
3510 // Verifing local offer and remote answer have matching m-lines as per RFC 3264. | |
3511 TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) { | |
3512 Init(); | |
3513 SendAudioVideoStream1(); | |
3514 SessionDescriptionInterface* offer = CreateOffer(); | |
3515 SetLocalDescriptionWithoutError(offer); | |
3516 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
3517 CreateRemoteAnswer(session_->local_description())); | |
3518 | |
3519 cricket::SessionDescription* answer_copy = answer->description()->Copy(); | |
3520 answer_copy->RemoveContentByName("video"); | |
3521 JsepSessionDescription* modified_answer = | |
3522 new JsepSessionDescription(JsepSessionDescription::kAnswer); | |
3523 | |
3524 EXPECT_TRUE(modified_answer->Initialize(answer_copy, | |
3525 answer->session_id(), | |
3526 answer->session_version())); | |
3527 SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer); | |
3528 | |
3529 // Different content names. | |
3530 std::string sdp; | |
3531 EXPECT_TRUE(answer->ToString(&sdp)); | |
3532 const std::string kAudioMid = "a=mid:audio"; | |
3533 const std::string kAudioMidReplaceStr = "a=mid:audio_content_name"; | |
3534 rtc::replace_substrs(kAudioMid.c_str(), kAudioMid.length(), | |
3535 kAudioMidReplaceStr.c_str(), | |
3536 kAudioMidReplaceStr.length(), | |
3537 &sdp); | |
3538 SessionDescriptionInterface* modified_answer1 = | |
3539 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL); | |
3540 SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer1); | |
3541 | |
3542 // Different media types. | |
3543 EXPECT_TRUE(answer->ToString(&sdp)); | |
3544 const std::string kAudioMline = "m=audio"; | |
3545 const std::string kAudioMlineReplaceStr = "m=video"; | |
3546 rtc::replace_substrs(kAudioMline.c_str(), kAudioMline.length(), | |
3547 kAudioMlineReplaceStr.c_str(), | |
3548 kAudioMlineReplaceStr.length(), | |
3549 &sdp); | |
3550 SessionDescriptionInterface* modified_answer2 = | |
3551 CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL); | |
3552 SetRemoteDescriptionAnswerExpectError(kMlineMismatch, modified_answer2); | |
3553 | |
3554 SetRemoteDescriptionWithoutError(answer.release()); | |
3555 } | |
3556 | |
3557 // Verifying remote offer and local answer have matching m-lines as per | |
3558 // RFC 3264. | |
3559 TEST_F(WebRtcSessionTest, TestIncorrectMLinesInLocalAnswer) { | |
3560 Init(); | |
3561 SendAudioVideoStream1(); | |
3562 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
3563 SetRemoteDescriptionWithoutError(offer); | |
3564 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
3565 | |
3566 cricket::SessionDescription* answer_copy = answer->description()->Copy(); | |
3567 answer_copy->RemoveContentByName("video"); | |
3568 JsepSessionDescription* modified_answer = | |
3569 new JsepSessionDescription(JsepSessionDescription::kAnswer); | |
3570 | |
3571 EXPECT_TRUE(modified_answer->Initialize(answer_copy, | |
3572 answer->session_id(), | |
3573 answer->session_version())); | |
3574 SetLocalDescriptionAnswerExpectError(kMlineMismatch, modified_answer); | |
3575 SetLocalDescriptionWithoutError(answer); | |
3576 } | |
3577 | |
3578 // This test verifies that WebRtcSession does not start candidate allocation | |
3579 // before SetLocalDescription is called. | |
3580 TEST_F(WebRtcSessionTest, TestIceStartAfterSetLocalDescriptionOnly) { | |
3581 Init(); | |
3582 SendAudioVideoStream1(); | |
3583 SessionDescriptionInterface* offer = CreateRemoteOffer(); | |
3584 cricket::Candidate candidate; | |
3585 candidate.set_component(1); | |
3586 JsepIceCandidate ice_candidate(kMediaContentName0, kMediaContentIndex0, | |
3587 candidate); | |
3588 EXPECT_TRUE(offer->AddCandidate(&ice_candidate)); | |
3589 cricket::Candidate candidate1; | |
3590 candidate1.set_component(1); | |
3591 JsepIceCandidate ice_candidate1(kMediaContentName1, kMediaContentIndex1, | |
3592 candidate1); | |
3593 EXPECT_TRUE(offer->AddCandidate(&ice_candidate1)); | |
3594 SetRemoteDescriptionWithoutError(offer); | |
3595 ASSERT_TRUE(session_->voice_rtp_transport_channel() != NULL); | |
3596 ASSERT_TRUE(session_->video_rtp_transport_channel() != NULL); | |
3597 | |
3598 // Pump for 1 second and verify that no candidates are generated. | |
3599 rtc::Thread::Current()->ProcessMessages(1000); | |
3600 EXPECT_TRUE(observer_.mline_0_candidates_.empty()); | |
3601 EXPECT_TRUE(observer_.mline_1_candidates_.empty()); | |
3602 | |
3603 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
3604 SetLocalDescriptionWithoutError(answer); | |
3605 EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); | |
3606 } | |
3607 | |
3608 // This test verifies that crypto parameter is updated in local session | |
3609 // description as per security policy set in MediaSessionDescriptionFactory. | |
3610 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescription) { | |
3611 Init(); | |
3612 SendAudioVideoStream1(); | |
3613 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
3614 | |
3615 // Making sure SetLocalDescription correctly sets crypto value in | |
3616 // SessionDescription object after de-serialization of sdp string. The value | |
3617 // will be set as per MediaSessionDescriptionFactory. | |
3618 std::string offer_str; | |
3619 offer->ToString(&offer_str); | |
3620 SessionDescriptionInterface* jsep_offer_str = | |
3621 CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL); | |
3622 SetLocalDescriptionWithoutError(jsep_offer_str); | |
3623 EXPECT_TRUE(session_->voice_channel()->secure_required()); | |
3624 EXPECT_TRUE(session_->video_channel()->secure_required()); | |
3625 } | |
3626 | |
3627 // This test verifies the crypto parameter when security is disabled. | |
3628 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) { | |
3629 options_.disable_encryption = true; | |
3630 Init(); | |
3631 SendAudioVideoStream1(); | |
3632 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
3633 | |
3634 // Making sure SetLocalDescription correctly sets crypto value in | |
3635 // SessionDescription object after de-serialization of sdp string. The value | |
3636 // will be set as per MediaSessionDescriptionFactory. | |
3637 std::string offer_str; | |
3638 offer->ToString(&offer_str); | |
3639 SessionDescriptionInterface* jsep_offer_str = | |
3640 CreateSessionDescription(JsepSessionDescription::kOffer, offer_str, NULL); | |
3641 SetLocalDescriptionWithoutError(jsep_offer_str); | |
3642 EXPECT_FALSE(session_->voice_channel()->secure_required()); | |
3643 EXPECT_FALSE(session_->video_channel()->secure_required()); | |
3644 } | |
3645 | |
3646 // This test verifies that an answer contains new ufrag and password if an offer | |
3647 // with new ufrag and password is received. | |
3648 TEST_F(WebRtcSessionTest, TestCreateAnswerWithNewUfragAndPassword) { | |
3649 Init(); | |
3650 cricket::MediaSessionOptions options; | |
3651 options.recv_video = true; | |
3652 rtc::scoped_ptr<JsepSessionDescription> offer( | |
3653 CreateRemoteOffer(options)); | |
3654 SetRemoteDescriptionWithoutError(offer.release()); | |
3655 | |
3656 SendAudioVideoStream1(); | |
3657 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
3658 CreateAnswer(NULL)); | |
3659 SetLocalDescriptionWithoutError(answer.release()); | |
3660 | |
3661 // Receive an offer with new ufrag and password. | |
3662 options.audio_transport_options.ice_restart = true; | |
3663 options.video_transport_options.ice_restart = true; | |
3664 options.data_transport_options.ice_restart = true; | |
3665 rtc::scoped_ptr<JsepSessionDescription> updated_offer1( | |
3666 CreateRemoteOffer(options, session_->remote_description())); | |
3667 SetRemoteDescriptionWithoutError(updated_offer1.release()); | |
3668 | |
3669 rtc::scoped_ptr<SessionDescriptionInterface> updated_answer1( | |
3670 CreateAnswer(NULL)); | |
3671 | |
3672 CompareIceUfragAndPassword(updated_answer1->description(), | |
3673 session_->local_description()->description(), | |
3674 false); | |
3675 | |
3676 SetLocalDescriptionWithoutError(updated_answer1.release()); | |
3677 } | |
3678 | |
3679 // This test verifies that an answer contains old ufrag and password if an offer | |
3680 // with old ufrag and password is received. | |
3681 TEST_F(WebRtcSessionTest, TestCreateAnswerWithOldUfragAndPassword) { | |
3682 Init(); | |
3683 cricket::MediaSessionOptions options; | |
3684 options.recv_video = true; | |
3685 rtc::scoped_ptr<JsepSessionDescription> offer( | |
3686 CreateRemoteOffer(options)); | |
3687 SetRemoteDescriptionWithoutError(offer.release()); | |
3688 | |
3689 SendAudioVideoStream1(); | |
3690 rtc::scoped_ptr<SessionDescriptionInterface> answer( | |
3691 CreateAnswer(NULL)); | |
3692 SetLocalDescriptionWithoutError(answer.release()); | |
3693 | |
3694 // Receive an offer without changed ufrag or password. | |
3695 options.audio_transport_options.ice_restart = false; | |
3696 options.video_transport_options.ice_restart = false; | |
3697 options.data_transport_options.ice_restart = false; | |
3698 rtc::scoped_ptr<JsepSessionDescription> updated_offer2( | |
3699 CreateRemoteOffer(options, session_->remote_description())); | |
3700 SetRemoteDescriptionWithoutError(updated_offer2.release()); | |
3701 | |
3702 rtc::scoped_ptr<SessionDescriptionInterface> updated_answer2( | |
3703 CreateAnswer(NULL)); | |
3704 | |
3705 CompareIceUfragAndPassword(updated_answer2->description(), | |
3706 session_->local_description()->description(), | |
3707 true); | |
3708 | |
3709 SetLocalDescriptionWithoutError(updated_answer2.release()); | |
3710 } | |
3711 | |
3712 TEST_F(WebRtcSessionTest, TestSessionContentError) { | |
3713 Init(); | |
3714 SendAudioVideoStream1(); | |
3715 SessionDescriptionInterface* offer = CreateOffer(); | |
3716 const std::string session_id_orig = offer->session_id(); | |
3717 const std::string session_version_orig = offer->session_version(); | |
3718 SetLocalDescriptionWithoutError(offer); | |
3719 | |
3720 video_channel_ = media_engine_->GetVideoChannel(0); | |
3721 video_channel_->set_fail_set_send_codecs(true); | |
3722 | |
3723 SessionDescriptionInterface* answer = | |
3724 CreateRemoteAnswer(session_->local_description()); | |
3725 SetRemoteDescriptionAnswerExpectError("ERROR_CONTENT", answer); | |
3726 | |
3727 // Test that after a content error, setting any description will | |
3728 // result in an error. | |
3729 video_channel_->set_fail_set_send_codecs(false); | |
3730 answer = CreateRemoteAnswer(session_->local_description()); | |
3731 SetRemoteDescriptionExpectError("", "ERROR_CONTENT", answer); | |
3732 offer = CreateRemoteOffer(); | |
3733 SetLocalDescriptionExpectError("", "ERROR_CONTENT", offer); | |
3734 } | |
3735 | |
3736 // Runs the loopback call test with BUNDLE and STUN disabled. | |
3737 TEST_F(WebRtcSessionTest, TestIceStatesBasic) { | |
3738 // Lets try with only UDP ports. | |
3739 allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | | |
3740 cricket::PORTALLOCATOR_DISABLE_STUN | | |
3741 cricket::PORTALLOCATOR_DISABLE_RELAY); | |
3742 TestLoopbackCall(); | |
3743 } | |
3744 | |
3745 TEST_F(WebRtcSessionTest, TestIceStatesBasicIPv6) { | |
3746 allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | | |
3747 cricket::PORTALLOCATOR_DISABLE_STUN | | |
3748 cricket::PORTALLOCATOR_ENABLE_IPV6 | | |
3749 cricket::PORTALLOCATOR_DISABLE_RELAY); | |
3750 | |
3751 // best connection is IPv6 since it has higher network preference. | |
3752 LoopbackNetworkConfiguration config; | |
3753 config.test_ipv6_network_ = true; | |
3754 config.best_connection_after_initial_ice_converged_ = | |
3755 LoopbackNetworkConfiguration::ExpectedBestConnection(0, 1); | |
3756 | |
3757 TestLoopbackCall(config); | |
3758 } | |
3759 | |
3760 // Runs the loopback call test with BUNDLE and STUN enabled. | |
3761 TEST_F(WebRtcSessionTest, TestIceStatesBundle) { | |
3762 allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | | |
3763 cricket::PORTALLOCATOR_DISABLE_RELAY); | |
3764 TestLoopbackCall(); | |
3765 } | |
3766 | |
3767 TEST_F(WebRtcSessionTest, TestRtpDataChannel) { | |
3768 constraints_.reset(new FakeConstraints()); | |
3769 constraints_->AddOptional( | |
3770 webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true); | |
3771 Init(); | |
3772 | |
3773 SetLocalDescriptionWithDataChannel(); | |
3774 EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type()); | |
3775 } | |
3776 | |
3777 TEST_P(WebRtcSessionTest, TestRtpDataChannelConstraintTakesPrecedence) { | |
3778 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3779 | |
3780 constraints_.reset(new FakeConstraints()); | |
3781 constraints_->AddOptional( | |
3782 webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true); | |
3783 options_.disable_sctp_data_channels = false; | |
3784 | |
3785 InitWithDtls(GetParam()); | |
3786 | |
3787 SetLocalDescriptionWithDataChannel(); | |
3788 EXPECT_EQ(cricket::DCT_RTP, data_engine_->last_channel_type()); | |
3789 } | |
3790 | |
3791 TEST_P(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) { | |
3792 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3793 | |
3794 InitWithDtls(GetParam()); | |
3795 | |
3796 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
3797 EXPECT_TRUE(offer->description()->GetContentByName("data") == NULL); | |
3798 EXPECT_TRUE(offer->description()->GetTransportInfoByName("data") == NULL); | |
3799 } | |
3800 | |
3801 TEST_P(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) { | |
3802 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3803 SetFactoryDtlsSrtp(); | |
3804 InitWithDtls(GetParam()); | |
3805 | |
3806 // Create remote offer with SCTP. | |
3807 cricket::MediaSessionOptions options; | |
3808 options.data_channel_type = cricket::DCT_SCTP; | |
3809 JsepSessionDescription* offer = | |
3810 CreateRemoteOffer(options, cricket::SEC_DISABLED); | |
3811 SetRemoteDescriptionWithoutError(offer); | |
3812 | |
3813 // Verifies the answer contains SCTP. | |
3814 rtc::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); | |
3815 EXPECT_TRUE(answer != NULL); | |
3816 EXPECT_TRUE(answer->description()->GetContentByName("data") != NULL); | |
3817 EXPECT_TRUE(answer->description()->GetTransportInfoByName("data") != NULL); | |
3818 } | |
3819 | |
3820 TEST_P(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) { | |
3821 constraints_.reset(new FakeConstraints()); | |
3822 constraints_->AddOptional( | |
3823 webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, false); | |
3824 InitWithDtls(GetParam()); | |
3825 | |
3826 SetLocalDescriptionWithDataChannel(); | |
3827 EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type()); | |
3828 } | |
3829 | |
3830 TEST_P(WebRtcSessionTest, TestSctpDataChannelWithDtls) { | |
3831 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3832 | |
3833 InitWithDtls(GetParam()); | |
3834 | |
3835 SetLocalDescriptionWithDataChannel(); | |
3836 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type()); | |
3837 } | |
3838 | |
3839 TEST_P(WebRtcSessionTest, TestDisableSctpDataChannels) { | |
3840 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3841 options_.disable_sctp_data_channels = true; | |
3842 InitWithDtls(GetParam()); | |
3843 | |
3844 SetLocalDescriptionWithDataChannel(); | |
3845 EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type()); | |
3846 } | |
3847 | |
3848 TEST_P(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) { | |
3849 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3850 const int new_send_port = 9998; | |
3851 const int new_recv_port = 7775; | |
3852 | |
3853 InitWithDtls(GetParam()); | |
3854 SetFactoryDtlsSrtp(); | |
3855 | |
3856 // By default, don't actually add the codecs to desc_factory_; they don't | |
3857 // actually get serialized for SCTP in BuildMediaDescription(). Instead, | |
3858 // let the session description get parsed. That'll get the proper codecs | |
3859 // into the stream. | |
3860 cricket::MediaSessionOptions options; | |
3861 JsepSessionDescription* offer = CreateRemoteOfferWithSctpPort( | |
3862 "stream1", new_send_port, options); | |
3863 | |
3864 // SetRemoteDescription will take the ownership of the offer. | |
3865 SetRemoteDescriptionWithoutError(offer); | |
3866 | |
3867 SessionDescriptionInterface* answer = ChangeSDPSctpPort( | |
3868 new_recv_port, CreateAnswer(NULL)); | |
3869 ASSERT_TRUE(answer != NULL); | |
3870 | |
3871 // Now set the local description, which'll take ownership of the answer. | |
3872 SetLocalDescriptionWithoutError(answer); | |
3873 | |
3874 // TEST PLAN: Set the port number to something new, set it in the SDP, | |
3875 // and pass it all the way down. | |
3876 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type()); | |
3877 CreateDataChannel(); | |
3878 | |
3879 cricket::FakeDataMediaChannel* ch = data_engine_->GetChannel(0); | |
3880 int portnum = -1; | |
3881 ASSERT_TRUE(ch != NULL); | |
3882 ASSERT_EQ(1UL, ch->send_codecs().size()); | |
3883 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, ch->send_codecs()[0].id); | |
3884 EXPECT_EQ(0, strcmp(cricket::kGoogleSctpDataCodecName, | |
3885 ch->send_codecs()[0].name.c_str())); | |
3886 EXPECT_TRUE(ch->send_codecs()[0].GetParam(cricket::kCodecParamPort, | |
3887 &portnum)); | |
3888 EXPECT_EQ(new_send_port, portnum); | |
3889 | |
3890 ASSERT_EQ(1UL, ch->recv_codecs().size()); | |
3891 EXPECT_EQ(cricket::kGoogleSctpDataCodecId, ch->recv_codecs()[0].id); | |
3892 EXPECT_EQ(0, strcmp(cricket::kGoogleSctpDataCodecName, | |
3893 ch->recv_codecs()[0].name.c_str())); | |
3894 EXPECT_TRUE(ch->recv_codecs()[0].GetParam(cricket::kCodecParamPort, | |
3895 &portnum)); | |
3896 EXPECT_EQ(new_recv_port, portnum); | |
3897 } | |
3898 | |
3899 // Verifies that when a session's DataChannel receives an OPEN message, | |
3900 // WebRtcSession signals the DataChannel creation request with the expected | |
3901 // config. | |
3902 TEST_P(WebRtcSessionTest, TestSctpDataChannelOpenMessage) { | |
3903 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3904 | |
3905 InitWithDtls(GetParam()); | |
3906 | |
3907 SetLocalDescriptionWithDataChannel(); | |
3908 EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type()); | |
3909 | |
3910 webrtc::DataChannelInit config; | |
3911 config.id = 1; | |
3912 rtc::Buffer payload; | |
3913 webrtc::WriteDataChannelOpenMessage("a", config, &payload); | |
3914 cricket::ReceiveDataParams params; | |
3915 params.ssrc = config.id; | |
3916 params.type = cricket::DMT_CONTROL; | |
3917 | |
3918 cricket::DataChannel* data_channel = session_->data_channel(); | |
3919 data_channel->SignalDataReceived(data_channel, params, payload); | |
3920 | |
3921 EXPECT_EQ("a", last_data_channel_label_); | |
3922 EXPECT_EQ(config.id, last_data_channel_config_.id); | |
3923 EXPECT_FALSE(last_data_channel_config_.negotiated); | |
3924 EXPECT_EQ(webrtc::InternalDataChannelInit::kAcker, | |
3925 last_data_channel_config_.open_handshake_role); | |
3926 } | |
3927 | |
3928 TEST_P(WebRtcSessionTest, TestUsesProvidedCertificate) { | |
3929 rtc::scoped_refptr<rtc::RTCCertificate> certificate = | |
3930 FakeDtlsIdentityStore::GenerateCertificate(); | |
3931 | |
3932 PeerConnectionInterface::RTCConfiguration configuration; | |
3933 configuration.certificates.push_back(certificate); | |
3934 Init(nullptr, configuration); | |
3935 EXPECT_TRUE_WAIT(!session_->waiting_for_certificate_for_testing(), 1000); | |
3936 | |
3937 EXPECT_EQ(session_->certificate_for_testing(), certificate); | |
3938 } | |
3939 | |
3940 // Verifies that CreateOffer succeeds when CreateOffer is called before async | |
3941 // identity generation is finished (even if a certificate is provided this is | |
3942 // an async op). | |
3943 TEST_P(WebRtcSessionTest, TestCreateOfferBeforeIdentityRequestReturnSuccess) { | |
3944 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3945 InitWithDtls(GetParam()); | |
3946 | |
3947 EXPECT_TRUE(session_->waiting_for_certificate_for_testing()); | |
3948 SendAudioVideoStream1(); | |
3949 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
3950 | |
3951 EXPECT_TRUE(offer != NULL); | |
3952 VerifyNoCryptoParams(offer->description(), true); | |
3953 VerifyFingerprintStatus(offer->description(), true); | |
3954 } | |
3955 | |
3956 // Verifies that CreateAnswer succeeds when CreateOffer is called before async | |
3957 // identity generation is finished (even if a certificate is provided this is | |
3958 // an async op). | |
3959 TEST_P(WebRtcSessionTest, TestCreateAnswerBeforeIdentityRequestReturnSuccess) { | |
3960 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3961 InitWithDtls(GetParam()); | |
3962 SetFactoryDtlsSrtp(); | |
3963 | |
3964 cricket::MediaSessionOptions options; | |
3965 options.recv_video = true; | |
3966 scoped_ptr<JsepSessionDescription> offer( | |
3967 CreateRemoteOffer(options, cricket::SEC_DISABLED)); | |
3968 ASSERT_TRUE(offer.get() != NULL); | |
3969 SetRemoteDescriptionWithoutError(offer.release()); | |
3970 | |
3971 rtc::scoped_ptr<SessionDescriptionInterface> answer(CreateAnswer(NULL)); | |
3972 EXPECT_TRUE(answer != NULL); | |
3973 VerifyNoCryptoParams(answer->description(), true); | |
3974 VerifyFingerprintStatus(answer->description(), true); | |
3975 } | |
3976 | |
3977 // Verifies that CreateOffer succeeds when CreateOffer is called after async | |
3978 // identity generation is finished (even if a certificate is provided this is | |
3979 // an async op). | |
3980 TEST_P(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnSuccess) { | |
3981 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3982 InitWithDtls(GetParam()); | |
3983 | |
3984 EXPECT_TRUE_WAIT(!session_->waiting_for_certificate_for_testing(), 1000); | |
3985 | |
3986 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
3987 EXPECT_TRUE(offer != NULL); | |
3988 } | |
3989 | |
3990 // Verifies that CreateOffer fails when CreateOffer is called after async | |
3991 // identity generation fails. | |
3992 TEST_F(WebRtcSessionTest, TestCreateOfferAfterIdentityRequestReturnFailure) { | |
3993 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
3994 InitWithDtlsIdentityGenFail(); | |
3995 | |
3996 EXPECT_TRUE_WAIT(!session_->waiting_for_certificate_for_testing(), 1000); | |
3997 | |
3998 rtc::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer()); | |
3999 EXPECT_TRUE(offer == NULL); | |
4000 } | |
4001 | |
4002 // Verifies that CreateOffer succeeds when Multiple CreateOffer calls are made | |
4003 // before async identity generation is finished. | |
4004 TEST_P(WebRtcSessionTest, | |
4005 TestMultipleCreateOfferBeforeIdentityRequestReturnSuccess) { | |
4006 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
4007 VerifyMultipleAsyncCreateDescription(GetParam(), | |
4008 CreateSessionDescriptionRequest::kOffer); | |
4009 } | |
4010 | |
4011 // Verifies that CreateOffer fails when Multiple CreateOffer calls are made | |
4012 // before async identity generation fails. | |
4013 TEST_F(WebRtcSessionTest, | |
4014 TestMultipleCreateOfferBeforeIdentityRequestReturnFailure) { | |
4015 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
4016 VerifyMultipleAsyncCreateDescriptionIdentityGenFailure( | |
4017 CreateSessionDescriptionRequest::kOffer); | |
4018 } | |
4019 | |
4020 // Verifies that CreateAnswer succeeds when Multiple CreateAnswer calls are made | |
4021 // before async identity generation is finished. | |
4022 TEST_P(WebRtcSessionTest, | |
4023 TestMultipleCreateAnswerBeforeIdentityRequestReturnSuccess) { | |
4024 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
4025 VerifyMultipleAsyncCreateDescription( | |
4026 GetParam(), CreateSessionDescriptionRequest::kAnswer); | |
4027 } | |
4028 | |
4029 // Verifies that CreateAnswer fails when Multiple CreateAnswer calls are made | |
4030 // before async identity generation fails. | |
4031 TEST_F(WebRtcSessionTest, | |
4032 TestMultipleCreateAnswerBeforeIdentityRequestReturnFailure) { | |
4033 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
4034 VerifyMultipleAsyncCreateDescriptionIdentityGenFailure( | |
4035 CreateSessionDescriptionRequest::kAnswer); | |
4036 } | |
4037 | |
4038 // Verifies that setRemoteDescription fails when DTLS is disabled and the remote | |
4039 // offer has no SDES crypto but only DTLS fingerprint. | |
4040 TEST_F(WebRtcSessionTest, TestSetRemoteOfferFailIfDtlsDisabledAndNoCrypto) { | |
4041 // Init without DTLS. | |
4042 Init(); | |
4043 // Create a remote offer with secured transport disabled. | |
4044 cricket::MediaSessionOptions options; | |
4045 JsepSessionDescription* offer(CreateRemoteOffer( | |
4046 options, cricket::SEC_DISABLED)); | |
4047 // Adds a DTLS fingerprint to the remote offer. | |
4048 cricket::SessionDescription* sdp = offer->description(); | |
4049 TransportInfo* audio = sdp->GetTransportInfoByName("audio"); | |
4050 ASSERT_TRUE(audio != NULL); | |
4051 ASSERT_TRUE(audio->description.identity_fingerprint.get() == NULL); | |
4052 audio->description.identity_fingerprint.reset( | |
4053 rtc::SSLFingerprint::CreateFromRfc4572( | |
4054 rtc::DIGEST_SHA_256, kFakeDtlsFingerprint)); | |
4055 SetRemoteDescriptionOfferExpectError(kSdpWithoutSdesCrypto, | |
4056 offer); | |
4057 } | |
4058 | |
4059 // This test verifies DSCP is properly applied on the media channels. | |
4060 TEST_F(WebRtcSessionTest, TestDscpConstraint) { | |
4061 constraints_.reset(new FakeConstraints()); | |
4062 constraints_->AddOptional( | |
4063 webrtc::MediaConstraintsInterface::kEnableDscp, true); | |
4064 Init(); | |
4065 SendAudioVideoStream1(); | |
4066 SessionDescriptionInterface* offer = CreateOffer(); | |
4067 | |
4068 SetLocalDescriptionWithoutError(offer); | |
4069 | |
4070 video_channel_ = media_engine_->GetVideoChannel(0); | |
4071 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
4072 | |
4073 ASSERT_TRUE(video_channel_ != NULL); | |
4074 ASSERT_TRUE(voice_channel_ != NULL); | |
4075 const cricket::AudioOptions& audio_options = voice_channel_->options(); | |
4076 const cricket::VideoOptions& video_options = video_channel_->options(); | |
4077 EXPECT_EQ(rtc::Optional<bool>(true), audio_options.dscp); | |
4078 EXPECT_EQ(rtc::Optional<bool>(true), video_options.dscp); | |
4079 } | |
4080 | |
4081 TEST_F(WebRtcSessionTest, TestSuspendBelowMinBitrateConstraint) { | |
4082 constraints_.reset(new FakeConstraints()); | |
4083 constraints_->AddOptional( | |
4084 webrtc::MediaConstraintsInterface::kEnableVideoSuspendBelowMinBitrate, | |
4085 true); | |
4086 Init(); | |
4087 SendAudioVideoStream1(); | |
4088 SessionDescriptionInterface* offer = CreateOffer(); | |
4089 | |
4090 SetLocalDescriptionWithoutError(offer); | |
4091 | |
4092 video_channel_ = media_engine_->GetVideoChannel(0); | |
4093 | |
4094 ASSERT_TRUE(video_channel_ != NULL); | |
4095 const cricket::VideoOptions& video_options = video_channel_->options(); | |
4096 EXPECT_EQ(rtc::Optional<bool>(true), video_options.suspend_below_min_bitrate); | |
4097 } | |
4098 | |
4099 TEST_F(WebRtcSessionTest, TestCombinedAudioVideoBweConstraint) { | |
4100 constraints_.reset(new FakeConstraints()); | |
4101 constraints_->AddOptional( | |
4102 webrtc::MediaConstraintsInterface::kCombinedAudioVideoBwe, | |
4103 true); | |
4104 Init(); | |
4105 SendAudioVideoStream1(); | |
4106 SessionDescriptionInterface* offer = CreateOffer(); | |
4107 | |
4108 SetLocalDescriptionWithoutError(offer); | |
4109 | |
4110 voice_channel_ = media_engine_->GetVoiceChannel(0); | |
4111 | |
4112 ASSERT_TRUE(voice_channel_ != NULL); | |
4113 const cricket::AudioOptions& audio_options = voice_channel_->options(); | |
4114 EXPECT_EQ(rtc::Optional<bool>(true), audio_options.combined_audio_video_bwe); | |
4115 } | |
4116 | |
4117 // Tests that we can renegotiate new media content with ICE candidates in the | |
4118 // new remote SDP. | |
4119 TEST_P(WebRtcSessionTest, TestRenegotiateNewMediaWithCandidatesInSdp) { | |
4120 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
4121 InitWithDtls(GetParam()); | |
4122 SetFactoryDtlsSrtp(); | |
4123 | |
4124 SendAudioOnlyStream2(); | |
4125 SessionDescriptionInterface* offer = CreateOffer(); | |
4126 SetLocalDescriptionWithoutError(offer); | |
4127 | |
4128 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); | |
4129 SetRemoteDescriptionWithoutError(answer); | |
4130 | |
4131 cricket::MediaSessionOptions options; | |
4132 options.recv_video = true; | |
4133 offer = CreateRemoteOffer(options, cricket::SEC_DISABLED); | |
4134 | |
4135 cricket::Candidate candidate1; | |
4136 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 5000)); | |
4137 candidate1.set_component(1); | |
4138 JsepIceCandidate ice_candidate(kMediaContentName1, kMediaContentIndex1, | |
4139 candidate1); | |
4140 EXPECT_TRUE(offer->AddCandidate(&ice_candidate)); | |
4141 SetRemoteDescriptionWithoutError(offer); | |
4142 | |
4143 answer = CreateAnswer(NULL); | |
4144 SetLocalDescriptionWithoutError(answer); | |
4145 } | |
4146 | |
4147 // Tests that we can renegotiate new media content with ICE candidates separated | |
4148 // from the remote SDP. | |
4149 TEST_P(WebRtcSessionTest, TestRenegotiateNewMediaWithCandidatesSeparated) { | |
4150 MAYBE_SKIP_TEST(rtc::SSLStreamAdapter::HaveDtlsSrtp); | |
4151 InitWithDtls(GetParam()); | |
4152 SetFactoryDtlsSrtp(); | |
4153 | |
4154 SendAudioOnlyStream2(); | |
4155 SessionDescriptionInterface* offer = CreateOffer(); | |
4156 SetLocalDescriptionWithoutError(offer); | |
4157 | |
4158 SessionDescriptionInterface* answer = CreateRemoteAnswer(offer); | |
4159 SetRemoteDescriptionWithoutError(answer); | |
4160 | |
4161 cricket::MediaSessionOptions options; | |
4162 options.recv_video = true; | |
4163 offer = CreateRemoteOffer(options, cricket::SEC_DISABLED); | |
4164 SetRemoteDescriptionWithoutError(offer); | |
4165 | |
4166 cricket::Candidate candidate1; | |
4167 candidate1.set_address(rtc::SocketAddress("1.1.1.1", 5000)); | |
4168 candidate1.set_component(1); | |
4169 JsepIceCandidate ice_candidate(kMediaContentName1, kMediaContentIndex1, | |
4170 candidate1); | |
4171 EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate)); | |
4172 | |
4173 answer = CreateAnswer(NULL); | |
4174 SetLocalDescriptionWithoutError(answer); | |
4175 } | |
4176 | |
4177 // Flaky on Win and Mac only. See webrtc:4943 | |
4178 #if defined(WEBRTC_WIN) || defined(WEBRTC_MAC) | |
4179 #define MAYBE_TestRtxRemovedByCreateAnswer DISABLED_TestRtxRemovedByCreateAnswer | |
4180 #else | |
4181 #define MAYBE_TestRtxRemovedByCreateAnswer TestRtxRemovedByCreateAnswer | |
4182 #endif | |
4183 // Tests that RTX codec is removed from the answer when it isn't supported | |
4184 // by local side. | |
4185 TEST_F(WebRtcSessionTest, MAYBE_TestRtxRemovedByCreateAnswer) { | |
4186 Init(); | |
4187 SendAudioVideoStream1(); | |
4188 std::string offer_sdp(kSdpWithRtx); | |
4189 | |
4190 SessionDescriptionInterface* offer = | |
4191 CreateSessionDescription(JsepSessionDescription::kOffer, offer_sdp, NULL); | |
4192 EXPECT_TRUE(offer->ToString(&offer_sdp)); | |
4193 | |
4194 // Offer SDP contains the RTX codec. | |
4195 EXPECT_TRUE(offer_sdp.find("rtx") != std::string::npos); | |
4196 SetRemoteDescriptionWithoutError(offer); | |
4197 | |
4198 SessionDescriptionInterface* answer = CreateAnswer(NULL); | |
4199 std::string answer_sdp; | |
4200 answer->ToString(&answer_sdp); | |
4201 // Answer SDP removes the unsupported RTX codec. | |
4202 EXPECT_TRUE(answer_sdp.find("rtx") == std::string::npos); | |
4203 SetLocalDescriptionWithoutError(answer); | |
4204 } | |
4205 | |
4206 // This verifies that the voice channel after bundle has both options from video | |
4207 // and voice channels. | |
4208 TEST_F(WebRtcSessionTest, TestSetSocketOptionBeforeBundle) { | |
4209 InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced); | |
4210 SendAudioVideoStream1(); | |
4211 | |
4212 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
4213 options.use_rtp_mux = true; | |
4214 | |
4215 SessionDescriptionInterface* offer = CreateOffer(options); | |
4216 SetLocalDescriptionWithoutError(offer); | |
4217 | |
4218 session_->video_channel()->SetOption(cricket::BaseChannel::ST_RTP, | |
4219 rtc::Socket::Option::OPT_SNDBUF, 4000); | |
4220 | |
4221 session_->voice_channel()->SetOption(cricket::BaseChannel::ST_RTP, | |
4222 rtc::Socket::Option::OPT_RCVBUF, 8000); | |
4223 | |
4224 int option_val; | |
4225 EXPECT_TRUE(session_->video_rtp_transport_channel()->GetOption( | |
4226 rtc::Socket::Option::OPT_SNDBUF, &option_val)); | |
4227 EXPECT_EQ(4000, option_val); | |
4228 EXPECT_FALSE(session_->voice_rtp_transport_channel()->GetOption( | |
4229 rtc::Socket::Option::OPT_SNDBUF, &option_val)); | |
4230 | |
4231 EXPECT_TRUE(session_->voice_rtp_transport_channel()->GetOption( | |
4232 rtc::Socket::Option::OPT_RCVBUF, &option_val)); | |
4233 EXPECT_EQ(8000, option_val); | |
4234 EXPECT_FALSE(session_->video_rtp_transport_channel()->GetOption( | |
4235 rtc::Socket::Option::OPT_RCVBUF, &option_val)); | |
4236 | |
4237 EXPECT_NE(session_->voice_rtp_transport_channel(), | |
4238 session_->video_rtp_transport_channel()); | |
4239 | |
4240 SendAudioVideoStream2(); | |
4241 SessionDescriptionInterface* answer = | |
4242 CreateRemoteAnswer(session_->local_description()); | |
4243 SetRemoteDescriptionWithoutError(answer); | |
4244 | |
4245 EXPECT_TRUE(session_->voice_rtp_transport_channel()->GetOption( | |
4246 rtc::Socket::Option::OPT_SNDBUF, &option_val)); | |
4247 EXPECT_EQ(4000, option_val); | |
4248 | |
4249 EXPECT_TRUE(session_->voice_rtp_transport_channel()->GetOption( | |
4250 rtc::Socket::Option::OPT_RCVBUF, &option_val)); | |
4251 EXPECT_EQ(8000, option_val); | |
4252 } | |
4253 | |
4254 // Test creating a session, request multiple offers, destroy the session | |
4255 // and make sure we got success/failure callbacks for all of the requests. | |
4256 // Background: crbug.com/507307 | |
4257 TEST_F(WebRtcSessionTest, CreateOffersAndShutdown) { | |
4258 Init(); | |
4259 | |
4260 rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> observers[100]; | |
4261 PeerConnectionInterface::RTCOfferAnswerOptions options; | |
4262 options.offer_to_receive_audio = | |
4263 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue; | |
4264 cricket::MediaSessionOptions session_options; | |
4265 session_options.recv_audio = true; | |
4266 | |
4267 for (auto& o : observers) { | |
4268 o = new WebRtcSessionCreateSDPObserverForTest(); | |
4269 session_->CreateOffer(o, options, session_options); | |
4270 } | |
4271 | |
4272 session_.reset(); | |
4273 | |
4274 for (auto& o : observers) { | |
4275 // We expect to have received a notification now even if the session was | |
4276 // terminated. The offer creation may or may not have succeeded, but we | |
4277 // must have received a notification which, so the only invalid state | |
4278 // is kInit. | |
4279 EXPECT_NE(WebRtcSessionCreateSDPObserverForTest::kInit, o->state()); | |
4280 } | |
4281 } | |
4282 | |
4283 TEST_F(WebRtcSessionTest, TestPacketOptionsAndOnPacketSent) { | |
4284 TestPacketOptions(); | |
4285 } | |
4286 | |
4287 // Make sure the signal from "GetOnDestroyedSignal()" fires when the session | |
4288 // is destroyed. | |
4289 TEST_F(WebRtcSessionTest, TestOnDestroyedSignal) { | |
4290 Init(); | |
4291 session_.reset(); | |
4292 EXPECT_TRUE(session_destroyed_); | |
4293 } | |
4294 | |
4295 // TODO(bemasc): Add a TestIceStatesBundle with BUNDLE enabled. That test | |
4296 // currently fails because upon disconnection and reconnection OnIceComplete is | |
4297 // called more than once without returning to IceGatheringGathering. | |
4298 | |
4299 INSTANTIATE_TEST_CASE_P(WebRtcSessionTests, | |
4300 WebRtcSessionTest, | |
4301 testing::Values(ALREADY_GENERATED, | |
4302 DTLS_IDENTITY_STORE)); | |
OLD | NEW |