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