blob: dfd47cde796e9e9196e7295c8e586e09bb1b4a53 [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;
Steve Anton7464fca2018-01-19 11:10:37 -080038using ::testing::Combine;
Steve Anton6f25b092017-10-23 09:39:20 -070039using ::testing::ElementsAre;
40using ::testing::UnorderedElementsAre;
41using ::testing::Values;
42
43constexpr int kDefaultTimeout = 10000;
44
45// TODO(steveanton): These tests should be rewritten to use the standard
46// RtpSenderInterface/DtlsTransportInterface objects once they're available in
47// the API. The RtpSender can be used to determine which transport a given media
48// will use: https://www.w3.org/TR/webrtc/#dom-rtcrtpsender-transport
Steve Anton7464fca2018-01-19 11:10:37 -080049// Should also be able to remove GetTransceiversForTesting at that point.
Steve Anton6f25b092017-10-23 09:39:20 -070050
51class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
52 public:
53 using PeerConnectionWrapper::PeerConnectionWrapper;
54
55 bool AddIceCandidateToMedia(cricket::Candidate* candidate,
56 cricket::MediaType media_type) {
57 auto* desc = pc()->remote_description()->description();
58 for (size_t i = 0; i < desc->contents().size(); i++) {
59 const auto& content = desc->contents()[i];
Steve Antonb1c1de12017-12-21 15:14:30 -080060 if (content.media_description()->type() == media_type) {
Steve Anton6f25b092017-10-23 09:39:20 -070061 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
Zhi Huange830e682018-03-30 10:48:35 -070070 rtc::PacketTransportInternal* voice_rtp_transport() {
71 return (voice_channel() ? voice_channel()->rtp_packet_transport()
72 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -070073 }
74
Zhi Huange830e682018-03-30 10:48:35 -070075 rtc::PacketTransportInternal* voice_rtcp_transport() {
76 return (voice_channel() ? voice_channel()->rtcp_packet_transport()
77 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -070078 }
79
80 cricket::VoiceChannel* voice_channel() {
Steve Antonb8867112018-02-13 10:07:54 -080081 auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
Steve Anton7464fca2018-01-19 11:10:37 -080082 for (auto transceiver : transceivers) {
Steve Anton69470252018-02-09 11:43:08 -080083 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Steve Anton7464fca2018-01-19 11:10:37 -080084 return static_cast<cricket::VoiceChannel*>(
85 transceiver->internal()->channel());
86 }
87 }
88 return nullptr;
Steve Anton6f25b092017-10-23 09:39:20 -070089 }
90
Zhi Huange830e682018-03-30 10:48:35 -070091 rtc::PacketTransportInternal* video_rtp_transport() {
92 return (video_channel() ? video_channel()->rtp_packet_transport()
93 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -070094 }
95
Zhi Huange830e682018-03-30 10:48:35 -070096 rtc::PacketTransportInternal* video_rtcp_transport() {
97 return (video_channel() ? video_channel()->rtcp_packet_transport()
98 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -070099 }
100
101 cricket::VideoChannel* video_channel() {
Steve Antonb8867112018-02-13 10:07:54 -0800102 auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
Steve Anton7464fca2018-01-19 11:10:37 -0800103 for (auto transceiver : transceivers) {
Steve Anton69470252018-02-09 11:43:08 -0800104 if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
Steve Anton7464fca2018-01-19 11:10:37 -0800105 return static_cast<cricket::VideoChannel*>(
106 transceiver->internal()->channel());
107 }
108 }
109 return nullptr;
Steve Anton6f25b092017-10-23 09:39:20 -0700110 }
111
112 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100113 auto* pci =
114 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
115 pc());
116 return static_cast<PeerConnection*>(pci->internal());
Steve Anton6f25b092017-10-23 09:39:20 -0700117 }
118
119 // Returns true if the stats indicate that an ICE connection is either in
120 // progress or established with the given remote address.
121 bool HasConnectionWithRemoteAddress(const SocketAddress& address) {
122 auto report = GetStats();
123 if (!report) {
124 return false;
125 }
126 std::string matching_candidate_id;
127 for (auto* ice_candidate_stats :
128 report->GetStatsOfType<RTCRemoteIceCandidateStats>()) {
129 if (*ice_candidate_stats->ip == address.HostAsURIString() &&
130 *ice_candidate_stats->port == address.port()) {
131 matching_candidate_id = ice_candidate_stats->id();
132 break;
133 }
134 }
135 if (matching_candidate_id.empty()) {
136 return false;
137 }
138 for (auto* pair_stats :
139 report->GetStatsOfType<RTCIceCandidatePairStats>()) {
140 if (*pair_stats->remote_candidate_id == matching_candidate_id) {
141 if (*pair_stats->state == RTCStatsIceCandidatePairState::kInProgress ||
142 *pair_stats->state == RTCStatsIceCandidatePairState::kSucceeded) {
143 return true;
144 }
145 }
146 }
147 return false;
148 }
149
150 rtc::FakeNetworkManager* network() { return network_; }
151
152 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
153
154 private:
155 rtc::FakeNetworkManager* network_;
156};
157
Steve Anton7464fca2018-01-19 11:10:37 -0800158class PeerConnectionBundleBaseTest : public ::testing::Test {
Steve Anton6f25b092017-10-23 09:39:20 -0700159 protected:
160 typedef std::unique_ptr<PeerConnectionWrapperForBundleTest> WrapperPtr;
161
Steve Anton7464fca2018-01-19 11:10:37 -0800162 explicit PeerConnectionBundleBaseTest(SdpSemantics sdp_semantics)
163 : vss_(new rtc::VirtualSocketServer()),
164 main_(vss_.get()),
165 sdp_semantics_(sdp_semantics) {
Steve Anton6f25b092017-10-23 09:39:20 -0700166#ifdef WEBRTC_ANDROID
167 InitializeAndroidObjects();
168#endif
169 pc_factory_ = CreatePeerConnectionFactory(
170 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Karl Wiberg32df86e2017-11-03 10:24:27 +0100171 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
172 CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -0700173 }
174
175 WrapperPtr CreatePeerConnection() {
176 return CreatePeerConnection(RTCConfiguration());
177 }
178
179 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
180 auto* fake_network = NewFakeNetwork();
181 auto port_allocator =
182 rtc::MakeUnique<cricket::BasicPortAllocator>(fake_network);
183 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
184 cricket::PORTALLOCATOR_DISABLE_RELAY);
185 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
186 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
Steve Anton7464fca2018-01-19 11:10:37 -0800187 RTCConfiguration modified_config = config;
188 modified_config.sdp_semantics = sdp_semantics_;
Steve Anton6f25b092017-10-23 09:39:20 -0700189 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton7464fca2018-01-19 11:10:37 -0800190 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Anton6f25b092017-10-23 09:39:20 -0700191 if (!pc) {
192 return nullptr;
193 }
194
195 auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForBundleTest>(
196 pc_factory_, pc, std::move(observer));
197 wrapper->set_network(fake_network);
198 return wrapper;
199 }
200
201 // Accepts the same arguments as CreatePeerConnection and adds default audio
202 // and video tracks.
203 template <typename... Args>
204 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
205 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
206 if (!wrapper) {
207 return nullptr;
208 }
209 wrapper->AddAudioTrack("a");
210 wrapper->AddVideoTrack("v");
211 return wrapper;
212 }
213
214 cricket::Candidate CreateLocalUdpCandidate(
215 const rtc::SocketAddress& address) {
216 cricket::Candidate candidate;
217 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
218 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
219 candidate.set_address(address);
220 candidate.set_type(cricket::LOCAL_PORT_TYPE);
221 return candidate;
222 }
223
224 rtc::FakeNetworkManager* NewFakeNetwork() {
225 // The PeerConnection's port allocator is tied to the PeerConnection's
226 // lifetime and expects the underlying NetworkManager to outlive it. If
227 // PeerConnectionWrapper owned the NetworkManager, it would be destroyed
228 // before the PeerConnection (since subclass members are destroyed before
229 // base class members). Therefore, the test fixture will own all the fake
230 // networks even though tests should access the fake network through the
231 // PeerConnectionWrapper.
232 auto* fake_network = new rtc::FakeNetworkManager();
233 fake_networks_.emplace_back(fake_network);
234 return fake_network;
235 }
236
237 std::unique_ptr<rtc::VirtualSocketServer> vss_;
238 rtc::AutoSocketServerThread main_;
239 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
240 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton7464fca2018-01-19 11:10:37 -0800241 const SdpSemantics sdp_semantics_;
242};
243
244class PeerConnectionBundleTest
245 : public PeerConnectionBundleBaseTest,
246 public ::testing::WithParamInterface<SdpSemantics> {
247 protected:
248 PeerConnectionBundleTest() : PeerConnectionBundleBaseTest(GetParam()) {}
Steve Anton6f25b092017-10-23 09:39:20 -0700249};
250
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700251class PeerConnectionBundleTestUnifiedPlan
252 : public PeerConnectionBundleBaseTest {
253 protected:
254 PeerConnectionBundleTestUnifiedPlan()
255 : PeerConnectionBundleBaseTest(SdpSemantics::kUnifiedPlan) {}
256};
257
Steve Anton6f25b092017-10-23 09:39:20 -0700258SdpContentMutator RemoveRtcpMux() {
259 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800260 content->media_description()->set_rtcp_mux(false);
Steve Anton6f25b092017-10-23 09:39:20 -0700261 };
262}
263
264std::vector<int> GetCandidateComponents(
265 const std::vector<IceCandidateInterface*> candidates) {
266 std::vector<int> components;
267 for (auto* candidate : candidates) {
268 components.push_back(candidate->candidate().component());
269 }
270 return components;
271}
272
273// Test that there are 2 local UDP candidates (1 RTP and 1 RTCP candidate) for
274// each media section when disabling bundling and disabling RTCP multiplexing.
Steve Anton7464fca2018-01-19 11:10:37 -0800275TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700276 TwoCandidatesForEachTransportWhenNoBundleNoRtcpMux) {
277 const SocketAddress kCallerAddress("1.1.1.1", 0);
278 const SocketAddress kCalleeAddress("2.2.2.2", 0);
279
280 RTCConfiguration config;
281 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
282 auto caller = CreatePeerConnectionWithAudioVideo(config);
283 caller->network()->AddInterface(kCallerAddress);
284 auto callee = CreatePeerConnectionWithAudioVideo(config);
285 callee->network()->AddInterface(kCalleeAddress);
286
287 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
288 RTCOfferAnswerOptions options_no_bundle;
289 options_no_bundle.use_rtp_mux = false;
290 auto answer = callee->CreateAnswer(options_no_bundle);
291 SdpContentsForEach(RemoveRtcpMux(), answer->description());
292 ASSERT_TRUE(
293 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
294 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
295
296 // Check that caller has separate RTP and RTCP candidates for each media.
297 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
298 EXPECT_THAT(
299 GetCandidateComponents(caller->observer()->GetCandidatesByMline(0)),
300 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
301 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
302 EXPECT_THAT(
303 GetCandidateComponents(caller->observer()->GetCandidatesByMline(1)),
304 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
305 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
306
307 // Check that callee has separate RTP and RTCP candidates for each media.
308 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kDefaultTimeout);
309 EXPECT_THAT(
310 GetCandidateComponents(callee->observer()->GetCandidatesByMline(0)),
311 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
312 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
313 EXPECT_THAT(
314 GetCandidateComponents(callee->observer()->GetCandidatesByMline(1)),
315 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
316 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
317}
318
319// Test that there is 1 local UDP candidate for both RTP and RTCP for each media
320// section when disabling bundle but enabling RTCP multiplexing.
Steve Anton7464fca2018-01-19 11:10:37 -0800321TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700322 OneCandidateForEachTransportWhenNoBundleButRtcpMux) {
323 const SocketAddress kCallerAddress("1.1.1.1", 0);
324
325 auto caller = CreatePeerConnectionWithAudioVideo();
326 caller->network()->AddInterface(kCallerAddress);
327 auto callee = CreatePeerConnectionWithAudioVideo();
328
329 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
330 RTCOfferAnswerOptions options_no_bundle;
331 options_no_bundle.use_rtp_mux = false;
332 ASSERT_TRUE(
333 caller->SetRemoteDescription(callee->CreateAnswer(options_no_bundle)));
334
335 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
336
337 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
338 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(1).size());
339}
340
341// Test that there is 1 local UDP candidate in only the first media section when
342// bundling and enabling RTCP multiplexing.
Steve Anton7464fca2018-01-19 11:10:37 -0800343TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700344 OneCandidateOnlyOnFirstTransportWhenBundleAndRtcpMux) {
345 const SocketAddress kCallerAddress("1.1.1.1", 0);
346
347 RTCConfiguration config;
348 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
349 auto caller = CreatePeerConnectionWithAudioVideo(config);
350 caller->network()->AddInterface(kCallerAddress);
351 auto callee = CreatePeerConnectionWithAudioVideo(config);
352
353 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
354 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
355
356 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
357
358 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
359 EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size());
360}
361
Zhi Huange830e682018-03-30 10:48:35 -0700362// It will fail if the offerer uses the mux-BUNDLE policy but the answerer
363// doesn't support BUNDLE.
364TEST_P(PeerConnectionBundleTest, MaxBundleNotSupportedInAnswer) {
365 RTCConfiguration config;
366 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
367 auto caller = CreatePeerConnectionWithAudioVideo(config);
368 auto callee = CreatePeerConnectionWithAudioVideo();
369
370 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
371 bool equal_before =
372 (caller->voice_rtp_transport() == caller->video_rtp_transport());
373 EXPECT_EQ(true, equal_before);
374 RTCOfferAnswerOptions options;
375 options.use_rtp_mux = false;
376 EXPECT_FALSE(
377 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
378}
379
Steve Anton6f25b092017-10-23 09:39:20 -0700380// The following parameterized test verifies that an offer/answer with varying
381// bundle policies and either bundle in the answer or not will produce the
382// expected RTP transports for audio and video. In particular, for bundling we
383// care about whether they are separate transports or the same.
384
385enum class BundleIncluded { kBundleInAnswer, kBundleNotInAnswer };
386std::ostream& operator<<(std::ostream& out, BundleIncluded value) {
387 switch (value) {
388 case BundleIncluded::kBundleInAnswer:
389 return out << "bundle in answer";
390 case BundleIncluded::kBundleNotInAnswer:
391 return out << "bundle not in answer";
392 }
393 return out << "unknown";
394}
395
396class PeerConnectionBundleMatrixTest
Steve Anton7464fca2018-01-19 11:10:37 -0800397 : public PeerConnectionBundleBaseTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700398 public ::testing::WithParamInterface<
Steve Anton7464fca2018-01-19 11:10:37 -0800399 std::tuple<SdpSemantics,
400 std::tuple<BundlePolicy, BundleIncluded, bool, bool>>> {
Steve Anton6f25b092017-10-23 09:39:20 -0700401 protected:
Steve Anton7464fca2018-01-19 11:10:37 -0800402 PeerConnectionBundleMatrixTest()
403 : PeerConnectionBundleBaseTest(std::get<0>(GetParam())) {
404 auto param = std::get<1>(GetParam());
405 bundle_policy_ = std::get<0>(param);
406 bundle_included_ = std::get<1>(param);
407 expected_same_before_ = std::get<2>(param);
408 expected_same_after_ = std::get<3>(param);
Steve Anton6f25b092017-10-23 09:39:20 -0700409 }
410
411 PeerConnectionInterface::BundlePolicy bundle_policy_;
412 BundleIncluded bundle_included_;
413 bool expected_same_before_;
414 bool expected_same_after_;
415};
416
417TEST_P(PeerConnectionBundleMatrixTest,
418 VerifyTransportsBeforeAndAfterSettingRemoteAnswer) {
419 RTCConfiguration config;
420 config.bundle_policy = bundle_policy_;
421 auto caller = CreatePeerConnectionWithAudioVideo(config);
422 auto callee = CreatePeerConnectionWithAudioVideo();
423
424 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Zhi Huange830e682018-03-30 10:48:35 -0700425 bool equal_before =
426 (caller->voice_rtp_transport() == caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700427 EXPECT_EQ(expected_same_before_, equal_before);
428
429 RTCOfferAnswerOptions options;
430 options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer);
431 ASSERT_TRUE(
432 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
Zhi Huange830e682018-03-30 10:48:35 -0700433 bool equal_after =
434 (caller->voice_rtp_transport() == caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700435 EXPECT_EQ(expected_same_after_, equal_after);
436}
437
438// The max-bundle policy means we should anticipate bundling being negotiated,
439// and multiplex audio/video from the start.
440// For all other policies, bundling should only be enabled if negotiated by the
441// answer.
442INSTANTIATE_TEST_CASE_P(
443 PeerConnectionBundleTest,
444 PeerConnectionBundleMatrixTest,
Steve Anton7464fca2018-01-19 11:10:37 -0800445 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
446 Values(std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
447 BundleIncluded::kBundleInAnswer,
448 false,
449 true),
450 std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
451 BundleIncluded::kBundleNotInAnswer,
452 false,
453 false),
454 std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
455 BundleIncluded::kBundleInAnswer,
456 true,
457 true),
Steve Anton7464fca2018-01-19 11:10:37 -0800458 std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
459 BundleIncluded::kBundleInAnswer,
460 false,
461 true),
462 std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
463 BundleIncluded::kBundleNotInAnswer,
464 false,
465 false))));
Steve Anton6f25b092017-10-23 09:39:20 -0700466
467// Test that the audio/video transports on the callee side are the same before
468// and after setting a local answer when max BUNDLE is enabled and an offer with
469// BUNDLE is received.
Steve Anton7464fca2018-01-19 11:10:37 -0800470TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700471 TransportsSameForMaxBundleWithBundleInRemoteOffer) {
472 auto caller = CreatePeerConnectionWithAudioVideo();
473 RTCConfiguration config;
474 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
475 auto callee = CreatePeerConnectionWithAudioVideo(config);
476
477 RTCOfferAnswerOptions options_with_bundle;
478 options_with_bundle.use_rtp_mux = true;
479 ASSERT_TRUE(callee->SetRemoteDescription(
480 caller->CreateOfferAndSetAsLocal(options_with_bundle)));
481
Zhi Huange830e682018-03-30 10:48:35 -0700482 EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700483
484 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
485
Zhi Huange830e682018-03-30 10:48:35 -0700486 EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700487}
488
Steve Anton7464fca2018-01-19 11:10:37 -0800489TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700490 FailToSetRemoteOfferWithNoBundleWhenBundlePolicyMaxBundle) {
491 auto caller = CreatePeerConnectionWithAudioVideo();
492 RTCConfiguration config;
493 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
494 auto callee = CreatePeerConnectionWithAudioVideo(config);
495
496 RTCOfferAnswerOptions options_no_bundle;
497 options_no_bundle.use_rtp_mux = false;
498 EXPECT_FALSE(callee->SetRemoteDescription(
499 caller->CreateOfferAndSetAsLocal(options_no_bundle)));
500}
501
502// Test that if the media section which has the bundled transport is rejected,
503// then the peers still connect and the bundled transport switches to the other
504// media section.
505// Note: This is currently failing because of the following bug:
506// https://bugs.chromium.org/p/webrtc/issues/detail?id=6280
Steve Anton7464fca2018-01-19 11:10:37 -0800507TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700508 DISABLED_SuccessfullyNegotiateMaxBundleIfBundleTransportMediaRejected) {
509 RTCConfiguration config;
510 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
511 auto caller = CreatePeerConnectionWithAudioVideo(config);
512 auto callee = CreatePeerConnection();
513 callee->AddVideoTrack("v");
514
515 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
516
517 RTCOfferAnswerOptions options;
518 options.offer_to_receive_audio = 0;
519 ASSERT_TRUE(
520 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
521
Zhi Huange830e682018-03-30 10:48:35 -0700522 EXPECT_FALSE(caller->voice_rtp_transport());
523 EXPECT_TRUE(caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700524}
525
526// When requiring RTCP multiplexing, the PeerConnection never makes RTCP
527// transport channels.
Steve Anton7464fca2018-01-19 11:10:37 -0800528TEST_P(PeerConnectionBundleTest, NeverCreateRtcpTransportWithRtcpMuxRequired) {
Steve Anton6f25b092017-10-23 09:39:20 -0700529 RTCConfiguration config;
530 config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyRequire;
531 auto caller = CreatePeerConnectionWithAudioVideo(config);
532 auto callee = CreatePeerConnectionWithAudioVideo();
533
534 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
535
Zhi Huange830e682018-03-30 10:48:35 -0700536 EXPECT_FALSE(caller->voice_rtcp_transport());
537 EXPECT_FALSE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700538
539 ASSERT_TRUE(
540 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
541
Zhi Huange830e682018-03-30 10:48:35 -0700542 EXPECT_FALSE(caller->voice_rtcp_transport());
543 EXPECT_FALSE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700544}
545
Zhi Huange830e682018-03-30 10:48:35 -0700546// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transports
547// when the offer is sent, but will destroy them once the remote answer is set.
Steve Anton7464fca2018-01-19 11:10:37 -0800548TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700549 CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) {
550 RTCConfiguration config;
551 config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyNegotiate;
552 auto caller = CreatePeerConnectionWithAudioVideo(config);
553 auto callee = CreatePeerConnectionWithAudioVideo();
554
555 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
556
Zhi Huange830e682018-03-30 10:48:35 -0700557 EXPECT_TRUE(caller->voice_rtcp_transport());
558 EXPECT_TRUE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700559
560 ASSERT_TRUE(
561 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
562
Zhi Huange830e682018-03-30 10:48:35 -0700563 EXPECT_FALSE(caller->voice_rtcp_transport());
564 EXPECT_FALSE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700565}
566
Steve Anton7464fca2018-01-19 11:10:37 -0800567TEST_P(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) {
Steve Anton6f25b092017-10-23 09:39:20 -0700568 auto caller = CreatePeerConnectionWithAudioVideo();
569 auto callee = CreatePeerConnectionWithAudioVideo();
570
571 RTCOfferAnswerOptions options;
572 options.use_rtp_mux = true;
573
574 auto offer = caller->CreateOffer(options);
575 SdpContentsForEach(RemoveRtcpMux(), offer->description());
576
577 std::string error;
578 EXPECT_FALSE(caller->SetLocalDescription(CloneSessionDescription(offer.get()),
579 &error));
580 EXPECT_EQ(
581 "Failed to set local offer sdp: rtcp-mux must be enabled when BUNDLE is "
582 "enabled.",
583 error);
584
585 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
586 EXPECT_EQ(
587 "Failed to set remote offer sdp: rtcp-mux must be enabled when BUNDLE is "
588 "enabled.",
589 error);
590}
591
592// Test that candidates sent to the "video" transport do not get pushed down to
593// the "audio" transport channel when bundling.
Steve Anton7464fca2018-01-19 11:10:37 -0800594TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700595 IgnoreCandidatesForUnusedTransportWhenBundling) {
596 const SocketAddress kAudioAddress1("1.1.1.1", 1111);
597 const SocketAddress kAudioAddress2("2.2.2.2", 2222);
598 const SocketAddress kVideoAddress("3.3.3.3", 3333);
599 const SocketAddress kCallerAddress("4.4.4.4", 0);
600 const SocketAddress kCalleeAddress("5.5.5.5", 0);
601
602 auto caller = CreatePeerConnectionWithAudioVideo();
603 auto callee = CreatePeerConnectionWithAudioVideo();
604
605 caller->network()->AddInterface(kCallerAddress);
606 callee->network()->AddInterface(kCalleeAddress);
607
608 RTCOfferAnswerOptions options;
609 options.use_rtp_mux = true;
610
611 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
612 ASSERT_TRUE(
Zhi Huange830e682018-03-30 10:48:35 -0700613 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
Steve Anton6f25b092017-10-23 09:39:20 -0700614
615 // The way the *_WAIT checks work is they only wait if the condition fails,
616 // which does not help in the case where state is not changing. This is
617 // problematic in this test since we want to verify that adding a video
618 // candidate does _not_ change state. So we interleave candidates and assume
619 // that messages are executed in the order they were posted.
620
621 cricket::Candidate audio_candidate1 = CreateLocalUdpCandidate(kAudioAddress1);
622 ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate1,
623 cricket::MEDIA_TYPE_AUDIO));
624
625 cricket::Candidate video_candidate = CreateLocalUdpCandidate(kVideoAddress);
626 ASSERT_TRUE(caller->AddIceCandidateToMedia(&video_candidate,
627 cricket::MEDIA_TYPE_VIDEO));
628
629 cricket::Candidate audio_candidate2 = CreateLocalUdpCandidate(kAudioAddress2);
630 ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate2,
631 cricket::MEDIA_TYPE_AUDIO));
632
633 EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress1),
634 kDefaultTimeout);
635 EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress2),
636 kDefaultTimeout);
637 EXPECT_FALSE(caller->HasConnectionWithRemoteAddress(kVideoAddress));
638}
639
640// Test that the transport used by both audio and video is the transport
641// associated with the first MID in the answer BUNDLE group, even if it's in a
642// different order from the offer.
Steve Anton7464fca2018-01-19 11:10:37 -0800643TEST_P(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) {
Steve Anton6f25b092017-10-23 09:39:20 -0700644 auto caller = CreatePeerConnectionWithAudioVideo();
645 auto callee = CreatePeerConnectionWithAudioVideo();
646
647 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
648
Zhi Huange830e682018-03-30 10:48:35 -0700649 auto* old_video_transport = caller->video_rtp_transport();
Steve Anton6f25b092017-10-23 09:39:20 -0700650
651 auto answer = callee->CreateAnswer();
652 auto* old_bundle_group =
653 answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
Steve Anton7464fca2018-01-19 11:10:37 -0800654 std::string first_mid = old_bundle_group->content_names()[0];
655 std::string second_mid = old_bundle_group->content_names()[1];
Steve Anton6f25b092017-10-23 09:39:20 -0700656 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
657
658 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
Steve Anton7464fca2018-01-19 11:10:37 -0800659 new_bundle_group.AddContentName(second_mid);
660 new_bundle_group.AddContentName(first_mid);
Steve Anton6f25b092017-10-23 09:39:20 -0700661 answer->description()->AddGroup(new_bundle_group);
662
663 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
664
Zhi Huange830e682018-03-30 10:48:35 -0700665 EXPECT_EQ(old_video_transport, caller->video_rtp_transport());
666 EXPECT_EQ(caller->voice_rtp_transport(), caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700667}
668
Zhi Huang365381f2018-04-13 16:44:34 -0700669// This tests that applying description with conflicted RTP demuxing criteria
670// will fail.
671TEST_P(PeerConnectionBundleTest,
672 ApplyDescriptionWithConflictedDemuxCriteriaFail) {
673 auto caller = CreatePeerConnectionWithAudioVideo();
674 auto callee = CreatePeerConnectionWithAudioVideo();
675
676 RTCOfferAnswerOptions options;
677 options.use_rtp_mux = false;
678 auto offer = caller->CreateOffer(options);
679 // Modified the SDP to make two m= sections have the same SSRC.
680 ASSERT_GE(offer->description()->contents().size(), 2U);
681 offer->description()
682 ->contents()[0]
683 .description->mutable_streams()[0]
684 .ssrcs[0] = 1111222;
685 offer->description()
686 ->contents()[1]
687 .description->mutable_streams()[0]
688 .ssrcs[0] = 1111222;
689 EXPECT_TRUE(
690 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
691 EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
692 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal(options));
693
694 // Enable BUNDLE in subsequent offer/answer exchange and two m= sections are
695 // expectd to use one RtpTransport underneath.
696 options.use_rtp_mux = true;
697 EXPECT_TRUE(
698 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
699 auto answer = callee->CreateAnswer(options);
700 // When BUNDLE is enabled, applying the description is expected to fail
701 // because the demuxing criteria is conflicted.
702 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
703}
704
Zhi Huangd2248f82018-04-10 14:41:03 -0700705// This tests that changing the pre-negotiated BUNDLE tag is not supported.
706TEST_P(PeerConnectionBundleTest, RejectDescriptionChangingBundleTag) {
707 RTCConfiguration config;
708 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
709 auto caller = CreatePeerConnectionWithAudioVideo(config);
710 auto callee = CreatePeerConnectionWithAudioVideo(config);
711
712 RTCOfferAnswerOptions options;
713 options.use_rtp_mux = true;
714 auto offer = caller->CreateOfferAndSetAsLocal(options);
715
716 // Create a new bundle-group with different bundled_mid.
717 auto* old_bundle_group =
718 offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
719 std::string first_mid = old_bundle_group->content_names()[0];
720 std::string second_mid = old_bundle_group->content_names()[1];
721 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
722 new_bundle_group.AddContentName(second_mid);
723
724 auto re_offer = CloneSessionDescription(offer.get());
725 callee->SetRemoteDescription(std::move(offer));
726 auto answer = callee->CreateAnswer(options);
727 // Reject the first MID.
728 answer->description()->contents()[0].rejected = true;
729 // Remove the first MID from the bundle group.
730 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
731 answer->description()->AddGroup(new_bundle_group);
732 // The answer is expected to be rejected.
733 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
734
735 // Do the same thing for re-offer.
736 re_offer->description()->contents()[0].rejected = true;
737 re_offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
738 re_offer->description()->AddGroup(new_bundle_group);
739 // The re-offer is expected to be rejected.
740 EXPECT_FALSE(caller->SetLocalDescription(std::move(re_offer)));
741}
742
743// This tests that removing contents from BUNDLE group and reject the whole
744// BUNDLE group could work. This is a regression test for
745// (https://bugs.chromium.org/p/chromium/issues/detail?id=827917)
746TEST_P(PeerConnectionBundleTest, RemovingContentAndRejectBundleGroup) {
747 RTCConfiguration config;
748#ifndef HAVE_SCTP
749 config.enable_rtp_data_channel = true;
750#endif
751 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
752 auto caller = CreatePeerConnectionWithAudioVideo(config);
753 caller->CreateDataChannel("dc");
754
755 auto offer = caller->CreateOfferAndSetAsLocal();
756 auto re_offer = CloneSessionDescription(offer.get());
757
758 // Removing the second MID from the BUNDLE group.
759 auto* old_bundle_group =
760 offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
761 std::string first_mid = old_bundle_group->content_names()[0];
762 std::string third_mid = old_bundle_group->content_names()[2];
763 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
764 new_bundle_group.AddContentName(first_mid);
765 new_bundle_group.AddContentName(third_mid);
766
767 // Reject the entire new bundle group.
768 re_offer->description()->contents()[0].rejected = true;
769 re_offer->description()->contents()[2].rejected = true;
770 re_offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
771 re_offer->description()->AddGroup(new_bundle_group);
772
773 EXPECT_TRUE(caller->SetLocalDescription(std::move(re_offer)));
774}
775
776// This tests that the BUNDLE group in answer should be a subset of the offered
777// group.
778TEST_P(PeerConnectionBundleTest, AddContentToBundleGroupInAnswerNotSupported) {
779 auto caller = CreatePeerConnectionWithAudioVideo();
780 auto callee = CreatePeerConnectionWithAudioVideo();
781
782 auto offer = caller->CreateOffer();
783 std::string first_mid = offer->description()->contents()[0].name;
784 std::string second_mid = offer->description()->contents()[1].name;
785
786 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
787 bundle_group.AddContentName(first_mid);
788 offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
789 offer->description()->AddGroup(bundle_group);
790 EXPECT_TRUE(
791 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
792 EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
793
794 auto answer = callee->CreateAnswer();
795 bundle_group.AddContentName(second_mid);
796 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
797 answer->description()->AddGroup(bundle_group);
798
799 // The answer is expected to be rejected because second mid is not in the
800 // offered BUNDLE group.
801 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
802}
803
804// This tests that the BUNDLE group with non-existing MID should be rejectd.
805TEST_P(PeerConnectionBundleTest, RejectBundleGroupWithNonExistingMid) {
806 auto caller = CreatePeerConnectionWithAudioVideo();
807 auto callee = CreatePeerConnectionWithAudioVideo();
808
809 auto offer = caller->CreateOffer();
810 auto invalid_bundle_group =
811 *offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
812 invalid_bundle_group.AddContentName("non-existing-MID");
813 offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
814 offer->description()->AddGroup(invalid_bundle_group);
815
816 EXPECT_FALSE(
817 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
818 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
819}
820
821// This tests that an answer shouldn't be able to remove an m= section from an
822// established group without rejecting it.
823TEST_P(PeerConnectionBundleTest, RemoveContentFromBundleGroup) {
824 auto caller = CreatePeerConnectionWithAudioVideo();
825 auto callee = CreatePeerConnectionWithAudioVideo();
826
827 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
828 EXPECT_TRUE(
829 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
830
831 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
832 auto answer = callee->CreateAnswer();
833 std::string second_mid = answer->description()->contents()[1].name;
834
835 auto invalid_bundle_group =
836 *answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
837 invalid_bundle_group.RemoveContentName(second_mid);
838 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
839 answer->description()->AddGroup(invalid_bundle_group);
840
841 EXPECT_FALSE(
842 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
843}
844
Steve Anton7464fca2018-01-19 11:10:37 -0800845INSTANTIATE_TEST_CASE_P(PeerConnectionBundleTest,
846 PeerConnectionBundleTest,
847 Values(SdpSemantics::kPlanB,
848 SdpSemantics::kUnifiedPlan));
849
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700850// According to RFC5888, if an endpoint understands the semantics of an
851// "a=group", it MUST return an answer with that group. So, an empty BUNDLE
852// group is valid when the answerer rejects all m= sections (by stopping all
853// transceivers), meaning there's nothing to bundle.
854//
855// Only writing this test for Unified Plan mode, since there's no way to reject
856// m= sections in answers for Plan B without SDP munging.
857TEST_F(PeerConnectionBundleTestUnifiedPlan,
858 EmptyBundleGroupCreatedInAnswerWhenAppropriate) {
859 auto caller = CreatePeerConnectionWithAudioVideo();
860 auto callee = CreatePeerConnection();
861
862 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
863
864 // Stop all transceivers, causing all m= sections to be rejected.
865 for (const auto& transceiver : callee->pc()->GetTransceivers()) {
866 transceiver->Stop();
867 }
868 EXPECT_TRUE(
869 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
870
871 // Verify that the answer actually contained an empty bundle group.
872 const SessionDescriptionInterface* desc = callee->pc()->local_description();
873 ASSERT_NE(nullptr, desc);
874 const cricket::ContentGroup* bundle_group =
875 desc->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
876 ASSERT_NE(nullptr, bundle_group);
877 EXPECT_TRUE(bundle_group->content_names().empty());
878}
879
Steve Anton6f25b092017-10-23 09:39:20 -0700880} // namespace webrtc