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