xref: /aosp_15_r20/external/webrtc/pc/peer_connection_bundle_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
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 
11 #include <stddef.h>
12 
13 #include <cstdint>
14 #include <memory>
15 #include <ostream>
16 #include <string>
17 #include <tuple>
18 #include <type_traits>
19 #include <utility>
20 #include <vector>
21 
22 #include "api/audio/audio_mixer.h"
23 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
24 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
25 #include "api/candidate.h"
26 #include "api/create_peerconnection_factory.h"
27 #include "api/jsep.h"
28 #include "api/media_types.h"
29 #include "api/peer_connection_interface.h"
30 #include "api/rtp_receiver_interface.h"
31 #include "api/rtp_sender_interface.h"
32 #include "api/rtp_transceiver_interface.h"
33 #include "api/scoped_refptr.h"
34 #include "api/stats/rtc_stats.h"
35 #include "api/stats/rtc_stats_report.h"
36 #include "api/stats/rtcstats_objects.h"
37 #include "api/video_codecs/builtin_video_decoder_factory.h"
38 #include "api/video_codecs/builtin_video_encoder_factory.h"
39 #include "media/base/stream_params.h"
40 #include "modules/audio_device/include/audio_device.h"
41 #include "modules/audio_processing/include/audio_processing.h"
42 #include "p2p/base/p2p_constants.h"
43 #include "p2p/base/port.h"
44 #include "p2p/base/port_allocator.h"
45 #include "p2p/base/transport_info.h"
46 #include "p2p/client/basic_port_allocator.h"
47 #include "pc/channel.h"
48 #include "pc/peer_connection.h"
49 #include "pc/peer_connection_proxy.h"
50 #include "pc/peer_connection_wrapper.h"
51 #include "pc/rtp_transceiver.h"
52 #include "pc/rtp_transport_internal.h"
53 #include "pc/sdp_utils.h"
54 #include "pc/session_description.h"
55 #include "pc/test/mock_peer_connection_observers.h"
56 #include "rtc_base/checks.h"
57 #include "rtc_base/logging.h"
58 #include "rtc_base/net_helper.h"
59 #include "rtc_base/network.h"
60 #include "rtc_base/rtc_certificate_generator.h"
61 #include "rtc_base/socket_address.h"
62 #include "rtc_base/thread.h"
63 #include "test/gtest.h"
64 #ifdef WEBRTC_ANDROID
65 #include "pc/test/android_test_initializer.h"
66 #endif
67 #include "pc/test/fake_audio_capture_module.h"
68 #include "rtc_base/fake_network.h"
69 #include "rtc_base/gunit.h"
70 #include "rtc_base/virtual_socket_server.h"
71 #include "test/gmock.h"
72 
73 namespace webrtc {
74 
75 using BundlePolicy = PeerConnectionInterface::BundlePolicy;
76 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
77 using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
78 using RtcpMuxPolicy = PeerConnectionInterface::RtcpMuxPolicy;
79 using rtc::SocketAddress;
80 using ::testing::Combine;
81 using ::testing::ElementsAre;
82 using ::testing::UnorderedElementsAre;
83 using ::testing::Values;
84 
85 constexpr int kDefaultTimeout = 10000;
86 
87 // TODO(steveanton): These tests should be rewritten to use the standard
88 // RtpSenderInterface/DtlsTransportInterface objects once they're available in
89 // the API. The RtpSender can be used to determine which transport a given media
90 // will use: https://www.w3.org/TR/webrtc/#dom-rtcrtpsender-transport
91 // Should also be able to remove GetTransceiversForTesting at that point.
92 
93 class FakeNetworkManagerWithNoAnyNetwork : public rtc::FakeNetworkManager {
94  public:
GetAnyAddressNetworks()95   std::vector<const rtc::Network*> GetAnyAddressNetworks() override {
96     // This function allocates networks that are owned by the
97     // NetworkManager. But some tests assume that they can release
98     // all networks independent of the network manager.
99     // In order to prevent use-after-free issues, don't allow this
100     // function to have any effect when run in tests.
101     RTC_LOG(LS_INFO) << "FakeNetworkManager::GetAnyAddressNetworks ignored";
102     return {};
103   }
104 };
105 
106 class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
107  public:
108   using PeerConnectionWrapper::PeerConnectionWrapper;
109 
AddIceCandidateToMedia(cricket::Candidate * candidate,cricket::MediaType media_type)110   bool AddIceCandidateToMedia(cricket::Candidate* candidate,
111                               cricket::MediaType media_type) {
112     auto* desc = pc()->remote_description()->description();
113     for (size_t i = 0; i < desc->contents().size(); i++) {
114       const auto& content = desc->contents()[i];
115       if (content.media_description()->type() == media_type) {
116         candidate->set_transport_name(content.name);
117         std::unique_ptr<IceCandidateInterface> jsep_candidate =
118             CreateIceCandidate(content.name, i, *candidate);
119         return pc()->AddIceCandidate(jsep_candidate.get());
120       }
121     }
122     RTC_DCHECK_NOTREACHED();
123     return false;
124   }
125 
voice_rtp_transport()126   RtpTransportInternal* voice_rtp_transport() {
127     return (voice_channel() ? voice_channel()->rtp_transport() : nullptr);
128   }
129 
voice_channel()130   cricket::VoiceChannel* voice_channel() {
131     auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
132     for (const auto& transceiver : transceivers) {
133       if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
134         return static_cast<cricket::VoiceChannel*>(
135             transceiver->internal()->channel());
136       }
137     }
138     return nullptr;
139   }
140 
video_rtp_transport()141   RtpTransportInternal* video_rtp_transport() {
142     return (video_channel() ? video_channel()->rtp_transport() : nullptr);
143   }
144 
video_channel()145   cricket::VideoChannel* video_channel() {
146     auto transceivers = GetInternalPeerConnection()->GetTransceiversInternal();
147     for (const auto& transceiver : transceivers) {
148       if (transceiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
149         return static_cast<cricket::VideoChannel*>(
150             transceiver->internal()->channel());
151       }
152     }
153     return nullptr;
154   }
155 
GetInternalPeerConnection()156   PeerConnection* GetInternalPeerConnection() {
157     auto* pci =
158         static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
159             pc());
160     return static_cast<PeerConnection*>(pci->internal());
161   }
162 
163   // Returns true if the stats indicate that an ICE connection is either in
164   // progress or established with the given remote address.
HasConnectionWithRemoteAddress(const SocketAddress & address)165   bool HasConnectionWithRemoteAddress(const SocketAddress& address) {
166     auto report = GetStats();
167     if (!report) {
168       return false;
169     }
170     std::string matching_candidate_id;
171     for (auto* ice_candidate_stats :
172          report->GetStatsOfType<RTCRemoteIceCandidateStats>()) {
173       if (*ice_candidate_stats->ip == address.HostAsURIString() &&
174           *ice_candidate_stats->port == address.port()) {
175         matching_candidate_id = ice_candidate_stats->id();
176         break;
177       }
178     }
179     if (matching_candidate_id.empty()) {
180       return false;
181     }
182     for (auto* pair_stats :
183          report->GetStatsOfType<RTCIceCandidatePairStats>()) {
184       if (*pair_stats->remote_candidate_id == matching_candidate_id) {
185         if (*pair_stats->state == RTCStatsIceCandidatePairState::kInProgress ||
186             *pair_stats->state == RTCStatsIceCandidatePairState::kSucceeded) {
187           return true;
188         }
189       }
190     }
191     return false;
192   }
193 
network()194   rtc::FakeNetworkManager* network() { return network_; }
195 
set_network(rtc::FakeNetworkManager * network)196   void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
197 
198  private:
199   rtc::FakeNetworkManager* network_;
200 };
201 
202 class PeerConnectionBundleBaseTest : public ::testing::Test {
203  protected:
204   typedef std::unique_ptr<PeerConnectionWrapperForBundleTest> WrapperPtr;
205 
PeerConnectionBundleBaseTest(SdpSemantics sdp_semantics)206   explicit PeerConnectionBundleBaseTest(SdpSemantics sdp_semantics)
207       : vss_(new rtc::VirtualSocketServer()),
208         main_(vss_.get()),
209         sdp_semantics_(sdp_semantics) {
210 #ifdef WEBRTC_ANDROID
211     InitializeAndroidObjects();
212 #endif
213     pc_factory_ = CreatePeerConnectionFactory(
214         rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
215         rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
216         CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
217         CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
218         nullptr /* audio_mixer */, nullptr /* audio_processing */);
219   }
220 
CreatePeerConnection()221   WrapperPtr CreatePeerConnection() {
222     return CreatePeerConnection(RTCConfiguration());
223   }
224 
CreatePeerConnection(const RTCConfiguration & config)225   WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
226     auto* fake_network = NewFakeNetwork();
227     auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
228         fake_network,
229         std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
230     port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
231                               cricket::PORTALLOCATOR_DISABLE_RELAY);
232     port_allocator->set_step_delay(cricket::kMinimumStepDelay);
233     auto observer = std::make_unique<MockPeerConnectionObserver>();
234     RTCConfiguration modified_config = config;
235     modified_config.sdp_semantics = sdp_semantics_;
236     PeerConnectionDependencies pc_dependencies(observer.get());
237     pc_dependencies.allocator = std::move(port_allocator);
238     auto result = pc_factory_->CreatePeerConnectionOrError(
239         modified_config, std::move(pc_dependencies));
240     if (!result.ok()) {
241       return nullptr;
242     }
243 
244     auto wrapper = std::make_unique<PeerConnectionWrapperForBundleTest>(
245         pc_factory_, result.MoveValue(), std::move(observer));
246     wrapper->set_network(fake_network);
247     return wrapper;
248   }
249 
250   // Accepts the same arguments as CreatePeerConnection and adds default audio
251   // and video tracks.
252   template <typename... Args>
CreatePeerConnectionWithAudioVideo(Args &&...args)253   WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
254     auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
255     if (!wrapper) {
256       return nullptr;
257     }
258     wrapper->AddAudioTrack("a");
259     wrapper->AddVideoTrack("v");
260     return wrapper;
261   }
262 
CreateLocalUdpCandidate(const rtc::SocketAddress & address)263   cricket::Candidate CreateLocalUdpCandidate(
264       const rtc::SocketAddress& address) {
265     cricket::Candidate candidate;
266     candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
267     candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
268     candidate.set_address(address);
269     candidate.set_type(cricket::LOCAL_PORT_TYPE);
270     return candidate;
271   }
272 
NewFakeNetwork()273   rtc::FakeNetworkManager* NewFakeNetwork() {
274     // The PeerConnection's port allocator is tied to the PeerConnection's
275     // lifetime and expects the underlying NetworkManager to outlive it. If
276     // PeerConnectionWrapper owned the NetworkManager, it would be destroyed
277     // before the PeerConnection (since subclass members are destroyed before
278     // base class members). Therefore, the test fixture will own all the fake
279     // networks even though tests should access the fake network through the
280     // PeerConnectionWrapper.
281     auto* fake_network = new FakeNetworkManagerWithNoAnyNetwork();
282     fake_networks_.emplace_back(fake_network);
283     return fake_network;
284   }
285 
286   std::unique_ptr<rtc::VirtualSocketServer> vss_;
287   rtc::AutoSocketServerThread main_;
288   rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
289   std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
290   const SdpSemantics sdp_semantics_;
291 };
292 
293 class PeerConnectionBundleTest
294     : public PeerConnectionBundleBaseTest,
295       public ::testing::WithParamInterface<SdpSemantics> {
296  protected:
PeerConnectionBundleTest()297   PeerConnectionBundleTest() : PeerConnectionBundleBaseTest(GetParam()) {}
298 };
299 
300 class PeerConnectionBundleTestUnifiedPlan
301     : public PeerConnectionBundleBaseTest {
302  protected:
PeerConnectionBundleTestUnifiedPlan()303   PeerConnectionBundleTestUnifiedPlan()
304       : PeerConnectionBundleBaseTest(SdpSemantics::kUnifiedPlan) {}
305 };
306 
RemoveRtcpMux()307 SdpContentMutator RemoveRtcpMux() {
308   return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
309     content->media_description()->set_rtcp_mux(false);
310   };
311 }
312 
GetCandidateComponents(const std::vector<IceCandidateInterface * > candidates)313 std::vector<int> GetCandidateComponents(
314     const std::vector<IceCandidateInterface*> candidates) {
315   std::vector<int> components;
316   components.reserve(candidates.size());
317   for (auto* candidate : candidates) {
318     components.push_back(candidate->candidate().component());
319   }
320   return components;
321 }
322 
323 // Test that there are 2 local UDP candidates (1 RTP and 1 RTCP candidate) for
324 // each media section when disabling bundling and disabling RTCP multiplexing.
TEST_P(PeerConnectionBundleTest,TwoCandidatesForEachTransportWhenNoBundleNoRtcpMux)325 TEST_P(PeerConnectionBundleTest,
326        TwoCandidatesForEachTransportWhenNoBundleNoRtcpMux) {
327   const SocketAddress kCallerAddress("1.1.1.1", 0);
328   const SocketAddress kCalleeAddress("2.2.2.2", 0);
329 
330   RTCConfiguration config;
331   config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
332   auto caller = CreatePeerConnectionWithAudioVideo(config);
333   caller->network()->AddInterface(kCallerAddress);
334   auto callee = CreatePeerConnectionWithAudioVideo(config);
335   callee->network()->AddInterface(kCalleeAddress);
336 
337   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
338   RTCOfferAnswerOptions options_no_bundle;
339   options_no_bundle.use_rtp_mux = false;
340   auto answer = callee->CreateAnswer(options_no_bundle);
341   SdpContentsForEach(RemoveRtcpMux(), answer->description());
342   ASSERT_TRUE(
343       callee->SetLocalDescription(CloneSessionDescription(answer.get())));
344   ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
345 
346   // Check that caller has separate RTP and RTCP candidates for each media.
347   EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
348   EXPECT_THAT(
349       GetCandidateComponents(caller->observer()->GetCandidatesByMline(0)),
350       UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
351                            cricket::ICE_CANDIDATE_COMPONENT_RTCP));
352   EXPECT_THAT(
353       GetCandidateComponents(caller->observer()->GetCandidatesByMline(1)),
354       UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
355                            cricket::ICE_CANDIDATE_COMPONENT_RTCP));
356 
357   // Check that callee has separate RTP and RTCP candidates for each media.
358   EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kDefaultTimeout);
359   EXPECT_THAT(
360       GetCandidateComponents(callee->observer()->GetCandidatesByMline(0)),
361       UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
362                            cricket::ICE_CANDIDATE_COMPONENT_RTCP));
363   EXPECT_THAT(
364       GetCandidateComponents(callee->observer()->GetCandidatesByMline(1)),
365       UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
366                            cricket::ICE_CANDIDATE_COMPONENT_RTCP));
367 }
368 
369 // Test that there is 1 local UDP candidate for both RTP and RTCP for each media
370 // section when disabling bundle but enabling RTCP multiplexing.
TEST_P(PeerConnectionBundleTest,OneCandidateForEachTransportWhenNoBundleButRtcpMux)371 TEST_P(PeerConnectionBundleTest,
372        OneCandidateForEachTransportWhenNoBundleButRtcpMux) {
373   const SocketAddress kCallerAddress("1.1.1.1", 0);
374 
375   auto caller = CreatePeerConnectionWithAudioVideo();
376   caller->network()->AddInterface(kCallerAddress);
377   auto callee = CreatePeerConnectionWithAudioVideo();
378 
379   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
380   RTCOfferAnswerOptions options_no_bundle;
381   options_no_bundle.use_rtp_mux = false;
382   ASSERT_TRUE(
383       caller->SetRemoteDescription(callee->CreateAnswer(options_no_bundle)));
384 
385   EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
386 
387   EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
388   EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(1).size());
389 }
390 
391 // Test that there is 1 local UDP candidate in only the first media section when
392 // bundling and enabling RTCP multiplexing.
TEST_P(PeerConnectionBundleTest,OneCandidateOnlyOnFirstTransportWhenBundleAndRtcpMux)393 TEST_P(PeerConnectionBundleTest,
394        OneCandidateOnlyOnFirstTransportWhenBundleAndRtcpMux) {
395   const SocketAddress kCallerAddress("1.1.1.1", 0);
396 
397   RTCConfiguration config;
398   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
399   auto caller = CreatePeerConnectionWithAudioVideo(config);
400   caller->network()->AddInterface(kCallerAddress);
401   auto callee = CreatePeerConnectionWithAudioVideo(config);
402 
403   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
404   ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
405 
406   EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
407 
408   EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
409   EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size());
410 }
411 
412 // It will fail if the offerer uses the mux-BUNDLE policy but the answerer
413 // doesn't support BUNDLE.
TEST_P(PeerConnectionBundleTest,MaxBundleNotSupportedInAnswer)414 TEST_P(PeerConnectionBundleTest, MaxBundleNotSupportedInAnswer) {
415   RTCConfiguration config;
416   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
417   auto caller = CreatePeerConnectionWithAudioVideo(config);
418   auto callee = CreatePeerConnectionWithAudioVideo();
419 
420   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
421   bool equal_before =
422       (caller->voice_rtp_transport() == caller->video_rtp_transport());
423   EXPECT_EQ(true, equal_before);
424   RTCOfferAnswerOptions options;
425   options.use_rtp_mux = false;
426   EXPECT_FALSE(
427       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
428 }
429 
430 // The following parameterized test verifies that an offer/answer with varying
431 // bundle policies and either bundle in the answer or not will produce the
432 // expected RTP transports for audio and video. In particular, for bundling we
433 // care about whether they are separate transports or the same.
434 
435 enum class BundleIncluded { kBundleInAnswer, kBundleNotInAnswer };
operator <<(std::ostream & out,BundleIncluded value)436 std::ostream& operator<<(std::ostream& out, BundleIncluded value) {
437   switch (value) {
438     case BundleIncluded::kBundleInAnswer:
439       return out << "bundle in answer";
440     case BundleIncluded::kBundleNotInAnswer:
441       return out << "bundle not in answer";
442   }
443   return out << "unknown";
444 }
445 
446 class PeerConnectionBundleMatrixTest
447     : public PeerConnectionBundleBaseTest,
448       public ::testing::WithParamInterface<
449           std::tuple<SdpSemantics,
450                      std::tuple<BundlePolicy, BundleIncluded, bool, bool>>> {
451  protected:
PeerConnectionBundleMatrixTest()452   PeerConnectionBundleMatrixTest()
453       : PeerConnectionBundleBaseTest(std::get<0>(GetParam())) {
454     auto param = std::get<1>(GetParam());
455     bundle_policy_ = std::get<0>(param);
456     bundle_included_ = std::get<1>(param);
457     expected_same_before_ = std::get<2>(param);
458     expected_same_after_ = std::get<3>(param);
459   }
460 
461   PeerConnectionInterface::BundlePolicy bundle_policy_;
462   BundleIncluded bundle_included_;
463   bool expected_same_before_;
464   bool expected_same_after_;
465 };
466 
TEST_P(PeerConnectionBundleMatrixTest,VerifyTransportsBeforeAndAfterSettingRemoteAnswer)467 TEST_P(PeerConnectionBundleMatrixTest,
468        VerifyTransportsBeforeAndAfterSettingRemoteAnswer) {
469   RTCConfiguration config;
470   config.bundle_policy = bundle_policy_;
471   auto caller = CreatePeerConnectionWithAudioVideo(config);
472   auto callee = CreatePeerConnectionWithAudioVideo();
473 
474   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
475   bool equal_before =
476       (caller->voice_rtp_transport() == caller->video_rtp_transport());
477   EXPECT_EQ(expected_same_before_, equal_before);
478 
479   RTCOfferAnswerOptions options;
480   options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer);
481   ASSERT_TRUE(
482       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
483   bool equal_after =
484       (caller->voice_rtp_transport() == caller->video_rtp_transport());
485   EXPECT_EQ(expected_same_after_, equal_after);
486 }
487 
488 // The max-bundle policy means we should anticipate bundling being negotiated,
489 // and multiplex audio/video from the start.
490 // For all other policies, bundling should only be enabled if negotiated by the
491 // answer.
492 INSTANTIATE_TEST_SUITE_P(
493     PeerConnectionBundleTest,
494     PeerConnectionBundleMatrixTest,
495     Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
496             Values(std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
497                                    BundleIncluded::kBundleInAnswer,
498                                    false,
499                                    true),
500                    std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
501                                    BundleIncluded::kBundleNotInAnswer,
502                                    false,
503                                    false),
504                    std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
505                                    BundleIncluded::kBundleInAnswer,
506                                    true,
507                                    true),
508                    std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
509                                    BundleIncluded::kBundleInAnswer,
510                                    false,
511                                    true),
512                    std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
513                                    BundleIncluded::kBundleNotInAnswer,
514                                    false,
515                                    false))));
516 
517 // Test that the audio/video transports on the callee side are the same before
518 // and after setting a local answer when max BUNDLE is enabled and an offer with
519 // BUNDLE is received.
TEST_P(PeerConnectionBundleTest,TransportsSameForMaxBundleWithBundleInRemoteOffer)520 TEST_P(PeerConnectionBundleTest,
521        TransportsSameForMaxBundleWithBundleInRemoteOffer) {
522   auto caller = CreatePeerConnectionWithAudioVideo();
523   RTCConfiguration config;
524   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
525   auto callee = CreatePeerConnectionWithAudioVideo(config);
526 
527   RTCOfferAnswerOptions options_with_bundle;
528   options_with_bundle.use_rtp_mux = true;
529   ASSERT_TRUE(callee->SetRemoteDescription(
530       caller->CreateOfferAndSetAsLocal(options_with_bundle)));
531 
532   EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
533 
534   ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
535 
536   EXPECT_EQ(callee->voice_rtp_transport(), callee->video_rtp_transport());
537 }
538 
TEST_P(PeerConnectionBundleTest,FailToSetRemoteOfferWithNoBundleWhenBundlePolicyMaxBundle)539 TEST_P(PeerConnectionBundleTest,
540        FailToSetRemoteOfferWithNoBundleWhenBundlePolicyMaxBundle) {
541   auto caller = CreatePeerConnectionWithAudioVideo();
542   RTCConfiguration config;
543   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
544   auto callee = CreatePeerConnectionWithAudioVideo(config);
545 
546   RTCOfferAnswerOptions options_no_bundle;
547   options_no_bundle.use_rtp_mux = false;
548   EXPECT_FALSE(callee->SetRemoteDescription(
549       caller->CreateOfferAndSetAsLocal(options_no_bundle)));
550 }
551 
552 // Test that if the media section which has the bundled transport is rejected,
553 // then the peers still connect and the bundled transport switches to the other
554 // media section.
555 // Note: This is currently failing because of the following bug:
556 // https://bugs.chromium.org/p/webrtc/issues/detail?id=6280
TEST_P(PeerConnectionBundleTest,DISABLED_SuccessfullyNegotiateMaxBundleIfBundleTransportMediaRejected)557 TEST_P(PeerConnectionBundleTest,
558        DISABLED_SuccessfullyNegotiateMaxBundleIfBundleTransportMediaRejected) {
559   RTCConfiguration config;
560   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
561   auto caller = CreatePeerConnectionWithAudioVideo(config);
562   auto callee = CreatePeerConnection();
563   callee->AddVideoTrack("v");
564 
565   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
566 
567   RTCOfferAnswerOptions options;
568   options.offer_to_receive_audio = 0;
569   ASSERT_TRUE(
570       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
571 
572   EXPECT_FALSE(caller->voice_rtp_transport());
573   EXPECT_TRUE(caller->video_rtp_transport());
574 }
575 
576 // When requiring RTCP multiplexing, the PeerConnection never makes RTCP
577 // transport channels.
TEST_P(PeerConnectionBundleTest,NeverCreateRtcpTransportWithRtcpMuxRequired)578 TEST_P(PeerConnectionBundleTest, NeverCreateRtcpTransportWithRtcpMuxRequired) {
579   RTCConfiguration config;
580   config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyRequire;
581   auto caller = CreatePeerConnectionWithAudioVideo(config);
582   auto callee = CreatePeerConnectionWithAudioVideo();
583 
584   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
585 
586   EXPECT_FALSE(caller->voice_rtp_transport()->rtcp_mux_enabled());
587   EXPECT_FALSE(caller->video_rtp_transport()->rtcp_mux_enabled());
588 
589   ASSERT_TRUE(
590       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
591 
592   EXPECT_TRUE(caller->voice_rtp_transport()->rtcp_mux_enabled());
593   EXPECT_TRUE(caller->video_rtp_transport()->rtcp_mux_enabled());
594 }
595 
596 // When negotiating RTCP multiplexing, the PeerConnection makes RTCP transports
597 // when the offer is sent, but will destroy them once the remote answer is set.
TEST_P(PeerConnectionBundleTest,CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate)598 TEST_P(PeerConnectionBundleTest,
599        CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) {
600   RTCConfiguration config;
601   config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyNegotiate;
602   auto caller = CreatePeerConnectionWithAudioVideo(config);
603   auto callee = CreatePeerConnectionWithAudioVideo();
604 
605   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
606 
607   EXPECT_FALSE(caller->voice_rtp_transport()->rtcp_mux_enabled());
608   EXPECT_FALSE(caller->video_rtp_transport()->rtcp_mux_enabled());
609 
610   ASSERT_TRUE(
611       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
612 
613   EXPECT_TRUE(caller->voice_rtp_transport()->rtcp_mux_enabled());
614   EXPECT_TRUE(caller->video_rtp_transport()->rtcp_mux_enabled());
615 }
616 
TEST_P(PeerConnectionBundleTest,FailToSetDescriptionWithBundleAndNoRtcpMux)617 TEST_P(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) {
618   auto caller = CreatePeerConnectionWithAudioVideo();
619   auto callee = CreatePeerConnectionWithAudioVideo();
620 
621   RTCOfferAnswerOptions options;
622   options.use_rtp_mux = true;
623 
624   auto offer = caller->CreateOffer(options);
625   SdpContentsForEach(RemoveRtcpMux(), offer->description());
626 
627   std::string error;
628   EXPECT_FALSE(caller->SetLocalDescription(CloneSessionDescription(offer.get()),
629                                            &error));
630   EXPECT_EQ(
631       "Failed to set local offer sdp: rtcp-mux must be enabled when BUNDLE is "
632       "enabled.",
633       error);
634 
635   EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
636   EXPECT_EQ(
637       "Failed to set remote offer sdp: rtcp-mux must be enabled when BUNDLE is "
638       "enabled.",
639       error);
640 }
641 
642 // Test that candidates sent to the "video" transport do not get pushed down to
643 // the "audio" transport channel when bundling.
TEST_P(PeerConnectionBundleTest,IgnoreCandidatesForUnusedTransportWhenBundling)644 TEST_P(PeerConnectionBundleTest,
645        IgnoreCandidatesForUnusedTransportWhenBundling) {
646   const SocketAddress kAudioAddress1("1.1.1.1", 1111);
647   const SocketAddress kAudioAddress2("2.2.2.2", 2222);
648   const SocketAddress kVideoAddress("3.3.3.3", 3333);
649   const SocketAddress kCallerAddress("4.4.4.4", 0);
650   const SocketAddress kCalleeAddress("5.5.5.5", 0);
651 
652   auto caller = CreatePeerConnectionWithAudioVideo();
653   auto callee = CreatePeerConnectionWithAudioVideo();
654 
655   caller->network()->AddInterface(kCallerAddress);
656   callee->network()->AddInterface(kCalleeAddress);
657 
658   RTCOfferAnswerOptions options;
659   options.use_rtp_mux = true;
660 
661   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
662   ASSERT_TRUE(
663       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
664 
665   // The way the *_WAIT checks work is they only wait if the condition fails,
666   // which does not help in the case where state is not changing. This is
667   // problematic in this test since we want to verify that adding a video
668   // candidate does _not_ change state. So we interleave candidates and assume
669   // that messages are executed in the order they were posted.
670 
671   cricket::Candidate audio_candidate1 = CreateLocalUdpCandidate(kAudioAddress1);
672   ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate1,
673                                              cricket::MEDIA_TYPE_AUDIO));
674 
675   cricket::Candidate video_candidate = CreateLocalUdpCandidate(kVideoAddress);
676   ASSERT_TRUE(caller->AddIceCandidateToMedia(&video_candidate,
677                                              cricket::MEDIA_TYPE_VIDEO));
678 
679   cricket::Candidate audio_candidate2 = CreateLocalUdpCandidate(kAudioAddress2);
680   ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate2,
681                                              cricket::MEDIA_TYPE_AUDIO));
682 
683   EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress1),
684                    kDefaultTimeout);
685   EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress2),
686                    kDefaultTimeout);
687   EXPECT_FALSE(caller->HasConnectionWithRemoteAddress(kVideoAddress));
688 }
689 
690 // Test that the transport used by both audio and video is the transport
691 // associated with the first MID in the answer BUNDLE group, even if it's in a
692 // different order from the offer.
TEST_P(PeerConnectionBundleTest,BundleOnFirstMidInAnswer)693 TEST_P(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) {
694   auto caller = CreatePeerConnectionWithAudioVideo();
695   auto callee = CreatePeerConnectionWithAudioVideo();
696 
697   ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
698 
699   auto* old_video_transport = caller->video_rtp_transport();
700 
701   auto answer = callee->CreateAnswer();
702   auto* old_bundle_group =
703       answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
704   std::string first_mid = old_bundle_group->content_names()[0];
705   std::string second_mid = old_bundle_group->content_names()[1];
706   answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
707 
708   cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
709   new_bundle_group.AddContentName(second_mid);
710   new_bundle_group.AddContentName(first_mid);
711   answer->description()->AddGroup(new_bundle_group);
712 
713   ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
714 
715   EXPECT_EQ(old_video_transport, caller->video_rtp_transport());
716   EXPECT_EQ(caller->voice_rtp_transport(), caller->video_rtp_transport());
717 }
718 
719 // This tests that applying description with conflicted RTP demuxing criteria
720 // will fail.
TEST_P(PeerConnectionBundleTest,ApplyDescriptionWithConflictedDemuxCriteriaFail)721 TEST_P(PeerConnectionBundleTest,
722        ApplyDescriptionWithConflictedDemuxCriteriaFail) {
723   auto caller = CreatePeerConnectionWithAudioVideo();
724   auto callee = CreatePeerConnectionWithAudioVideo();
725 
726   RTCOfferAnswerOptions options;
727   options.use_rtp_mux = false;
728   auto offer = caller->CreateOffer(options);
729   // Modified the SDP to make two m= sections have the same SSRC.
730   ASSERT_GE(offer->description()->contents().size(), 2U);
731   offer->description()
732       ->contents()[0]
733       .media_description()
734       ->mutable_streams()[0]
735       .ssrcs[0] = 1111222;
736   offer->description()
737       ->contents()[1]
738       .media_description()
739       ->mutable_streams()[0]
740       .ssrcs[0] = 1111222;
741   EXPECT_TRUE(
742       caller->SetLocalDescription(CloneSessionDescription(offer.get())));
743   EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
744   EXPECT_TRUE(callee->CreateAnswerAndSetAsLocal(options));
745 
746   // Enable BUNDLE in subsequent offer/answer exchange and two m= sections are
747   // expectd to use one RtpTransport underneath.
748   options.use_rtp_mux = true;
749   EXPECT_TRUE(
750       callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
751   auto answer = callee->CreateAnswer(options);
752   // When BUNDLE is enabled, applying the description is expected to fail
753   // because the demuxing criteria is conflicted.
754   EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
755 }
756 
757 // This tests that changing the pre-negotiated BUNDLE tag is not supported.
TEST_P(PeerConnectionBundleTest,RejectDescriptionChangingBundleTag)758 TEST_P(PeerConnectionBundleTest, RejectDescriptionChangingBundleTag) {
759   RTCConfiguration config;
760   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
761   auto caller = CreatePeerConnectionWithAudioVideo(config);
762   auto callee = CreatePeerConnectionWithAudioVideo(config);
763 
764   RTCOfferAnswerOptions options;
765   options.use_rtp_mux = true;
766   auto offer = caller->CreateOfferAndSetAsLocal(options);
767 
768   // Create a new bundle-group with different bundled_mid.
769   auto* old_bundle_group =
770       offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
771   std::string first_mid = old_bundle_group->content_names()[0];
772   std::string second_mid = old_bundle_group->content_names()[1];
773   cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
774   new_bundle_group.AddContentName(second_mid);
775 
776   auto re_offer = CloneSessionDescription(offer.get());
777   callee->SetRemoteDescription(std::move(offer));
778   auto answer = callee->CreateAnswer(options);
779   // Reject the first MID.
780   answer->description()->contents()[0].rejected = true;
781   // Remove the first MID from the bundle group.
782   answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
783   answer->description()->AddGroup(new_bundle_group);
784   // The answer is expected to be rejected.
785   EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
786 
787   // Do the same thing for re-offer.
788   re_offer->description()->contents()[0].rejected = true;
789   re_offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
790   re_offer->description()->AddGroup(new_bundle_group);
791   // The re-offer is expected to be rejected.
792   EXPECT_FALSE(caller->SetLocalDescription(std::move(re_offer)));
793 }
794 
795 // This tests that removing contents from BUNDLE group and reject the whole
796 // BUNDLE group could work. This is a regression test for
797 // (https://bugs.chromium.org/p/chromium/issues/detail?id=827917)
798 #ifdef HAVE_SCTP
TEST_P(PeerConnectionBundleTest,RemovingContentAndRejectBundleGroup)799 TEST_P(PeerConnectionBundleTest, RemovingContentAndRejectBundleGroup) {
800   RTCConfiguration config;
801   config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
802   auto caller = CreatePeerConnectionWithAudioVideo(config);
803   caller->CreateDataChannel("dc");
804 
805   auto offer = caller->CreateOfferAndSetAsLocal();
806   auto re_offer = CloneSessionDescription(offer.get());
807 
808   // Removing the second MID from the BUNDLE group.
809   auto* old_bundle_group =
810       offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
811   std::string first_mid = old_bundle_group->content_names()[0];
812   std::string third_mid = old_bundle_group->content_names()[2];
813   cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
814   new_bundle_group.AddContentName(first_mid);
815   new_bundle_group.AddContentName(third_mid);
816 
817   // Reject the entire new bundle group.
818   re_offer->description()->contents()[0].rejected = true;
819   re_offer->description()->contents()[2].rejected = true;
820   re_offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
821   re_offer->description()->AddGroup(new_bundle_group);
822 
823   EXPECT_TRUE(caller->SetLocalDescription(std::move(re_offer)));
824 }
825 #endif
826 
827 // This tests that the BUNDLE group in answer should be a subset of the offered
828 // group.
TEST_P(PeerConnectionBundleTest,AddContentToBundleGroupInAnswerNotSupported)829 TEST_P(PeerConnectionBundleTest, AddContentToBundleGroupInAnswerNotSupported) {
830   auto caller = CreatePeerConnectionWithAudioVideo();
831   auto callee = CreatePeerConnectionWithAudioVideo();
832 
833   auto offer = caller->CreateOffer();
834   std::string first_mid = offer->description()->contents()[0].name;
835   std::string second_mid = offer->description()->contents()[1].name;
836 
837   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
838   bundle_group.AddContentName(first_mid);
839   offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
840   offer->description()->AddGroup(bundle_group);
841   EXPECT_TRUE(
842       caller->SetLocalDescription(CloneSessionDescription(offer.get())));
843   EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
844 
845   auto answer = callee->CreateAnswer();
846   bundle_group.AddContentName(second_mid);
847   answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
848   answer->description()->AddGroup(bundle_group);
849 
850   // The answer is expected to be rejected because second mid is not in the
851   // offered BUNDLE group.
852   EXPECT_FALSE(callee->SetLocalDescription(std::move(answer)));
853 }
854 
855 // This tests that the BUNDLE group with non-existing MID should be rejectd.
TEST_P(PeerConnectionBundleTest,RejectBundleGroupWithNonExistingMid)856 TEST_P(PeerConnectionBundleTest, RejectBundleGroupWithNonExistingMid) {
857   auto caller = CreatePeerConnectionWithAudioVideo();
858   auto callee = CreatePeerConnectionWithAudioVideo();
859 
860   auto offer = caller->CreateOffer();
861   auto invalid_bundle_group =
862       *offer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
863   invalid_bundle_group.AddContentName("non-existing-MID");
864   offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
865   offer->description()->AddGroup(invalid_bundle_group);
866 
867   EXPECT_FALSE(
868       caller->SetLocalDescription(CloneSessionDescription(offer.get())));
869   EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
870 }
871 
872 // This tests that an answer shouldn't be able to remove an m= section from an
873 // established group without rejecting it.
TEST_P(PeerConnectionBundleTest,RemoveContentFromBundleGroup)874 TEST_P(PeerConnectionBundleTest, RemoveContentFromBundleGroup) {
875   auto caller = CreatePeerConnectionWithAudioVideo();
876   auto callee = CreatePeerConnectionWithAudioVideo();
877 
878   EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
879   EXPECT_TRUE(
880       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
881 
882   EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
883   auto answer = callee->CreateAnswer();
884   std::string second_mid = answer->description()->contents()[1].name;
885 
886   auto invalid_bundle_group =
887       *answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
888   invalid_bundle_group.RemoveContentName(second_mid);
889   answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
890   answer->description()->AddGroup(invalid_bundle_group);
891 
892   EXPECT_FALSE(
893       callee->SetLocalDescription(CloneSessionDescription(answer.get())));
894 }
895 
896 INSTANTIATE_TEST_SUITE_P(PeerConnectionBundleTest,
897                          PeerConnectionBundleTest,
898                          Values(SdpSemantics::kPlanB_DEPRECATED,
899                                 SdpSemantics::kUnifiedPlan));
900 
901 // According to RFC5888, if an endpoint understands the semantics of an
902 // "a=group", it MUST return an answer with that group. So, an empty BUNDLE
903 // group is valid when the answerer rejects all m= sections (by stopping all
904 // transceivers), meaning there's nothing to bundle.
905 //
906 // Only writing this test for Unified Plan mode, since there's no way to reject
907 // m= sections in answers for Plan B without SDP munging.
TEST_F(PeerConnectionBundleTestUnifiedPlan,EmptyBundleGroupCreatedInAnswerWhenAppropriate)908 TEST_F(PeerConnectionBundleTestUnifiedPlan,
909        EmptyBundleGroupCreatedInAnswerWhenAppropriate) {
910   auto caller = CreatePeerConnectionWithAudioVideo();
911   auto callee = CreatePeerConnection();
912 
913   EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
914 
915   // Stop all transceivers, causing all m= sections to be rejected.
916   for (const auto& transceiver : callee->pc()->GetTransceivers()) {
917     transceiver->StopInternal();
918   }
919   EXPECT_TRUE(
920       caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
921 
922   // Verify that the answer actually contained an empty bundle group.
923   const SessionDescriptionInterface* desc = callee->pc()->local_description();
924   ASSERT_NE(nullptr, desc);
925   const cricket::ContentGroup* bundle_group =
926       desc->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
927   ASSERT_NE(nullptr, bundle_group);
928   EXPECT_TRUE(bundle_group->content_names().empty());
929 }
930 
TEST_F(PeerConnectionBundleTestUnifiedPlan,MultipleBundleGroups)931 TEST_F(PeerConnectionBundleTestUnifiedPlan, MultipleBundleGroups) {
932   auto caller = CreatePeerConnection();
933   caller->AddAudioTrack("0_audio");
934   caller->AddAudioTrack("1_audio");
935   caller->AddVideoTrack("2_audio");
936   caller->AddVideoTrack("3_audio");
937   auto callee = CreatePeerConnection();
938 
939   auto offer = caller->CreateOffer(RTCOfferAnswerOptions());
940   // Modify the GROUP to have two BUNDLEs. We know that the MIDs will be 0,1,2,4
941   // because our implementation has predictable MIDs.
942   offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
943   cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
944   bundle_group1.AddContentName("0");
945   bundle_group1.AddContentName("1");
946   cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
947   bundle_group2.AddContentName("2");
948   bundle_group2.AddContentName("3");
949   offer->description()->AddGroup(bundle_group1);
950   offer->description()->AddGroup(bundle_group2);
951 
952   EXPECT_TRUE(
953       caller->SetLocalDescription(CloneSessionDescription(offer.get())));
954   EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
955   auto answer = callee->CreateAnswer();
956   EXPECT_TRUE(
957       callee->SetLocalDescription(CloneSessionDescription(answer.get())));
958   EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
959 
960   // Verify bundling on sender side.
961   auto senders = caller->pc()->GetSenders();
962   ASSERT_EQ(senders.size(), 4u);
963   auto sender0_transport = senders[0]->dtls_transport();
964   auto sender1_transport = senders[1]->dtls_transport();
965   auto sender2_transport = senders[2]->dtls_transport();
966   auto sender3_transport = senders[3]->dtls_transport();
967   EXPECT_EQ(sender0_transport, sender1_transport);
968   EXPECT_EQ(sender2_transport, sender3_transport);
969   EXPECT_NE(sender0_transport, sender2_transport);
970 
971   // Verify bundling on receiver side.
972   auto receivers = callee->pc()->GetReceivers();
973   ASSERT_EQ(receivers.size(), 4u);
974   auto receiver0_transport = receivers[0]->dtls_transport();
975   auto receiver1_transport = receivers[1]->dtls_transport();
976   auto receiver2_transport = receivers[2]->dtls_transport();
977   auto receiver3_transport = receivers[3]->dtls_transport();
978   EXPECT_EQ(receiver0_transport, receiver1_transport);
979   EXPECT_EQ(receiver2_transport, receiver3_transport);
980   EXPECT_NE(receiver0_transport, receiver2_transport);
981 }
982 
983 // Test that, with the "max-compat" bundle policy, it's possible to add an m=
984 // section that's not part of an existing bundle group.
TEST_F(PeerConnectionBundleTestUnifiedPlan,AddNonBundledSection)985 TEST_F(PeerConnectionBundleTestUnifiedPlan, AddNonBundledSection) {
986   RTCConfiguration config;
987   config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxCompat;
988   auto caller = CreatePeerConnection(config);
989   caller->AddAudioTrack("0_audio");
990   caller->AddAudioTrack("1_audio");
991   auto callee = CreatePeerConnection(config);
992 
993   // Establish an existing BUNDLE group.
994   auto offer = caller->CreateOffer(RTCOfferAnswerOptions());
995   EXPECT_TRUE(
996       caller->SetLocalDescription(CloneSessionDescription(offer.get())));
997   EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
998   auto answer = callee->CreateAnswer();
999   EXPECT_TRUE(
1000       callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1001   EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1002 
1003   // Add a track but munge SDP so it's not part of the bundle group.
1004   caller->AddAudioTrack("3_audio");
1005   offer = caller->CreateOffer(RTCOfferAnswerOptions());
1006   offer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1007   cricket::ContentGroup bundle_group(cricket::GROUP_TYPE_BUNDLE);
1008   bundle_group.AddContentName("0");
1009   bundle_group.AddContentName("1");
1010   offer->description()->AddGroup(bundle_group);
1011   EXPECT_TRUE(
1012       caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1013   EXPECT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1014   answer = callee->CreateAnswer();
1015   EXPECT_TRUE(
1016       callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1017   EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1018 
1019   // Verify bundling on the sender side.
1020   auto senders = caller->pc()->GetSenders();
1021   ASSERT_EQ(senders.size(), 3u);
1022   auto sender0_transport = senders[0]->dtls_transport();
1023   auto sender1_transport = senders[1]->dtls_transport();
1024   auto sender2_transport = senders[2]->dtls_transport();
1025   EXPECT_EQ(sender0_transport, sender1_transport);
1026   EXPECT_NE(sender0_transport, sender2_transport);
1027 
1028   // Verify bundling on receiver side.
1029   auto receivers = callee->pc()->GetReceivers();
1030   ASSERT_EQ(receivers.size(), 3u);
1031   auto receiver0_transport = receivers[0]->dtls_transport();
1032   auto receiver1_transport = receivers[1]->dtls_transport();
1033   auto receiver2_transport = receivers[2]->dtls_transport();
1034   EXPECT_EQ(receiver0_transport, receiver1_transport);
1035   EXPECT_NE(receiver0_transport, receiver2_transport);
1036 }
1037 
1038 }  // namespace webrtc
1039