blob: 925156f97a7440c42737916dfeacc9032f79206a [file] [log] [blame]
Steve Anton6f25b092017-10-23 09:39:20 -07001/*
2 * Copyright 2017 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
Karl Wiberg32df86e2017-11-03 10:24:27 +010011#include "api/audio_codecs/builtin_audio_decoder_factory.h"
12#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Steve Anton6f25b092017-10-23 09:39:20 -070013#include "api/peerconnectionproxy.h"
14#include "p2p/base/fakeportallocator.h"
15#include "p2p/base/teststunserver.h"
16#include "p2p/client/basicportallocator.h"
17#include "pc/mediasession.h"
18#include "pc/peerconnection.h"
19#include "pc/peerconnectionwrapper.h"
20#include "pc/sdputils.h"
21#ifdef WEBRTC_ANDROID
22#include "pc/test/androidtestinitializer.h"
23#endif
24#include "pc/test/fakeaudiocapturemodule.h"
25#include "rtc_base/fakenetwork.h"
26#include "rtc_base/gunit.h"
27#include "rtc_base/ptr_util.h"
28#include "rtc_base/virtualsocketserver.h"
29#include "test/gmock.h"
30
31namespace webrtc {
32
33using BundlePolicy = PeerConnectionInterface::BundlePolicy;
34using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
35using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
36using RtcpMuxPolicy = PeerConnectionInterface::RtcpMuxPolicy;
37using rtc::SocketAddress;
38using ::testing::ElementsAre;
39using ::testing::UnorderedElementsAre;
40using ::testing::Values;
41
42constexpr int kDefaultTimeout = 10000;
43
44// TODO(steveanton): These tests should be rewritten to use the standard
45// RtpSenderInterface/DtlsTransportInterface objects once they're available in
46// the API. The RtpSender can be used to determine which transport a given media
47// will use: https://www.w3.org/TR/webrtc/#dom-rtcrtpsender-transport
48
49class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
50 public:
51 using PeerConnectionWrapper::PeerConnectionWrapper;
52
53 bool AddIceCandidateToMedia(cricket::Candidate* candidate,
54 cricket::MediaType media_type) {
55 auto* desc = pc()->remote_description()->description();
56 for (size_t i = 0; i < desc->contents().size(); i++) {
57 const auto& content = desc->contents()[i];
Steve Antonb1c1de12017-12-21 15:14:30 -080058 if (content.media_description()->type() == media_type) {
Steve Anton6f25b092017-10-23 09:39:20 -070059 candidate->set_transport_name(content.name);
60 JsepIceCandidate jsep_candidate(content.name, i, *candidate);
61 return pc()->AddIceCandidate(&jsep_candidate);
62 }
63 }
64 RTC_NOTREACHED();
65 return false;
66 }
67
68 rtc::PacketTransportInternal* voice_rtp_transport_channel() {
69 return (voice_channel() ? voice_channel()->rtp_dtls_transport() : nullptr);
70 }
71
72 rtc::PacketTransportInternal* voice_rtcp_transport_channel() {
73 return (voice_channel() ? voice_channel()->rtcp_dtls_transport() : nullptr);
74 }
75
76 cricket::VoiceChannel* voice_channel() {
77 return GetInternalPeerConnection()->voice_channel();
78 }
79
80 rtc::PacketTransportInternal* video_rtp_transport_channel() {
81 return (video_channel() ? video_channel()->rtp_dtls_transport() : nullptr);
82 }
83
84 rtc::PacketTransportInternal* video_rtcp_transport_channel() {
85 return (video_channel() ? video_channel()->rtcp_dtls_transport() : nullptr);
86 }
87
88 cricket::VideoChannel* video_channel() {
89 return GetInternalPeerConnection()->video_channel();
90 }
91
92 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +010093 auto* pci =
94 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
95 pc());
96 return static_cast<PeerConnection*>(pci->internal());
Steve Anton6f25b092017-10-23 09:39:20 -070097 }
98
99 // Returns true if the stats indicate that an ICE connection is either in
100 // progress or established with the given remote address.
101 bool HasConnectionWithRemoteAddress(const SocketAddress& address) {
102 auto report = GetStats();
103 if (!report) {
104 return false;
105 }
106 std::string matching_candidate_id;
107 for (auto* ice_candidate_stats :
108 report->GetStatsOfType<RTCRemoteIceCandidateStats>()) {
109 if (*ice_candidate_stats->ip == address.HostAsURIString() &&
110 *ice_candidate_stats->port == address.port()) {
111 matching_candidate_id = ice_candidate_stats->id();
112 break;
113 }
114 }
115 if (matching_candidate_id.empty()) {
116 return false;
117 }
118 for (auto* pair_stats :
119 report->GetStatsOfType<RTCIceCandidatePairStats>()) {
120 if (*pair_stats->remote_candidate_id == matching_candidate_id) {
121 if (*pair_stats->state == RTCStatsIceCandidatePairState::kInProgress ||
122 *pair_stats->state == RTCStatsIceCandidatePairState::kSucceeded) {
123 return true;
124 }
125 }
126 }
127 return false;
128 }
129
130 rtc::FakeNetworkManager* network() { return network_; }
131
132 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
133
134 private:
135 rtc::FakeNetworkManager* network_;
136};
137
138class PeerConnectionBundleTest : public ::testing::Test {
139 protected:
140 typedef std::unique_ptr<PeerConnectionWrapperForBundleTest> WrapperPtr;
141
142 PeerConnectionBundleTest()
143 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
144#ifdef WEBRTC_ANDROID
145 InitializeAndroidObjects();
146#endif
147 pc_factory_ = CreatePeerConnectionFactory(
148 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Karl Wiberg32df86e2017-11-03 10:24:27 +0100149 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
150 CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -0700151 }
152
153 WrapperPtr CreatePeerConnection() {
154 return CreatePeerConnection(RTCConfiguration());
155 }
156
157 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
158 auto* fake_network = NewFakeNetwork();
159 auto port_allocator =
160 rtc::MakeUnique<cricket::BasicPortAllocator>(fake_network);
161 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
162 cricket::PORTALLOCATOR_DISABLE_RELAY);
163 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
164 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
165 auto pc = pc_factory_->CreatePeerConnection(
166 config, std::move(port_allocator), nullptr, observer.get());
167 if (!pc) {
168 return nullptr;
169 }
170
171 auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForBundleTest>(
172 pc_factory_, pc, std::move(observer));
173 wrapper->set_network(fake_network);
174 return wrapper;
175 }
176
177 // Accepts the same arguments as CreatePeerConnection and adds default audio
178 // and video tracks.
179 template <typename... Args>
180 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
181 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
182 if (!wrapper) {
183 return nullptr;
184 }
185 wrapper->AddAudioTrack("a");
186 wrapper->AddVideoTrack("v");
187 return wrapper;
188 }
189
190 cricket::Candidate CreateLocalUdpCandidate(
191 const rtc::SocketAddress& address) {
192 cricket::Candidate candidate;
193 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
194 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
195 candidate.set_address(address);
196 candidate.set_type(cricket::LOCAL_PORT_TYPE);
197 return candidate;
198 }
199
200 rtc::FakeNetworkManager* NewFakeNetwork() {
201 // The PeerConnection's port allocator is tied to the PeerConnection's
202 // lifetime and expects the underlying NetworkManager to outlive it. If
203 // PeerConnectionWrapper owned the NetworkManager, it would be destroyed
204 // before the PeerConnection (since subclass members are destroyed before
205 // base class members). Therefore, the test fixture will own all the fake
206 // networks even though tests should access the fake network through the
207 // PeerConnectionWrapper.
208 auto* fake_network = new rtc::FakeNetworkManager();
209 fake_networks_.emplace_back(fake_network);
210 return fake_network;
211 }
212
213 std::unique_ptr<rtc::VirtualSocketServer> vss_;
214 rtc::AutoSocketServerThread main_;
215 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
216 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
217};
218
219SdpContentMutator RemoveRtcpMux() {
220 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800221 content->media_description()->set_rtcp_mux(false);
Steve Anton6f25b092017-10-23 09:39:20 -0700222 };
223}
224
225std::vector<int> GetCandidateComponents(
226 const std::vector<IceCandidateInterface*> candidates) {
227 std::vector<int> components;
228 for (auto* candidate : candidates) {
229 components.push_back(candidate->candidate().component());
230 }
231 return components;
232}
233
234// Test that there are 2 local UDP candidates (1 RTP and 1 RTCP candidate) for
235// each media section when disabling bundling and disabling RTCP multiplexing.
236TEST_F(PeerConnectionBundleTest,
237 TwoCandidatesForEachTransportWhenNoBundleNoRtcpMux) {
238 const SocketAddress kCallerAddress("1.1.1.1", 0);
239 const SocketAddress kCalleeAddress("2.2.2.2", 0);
240
241 RTCConfiguration config;
242 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
243 auto caller = CreatePeerConnectionWithAudioVideo(config);
244 caller->network()->AddInterface(kCallerAddress);
245 auto callee = CreatePeerConnectionWithAudioVideo(config);
246 callee->network()->AddInterface(kCalleeAddress);
247
248 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
249 RTCOfferAnswerOptions options_no_bundle;
250 options_no_bundle.use_rtp_mux = false;
251 auto answer = callee->CreateAnswer(options_no_bundle);
252 SdpContentsForEach(RemoveRtcpMux(), answer->description());
253 ASSERT_TRUE(
254 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
255 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
256
257 // Check that caller has separate RTP and RTCP candidates for each media.
258 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
259 EXPECT_THAT(
260 GetCandidateComponents(caller->observer()->GetCandidatesByMline(0)),
261 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
262 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
263 EXPECT_THAT(
264 GetCandidateComponents(caller->observer()->GetCandidatesByMline(1)),
265 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
266 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
267
268 // Check that callee has separate RTP and RTCP candidates for each media.
269 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kDefaultTimeout);
270 EXPECT_THAT(
271 GetCandidateComponents(callee->observer()->GetCandidatesByMline(0)),
272 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
273 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
274 EXPECT_THAT(
275 GetCandidateComponents(callee->observer()->GetCandidatesByMline(1)),
276 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
277 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
278}
279
280// Test that there is 1 local UDP candidate for both RTP and RTCP for each media
281// section when disabling bundle but enabling RTCP multiplexing.
282TEST_F(PeerConnectionBundleTest,
283 OneCandidateForEachTransportWhenNoBundleButRtcpMux) {
284 const SocketAddress kCallerAddress("1.1.1.1", 0);
285
286 auto caller = CreatePeerConnectionWithAudioVideo();
287 caller->network()->AddInterface(kCallerAddress);
288 auto callee = CreatePeerConnectionWithAudioVideo();
289
290 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
291 RTCOfferAnswerOptions options_no_bundle;
292 options_no_bundle.use_rtp_mux = false;
293 ASSERT_TRUE(
294 caller->SetRemoteDescription(callee->CreateAnswer(options_no_bundle)));
295
296 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
297
298 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
299 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(1).size());
300}
301
302// Test that there is 1 local UDP candidate in only the first media section when
303// bundling and enabling RTCP multiplexing.
304TEST_F(PeerConnectionBundleTest,
305 OneCandidateOnlyOnFirstTransportWhenBundleAndRtcpMux) {
306 const SocketAddress kCallerAddress("1.1.1.1", 0);
307
308 RTCConfiguration config;
309 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
310 auto caller = CreatePeerConnectionWithAudioVideo(config);
311 caller->network()->AddInterface(kCallerAddress);
312 auto callee = CreatePeerConnectionWithAudioVideo(config);
313
314 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
315 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
316
317 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
318
319 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
320 EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size());
321}
322
323// The following parameterized test verifies that an offer/answer with varying
324// bundle policies and either bundle in the answer or not will produce the
325// expected RTP transports for audio and video. In particular, for bundling we
326// care about whether they are separate transports or the same.
327
328enum class BundleIncluded { kBundleInAnswer, kBundleNotInAnswer };
329std::ostream& operator<<(std::ostream& out, BundleIncluded value) {
330 switch (value) {
331 case BundleIncluded::kBundleInAnswer:
332 return out << "bundle in answer";
333 case BundleIncluded::kBundleNotInAnswer:
334 return out << "bundle not in answer";
335 }
336 return out << "unknown";
337}
338
339class PeerConnectionBundleMatrixTest
340 : public PeerConnectionBundleTest,
341 public ::testing::WithParamInterface<
342 std::tuple<BundlePolicy, BundleIncluded, bool, bool>> {
343 protected:
344 PeerConnectionBundleMatrixTest() {
345 bundle_policy_ = std::get<0>(GetParam());
346 bundle_included_ = std::get<1>(GetParam());
347 expected_same_before_ = std::get<2>(GetParam());
348 expected_same_after_ = std::get<3>(GetParam());
349 }
350
351 PeerConnectionInterface::BundlePolicy bundle_policy_;
352 BundleIncluded bundle_included_;
353 bool expected_same_before_;
354 bool expected_same_after_;
355};
356
357TEST_P(PeerConnectionBundleMatrixTest,
358 VerifyTransportsBeforeAndAfterSettingRemoteAnswer) {
359 RTCConfiguration config;
360 config.bundle_policy = bundle_policy_;
361 auto caller = CreatePeerConnectionWithAudioVideo(config);
362 auto callee = CreatePeerConnectionWithAudioVideo();
363
364 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
365 bool equal_before = (caller->voice_rtp_transport_channel() ==
366 caller->video_rtp_transport_channel());
367 EXPECT_EQ(expected_same_before_, equal_before);
368
369 RTCOfferAnswerOptions options;
370 options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer);
371 ASSERT_TRUE(
372 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
373 bool equal_after = (caller->voice_rtp_transport_channel() ==
374 caller->video_rtp_transport_channel());
375 EXPECT_EQ(expected_same_after_, equal_after);
376}
377
378// The max-bundle policy means we should anticipate bundling being negotiated,
379// and multiplex audio/video from the start.
380// For all other policies, bundling should only be enabled if negotiated by the
381// answer.
382INSTANTIATE_TEST_CASE_P(
383 PeerConnectionBundleTest,
384 PeerConnectionBundleMatrixTest,
385 Values(std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
386 BundleIncluded::kBundleInAnswer,
387 false,
388 true),
389 std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
390 BundleIncluded::kBundleNotInAnswer,
391 false,
392 false),
393 std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
394 BundleIncluded::kBundleInAnswer,
395 true,
396 true),
397 std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
398 BundleIncluded::kBundleNotInAnswer,
399 true,
400 true),
401 std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
402 BundleIncluded::kBundleInAnswer,
403 false,
404 true),
405 std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
406 BundleIncluded::kBundleNotInAnswer,
407 false,
408 false)));
409
410// Test that the audio/video transports on the callee side are the same before
411// and after setting a local answer when max BUNDLE is enabled and an offer with
412// BUNDLE is received.
413TEST_F(PeerConnectionBundleTest,
414 TransportsSameForMaxBundleWithBundleInRemoteOffer) {
415 auto caller = CreatePeerConnectionWithAudioVideo();
416 RTCConfiguration config;
417 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
418 auto callee = CreatePeerConnectionWithAudioVideo(config);
419
420 RTCOfferAnswerOptions options_with_bundle;
421 options_with_bundle.use_rtp_mux = true;
422 ASSERT_TRUE(callee->SetRemoteDescription(
423 caller->CreateOfferAndSetAsLocal(options_with_bundle)));
424
425 EXPECT_EQ(callee->voice_rtp_transport_channel(),
426 callee->video_rtp_transport_channel());
427
428 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
429
430 EXPECT_EQ(callee->voice_rtp_transport_channel(),
431 callee->video_rtp_transport_channel());
432}
433
434TEST_F(PeerConnectionBundleTest,
435 FailToSetRemoteOfferWithNoBundleWhenBundlePolicyMaxBundle) {
436 auto caller = CreatePeerConnectionWithAudioVideo();
437 RTCConfiguration config;
438 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
439 auto callee = CreatePeerConnectionWithAudioVideo(config);
440
441 RTCOfferAnswerOptions options_no_bundle;
442 options_no_bundle.use_rtp_mux = false;
443 EXPECT_FALSE(callee->SetRemoteDescription(
444 caller->CreateOfferAndSetAsLocal(options_no_bundle)));
445}
446
447// Test that if the media section which has the bundled transport is rejected,
448// then the peers still connect and the bundled transport switches to the other
449// media section.
450// Note: This is currently failing because of the following bug:
451// https://bugs.chromium.org/p/webrtc/issues/detail?id=6280
452TEST_F(PeerConnectionBundleTest,
453 DISABLED_SuccessfullyNegotiateMaxBundleIfBundleTransportMediaRejected) {
454 RTCConfiguration config;
455 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
456 auto caller = CreatePeerConnectionWithAudioVideo(config);
457 auto callee = CreatePeerConnection();
458 callee->AddVideoTrack("v");
459
460 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
461
462 RTCOfferAnswerOptions options;
463 options.offer_to_receive_audio = 0;
464 ASSERT_TRUE(
465 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
466
467 EXPECT_FALSE(caller->voice_rtp_transport_channel());
468 EXPECT_TRUE(caller->video_rtp_transport_channel());
469}
470
471// When requiring RTCP multiplexing, the PeerConnection never makes RTCP
472// transport channels.
473TEST_F(PeerConnectionBundleTest, NeverCreateRtcpTransportWithRtcpMuxRequired) {
474 RTCConfiguration config;
475 config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyRequire;
476 auto caller = CreatePeerConnectionWithAudioVideo(config);
477 auto callee = CreatePeerConnectionWithAudioVideo();
478
479 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
480
481 EXPECT_FALSE(caller->voice_rtcp_transport_channel());
482 EXPECT_FALSE(caller->video_rtcp_transport_channel());
483
484 ASSERT_TRUE(
485 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
486
487 EXPECT_FALSE(caller->voice_rtcp_transport_channel());
488 EXPECT_FALSE(caller->video_rtcp_transport_channel());
489}
490
491// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transport
492// channels when the offer is sent, but will destroy them once the remote answer
493// is set.
494TEST_F(PeerConnectionBundleTest,
495 CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) {
496 RTCConfiguration config;
497 config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyNegotiate;
498 auto caller = CreatePeerConnectionWithAudioVideo(config);
499 auto callee = CreatePeerConnectionWithAudioVideo();
500
501 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
502
503 EXPECT_TRUE(caller->voice_rtcp_transport_channel());
504 EXPECT_TRUE(caller->video_rtcp_transport_channel());
505
506 ASSERT_TRUE(
507 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
508
509 EXPECT_FALSE(caller->voice_rtcp_transport_channel());
510 EXPECT_FALSE(caller->video_rtcp_transport_channel());
511}
512
513TEST_F(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) {
514 auto caller = CreatePeerConnectionWithAudioVideo();
515 auto callee = CreatePeerConnectionWithAudioVideo();
516
517 RTCOfferAnswerOptions options;
518 options.use_rtp_mux = true;
519
520 auto offer = caller->CreateOffer(options);
521 SdpContentsForEach(RemoveRtcpMux(), offer->description());
522
523 std::string error;
524 EXPECT_FALSE(caller->SetLocalDescription(CloneSessionDescription(offer.get()),
525 &error));
526 EXPECT_EQ(
527 "Failed to set local offer sdp: rtcp-mux must be enabled when BUNDLE is "
528 "enabled.",
529 error);
530
531 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
532 EXPECT_EQ(
533 "Failed to set remote offer sdp: rtcp-mux must be enabled when BUNDLE is "
534 "enabled.",
535 error);
536}
537
538// Test that candidates sent to the "video" transport do not get pushed down to
539// the "audio" transport channel when bundling.
540TEST_F(PeerConnectionBundleTest,
541 IgnoreCandidatesForUnusedTransportWhenBundling) {
542 const SocketAddress kAudioAddress1("1.1.1.1", 1111);
543 const SocketAddress kAudioAddress2("2.2.2.2", 2222);
544 const SocketAddress kVideoAddress("3.3.3.3", 3333);
545 const SocketAddress kCallerAddress("4.4.4.4", 0);
546 const SocketAddress kCalleeAddress("5.5.5.5", 0);
547
548 auto caller = CreatePeerConnectionWithAudioVideo();
549 auto callee = CreatePeerConnectionWithAudioVideo();
550
551 caller->network()->AddInterface(kCallerAddress);
552 callee->network()->AddInterface(kCalleeAddress);
553
554 RTCOfferAnswerOptions options;
555 options.use_rtp_mux = true;
556
557 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
558 ASSERT_TRUE(
559 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
560
561 // The way the *_WAIT checks work is they only wait if the condition fails,
562 // which does not help in the case where state is not changing. This is
563 // problematic in this test since we want to verify that adding a video
564 // candidate does _not_ change state. So we interleave candidates and assume
565 // that messages are executed in the order they were posted.
566
567 cricket::Candidate audio_candidate1 = CreateLocalUdpCandidate(kAudioAddress1);
568 ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate1,
569 cricket::MEDIA_TYPE_AUDIO));
570
571 cricket::Candidate video_candidate = CreateLocalUdpCandidate(kVideoAddress);
572 ASSERT_TRUE(caller->AddIceCandidateToMedia(&video_candidate,
573 cricket::MEDIA_TYPE_VIDEO));
574
575 cricket::Candidate audio_candidate2 = CreateLocalUdpCandidate(kAudioAddress2);
576 ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate2,
577 cricket::MEDIA_TYPE_AUDIO));
578
579 EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress1),
580 kDefaultTimeout);
581 EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress2),
582 kDefaultTimeout);
583 EXPECT_FALSE(caller->HasConnectionWithRemoteAddress(kVideoAddress));
584}
585
586// Test that the transport used by both audio and video is the transport
587// associated with the first MID in the answer BUNDLE group, even if it's in a
588// different order from the offer.
589TEST_F(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) {
590 auto caller = CreatePeerConnectionWithAudioVideo();
591 auto callee = CreatePeerConnectionWithAudioVideo();
592
593 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
594
595 auto* old_video_transport = caller->video_rtp_transport_channel();
596
597 auto answer = callee->CreateAnswer();
598 auto* old_bundle_group =
599 answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
600 ASSERT_THAT(old_bundle_group->content_names(),
601 ElementsAre(cricket::CN_AUDIO, cricket::CN_VIDEO));
602 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
603
604 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
605 new_bundle_group.AddContentName(cricket::CN_VIDEO);
606 new_bundle_group.AddContentName(cricket::CN_AUDIO);
607 answer->description()->AddGroup(new_bundle_group);
608
609 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
610
611 EXPECT_EQ(old_video_transport, caller->video_rtp_transport_channel());
612 EXPECT_EQ(caller->voice_rtp_transport_channel(),
613 caller->video_rtp_transport_channel());
614}
615
616} // namespace webrtc