blob: b369db23da56782fb99e60b94ff8e3a32f852b7d [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"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010013#include "api/create_peerconnection_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080014#include "api/peer_connection_proxy.h"
Anders Carlsson67537952018-05-03 11:28:29 +020015#include "api/video_codecs/builtin_video_decoder_factory.h"
16#include "api/video_codecs/builtin_video_encoder_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "p2p/base/fake_port_allocator.h"
18#include "p2p/base/test_stun_server.h"
19#include "p2p/client/basic_port_allocator.h"
20#include "pc/media_session.h"
21#include "pc/peer_connection.h"
22#include "pc/peer_connection_wrapper.h"
23#include "pc/sdp_utils.h"
Steve Anton6f25b092017-10-23 09:39:20 -070024#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080025#include "pc/test/android_test_initializer.h"
Steve Anton6f25b092017-10-23 09:39:20 -070026#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020027#include "absl/memory/memory.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/test/fake_audio_capture_module.h"
29#include "rtc_base/fake_network.h"
Steve Anton6f25b092017-10-23 09:39:20 -070030#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/virtual_socket_server.h"
Steve Anton6f25b092017-10-23 09:39:20 -070032#include "test/gmock.h"
33
34namespace webrtc {
35
36using BundlePolicy = PeerConnectionInterface::BundlePolicy;
37using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
38using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
39using RtcpMuxPolicy = PeerConnectionInterface::RtcpMuxPolicy;
40using rtc::SocketAddress;
Steve Anton7464fca2018-01-19 11:10:37 -080041using ::testing::Combine;
Steve Anton6f25b092017-10-23 09:39:20 -070042using ::testing::ElementsAre;
43using ::testing::UnorderedElementsAre;
44using ::testing::Values;
45
46constexpr int kDefaultTimeout = 10000;
47
48// TODO(steveanton): These tests should be rewritten to use the standard
49// RtpSenderInterface/DtlsTransportInterface objects once they're available in
50// the API. The RtpSender can be used to determine which transport a given media
51// will use: https://www.w3.org/TR/webrtc/#dom-rtcrtpsender-transport
Steve Anton7464fca2018-01-19 11:10:37 -080052// Should also be able to remove GetTransceiversForTesting at that point.
Steve Anton6f25b092017-10-23 09:39:20 -070053
Harald Alvestrandad88c882018-11-28 16:47:46 +010054class FakeNetworkManagerWithNoAnyNetwork : public rtc::FakeNetworkManager {
55 public:
56 void GetAnyAddressNetworks(NetworkList* networks) override {
57 // This function allocates networks that are owned by the
58 // NetworkManager. But some tests assume that they can release
59 // all networks independent of the network manager.
60 // In order to prevent use-after-free issues, don't allow this
61 // function to have any effect when run in tests.
62 RTC_LOG(LS_INFO) << "FakeNetworkManager::GetAnyAddressNetworks ignored";
63 }
64};
65
Steve Anton6f25b092017-10-23 09:39:20 -070066class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
67 public:
68 using PeerConnectionWrapper::PeerConnectionWrapper;
69
70 bool AddIceCandidateToMedia(cricket::Candidate* candidate,
71 cricket::MediaType media_type) {
72 auto* desc = pc()->remote_description()->description();
73 for (size_t i = 0; i < desc->contents().size(); i++) {
74 const auto& content = desc->contents()[i];
Steve Antonb1c1de12017-12-21 15:14:30 -080075 if (content.media_description()->type() == media_type) {
Steve Anton6f25b092017-10-23 09:39:20 -070076 candidate->set_transport_name(content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -070077 std::unique_ptr<IceCandidateInterface> jsep_candidate =
78 CreateIceCandidate(content.name, i, *candidate);
79 return pc()->AddIceCandidate(jsep_candidate.get());
Steve Anton6f25b092017-10-23 09:39:20 -070080 }
81 }
82 RTC_NOTREACHED();
83 return false;
84 }
85
Zhi Huange830e682018-03-30 10:48:35 -070086 rtc::PacketTransportInternal* voice_rtp_transport() {
87 return (voice_channel() ? voice_channel()->rtp_packet_transport()
88 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -070089 }
90
Zhi Huange830e682018-03-30 10:48:35 -070091 rtc::PacketTransportInternal* voice_rtcp_transport() {
92 return (voice_channel() ? voice_channel()->rtcp_packet_transport()
93 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -070094 }
95
96 cricket::VoiceChannel* voice_channel() {
Steve Antonb8867112018-02-13 10:07:54 -080097 auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
Mirko Bonadei739baf02019-01-27 17:29:42 +010098 for (const auto& transceiver : transceivers) {
Steve Anton69470252018-02-09 11:43:08 -080099 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Steve Anton7464fca2018-01-19 11:10:37 -0800100 return static_cast<cricket::VoiceChannel*>(
101 transceiver->internal()->channel());
102 }
103 }
104 return nullptr;
Steve Anton6f25b092017-10-23 09:39:20 -0700105 }
106
Zhi Huange830e682018-03-30 10:48:35 -0700107 rtc::PacketTransportInternal* video_rtp_transport() {
108 return (video_channel() ? video_channel()->rtp_packet_transport()
109 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -0700110 }
111
Zhi Huange830e682018-03-30 10:48:35 -0700112 rtc::PacketTransportInternal* video_rtcp_transport() {
113 return (video_channel() ? video_channel()->rtcp_packet_transport()
114 : nullptr);
Steve Anton6f25b092017-10-23 09:39:20 -0700115 }
116
117 cricket::VideoChannel* video_channel() {
Steve Antonb8867112018-02-13 10:07:54 -0800118 auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
Mirko Bonadei739baf02019-01-27 17:29:42 +0100119 for (const auto& transceiver : transceivers) {
Steve Anton69470252018-02-09 11:43:08 -0800120 if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
Steve Anton7464fca2018-01-19 11:10:37 -0800121 return static_cast<cricket::VideoChannel*>(
122 transceiver->internal()->channel());
123 }
124 }
125 return nullptr;
Steve Anton6f25b092017-10-23 09:39:20 -0700126 }
127
128 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100129 auto* pci =
130 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
131 pc());
132 return static_cast<PeerConnection*>(pci->internal());
Steve Anton6f25b092017-10-23 09:39:20 -0700133 }
134
135 // Returns true if the stats indicate that an ICE connection is either in
136 // progress or established with the given remote address.
137 bool HasConnectionWithRemoteAddress(const SocketAddress& address) {
138 auto report = GetStats();
139 if (!report) {
140 return false;
141 }
142 std::string matching_candidate_id;
143 for (auto* ice_candidate_stats :
144 report->GetStatsOfType<RTCRemoteIceCandidateStats>()) {
145 if (*ice_candidate_stats->ip == address.HostAsURIString() &&
146 *ice_candidate_stats->port == address.port()) {
147 matching_candidate_id = ice_candidate_stats->id();
148 break;
149 }
150 }
151 if (matching_candidate_id.empty()) {
152 return false;
153 }
154 for (auto* pair_stats :
155 report->GetStatsOfType<RTCIceCandidatePairStats>()) {
156 if (*pair_stats->remote_candidate_id == matching_candidate_id) {
157 if (*pair_stats->state == RTCStatsIceCandidatePairState::kInProgress ||
158 *pair_stats->state == RTCStatsIceCandidatePairState::kSucceeded) {
159 return true;
160 }
161 }
162 }
163 return false;
164 }
165
166 rtc::FakeNetworkManager* network() { return network_; }
167
168 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
169
170 private:
171 rtc::FakeNetworkManager* network_;
172};
173
Steve Anton7464fca2018-01-19 11:10:37 -0800174class PeerConnectionBundleBaseTest : public ::testing::Test {
Steve Anton6f25b092017-10-23 09:39:20 -0700175 protected:
176 typedef std::unique_ptr<PeerConnectionWrapperForBundleTest> WrapperPtr;
177
Steve Anton7464fca2018-01-19 11:10:37 -0800178 explicit PeerConnectionBundleBaseTest(SdpSemantics sdp_semantics)
179 : vss_(new rtc::VirtualSocketServer()),
180 main_(vss_.get()),
181 sdp_semantics_(sdp_semantics) {
Steve Anton6f25b092017-10-23 09:39:20 -0700182#ifdef WEBRTC_ANDROID
183 InitializeAndroidObjects();
184#endif
185 pc_factory_ = CreatePeerConnectionFactory(
186 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200187 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
188 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
189 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
190 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Anton6f25b092017-10-23 09:39:20 -0700191 }
192
193 WrapperPtr CreatePeerConnection() {
194 return CreatePeerConnection(RTCConfiguration());
195 }
196
197 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
198 auto* fake_network = NewFakeNetwork();
199 auto port_allocator =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200200 absl::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Anton6f25b092017-10-23 09:39:20 -0700201 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
202 cricket::PORTALLOCATOR_DISABLE_RELAY);
203 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200204 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Anton7464fca2018-01-19 11:10:37 -0800205 RTCConfiguration modified_config = config;
206 modified_config.sdp_semantics = sdp_semantics_;
Steve Anton6f25b092017-10-23 09:39:20 -0700207 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton7464fca2018-01-19 11:10:37 -0800208 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Anton6f25b092017-10-23 09:39:20 -0700209 if (!pc) {
210 return nullptr;
211 }
212
Karl Wiberg918f50c2018-07-05 11:40:33 +0200213 auto wrapper = absl::make_unique<PeerConnectionWrapperForBundleTest>(
Steve Anton6f25b092017-10-23 09:39:20 -0700214 pc_factory_, pc, std::move(observer));
215 wrapper->set_network(fake_network);
216 return wrapper;
217 }
218
219 // Accepts the same arguments as CreatePeerConnection and adds default audio
220 // and video tracks.
221 template <typename... Args>
222 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
223 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
224 if (!wrapper) {
225 return nullptr;
226 }
227 wrapper->AddAudioTrack("a");
228 wrapper->AddVideoTrack("v");
229 return wrapper;
230 }
231
232 cricket::Candidate CreateLocalUdpCandidate(
233 const rtc::SocketAddress& address) {
234 cricket::Candidate candidate;
235 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
236 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
237 candidate.set_address(address);
238 candidate.set_type(cricket::LOCAL_PORT_TYPE);
239 return candidate;
240 }
241
242 rtc::FakeNetworkManager* NewFakeNetwork() {
243 // The PeerConnection's port allocator is tied to the PeerConnection's
244 // lifetime and expects the underlying NetworkManager to outlive it. If
245 // PeerConnectionWrapper owned the NetworkManager, it would be destroyed
246 // before the PeerConnection (since subclass members are destroyed before
247 // base class members). Therefore, the test fixture will own all the fake
248 // networks even though tests should access the fake network through the
249 // PeerConnectionWrapper.
Harald Alvestrandad88c882018-11-28 16:47:46 +0100250 auto* fake_network = new FakeNetworkManagerWithNoAnyNetwork();
Steve Anton6f25b092017-10-23 09:39:20 -0700251 fake_networks_.emplace_back(fake_network);
252 return fake_network;
253 }
254
255 std::unique_ptr<rtc::VirtualSocketServer> vss_;
256 rtc::AutoSocketServerThread main_;
257 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
258 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton7464fca2018-01-19 11:10:37 -0800259 const SdpSemantics sdp_semantics_;
260};
261
262class PeerConnectionBundleTest
263 : public PeerConnectionBundleBaseTest,
264 public ::testing::WithParamInterface<SdpSemantics> {
265 protected:
266 PeerConnectionBundleTest() : PeerConnectionBundleBaseTest(GetParam()) {}
Steve Anton6f25b092017-10-23 09:39:20 -0700267};
268
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700269class PeerConnectionBundleTestUnifiedPlan
270 : public PeerConnectionBundleBaseTest {
271 protected:
272 PeerConnectionBundleTestUnifiedPlan()
273 : PeerConnectionBundleBaseTest(SdpSemantics::kUnifiedPlan) {}
274};
275
Steve Anton6f25b092017-10-23 09:39:20 -0700276SdpContentMutator RemoveRtcpMux() {
277 return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800278 content->media_description()->set_rtcp_mux(false);
Steve Anton6f25b092017-10-23 09:39:20 -0700279 };
280}
281
282std::vector<int> GetCandidateComponents(
283 const std::vector<IceCandidateInterface*> candidates) {
284 std::vector<int> components;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100285 components.reserve(candidates.size());
Steve Anton6f25b092017-10-23 09:39:20 -0700286 for (auto* candidate : candidates) {
287 components.push_back(candidate->candidate().component());
288 }
289 return components;
290}
291
292// Test that there are 2 local UDP candidates (1 RTP and 1 RTCP candidate) for
293// each media section when disabling bundling and disabling RTCP multiplexing.
Steve Anton7464fca2018-01-19 11:10:37 -0800294TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700295 TwoCandidatesForEachTransportWhenNoBundleNoRtcpMux) {
296 const SocketAddress kCallerAddress("1.1.1.1", 0);
297 const SocketAddress kCalleeAddress("2.2.2.2", 0);
298
299 RTCConfiguration config;
300 config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
301 auto caller = CreatePeerConnectionWithAudioVideo(config);
302 caller->network()->AddInterface(kCallerAddress);
303 auto callee = CreatePeerConnectionWithAudioVideo(config);
304 callee->network()->AddInterface(kCalleeAddress);
305
306 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
307 RTCOfferAnswerOptions options_no_bundle;
308 options_no_bundle.use_rtp_mux = false;
309 auto answer = callee->CreateAnswer(options_no_bundle);
310 SdpContentsForEach(RemoveRtcpMux(), answer->description());
311 ASSERT_TRUE(
312 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
313 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
314
315 // Check that caller has separate RTP and RTCP candidates for each media.
316 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
317 EXPECT_THAT(
318 GetCandidateComponents(caller->observer()->GetCandidatesByMline(0)),
319 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
320 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
321 EXPECT_THAT(
322 GetCandidateComponents(caller->observer()->GetCandidatesByMline(1)),
323 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
324 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
325
326 // Check that callee has separate RTP and RTCP candidates for each media.
327 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kDefaultTimeout);
328 EXPECT_THAT(
329 GetCandidateComponents(callee->observer()->GetCandidatesByMline(0)),
330 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
331 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
332 EXPECT_THAT(
333 GetCandidateComponents(callee->observer()->GetCandidatesByMline(1)),
334 UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
335 cricket::ICE_CANDIDATE_COMPONENT_RTCP));
336}
337
338// Test that there is 1 local UDP candidate for both RTP and RTCP for each media
339// section when disabling bundle but enabling RTCP multiplexing.
Steve Anton7464fca2018-01-19 11:10:37 -0800340TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700341 OneCandidateForEachTransportWhenNoBundleButRtcpMux) {
342 const SocketAddress kCallerAddress("1.1.1.1", 0);
343
344 auto caller = CreatePeerConnectionWithAudioVideo();
345 caller->network()->AddInterface(kCallerAddress);
346 auto callee = CreatePeerConnectionWithAudioVideo();
347
348 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
349 RTCOfferAnswerOptions options_no_bundle;
350 options_no_bundle.use_rtp_mux = false;
351 ASSERT_TRUE(
352 caller->SetRemoteDescription(callee->CreateAnswer(options_no_bundle)));
353
354 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
355
356 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
357 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(1).size());
358}
359
360// Test that there is 1 local UDP candidate in only the first media section when
361// bundling and enabling RTCP multiplexing.
Steve Anton7464fca2018-01-19 11:10:37 -0800362TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700363 OneCandidateOnlyOnFirstTransportWhenBundleAndRtcpMux) {
364 const SocketAddress kCallerAddress("1.1.1.1", 0);
365
366 RTCConfiguration config;
367 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
368 auto caller = CreatePeerConnectionWithAudioVideo(config);
369 caller->network()->AddInterface(kCallerAddress);
370 auto callee = CreatePeerConnectionWithAudioVideo(config);
371
372 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
373 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
374
375 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
376
377 EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
378 EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size());
379}
380
Zhi Huange830e682018-03-30 10:48:35 -0700381// It will fail if the offerer uses the mux-BUNDLE policy but the answerer
382// doesn't support BUNDLE.
383TEST_P(PeerConnectionBundleTest, MaxBundleNotSupportedInAnswer) {
384 RTCConfiguration config;
385 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
386 auto caller = CreatePeerConnectionWithAudioVideo(config);
387 auto callee = CreatePeerConnectionWithAudioVideo();
388
389 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
390 bool equal_before =
391 (caller->voice_rtp_transport() == caller->video_rtp_transport());
392 EXPECT_EQ(true, equal_before);
393 RTCOfferAnswerOptions options;
394 options.use_rtp_mux = false;
395 EXPECT_FALSE(
396 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
397}
398
Steve Anton6f25b092017-10-23 09:39:20 -0700399// The following parameterized test verifies that an offer/answer with varying
400// bundle policies and either bundle in the answer or not will produce the
401// expected RTP transports for audio and video. In particular, for bundling we
402// care about whether they are separate transports or the same.
403
404enum class BundleIncluded { kBundleInAnswer, kBundleNotInAnswer };
405std::ostream& operator<<(std::ostream& out, BundleIncluded value) {
406 switch (value) {
407 case BundleIncluded::kBundleInAnswer:
408 return out << "bundle in answer";
409 case BundleIncluded::kBundleNotInAnswer:
410 return out << "bundle not in answer";
411 }
412 return out << "unknown";
413}
414
415class PeerConnectionBundleMatrixTest
Steve Anton7464fca2018-01-19 11:10:37 -0800416 : public PeerConnectionBundleBaseTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700417 public ::testing::WithParamInterface<
Steve Anton7464fca2018-01-19 11:10:37 -0800418 std::tuple<SdpSemantics,
419 std::tuple<BundlePolicy, BundleIncluded, bool, bool>>> {
Steve Anton6f25b092017-10-23 09:39:20 -0700420 protected:
Steve Anton7464fca2018-01-19 11:10:37 -0800421 PeerConnectionBundleMatrixTest()
422 : PeerConnectionBundleBaseTest(std::get<0>(GetParam())) {
423 auto param = std::get<1>(GetParam());
424 bundle_policy_ = std::get<0>(param);
425 bundle_included_ = std::get<1>(param);
426 expected_same_before_ = std::get<2>(param);
427 expected_same_after_ = std::get<3>(param);
Steve Anton6f25b092017-10-23 09:39:20 -0700428 }
429
430 PeerConnectionInterface::BundlePolicy bundle_policy_;
431 BundleIncluded bundle_included_;
432 bool expected_same_before_;
433 bool expected_same_after_;
434};
435
436TEST_P(PeerConnectionBundleMatrixTest,
437 VerifyTransportsBeforeAndAfterSettingRemoteAnswer) {
438 RTCConfiguration config;
439 config.bundle_policy = bundle_policy_;
440 auto caller = CreatePeerConnectionWithAudioVideo(config);
441 auto callee = CreatePeerConnectionWithAudioVideo();
442
443 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Zhi Huange830e682018-03-30 10:48:35 -0700444 bool equal_before =
445 (caller->voice_rtp_transport() == caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700446 EXPECT_EQ(expected_same_before_, equal_before);
447
448 RTCOfferAnswerOptions options;
449 options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer);
450 ASSERT_TRUE(
451 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
Zhi Huange830e682018-03-30 10:48:35 -0700452 bool equal_after =
453 (caller->voice_rtp_transport() == caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700454 EXPECT_EQ(expected_same_after_, equal_after);
455}
456
457// The max-bundle policy means we should anticipate bundling being negotiated,
458// and multiplex audio/video from the start.
459// For all other policies, bundling should only be enabled if negotiated by the
460// answer.
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100461INSTANTIATE_TEST_SUITE_P(
Steve Anton6f25b092017-10-23 09:39:20 -0700462 PeerConnectionBundleTest,
463 PeerConnectionBundleMatrixTest,
Steve Anton7464fca2018-01-19 11:10:37 -0800464 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
465 Values(std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
466 BundleIncluded::kBundleInAnswer,
467 false,
468 true),
469 std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
470 BundleIncluded::kBundleNotInAnswer,
471 false,
472 false),
473 std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
474 BundleIncluded::kBundleInAnswer,
475 true,
476 true),
Steve Anton7464fca2018-01-19 11:10:37 -0800477 std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
478 BundleIncluded::kBundleInAnswer,
479 false,
480 true),
481 std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
482 BundleIncluded::kBundleNotInAnswer,
483 false,
484 false))));
Steve Anton6f25b092017-10-23 09:39:20 -0700485
486// Test that the audio/video transports on the callee side are the same before
487// and after setting a local answer when max BUNDLE is enabled and an offer with
488// BUNDLE is received.
Steve Anton7464fca2018-01-19 11:10:37 -0800489TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700490 TransportsSameForMaxBundleWithBundleInRemoteOffer) {
491 auto caller = CreatePeerConnectionWithAudioVideo();
492 RTCConfiguration config;
493 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
494 auto callee = CreatePeerConnectionWithAudioVideo(config);
495
496 RTCOfferAnswerOptions options_with_bundle;
497 options_with_bundle.use_rtp_mux = true;
498 ASSERT_TRUE(callee->SetRemoteDescription(
499 caller->CreateOfferAndSetAsLocal(options_with_bundle)));
500
Zhi Huange830e682018-03-30 10:48:35 -0700501 EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700502
503 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
504
Zhi Huange830e682018-03-30 10:48:35 -0700505 EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700506}
507
Steve Anton7464fca2018-01-19 11:10:37 -0800508TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700509 FailToSetRemoteOfferWithNoBundleWhenBundlePolicyMaxBundle) {
510 auto caller = CreatePeerConnectionWithAudioVideo();
511 RTCConfiguration config;
512 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
513 auto callee = CreatePeerConnectionWithAudioVideo(config);
514
515 RTCOfferAnswerOptions options_no_bundle;
516 options_no_bundle.use_rtp_mux = false;
517 EXPECT_FALSE(callee->SetRemoteDescription(
518 caller->CreateOfferAndSetAsLocal(options_no_bundle)));
519}
520
521// Test that if the media section which has the bundled transport is rejected,
522// then the peers still connect and the bundled transport switches to the other
523// media section.
524// Note: This is currently failing because of the following bug:
525// https://bugs.chromium.org/p/webrtc/issues/detail?id=6280
Steve Anton7464fca2018-01-19 11:10:37 -0800526TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700527 DISABLED_SuccessfullyNegotiateMaxBundleIfBundleTransportMediaRejected) {
528 RTCConfiguration config;
529 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
530 auto caller = CreatePeerConnectionWithAudioVideo(config);
531 auto callee = CreatePeerConnection();
532 callee->AddVideoTrack("v");
533
534 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
535
536 RTCOfferAnswerOptions options;
537 options.offer_to_receive_audio = 0;
538 ASSERT_TRUE(
539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
540
Zhi Huange830e682018-03-30 10:48:35 -0700541 EXPECT_FALSE(caller->voice_rtp_transport());
542 EXPECT_TRUE(caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700543}
544
545// When requiring RTCP multiplexing, the PeerConnection never makes RTCP
546// transport channels.
Steve Anton7464fca2018-01-19 11:10:37 -0800547TEST_P(PeerConnectionBundleTest, NeverCreateRtcpTransportWithRtcpMuxRequired) {
Steve Anton6f25b092017-10-23 09:39:20 -0700548 RTCConfiguration config;
549 config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyRequire;
550 auto caller = CreatePeerConnectionWithAudioVideo(config);
551 auto callee = CreatePeerConnectionWithAudioVideo();
552
553 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
554
Zhi Huange830e682018-03-30 10:48:35 -0700555 EXPECT_FALSE(caller->voice_rtcp_transport());
556 EXPECT_FALSE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700557
558 ASSERT_TRUE(
559 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
560
Zhi Huange830e682018-03-30 10:48:35 -0700561 EXPECT_FALSE(caller->voice_rtcp_transport());
562 EXPECT_FALSE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700563}
564
Zhi Huange830e682018-03-30 10:48:35 -0700565// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transports
566// when the offer is sent, but will destroy them once the remote answer is set.
Steve Anton7464fca2018-01-19 11:10:37 -0800567TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700568 CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) {
569 RTCConfiguration config;
570 config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyNegotiate;
571 auto caller = CreatePeerConnectionWithAudioVideo(config);
572 auto callee = CreatePeerConnectionWithAudioVideo();
573
574 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
575
Zhi Huange830e682018-03-30 10:48:35 -0700576 EXPECT_TRUE(caller->voice_rtcp_transport());
577 EXPECT_TRUE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700578
579 ASSERT_TRUE(
580 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
581
Zhi Huange830e682018-03-30 10:48:35 -0700582 EXPECT_FALSE(caller->voice_rtcp_transport());
583 EXPECT_FALSE(caller->video_rtcp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700584}
585
Steve Anton7464fca2018-01-19 11:10:37 -0800586TEST_P(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) {
Steve Anton6f25b092017-10-23 09:39:20 -0700587 auto caller = CreatePeerConnectionWithAudioVideo();
588 auto callee = CreatePeerConnectionWithAudioVideo();
589
590 RTCOfferAnswerOptions options;
591 options.use_rtp_mux = true;
592
593 auto offer = caller->CreateOffer(options);
594 SdpContentsForEach(RemoveRtcpMux(), offer->description());
595
596 std::string error;
597 EXPECT_FALSE(caller->SetLocalDescription(CloneSessionDescription(offer.get()),
598 &error));
599 EXPECT_EQ(
600 "Failed to set local offer sdp: rtcp-mux must be enabled when BUNDLE is "
601 "enabled.",
602 error);
603
604 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
605 EXPECT_EQ(
606 "Failed to set remote offer sdp: rtcp-mux must be enabled when BUNDLE is "
607 "enabled.",
608 error);
609}
610
611// Test that candidates sent to the "video" transport do not get pushed down to
612// the "audio" transport channel when bundling.
Steve Anton7464fca2018-01-19 11:10:37 -0800613TEST_P(PeerConnectionBundleTest,
Steve Anton6f25b092017-10-23 09:39:20 -0700614 IgnoreCandidatesForUnusedTransportWhenBundling) {
615 const SocketAddress kAudioAddress1("1.1.1.1", 1111);
616 const SocketAddress kAudioAddress2("2.2.2.2", 2222);
617 const SocketAddress kVideoAddress("3.3.3.3", 3333);
618 const SocketAddress kCallerAddress("4.4.4.4", 0);
619 const SocketAddress kCalleeAddress("5.5.5.5", 0);
620
621 auto caller = CreatePeerConnectionWithAudioVideo();
622 auto callee = CreatePeerConnectionWithAudioVideo();
623
624 caller->network()->AddInterface(kCallerAddress);
625 callee->network()->AddInterface(kCalleeAddress);
626
627 RTCOfferAnswerOptions options;
628 options.use_rtp_mux = true;
629
630 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
631 ASSERT_TRUE(
Zhi Huange830e682018-03-30 10:48:35 -0700632 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
Steve Anton6f25b092017-10-23 09:39:20 -0700633
634 // The way the *_WAIT checks work is they only wait if the condition fails,
635 // which does not help in the case where state is not changing. This is
636 // problematic in this test since we want to verify that adding a video
637 // candidate does _not_ change state. So we interleave candidates and assume
638 // that messages are executed in the order they were posted.
639
640 cricket::Candidate audio_candidate1 = CreateLocalUdpCandidate(kAudioAddress1);
641 ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate1,
642 cricket::MEDIA_TYPE_AUDIO));
643
644 cricket::Candidate video_candidate = CreateLocalUdpCandidate(kVideoAddress);
645 ASSERT_TRUE(caller->AddIceCandidateToMedia(&video_candidate,
646 cricket::MEDIA_TYPE_VIDEO));
647
648 cricket::Candidate audio_candidate2 = CreateLocalUdpCandidate(kAudioAddress2);
649 ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate2,
650 cricket::MEDIA_TYPE_AUDIO));
651
652 EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress1),
653 kDefaultTimeout);
654 EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress2),
655 kDefaultTimeout);
656 EXPECT_FALSE(caller->HasConnectionWithRemoteAddress(kVideoAddress));
657}
658
659// Test that the transport used by both audio and video is the transport
660// associated with the first MID in the answer BUNDLE group, even if it's in a
661// different order from the offer.
Steve Anton7464fca2018-01-19 11:10:37 -0800662TEST_P(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) {
Steve Anton6f25b092017-10-23 09:39:20 -0700663 auto caller = CreatePeerConnectionWithAudioVideo();
664 auto callee = CreatePeerConnectionWithAudioVideo();
665
666 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
667
Zhi Huange830e682018-03-30 10:48:35 -0700668 auto* old_video_transport = caller->video_rtp_transport();
Steve Anton6f25b092017-10-23 09:39:20 -0700669
670 auto answer = callee->CreateAnswer();
671 auto* old_bundle_group =
672 answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
Steve Anton7464fca2018-01-19 11:10:37 -0800673 std::string first_mid = old_bundle_group->content_names()[0];
674 std::string second_mid = old_bundle_group->content_names()[1];
Steve Anton6f25b092017-10-23 09:39:20 -0700675 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
676
677 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
Steve Anton7464fca2018-01-19 11:10:37 -0800678 new_bundle_group.AddContentName(second_mid);
679 new_bundle_group.AddContentName(first_mid);
Steve Anton6f25b092017-10-23 09:39:20 -0700680 answer->description()->AddGroup(new_bundle_group);
681
682 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
683
Zhi Huange830e682018-03-30 10:48:35 -0700684 EXPECT_EQ(old_video_transport, caller->video_rtp_transport());
685 EXPECT_EQ(caller->voice_rtp_transport(), caller->video_rtp_transport());
Steve Anton6f25b092017-10-23 09:39:20 -0700686}
687
Zhi Huang365381f2018-04-13 16:44:34 -0700688// This tests that applying description with conflicted RTP demuxing criteria
689// will fail.
690TEST_P(PeerConnectionBundleTest,
691 ApplyDescriptionWithConflictedDemuxCriteriaFail) {
692 auto caller = CreatePeerConnectionWithAudioVideo();
693 auto callee = CreatePeerConnectionWithAudioVideo();
694
695 RTCOfferAnswerOptions options;
696 options.use_rtp_mux = false;
697 auto offer = caller->CreateOffer(options);
698 // Modified the SDP to make two m= sections have the same SSRC.
699 ASSERT_GE(offer->description()->contents().size(), 2U);
700 offer->description()
701 ->contents()[0]
702 .description->mutable_streams()[0]
703 .ssrcs[0] = 1111222;
704 offer->description()
705 ->contents()[1]
706 .description->mutable_streams()[0]
707 .ssrcs[0] = 1111222;
708 EXPECT_TRUE(
709 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
710 EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
711 EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal(options));
712
713 // Enable BUNDLE in subsequent offer/answer exchange and two m= sections are
714 // expectd to use one RtpTransport underneath.
715 options.use_rtp_mux = true;
716 EXPECT_TRUE(
717 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
718 auto answer = callee->CreateAnswer(options);
719 // When BUNDLE is enabled, applying the description is expected to fail
720 // because the demuxing criteria is conflicted.
721 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
722}
723
Zhi Huangd2248f82018-04-10 14:41:03 -0700724// This tests that changing the pre-negotiated BUNDLE tag is not supported.
725TEST_P(PeerConnectionBundleTest, RejectDescriptionChangingBundleTag) {
726 RTCConfiguration config;
727 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
728 auto caller = CreatePeerConnectionWithAudioVideo(config);
729 auto callee = CreatePeerConnectionWithAudioVideo(config);
730
731 RTCOfferAnswerOptions options;
732 options.use_rtp_mux = true;
733 auto offer = caller->CreateOfferAndSetAsLocal(options);
734
735 // Create a new bundle-group with different bundled_mid.
736 auto* old_bundle_group =
737 offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
738 std::string first_mid = old_bundle_group->content_names()[0];
739 std::string second_mid = old_bundle_group->content_names()[1];
740 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
741 new_bundle_group.AddContentName(second_mid);
742
743 auto re_offer = CloneSessionDescription(offer.get());
744 callee->SetRemoteDescription(std::move(offer));
745 auto answer = callee->CreateAnswer(options);
746 // Reject the first MID.
747 answer->description()->contents()[0].rejected = true;
748 // Remove the first MID from the bundle group.
749 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
750 answer->description()->AddGroup(new_bundle_group);
751 // The answer is expected to be rejected.
752 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
753
754 // Do the same thing for re-offer.
755 re_offer->description()->contents()[0].rejected = true;
756 re_offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
757 re_offer->description()->AddGroup(new_bundle_group);
758 // The re-offer is expected to be rejected.
759 EXPECT_FALSE(caller->SetLocalDescription(std::move(re_offer)));
760}
761
762// This tests that removing contents from BUNDLE group and reject the whole
763// BUNDLE group could work. This is a regression test for
764// (https://bugs.chromium.org/p/chromium/issues/detail?id=827917)
765TEST_P(PeerConnectionBundleTest, RemovingContentAndRejectBundleGroup) {
766 RTCConfiguration config;
767#ifndef HAVE_SCTP
768 config.enable_rtp_data_channel = true;
769#endif
770 config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
771 auto caller = CreatePeerConnectionWithAudioVideo(config);
772 caller->CreateDataChannel("dc");
773
774 auto offer = caller->CreateOfferAndSetAsLocal();
775 auto re_offer = CloneSessionDescription(offer.get());
776
777 // Removing the second MID from the BUNDLE group.
778 auto* old_bundle_group =
779 offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
780 std::string first_mid = old_bundle_group->content_names()[0];
781 std::string third_mid = old_bundle_group->content_names()[2];
782 cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
783 new_bundle_group.AddContentName(first_mid);
784 new_bundle_group.AddContentName(third_mid);
785
786 // Reject the entire new bundle group.
787 re_offer->description()->contents()[0].rejected = true;
788 re_offer->description()->contents()[2].rejected = true;
789 re_offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
790 re_offer->description()->AddGroup(new_bundle_group);
791
792 EXPECT_TRUE(caller->SetLocalDescription(std::move(re_offer)));
793}
794
795// This tests that the BUNDLE group in answer should be a subset of the offered
796// group.
797TEST_P(PeerConnectionBundleTest, AddContentToBundleGroupInAnswerNotSupported) {
798 auto caller = CreatePeerConnectionWithAudioVideo();
799 auto callee = CreatePeerConnectionWithAudioVideo();
800
801 auto offer = caller->CreateOffer();
802 std::string first_mid = offer->description()->contents()[0].name;
803 std::string second_mid = offer->description()->contents()[1].name;
804
805 cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
806 bundle_group.AddContentName(first_mid);
807 offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
808 offer->description()->AddGroup(bundle_group);
809 EXPECT_TRUE(
810 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
811 EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
812
813 auto answer = callee->CreateAnswer();
814 bundle_group.AddContentName(second_mid);
815 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
816 answer->description()->AddGroup(bundle_group);
817
818 // The answer is expected to be rejected because second mid is not in the
819 // offered BUNDLE group.
820 EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
821}
822
823// This tests that the BUNDLE group with non-existing MID should be rejectd.
824TEST_P(PeerConnectionBundleTest, RejectBundleGroupWithNonExistingMid) {
825 auto caller = CreatePeerConnectionWithAudioVideo();
826 auto callee = CreatePeerConnectionWithAudioVideo();
827
828 auto offer = caller->CreateOffer();
829 auto invalid_bundle_group =
830 *offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
831 invalid_bundle_group.AddContentName("non-existing-MID");
832 offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
833 offer->description()->AddGroup(invalid_bundle_group);
834
835 EXPECT_FALSE(
836 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
837 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
838}
839
840// This tests that an answer shouldn't be able to remove an m= section from an
841// established group without rejecting it.
842TEST_P(PeerConnectionBundleTest, RemoveContentFromBundleGroup) {
843 auto caller = CreatePeerConnectionWithAudioVideo();
844 auto callee = CreatePeerConnectionWithAudioVideo();
845
846 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
847 EXPECT_TRUE(
848 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
849
850 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
851 auto answer = callee->CreateAnswer();
852 std::string second_mid = answer->description()->contents()[1].name;
853
854 auto invalid_bundle_group =
855 *answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
856 invalid_bundle_group.RemoveContentName(second_mid);
857 answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
858 answer->description()->AddGroup(invalid_bundle_group);
859
860 EXPECT_FALSE(
861 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
862}
863
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100864INSTANTIATE_TEST_SUITE_P(PeerConnectionBundleTest,
865 PeerConnectionBundleTest,
866 Values(SdpSemantics::kPlanB,
867 SdpSemantics::kUnifiedPlan));
Steve Anton7464fca2018-01-19 11:10:37 -0800868
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700869// According to RFC5888, if an endpoint understands the semantics of an
870// "a=group", it MUST return an answer with that group. So, an empty BUNDLE
871// group is valid when the answerer rejects all m= sections (by stopping all
872// transceivers), meaning there's nothing to bundle.
873//
874// Only writing this test for Unified Plan mode, since there's no way to reject
875// m= sections in answers for Plan B without SDP munging.
876TEST_F(PeerConnectionBundleTestUnifiedPlan,
877 EmptyBundleGroupCreatedInAnswerWhenAppropriate) {
878 auto caller = CreatePeerConnectionWithAudioVideo();
879 auto callee = CreatePeerConnection();
880
881 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
882
883 // Stop all transceivers, causing all m= sections to be rejected.
884 for (const auto& transceiver : callee->pc()->GetTransceivers()) {
885 transceiver->Stop();
886 }
887 EXPECT_TRUE(
888 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
889
890 // Verify that the answer actually contained an empty bundle group.
891 const SessionDescriptionInterface* desc = callee->pc()->local_description();
892 ASSERT_NE(nullptr, desc);
893 const cricket::ContentGroup* bundle_group =
894 desc->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
895 ASSERT_NE(nullptr, bundle_group);
896 EXPECT_TRUE(bundle_group->content_names().empty());
897}
898
Steve Anton6f25b092017-10-23 09:39:20 -0700899} // namespace webrtc