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