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