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