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