xref: /aosp_15_r20/external/webrtc/pc/peer_connection_simulcast_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2019 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 <algorithm>
12 #include <iterator>
13 #include <map>
14 #include <memory>
15 #include <ostream>  // no-presubmit-check TODO(webrtc:8982)
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include "absl/algorithm/container.h"
21 #include "absl/strings/string_view.h"
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/create_peerconnection_factory.h"
26 #include "api/jsep.h"
27 #include "api/media_types.h"
28 #include "api/peer_connection_interface.h"
29 #include "api/rtc_error.h"
30 #include "api/rtp_parameters.h"
31 #include "api/rtp_sender_interface.h"
32 #include "api/rtp_transceiver_direction.h"
33 #include "api/rtp_transceiver_interface.h"
34 #include "api/scoped_refptr.h"
35 #include "api/uma_metrics.h"
36 #include "api/video/video_codec_constants.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/rid_description.h"
40 #include "media/base/stream_params.h"
41 #include "modules/audio_device/include/audio_device.h"
42 #include "modules/audio_processing/include/audio_processing.h"
43 #include "pc/channel_interface.h"
44 #include "pc/peer_connection_wrapper.h"
45 #include "pc/session_description.h"
46 #include "pc/simulcast_description.h"
47 #include "pc/test/fake_audio_capture_module.h"
48 #include "pc/test/mock_peer_connection_observers.h"
49 #include "rtc_base/checks.h"
50 #include "rtc_base/strings/string_builder.h"
51 #include "rtc_base/thread.h"
52 #include "rtc_base/unique_id_generator.h"
53 #include "system_wrappers/include/metrics.h"
54 #include "test/gmock.h"
55 #include "test/gtest.h"
56 
57 using ::testing::Contains;
58 using ::testing::Each;
59 using ::testing::ElementsAre;
60 using ::testing::ElementsAreArray;
61 using ::testing::Eq;
62 using ::testing::Field;
63 using ::testing::IsEmpty;
64 using ::testing::Ne;
65 using ::testing::Pair;
66 using ::testing::Property;
67 using ::testing::SizeIs;
68 
69 using cricket::MediaContentDescription;
70 using cricket::RidDescription;
71 using cricket::SimulcastDescription;
72 using cricket::SimulcastLayer;
73 using cricket::StreamParams;
74 
75 namespace cricket {
76 
operator <<(std::ostream & os,const SimulcastLayer & layer)77 std::ostream& operator<<(  // no-presubmit-check TODO(webrtc:8982)
78     std::ostream& os,      // no-presubmit-check TODO(webrtc:8982)
79     const SimulcastLayer& layer) {
80   if (layer.is_paused) {
81     os << "~";
82   }
83   return os << layer.rid;
84 }
85 
86 }  // namespace cricket
87 
88 namespace {
89 
CreateLayers(const std::vector<std::string> & rids,const std::vector<bool> & active)90 std::vector<SimulcastLayer> CreateLayers(const std::vector<std::string>& rids,
91                                          const std::vector<bool>& active) {
92   RTC_DCHECK_EQ(rids.size(), active.size());
93   std::vector<SimulcastLayer> result;
94   absl::c_transform(rids, active, std::back_inserter(result),
95                     [](const std::string& rid, bool is_active) {
96                       return SimulcastLayer(rid, !is_active);
97                     });
98   return result;
99 }
CreateLayers(const std::vector<std::string> & rids,bool active)100 std::vector<SimulcastLayer> CreateLayers(const std::vector<std::string>& rids,
101                                          bool active) {
102   return CreateLayers(rids, std::vector<bool>(rids.size(), active));
103 }
104 
105 #if RTC_METRICS_ENABLED
CreateLayers(int num_layers,bool active)106 std::vector<SimulcastLayer> CreateLayers(int num_layers, bool active) {
107   rtc::UniqueStringGenerator rid_generator;
108   std::vector<std::string> rids;
109   for (int i = 0; i < num_layers; ++i) {
110     rids.push_back(rid_generator());
111   }
112   return CreateLayers(rids, active);
113 }
114 #endif
115 
116 }  // namespace
117 
118 namespace webrtc {
119 
120 class PeerConnectionSimulcastTests : public ::testing::Test {
121  public:
PeerConnectionSimulcastTests()122   PeerConnectionSimulcastTests()
123       : pc_factory_(
124             CreatePeerConnectionFactory(rtc::Thread::Current(),
125                                         rtc::Thread::Current(),
126                                         rtc::Thread::Current(),
127                                         FakeAudioCaptureModule::Create(),
128                                         CreateBuiltinAudioEncoderFactory(),
129                                         CreateBuiltinAudioDecoderFactory(),
130                                         CreateBuiltinVideoEncoderFactory(),
131                                         CreateBuiltinVideoDecoderFactory(),
132                                         nullptr,
133                                         nullptr)) {}
134 
CreatePeerConnection(MockPeerConnectionObserver * observer)135   rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
136       MockPeerConnectionObserver* observer) {
137     PeerConnectionInterface::RTCConfiguration config;
138     config.sdp_semantics = SdpSemantics::kUnifiedPlan;
139     PeerConnectionDependencies pcd(observer);
140     auto result =
141         pc_factory_->CreatePeerConnectionOrError(config, std::move(pcd));
142     EXPECT_TRUE(result.ok());
143     observer->SetPeerConnectionInterface(result.value().get());
144     return result.MoveValue();
145   }
146 
CreatePeerConnectionWrapper()147   std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWrapper() {
148     auto observer = std::make_unique<MockPeerConnectionObserver>();
149     auto pc = CreatePeerConnection(observer.get());
150     return std::make_unique<PeerConnectionWrapper>(pc_factory_, pc,
151                                                    std::move(observer));
152   }
153 
ExchangeOfferAnswer(PeerConnectionWrapper * local,PeerConnectionWrapper * remote,const std::vector<SimulcastLayer> & answer_layers)154   void ExchangeOfferAnswer(PeerConnectionWrapper* local,
155                            PeerConnectionWrapper* remote,
156                            const std::vector<SimulcastLayer>& answer_layers) {
157     auto offer = local->CreateOfferAndSetAsLocal();
158     // Remove simulcast as the second peer connection won't support it.
159     RemoveSimulcast(offer.get());
160     std::string err;
161     EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &err)) << err;
162     auto answer = remote->CreateAnswerAndSetAsLocal();
163     // Setup the answer to look like a server response.
164     auto mcd_answer = answer->description()->contents()[0].media_description();
165     auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
166     for (const SimulcastLayer& layer : answer_layers) {
167       receive_layers.AddLayer(layer);
168     }
169     EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &err)) << err;
170   }
171 
CreateTransceiverInit(const std::vector<SimulcastLayer> & layers)172   RtpTransceiverInit CreateTransceiverInit(
173       const std::vector<SimulcastLayer>& layers) {
174     RtpTransceiverInit init;
175     for (const SimulcastLayer& layer : layers) {
176       RtpEncodingParameters encoding;
177       encoding.rid = layer.rid;
178       encoding.active = !layer.is_paused;
179       init.send_encodings.push_back(encoding);
180     }
181     return init;
182   }
183 
AddTransceiver(PeerConnectionWrapper * pc,const std::vector<SimulcastLayer> & layers,cricket::MediaType media_type=cricket::MEDIA_TYPE_VIDEO)184   rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
185       PeerConnectionWrapper* pc,
186       const std::vector<SimulcastLayer>& layers,
187       cricket::MediaType media_type = cricket::MEDIA_TYPE_VIDEO) {
188     auto init = CreateTransceiverInit(layers);
189     return pc->AddTransceiver(media_type, init);
190   }
191 
RemoveSimulcast(SessionDescriptionInterface * sd)192   SimulcastDescription RemoveSimulcast(SessionDescriptionInterface* sd) {
193     auto mcd = sd->description()->contents()[0].media_description();
194     auto result = mcd->simulcast_description();
195     mcd->set_simulcast_description(SimulcastDescription());
196     return result;
197   }
198 
AddRequestToReceiveSimulcast(const std::vector<SimulcastLayer> & layers,SessionDescriptionInterface * sd)199   void AddRequestToReceiveSimulcast(const std::vector<SimulcastLayer>& layers,
200                                     SessionDescriptionInterface* sd) {
201     auto mcd = sd->description()->contents()[0].media_description();
202     SimulcastDescription simulcast;
203     auto& receive_layers = simulcast.receive_layers();
204     for (const SimulcastLayer& layer : layers) {
205       receive_layers.AddLayer(layer);
206     }
207     mcd->set_simulcast_description(simulcast);
208   }
209 
ValidateTransceiverParameters(rtc::scoped_refptr<RtpTransceiverInterface> transceiver,const std::vector<SimulcastLayer> & layers)210   void ValidateTransceiverParameters(
211       rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
212       const std::vector<SimulcastLayer>& layers) {
213     auto parameters = transceiver->sender()->GetParameters();
214     std::vector<SimulcastLayer> result_layers;
215     absl::c_transform(parameters.encodings, std::back_inserter(result_layers),
216                       [](const RtpEncodingParameters& encoding) {
217                         return SimulcastLayer(encoding.rid, !encoding.active);
218                       });
219     EXPECT_THAT(result_layers, ElementsAreArray(layers));
220   }
221 
222  private:
223   rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
224 };
225 
226 #if RTC_METRICS_ENABLED
227 // This class is used to test the metrics emitted for simulcast.
228 class PeerConnectionSimulcastMetricsTests
229     : public PeerConnectionSimulcastTests,
230       public ::testing::WithParamInterface<int> {
231  protected:
PeerConnectionSimulcastMetricsTests()232   PeerConnectionSimulcastMetricsTests() { webrtc::metrics::Reset(); }
233 
LocalDescriptionSamples()234   std::map<int, int> LocalDescriptionSamples() {
235     return metrics::Samples(
236         "WebRTC.PeerConnection.Simulcast.ApplyLocalDescription");
237   }
RemoteDescriptionSamples()238   std::map<int, int> RemoteDescriptionSamples() {
239     return metrics::Samples(
240         "WebRTC.PeerConnection.Simulcast.ApplyRemoteDescription");
241   }
242 };
243 #endif
244 
245 // Validates that RIDs are supported arguments when adding a transceiver.
TEST_F(PeerConnectionSimulcastTests,CanCreateTransceiverWithRid)246 TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithRid) {
247   auto pc = CreatePeerConnectionWrapper();
248   auto layers = CreateLayers({"f"}, true);
249   auto transceiver = AddTransceiver(pc.get(), layers);
250   ASSERT_TRUE(transceiver);
251   auto parameters = transceiver->sender()->GetParameters();
252   // Single RID should be removed.
253   EXPECT_THAT(parameters.encodings,
254               ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
255 }
256 
TEST_F(PeerConnectionSimulcastTests,CanCreateTransceiverWithSimulcast)257 TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithSimulcast) {
258   auto pc = CreatePeerConnectionWrapper();
259   auto layers = CreateLayers({"f", "h", "q"}, true);
260   auto transceiver = AddTransceiver(pc.get(), layers);
261   ASSERT_TRUE(transceiver);
262   ValidateTransceiverParameters(transceiver, layers);
263 }
264 
TEST_F(PeerConnectionSimulcastTests,RidsAreAutogeneratedIfNotProvided)265 TEST_F(PeerConnectionSimulcastTests, RidsAreAutogeneratedIfNotProvided) {
266   auto pc = CreatePeerConnectionWrapper();
267   auto init = CreateTransceiverInit(CreateLayers({"f", "h", "q"}, true));
268   for (RtpEncodingParameters& parameters : init.send_encodings) {
269     parameters.rid = "";
270   }
271   auto transceiver = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
272   auto parameters = transceiver->sender()->GetParameters();
273   ASSERT_EQ(3u, parameters.encodings.size());
274   EXPECT_THAT(parameters.encodings,
275               Each(Field("rid", &RtpEncodingParameters::rid, Ne(""))));
276 }
277 
278 // Validates that an error is returned when there is a mix of supplied and not
279 // supplied RIDs in a call to AddTransceiver.
TEST_F(PeerConnectionSimulcastTests,MustSupplyAllOrNoRidsInSimulcast)280 TEST_F(PeerConnectionSimulcastTests, MustSupplyAllOrNoRidsInSimulcast) {
281   auto pc_wrapper = CreatePeerConnectionWrapper();
282   auto pc = pc_wrapper->pc();
283   // Cannot create a layer with empty RID. Remove the RID after init is created.
284   auto layers = CreateLayers({"f", "h", "remove"}, true);
285   auto init = CreateTransceiverInit(layers);
286   init.send_encodings[2].rid = "";
287   auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
288   EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
289 }
290 
291 // Validates that an error is returned when illegal RIDs are supplied.
TEST_F(PeerConnectionSimulcastTests,ChecksForIllegalRidValues)292 TEST_F(PeerConnectionSimulcastTests, ChecksForIllegalRidValues) {
293   auto pc_wrapper = CreatePeerConnectionWrapper();
294   auto pc = pc_wrapper->pc();
295   auto layers = CreateLayers({"f", "h", "~q"}, true);
296   auto init = CreateTransceiverInit(layers);
297   auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
298   EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
299 }
300 
301 // Validates that a single RID is removed from the encoding layer.
TEST_F(PeerConnectionSimulcastTests,SingleRidIsRemovedFromSessionDescription)302 TEST_F(PeerConnectionSimulcastTests, SingleRidIsRemovedFromSessionDescription) {
303   auto pc = CreatePeerConnectionWrapper();
304   auto transceiver = AddTransceiver(pc.get(), CreateLayers({"1"}, true));
305   auto offer = pc->CreateOfferAndSetAsLocal();
306   ASSERT_TRUE(offer);
307   auto contents = offer->description()->contents();
308   ASSERT_EQ(1u, contents.size());
309   EXPECT_THAT(contents[0].media_description()->streams(),
310               ElementsAre(Property(&StreamParams::has_rids, false)));
311 }
312 
TEST_F(PeerConnectionSimulcastTests,SimulcastLayersRemovedFromTail)313 TEST_F(PeerConnectionSimulcastTests, SimulcastLayersRemovedFromTail) {
314   static_assert(
315       kMaxSimulcastStreams < 8,
316       "Test assumes that the platform does not allow 8 simulcast layers");
317   auto pc = CreatePeerConnectionWrapper();
318   auto layers = CreateLayers({"1", "2", "3", "4", "5", "6", "7", "8"}, true);
319   std::vector<SimulcastLayer> expected_layers;
320   std::copy_n(layers.begin(), kMaxSimulcastStreams,
321               std::back_inserter(expected_layers));
322   auto transceiver = AddTransceiver(pc.get(), layers);
323   ValidateTransceiverParameters(transceiver, expected_layers);
324 }
325 
326 // Checks that an offfer to send simulcast contains a SimulcastDescription.
TEST_F(PeerConnectionSimulcastTests,SimulcastAppearsInSessionDescription)327 TEST_F(PeerConnectionSimulcastTests, SimulcastAppearsInSessionDescription) {
328   auto pc = CreatePeerConnectionWrapper();
329   std::vector<std::string> rids({"f", "h", "q"});
330   auto layers = CreateLayers(rids, true);
331   auto transceiver = AddTransceiver(pc.get(), layers);
332   auto offer = pc->CreateOffer();
333   ASSERT_TRUE(offer);
334   auto contents = offer->description()->contents();
335   ASSERT_EQ(1u, contents.size());
336   auto content = contents[0];
337   auto mcd = content.media_description();
338   ASSERT_TRUE(mcd->HasSimulcast());
339   auto simulcast = mcd->simulcast_description();
340   EXPECT_THAT(simulcast.receive_layers(), IsEmpty());
341   // The size is validated separately because GetAllLayers() flattens the list.
342   EXPECT_THAT(simulcast.send_layers(), SizeIs(3));
343   std::vector<SimulcastLayer> result = simulcast.send_layers().GetAllLayers();
344   EXPECT_THAT(result, ElementsAreArray(layers));
345   auto streams = mcd->streams();
346   ASSERT_EQ(1u, streams.size());
347   auto stream = streams[0];
348   EXPECT_FALSE(stream.has_ssrcs());
349   EXPECT_TRUE(stream.has_rids());
350   std::vector<std::string> result_rids;
351   absl::c_transform(stream.rids(), std::back_inserter(result_rids),
352                     [](const RidDescription& rid) { return rid.rid; });
353   EXPECT_THAT(result_rids, ElementsAreArray(rids));
354 }
355 
356 // Checks that Simulcast layers propagate to the sender parameters.
TEST_F(PeerConnectionSimulcastTests,SimulcastLayersAreSetInSender)357 TEST_F(PeerConnectionSimulcastTests, SimulcastLayersAreSetInSender) {
358   auto local = CreatePeerConnectionWrapper();
359   auto remote = CreatePeerConnectionWrapper();
360   auto layers = CreateLayers({"f", "h", "q"}, true);
361   auto transceiver = AddTransceiver(local.get(), layers);
362   auto offer = local->CreateOfferAndSetAsLocal();
363   {
364     SCOPED_TRACE("after create offer");
365     ValidateTransceiverParameters(transceiver, layers);
366   }
367   // Remove simulcast as the second peer connection won't support it.
368   auto simulcast = RemoveSimulcast(offer.get());
369   std::string error;
370   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
371   auto answer = remote->CreateAnswerAndSetAsLocal();
372 
373   // Setup an answer that mimics a server accepting simulcast.
374   auto mcd_answer = answer->description()->contents()[0].media_description();
375   mcd_answer->mutable_streams().clear();
376   auto simulcast_layers = simulcast.send_layers().GetAllLayers();
377   auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
378   for (const auto& layer : simulcast_layers) {
379     receive_layers.AddLayer(layer);
380   }
381   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
382   {
383     SCOPED_TRACE("after set remote");
384     ValidateTransceiverParameters(transceiver, layers);
385   }
386 }
387 
388 // Checks that paused Simulcast layers propagate to the sender parameters.
TEST_F(PeerConnectionSimulcastTests,PausedSimulcastLayersAreDisabledInSender)389 TEST_F(PeerConnectionSimulcastTests, PausedSimulcastLayersAreDisabledInSender) {
390   auto local = CreatePeerConnectionWrapper();
391   auto remote = CreatePeerConnectionWrapper();
392   auto layers = CreateLayers({"f", "h", "q"}, {true, false, true});
393   auto server_layers = CreateLayers({"f", "h", "q"}, {true, false, false});
394   RTC_DCHECK_EQ(layers.size(), server_layers.size());
395   auto transceiver = AddTransceiver(local.get(), layers);
396   auto offer = local->CreateOfferAndSetAsLocal();
397   {
398     SCOPED_TRACE("after create offer");
399     ValidateTransceiverParameters(transceiver, layers);
400   }
401 
402   // Remove simulcast as the second peer connection won't support it.
403   RemoveSimulcast(offer.get());
404   std::string error;
405   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
406   auto answer = remote->CreateAnswerAndSetAsLocal();
407 
408   // Setup an answer that mimics a server accepting simulcast.
409   auto mcd_answer = answer->description()->contents()[0].media_description();
410   mcd_answer->mutable_streams().clear();
411   auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
412   for (const SimulcastLayer& layer : server_layers) {
413     receive_layers.AddLayer(layer);
414   }
415   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
416   {
417     SCOPED_TRACE("after set remote");
418     ValidateTransceiverParameters(transceiver, server_layers);
419   }
420 }
421 
422 // Checks that when Simulcast is not supported by the remote party, then all
423 // the layers (except the first) are removed.
TEST_F(PeerConnectionSimulcastTests,SimulcastRejectedRemovesExtraLayers)424 TEST_F(PeerConnectionSimulcastTests, SimulcastRejectedRemovesExtraLayers) {
425   auto local = CreatePeerConnectionWrapper();
426   auto remote = CreatePeerConnectionWrapper();
427   auto layers = CreateLayers({"1", "2", "3", "4"}, true);
428   auto transceiver = AddTransceiver(local.get(), layers);
429   ExchangeOfferAnswer(local.get(), remote.get(), {});
430   auto parameters = transceiver->sender()->GetParameters();
431   // Should only have the first layer.
432   EXPECT_THAT(parameters.encodings,
433               ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq("1"))));
434 }
435 
436 // Checks that if Simulcast is supported by remote party, but some layers are
437 // rejected, then only rejected layers are removed from the sender.
TEST_F(PeerConnectionSimulcastTests,RejectedSimulcastLayersAreDeactivated)438 TEST_F(PeerConnectionSimulcastTests, RejectedSimulcastLayersAreDeactivated) {
439   auto local = CreatePeerConnectionWrapper();
440   auto remote = CreatePeerConnectionWrapper();
441   auto layers = CreateLayers({"1", "2", "3"}, true);
442   auto expected_layers = CreateLayers({"2", "3"}, true);
443   auto transceiver = AddTransceiver(local.get(), layers);
444   auto offer = local->CreateOfferAndSetAsLocal();
445   {
446     SCOPED_TRACE("after create offer");
447     ValidateTransceiverParameters(transceiver, layers);
448   }
449   // Remove simulcast as the second peer connection won't support it.
450   auto removed_simulcast = RemoveSimulcast(offer.get());
451   std::string error;
452   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
453   auto answer = remote->CreateAnswerAndSetAsLocal();
454   auto mcd_answer = answer->description()->contents()[0].media_description();
455   // Setup the answer to look like a server response.
456   // Remove one of the layers to reject it in the answer.
457   auto simulcast_layers = removed_simulcast.send_layers().GetAllLayers();
458   simulcast_layers.erase(simulcast_layers.begin());
459   auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
460   for (const auto& layer : simulcast_layers) {
461     receive_layers.AddLayer(layer);
462   }
463   ASSERT_TRUE(mcd_answer->HasSimulcast());
464   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
465   {
466     SCOPED_TRACE("after set remote");
467     ValidateTransceiverParameters(transceiver, expected_layers);
468   }
469 }
470 
471 // Checks that simulcast is set up correctly when the server sends an offer
472 // requesting to receive simulcast.
TEST_F(PeerConnectionSimulcastTests,ServerSendsOfferToReceiveSimulcast)473 TEST_F(PeerConnectionSimulcastTests, ServerSendsOfferToReceiveSimulcast) {
474   auto local = CreatePeerConnectionWrapper();
475   auto remote = CreatePeerConnectionWrapper();
476   auto layers = CreateLayers({"f", "h", "q"}, true);
477   AddTransceiver(local.get(), layers);
478   auto offer = local->CreateOfferAndSetAsLocal();
479   // Remove simulcast as a sender and set it up as a receiver.
480   RemoveSimulcast(offer.get());
481   AddRequestToReceiveSimulcast(layers, offer.get());
482   std::string error;
483   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
484   auto transceiver = remote->pc()->GetTransceivers()[0];
485   transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
486   EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
487   ValidateTransceiverParameters(transceiver, layers);
488 }
489 
490 // Checks that SetRemoteDescription doesn't attempt to associate a transceiver
491 // when simulcast is requested by the server.
TEST_F(PeerConnectionSimulcastTests,TransceiverIsNotRecycledWithSimulcast)492 TEST_F(PeerConnectionSimulcastTests, TransceiverIsNotRecycledWithSimulcast) {
493   auto local = CreatePeerConnectionWrapper();
494   auto remote = CreatePeerConnectionWrapper();
495   auto layers = CreateLayers({"f", "h", "q"}, true);
496   AddTransceiver(local.get(), layers);
497   auto offer = local->CreateOfferAndSetAsLocal();
498   // Remove simulcast as a sender and set it up as a receiver.
499   RemoveSimulcast(offer.get());
500   AddRequestToReceiveSimulcast(layers, offer.get());
501   // Call AddTrack so that a transceiver is created.
502   remote->AddVideoTrack("fake_track");
503   std::string error;
504   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
505   auto transceivers = remote->pc()->GetTransceivers();
506   ASSERT_EQ(2u, transceivers.size());
507   auto transceiver = transceivers[1];
508   transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
509   EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
510   ValidateTransceiverParameters(transceiver, layers);
511 }
512 
513 // Checks that if the number of layers changes during negotiation, then any
514 // outstanding get/set parameters transaction is invalidated.
TEST_F(PeerConnectionSimulcastTests,ParametersAreInvalidatedWhenLayersChange)515 TEST_F(PeerConnectionSimulcastTests, ParametersAreInvalidatedWhenLayersChange) {
516   auto local = CreatePeerConnectionWrapper();
517   auto remote = CreatePeerConnectionWrapper();
518   auto layers = CreateLayers({"1", "2", "3"}, true);
519   auto transceiver = AddTransceiver(local.get(), layers);
520   auto parameters = transceiver->sender()->GetParameters();
521   ASSERT_EQ(3u, parameters.encodings.size());
522   // Response will reject simulcast altogether.
523   ExchangeOfferAnswer(local.get(), remote.get(), {});
524   auto result = transceiver->sender()->SetParameters(parameters);
525   EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type());
526 }
527 
528 // Checks that even though negotiation modifies the sender's parameters, an
529 // outstanding get/set parameters transaction is not invalidated.
530 // This test negotiates twice because initial parameters before negotiation
531 // is missing critical information and cannot be set on the sender.
TEST_F(PeerConnectionSimulcastTests,NegotiationDoesNotInvalidateParameterTransactions)532 TEST_F(PeerConnectionSimulcastTests,
533        NegotiationDoesNotInvalidateParameterTransactions) {
534   auto local = CreatePeerConnectionWrapper();
535   auto remote = CreatePeerConnectionWrapper();
536   auto layers = CreateLayers({"1", "2", "3"}, true);
537   auto expected_layers = CreateLayers({"1", "2", "3"}, false);
538   auto transceiver = AddTransceiver(local.get(), layers);
539   ExchangeOfferAnswer(local.get(), remote.get(), expected_layers);
540 
541   // Verify that negotiation does not invalidate the parameters.
542   auto parameters = transceiver->sender()->GetParameters();
543   ExchangeOfferAnswer(local.get(), remote.get(), expected_layers);
544 
545   auto result = transceiver->sender()->SetParameters(parameters);
546   EXPECT_TRUE(result.ok());
547   ValidateTransceiverParameters(transceiver, expected_layers);
548 }
549 
550 // Tests that simulcast is disabled if the RID extension is not negotiated
551 // regardless of if the RIDs and simulcast attribute were negotiated properly.
TEST_F(PeerConnectionSimulcastTests,NegotiationDoesNotHaveRidExtension)552 TEST_F(PeerConnectionSimulcastTests, NegotiationDoesNotHaveRidExtension) {
553   auto local = CreatePeerConnectionWrapper();
554   auto remote = CreatePeerConnectionWrapper();
555   auto layers = CreateLayers({"1", "2", "3"}, true);
556   auto expected_layers = CreateLayers({"1"}, true);
557   auto transceiver = AddTransceiver(local.get(), layers);
558   auto offer = local->CreateOfferAndSetAsLocal();
559   // Remove simulcast as the second peer connection won't support it.
560   RemoveSimulcast(offer.get());
561   std::string err;
562   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &err)) << err;
563   auto answer = remote->CreateAnswerAndSetAsLocal();
564   // Setup the answer to look like a server response.
565   // Drop the RID header extension.
566   auto mcd_answer = answer->description()->contents()[0].media_description();
567   auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
568   for (const SimulcastLayer& layer : layers) {
569     receive_layers.AddLayer(layer);
570   }
571   cricket::RtpHeaderExtensions extensions;
572   for (auto extension : mcd_answer->rtp_header_extensions()) {
573     if (extension.uri != RtpExtension::kRidUri) {
574       extensions.push_back(extension);
575     }
576   }
577   mcd_answer->set_rtp_header_extensions(extensions);
578   EXPECT_EQ(layers.size(), mcd_answer->simulcast_description()
579                                .receive_layers()
580                                .GetAllLayers()
581                                .size());
582   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &err)) << err;
583   ValidateTransceiverParameters(transceiver, expected_layers);
584 }
585 
TEST_F(PeerConnectionSimulcastTests,SimulcastAudioRejected)586 TEST_F(PeerConnectionSimulcastTests, SimulcastAudioRejected) {
587   auto local = CreatePeerConnectionWrapper();
588   auto remote = CreatePeerConnectionWrapper();
589   auto layers = CreateLayers({"1", "2", "3", "4"}, true);
590   auto transceiver =
591       AddTransceiver(local.get(), layers, cricket::MEDIA_TYPE_AUDIO);
592   // Should only have the first layer.
593   auto parameters = transceiver->sender()->GetParameters();
594   EXPECT_EQ(1u, parameters.encodings.size());
595   EXPECT_THAT(parameters.encodings,
596               ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
597   ExchangeOfferAnswer(local.get(), remote.get(), {});
598   // Still have a single layer after negotiation
599   parameters = transceiver->sender()->GetParameters();
600   EXPECT_EQ(1u, parameters.encodings.size());
601   EXPECT_THAT(parameters.encodings,
602               ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
603 }
604 
605 // Check that modifying the offer to remove simulcast and at the same
606 // time leaving in a RID line does not cause an exception.
TEST_F(PeerConnectionSimulcastTests,SimulcastSldModificationRejected)607 TEST_F(PeerConnectionSimulcastTests, SimulcastSldModificationRejected) {
608   auto local = CreatePeerConnectionWrapper();
609   auto remote = CreatePeerConnectionWrapper();
610   auto layers = CreateLayers({"1", "2", "3"}, true);
611   AddTransceiver(local.get(), layers);
612   auto offer = local->CreateOffer();
613   std::string as_string;
614   EXPECT_TRUE(offer->ToString(&as_string));
615   auto simulcast_marker = "a=rid:3 send\r\na=simulcast:send 1;2;3\r\n";
616   auto pos = as_string.find(simulcast_marker);
617   EXPECT_NE(pos, std::string::npos);
618   as_string.erase(pos, strlen(simulcast_marker));
619   SdpParseError parse_error;
620   auto modified_offer =
621       CreateSessionDescription(SdpType::kOffer, as_string, &parse_error);
622   EXPECT_TRUE(modified_offer);
623   EXPECT_TRUE(local->SetLocalDescription(std::move(modified_offer)));
624 }
625 
626 #if RTC_METRICS_ENABLED
627 //
628 // Checks the logged metrics when simulcast is not used.
TEST_F(PeerConnectionSimulcastMetricsTests,NoSimulcastUsageIsLogged)629 TEST_F(PeerConnectionSimulcastMetricsTests, NoSimulcastUsageIsLogged) {
630   auto local = CreatePeerConnectionWrapper();
631   auto remote = CreatePeerConnectionWrapper();
632   auto layers = CreateLayers(0, true);
633   AddTransceiver(local.get(), layers);
634   ExchangeOfferAnswer(local.get(), remote.get(), layers);
635 
636   EXPECT_THAT(LocalDescriptionSamples(),
637               ElementsAre(Pair(kSimulcastApiVersionNone, 2)));
638   EXPECT_THAT(RemoteDescriptionSamples(),
639               ElementsAre(Pair(kSimulcastApiVersionNone, 2)));
640 }
641 
642 // Checks the logged metrics when spec-compliant simulcast is used.
TEST_F(PeerConnectionSimulcastMetricsTests,SpecComplianceIsLogged)643 TEST_F(PeerConnectionSimulcastMetricsTests, SpecComplianceIsLogged) {
644   auto local = CreatePeerConnectionWrapper();
645   auto remote = CreatePeerConnectionWrapper();
646   auto layers = CreateLayers(3, true);
647   AddTransceiver(local.get(), layers);
648   ExchangeOfferAnswer(local.get(), remote.get(), layers);
649 
650   // Expecting 2 invocations of each, because we have 2 peer connections.
651   // Only the local peer connection will be aware of simulcast.
652   // The remote peer connection will think that there is no simulcast.
653   EXPECT_THAT(LocalDescriptionSamples(),
654               ElementsAre(Pair(kSimulcastApiVersionNone, 1),
655                           Pair(kSimulcastApiVersionSpecCompliant, 1)));
656   EXPECT_THAT(RemoteDescriptionSamples(),
657               ElementsAre(Pair(kSimulcastApiVersionNone, 1),
658                           Pair(kSimulcastApiVersionSpecCompliant, 1)));
659 }
660 
661 // Checks the logged metrics when and incoming request to send spec-compliant
662 // simulcast is received from the remote party.
TEST_F(PeerConnectionSimulcastMetricsTests,IncomingSimulcastIsLogged)663 TEST_F(PeerConnectionSimulcastMetricsTests, IncomingSimulcastIsLogged) {
664   auto local = CreatePeerConnectionWrapper();
665   auto remote = CreatePeerConnectionWrapper();
666   auto layers = CreateLayers(3, true);
667   AddTransceiver(local.get(), layers);
668   auto offer = local->CreateOfferAndSetAsLocal();
669   EXPECT_THAT(LocalDescriptionSamples(),
670               ElementsAre(Pair(kSimulcastApiVersionSpecCompliant, 1)));
671 
672   // Remove simulcast as a sender and set it up as a receiver.
673   RemoveSimulcast(offer.get());
674   AddRequestToReceiveSimulcast(layers, offer.get());
675   std::string error;
676   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
677   EXPECT_THAT(RemoteDescriptionSamples(),
678               ElementsAre(Pair(kSimulcastApiVersionSpecCompliant, 1)));
679 
680   auto transceiver = remote->pc()->GetTransceivers()[0];
681   transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
682   EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
683   EXPECT_THAT(LocalDescriptionSamples(),
684               ElementsAre(Pair(kSimulcastApiVersionSpecCompliant, 2)));
685 }
686 
687 // Checks that a spec-compliant simulcast offer that is rejected is logged.
TEST_F(PeerConnectionSimulcastMetricsTests,RejectedSimulcastIsLogged)688 TEST_F(PeerConnectionSimulcastMetricsTests, RejectedSimulcastIsLogged) {
689   auto local = CreatePeerConnectionWrapper();
690   auto remote = CreatePeerConnectionWrapper();
691   auto layers = CreateLayers({"1", "2", "3"}, true);
692   AddTransceiver(local.get(), layers);
693   auto offer = local->CreateOfferAndSetAsLocal();
694   EXPECT_THAT(LocalDescriptionSamples(),
695               ElementsAre(Pair(kSimulcastApiVersionSpecCompliant, 1)));
696   RemoveSimulcast(offer.get());
697   std::string error;
698   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
699   EXPECT_THAT(RemoteDescriptionSamples(),
700               ElementsAre(Pair(kSimulcastApiVersionNone, 1)));
701 
702   auto answer = remote->CreateAnswerAndSetAsLocal();
703   EXPECT_THAT(LocalDescriptionSamples(),
704               ElementsAre(Pair(kSimulcastApiVersionNone, 1),
705                           Pair(kSimulcastApiVersionSpecCompliant, 1)));
706   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
707   EXPECT_THAT(RemoteDescriptionSamples(),
708               ElementsAre(Pair(kSimulcastApiVersionNone, 2)));
709 }
710 
711 // Checks the logged metrics when legacy munging simulcast technique is used.
TEST_F(PeerConnectionSimulcastMetricsTests,LegacySimulcastIsLogged)712 TEST_F(PeerConnectionSimulcastMetricsTests, LegacySimulcastIsLogged) {
713   auto local = CreatePeerConnectionWrapper();
714   auto remote = CreatePeerConnectionWrapper();
715   auto layers = CreateLayers(0, true);
716   AddTransceiver(local.get(), layers);
717   auto offer = local->CreateOffer();
718   // Munge the SDP to set up legacy simulcast.
719   const std::string end_line = "\r\n";
720   std::string sdp;
721   offer->ToString(&sdp);
722   rtc::StringBuilder builder(sdp);
723   builder << "a=ssrc:1111 cname:slimshady" << end_line;
724   builder << "a=ssrc:2222 cname:slimshady" << end_line;
725   builder << "a=ssrc:3333 cname:slimshady" << end_line;
726   builder << "a=ssrc-group:SIM 1111 2222 3333" << end_line;
727 
728   SdpParseError parse_error;
729   auto sd =
730       CreateSessionDescription(SdpType::kOffer, builder.str(), &parse_error);
731   ASSERT_TRUE(sd) << parse_error.line << parse_error.description;
732   std::string error;
733   EXPECT_TRUE(local->SetLocalDescription(std::move(sd), &error)) << error;
734   EXPECT_THAT(LocalDescriptionSamples(),
735               ElementsAre(Pair(kSimulcastApiVersionLegacy, 1)));
736   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
737   EXPECT_THAT(RemoteDescriptionSamples(),
738               ElementsAre(Pair(kSimulcastApiVersionNone, 1)));
739   auto answer = remote->CreateAnswerAndSetAsLocal();
740   EXPECT_THAT(LocalDescriptionSamples(),
741               ElementsAre(Pair(kSimulcastApiVersionNone, 1),
742                           Pair(kSimulcastApiVersionLegacy, 1)));
743   // Legacy simulcast is not signaled in remote description.
744   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
745   EXPECT_THAT(RemoteDescriptionSamples(),
746               ElementsAre(Pair(kSimulcastApiVersionNone, 2)));
747 }
748 
749 // Checks that disabling simulcast is logged in the metrics.
TEST_F(PeerConnectionSimulcastMetricsTests,SimulcastDisabledIsLogged)750 TEST_F(PeerConnectionSimulcastMetricsTests, SimulcastDisabledIsLogged) {
751   auto local = CreatePeerConnectionWrapper();
752   auto remote = CreatePeerConnectionWrapper();
753   auto layers = CreateLayers({"1", "2", "3"}, true);
754   AddTransceiver(local.get(), layers);
755   auto offer = local->CreateOfferAndSetAsLocal();
756   RemoveSimulcast(offer.get());
757   std::string error;
758   EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
759   auto answer = remote->CreateAnswerAndSetAsLocal();
760   EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
761 
762   EXPECT_EQ(1, metrics::NumSamples("WebRTC.PeerConnection.Simulcast.Disabled"));
763   EXPECT_EQ(1,
764             metrics::NumEvents("WebRTC.PeerConnection.Simulcast.Disabled", 1));
765 }
766 
767 // Checks that the disabled metric is not logged if simulcast is not disabled.
TEST_F(PeerConnectionSimulcastMetricsTests,SimulcastDisabledIsNotLogged)768 TEST_F(PeerConnectionSimulcastMetricsTests, SimulcastDisabledIsNotLogged) {
769   auto local = CreatePeerConnectionWrapper();
770   auto remote = CreatePeerConnectionWrapper();
771   auto layers = CreateLayers({"1", "2", "3"}, true);
772   AddTransceiver(local.get(), layers);
773   ExchangeOfferAnswer(local.get(), remote.get(), layers);
774 
775   EXPECT_EQ(0, metrics::NumSamples("WebRTC.PeerConnection.Simulcast.Disabled"));
776 }
777 
778 const int kMaxLayersInMetricsTest = 8;
779 
780 // Checks that the number of send encodings is logged in a metric.
TEST_P(PeerConnectionSimulcastMetricsTests,NumberOfSendEncodingsIsLogged)781 TEST_P(PeerConnectionSimulcastMetricsTests, NumberOfSendEncodingsIsLogged) {
782   auto local = CreatePeerConnectionWrapper();
783   auto num_layers = GetParam();
784   auto layers = CreateLayers(num_layers, true);
785   AddTransceiver(local.get(), layers);
786   EXPECT_EQ(1, metrics::NumSamples(
787                    "WebRTC.PeerConnection.Simulcast.NumberOfSendEncodings"));
788   EXPECT_EQ(1, metrics::NumEvents(
789                    "WebRTC.PeerConnection.Simulcast.NumberOfSendEncodings",
790                    num_layers));
791 }
792 
793 INSTANTIATE_TEST_SUITE_P(NumberOfSendEncodings,
794                          PeerConnectionSimulcastMetricsTests,
795                          ::testing::Range(0, kMaxLayersInMetricsTest));
796 #endif
797 }  // namespace webrtc
798