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