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