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