blob: b2c0d715e8be35ab1b1a823ff4307e20d9b8e1b1 [file] [log] [blame]
Amit Hilbuchaa584152019-02-07 01:09:521/*
2 * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Harald Alvestrandc24a2182022-02-23 13:44:5911#include <algorithm>
12#include <iterator>
13#include <map>
Mirko Bonadei317a1f02019-09-17 15:06:1814#include <memory>
Harald Alvestrandc24a2182022-02-23 13:44:5915#include <string>
16#include <utility>
17#include <vector>
Amit Hilbuchaa584152019-02-07 01:09:5218
19#include "absl/algorithm/container.h"
Henrik Boström88ddfdb2023-02-08 13:42:1220#include "absl/strings/match.h"
Harald Alvestrandc24a2182022-02-23 13:44:5921#include "absl/strings/string_view.h"
Florent Castellif4673f92024-04-19 19:46:0322#include "api/audio/audio_device.h"
Harald Alvestrandc24a2182022-02-23 13:44:5923#include "api/audio/audio_mixer.h"
Florent Castelli0afde762024-04-19 15:07:0824#include "api/audio/audio_processing.h"
Amit Hilbuchaa584152019-02-07 01:09:5225#include "api/audio_codecs/builtin_audio_decoder_factory.h"
26#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Henrik Boströmfd4ddd12023-02-08 10:29:2027#include "api/audio_codecs/opus_audio_decoder_factory.h"
28#include "api/audio_codecs/opus_audio_encoder_factory.h"
Amit Hilbuchaa584152019-02-07 01:09:5229#include "api/create_peerconnection_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5930#include "api/jsep.h"
Amit Hilbuchf4770402019-04-08 21:11:5731#include "api/media_types.h"
Harald Alvestrandc24a2182022-02-23 13:44:5932#include "api/peer_connection_interface.h"
Amit Hilbuchf4770402019-04-08 21:11:5733#include "api/rtc_error.h"
Harald Alvestrandc24a2182022-02-23 13:44:5934#include "api/rtp_parameters.h"
35#include "api/rtp_sender_interface.h"
36#include "api/rtp_transceiver_direction.h"
Amit Hilbuchaa584152019-02-07 01:09:5237#include "api/rtp_transceiver_interface.h"
Harald Alvestrandc24a2182022-02-23 13:44:5938#include "api/scoped_refptr.h"
Amit Hilbuche2a284d2019-03-05 20:36:3139#include "api/uma_metrics.h"
Harald Alvestrandc24a2182022-02-23 13:44:5940#include "api/video/video_codec_constants.h"
Åsa Persson0587aae2023-03-31 14:49:1441#include "api/video_codecs/video_decoder_factory_template.h"
42#include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h"
43#include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h"
44#include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h"
45#include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h"
46#include "api/video_codecs/video_encoder_factory_template.h"
47#include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h"
48#include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h"
49#include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h"
50#include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h"
Henrik Boström88ddfdb2023-02-08 13:42:1251#include "media/base/media_constants.h"
Harald Alvestrandc24a2182022-02-23 13:44:5952#include "media/base/rid_description.h"
53#include "media/base/stream_params.h"
Harald Alvestrandc24a2182022-02-23 13:44:5954#include "pc/channel_interface.h"
Amit Hilbuchaa584152019-02-07 01:09:5255#include "pc/peer_connection_wrapper.h"
Henrik Boströmfd4ddd12023-02-08 10:29:2056#include "pc/sdp_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:5957#include "pc/session_description.h"
58#include "pc/simulcast_description.h"
Amit Hilbuchaa584152019-02-07 01:09:5259#include "pc/test/fake_audio_capture_module.h"
60#include "pc/test/mock_peer_connection_observers.h"
Henrik Boströmda9e2842023-04-06 13:27:3361#include "pc/test/simulcast_layer_util.h"
Harald Alvestrandc24a2182022-02-23 13:44:5962#include "rtc_base/checks.h"
Henrik Boströmfd4ddd12023-02-08 10:29:2063#include "rtc_base/gunit.h"
Harald Alvestrandc24a2182022-02-23 13:44:5964#include "rtc_base/strings/string_builder.h"
65#include "rtc_base/thread.h"
66#include "rtc_base/unique_id_generator.h"
Amit Hilbuche2a284d2019-03-05 20:36:3167#include "system_wrappers/include/metrics.h"
Amit Hilbuchaa584152019-02-07 01:09:5268#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:5969#include "test/gtest.h"
Amit Hilbuchaa584152019-02-07 01:09:5270
71using ::testing::Contains;
72using ::testing::Each;
73using ::testing::ElementsAre;
74using ::testing::ElementsAreArray;
75using ::testing::Eq;
76using ::testing::Field;
77using ::testing::IsEmpty;
Henrik Boström95250db2023-02-28 13:40:2478using ::testing::Le;
Amit Hilbuchaa584152019-02-07 01:09:5279using ::testing::Ne;
Amit Hilbuche2a284d2019-03-05 20:36:3180using ::testing::Pair;
Amit Hilbuchaa584152019-02-07 01:09:5281using ::testing::Property;
82using ::testing::SizeIs;
Henrik Boström88ddfdb2023-02-08 13:42:1283using ::testing::StartsWith;
Amit Hilbuchaa584152019-02-07 01:09:5284
85using cricket::MediaContentDescription;
86using cricket::RidDescription;
87using cricket::SimulcastDescription;
88using cricket::SimulcastLayer;
89using cricket::StreamParams;
90
Amit Hilbuchaa584152019-02-07 01:09:5291namespace webrtc {
92
Mirko Bonadei6a489f22019-04-09 13:11:1293class PeerConnectionSimulcastTests : public ::testing::Test {
Amit Hilbuchaa584152019-02-07 01:09:5294 public:
95 PeerConnectionSimulcastTests()
Åsa Persson0587aae2023-03-31 14:49:1496 : pc_factory_(CreatePeerConnectionFactory(
97 rtc::Thread::Current(),
98 rtc::Thread::Current(),
99 rtc::Thread::Current(),
100 FakeAudioCaptureModule::Create(),
101 CreateBuiltinAudioEncoderFactory(),
102 CreateBuiltinAudioDecoderFactory(),
103 std::make_unique<
104 VideoEncoderFactoryTemplate<LibvpxVp8EncoderTemplateAdapter,
105 LibvpxVp9EncoderTemplateAdapter,
106 OpenH264EncoderTemplateAdapter,
107 LibaomAv1EncoderTemplateAdapter>>(),
108 std::make_unique<
109 VideoDecoderFactoryTemplate<LibvpxVp8DecoderTemplateAdapter,
110 LibvpxVp9DecoderTemplateAdapter,
111 OpenH264DecoderTemplateAdapter,
112 Dav1dDecoderTemplateAdapter>>(),
113 nullptr,
114 nullptr)) {}
Amit Hilbuchaa584152019-02-07 01:09:52115
116 rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
117 MockPeerConnectionObserver* observer) {
118 PeerConnectionInterface::RTCConfiguration config;
119 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
120 PeerConnectionDependencies pcd(observer);
Florent Castelli72424402022-04-06 01:45:10121 auto result =
122 pc_factory_->CreatePeerConnectionOrError(config, std::move(pcd));
123 EXPECT_TRUE(result.ok());
Niels Möllerafb246b2022-04-20 12:26:50124 observer->SetPeerConnectionInterface(result.value().get());
Florent Castelli72424402022-04-06 01:45:10125 return result.MoveValue();
Amit Hilbuchaa584152019-02-07 01:09:52126 }
127
128 std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWrapper() {
Mirko Bonadei317a1f02019-09-17 15:06:18129 auto observer = std::make_unique<MockPeerConnectionObserver>();
Amit Hilbuchaa584152019-02-07 01:09:52130 auto pc = CreatePeerConnection(observer.get());
Mirko Bonadei317a1f02019-09-17 15:06:18131 return std::make_unique<PeerConnectionWrapper>(pc_factory_, pc,
132 std::move(observer));
Amit Hilbuchaa584152019-02-07 01:09:52133 }
134
Amit Hilbuch619b2942019-02-26 23:55:19135 void ExchangeOfferAnswer(PeerConnectionWrapper* local,
136 PeerConnectionWrapper* remote,
137 const std::vector<SimulcastLayer>& answer_layers) {
138 auto offer = local->CreateOfferAndSetAsLocal();
139 // Remove simulcast as the second peer connection won't support it.
Amit Hilbuchaabd0362019-03-01 21:14:46140 RemoveSimulcast(offer.get());
Amit Hilbuch619b2942019-02-26 23:55:19141 std::string err;
142 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &err)) << err;
143 auto answer = remote->CreateAnswerAndSetAsLocal();
144 // Setup the answer to look like a server response.
145 auto mcd_answer = answer->description()->contents()[0].media_description();
146 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
147 for (const SimulcastLayer& layer : answer_layers) {
148 receive_layers.AddLayer(layer);
149 }
150 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &err)) << err;
151 }
152
Amit Hilbuchaa584152019-02-07 01:09:52153 rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
154 PeerConnectionWrapper* pc,
Florent Castellie1b685a2021-04-30 17:11:37155 const std::vector<SimulcastLayer>& layers,
156 cricket::MediaType media_type = cricket::MEDIA_TYPE_VIDEO) {
Amit Hilbuchaa584152019-02-07 01:09:52157 auto init = CreateTransceiverInit(layers);
Florent Castellie1b685a2021-04-30 17:11:37158 return pc->AddTransceiver(media_type, init);
Amit Hilbuchaa584152019-02-07 01:09:52159 }
160
Amit Hilbuchaa584152019-02-07 01:09:52161 void AddRequestToReceiveSimulcast(const std::vector<SimulcastLayer>& layers,
162 SessionDescriptionInterface* sd) {
163 auto mcd = sd->description()->contents()[0].media_description();
164 SimulcastDescription simulcast;
165 auto& receive_layers = simulcast.receive_layers();
166 for (const SimulcastLayer& layer : layers) {
167 receive_layers.AddLayer(layer);
168 }
169 mcd->set_simulcast_description(simulcast);
170 }
171
Amit Hilbuche2a284d2019-03-05 20:36:31172 void ValidateTransceiverParameters(
Amit Hilbuchaa584152019-02-07 01:09:52173 rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
174 const std::vector<SimulcastLayer>& layers) {
Amit Hilbuchaa584152019-02-07 01:09:52175 auto parameters = transceiver->sender()->GetParameters();
176 std::vector<SimulcastLayer> result_layers;
177 absl::c_transform(parameters.encodings, std::back_inserter(result_layers),
178 [](const RtpEncodingParameters& encoding) {
179 return SimulcastLayer(encoding.rid, !encoding.active);
180 });
181 EXPECT_THAT(result_layers, ElementsAreArray(layers));
Amit Hilbuchaa584152019-02-07 01:09:52182 }
183
184 private:
185 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
186};
187
188// Validates that RIDs are supported arguments when adding a transceiver.
189TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithRid) {
190 auto pc = CreatePeerConnectionWrapper();
191 auto layers = CreateLayers({"f"}, true);
192 auto transceiver = AddTransceiver(pc.get(), layers);
193 ASSERT_TRUE(transceiver);
194 auto parameters = transceiver->sender()->GetParameters();
195 // Single RID should be removed.
196 EXPECT_THAT(parameters.encodings,
Amit Hilbuch2297d332019-02-19 20:49:22197 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
Amit Hilbuchaa584152019-02-07 01:09:52198}
199
200TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithSimulcast) {
201 auto pc = CreatePeerConnectionWrapper();
202 auto layers = CreateLayers({"f", "h", "q"}, true);
203 auto transceiver = AddTransceiver(pc.get(), layers);
204 ASSERT_TRUE(transceiver);
Amit Hilbuche2a284d2019-03-05 20:36:31205 ValidateTransceiverParameters(transceiver, layers);
Amit Hilbuchaa584152019-02-07 01:09:52206}
207
208TEST_F(PeerConnectionSimulcastTests, RidsAreAutogeneratedIfNotProvided) {
209 auto pc = CreatePeerConnectionWrapper();
210 auto init = CreateTransceiverInit(CreateLayers({"f", "h", "q"}, true));
211 for (RtpEncodingParameters& parameters : init.send_encodings) {
212 parameters.rid = "";
213 }
214 auto transceiver = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
215 auto parameters = transceiver->sender()->GetParameters();
216 ASSERT_EQ(3u, parameters.encodings.size());
217 EXPECT_THAT(parameters.encodings,
Amit Hilbuch2297d332019-02-19 20:49:22218 Each(Field("rid", &RtpEncodingParameters::rid, Ne(""))));
Amit Hilbuchaa584152019-02-07 01:09:52219}
220
221// Validates that an error is returned when there is a mix of supplied and not
222// supplied RIDs in a call to AddTransceiver.
223TEST_F(PeerConnectionSimulcastTests, MustSupplyAllOrNoRidsInSimulcast) {
224 auto pc_wrapper = CreatePeerConnectionWrapper();
225 auto pc = pc_wrapper->pc();
226 // Cannot create a layer with empty RID. Remove the RID after init is created.
227 auto layers = CreateLayers({"f", "h", "remove"}, true);
228 auto init = CreateTransceiverInit(layers);
229 init.send_encodings[2].rid = "";
230 auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
231 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
232}
233
Amit Hilbuchf4770402019-04-08 21:11:57234// Validates that an error is returned when illegal RIDs are supplied.
235TEST_F(PeerConnectionSimulcastTests, ChecksForIllegalRidValues) {
236 auto pc_wrapper = CreatePeerConnectionWrapper();
237 auto pc = pc_wrapper->pc();
238 auto layers = CreateLayers({"f", "h", "~q"}, true);
239 auto init = CreateTransceiverInit(layers);
240 auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
241 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
242}
243
Amit Hilbuch2297d332019-02-19 20:49:22244// Validates that a single RID is removed from the encoding layer.
Amit Hilbuchaa584152019-02-07 01:09:52245TEST_F(PeerConnectionSimulcastTests, SingleRidIsRemovedFromSessionDescription) {
246 auto pc = CreatePeerConnectionWrapper();
247 auto transceiver = AddTransceiver(pc.get(), CreateLayers({"1"}, true));
248 auto offer = pc->CreateOfferAndSetAsLocal();
249 ASSERT_TRUE(offer);
250 auto contents = offer->description()->contents();
251 ASSERT_EQ(1u, contents.size());
252 EXPECT_THAT(contents[0].media_description()->streams(),
253 ElementsAre(Property(&StreamParams::has_rids, false)));
254}
255
256TEST_F(PeerConnectionSimulcastTests, SimulcastLayersRemovedFromTail) {
257 static_assert(
258 kMaxSimulcastStreams < 8,
259 "Test assumes that the platform does not allow 8 simulcast layers");
260 auto pc = CreatePeerConnectionWrapper();
261 auto layers = CreateLayers({"1", "2", "3", "4", "5", "6", "7", "8"}, true);
262 std::vector<SimulcastLayer> expected_layers;
263 std::copy_n(layers.begin(), kMaxSimulcastStreams,
264 std::back_inserter(expected_layers));
265 auto transceiver = AddTransceiver(pc.get(), layers);
Amit Hilbuche2a284d2019-03-05 20:36:31266 ValidateTransceiverParameters(transceiver, expected_layers);
Amit Hilbuchaa584152019-02-07 01:09:52267}
268
269// Checks that an offfer to send simulcast contains a SimulcastDescription.
270TEST_F(PeerConnectionSimulcastTests, SimulcastAppearsInSessionDescription) {
271 auto pc = CreatePeerConnectionWrapper();
272 std::vector<std::string> rids({"f", "h", "q"});
273 auto layers = CreateLayers(rids, true);
274 auto transceiver = AddTransceiver(pc.get(), layers);
275 auto offer = pc->CreateOffer();
276 ASSERT_TRUE(offer);
277 auto contents = offer->description()->contents();
278 ASSERT_EQ(1u, contents.size());
279 auto content = contents[0];
280 auto mcd = content.media_description();
281 ASSERT_TRUE(mcd->HasSimulcast());
282 auto simulcast = mcd->simulcast_description();
283 EXPECT_THAT(simulcast.receive_layers(), IsEmpty());
284 // The size is validated separately because GetAllLayers() flattens the list.
285 EXPECT_THAT(simulcast.send_layers(), SizeIs(3));
286 std::vector<SimulcastLayer> result = simulcast.send_layers().GetAllLayers();
287 EXPECT_THAT(result, ElementsAreArray(layers));
288 auto streams = mcd->streams();
289 ASSERT_EQ(1u, streams.size());
290 auto stream = streams[0];
291 EXPECT_FALSE(stream.has_ssrcs());
292 EXPECT_TRUE(stream.has_rids());
293 std::vector<std::string> result_rids;
294 absl::c_transform(stream.rids(), std::back_inserter(result_rids),
295 [](const RidDescription& rid) { return rid.rid; });
296 EXPECT_THAT(result_rids, ElementsAreArray(rids));
297}
298
299// Checks that Simulcast layers propagate to the sender parameters.
300TEST_F(PeerConnectionSimulcastTests, SimulcastLayersAreSetInSender) {
301 auto local = CreatePeerConnectionWrapper();
302 auto remote = CreatePeerConnectionWrapper();
303 auto layers = CreateLayers({"f", "h", "q"}, true);
304 auto transceiver = AddTransceiver(local.get(), layers);
305 auto offer = local->CreateOfferAndSetAsLocal();
Amit Hilbuche2a284d2019-03-05 20:36:31306 {
307 SCOPED_TRACE("after create offer");
308 ValidateTransceiverParameters(transceiver, layers);
309 }
Amit Hilbuchaa584152019-02-07 01:09:52310 // Remove simulcast as the second peer connection won't support it.
311 auto simulcast = RemoveSimulcast(offer.get());
312 std::string error;
313 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
314 auto answer = remote->CreateAnswerAndSetAsLocal();
315
316 // Setup an answer that mimics a server accepting simulcast.
317 auto mcd_answer = answer->description()->contents()[0].media_description();
318 mcd_answer->mutable_streams().clear();
319 auto simulcast_layers = simulcast.send_layers().GetAllLayers();
320 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
321 for (const auto& layer : simulcast_layers) {
322 receive_layers.AddLayer(layer);
323 }
324 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuche2a284d2019-03-05 20:36:31325 {
326 SCOPED_TRACE("after set remote");
327 ValidateTransceiverParameters(transceiver, layers);
328 }
Amit Hilbuchaa584152019-02-07 01:09:52329}
330
331// Checks that paused Simulcast layers propagate to the sender parameters.
332TEST_F(PeerConnectionSimulcastTests, PausedSimulcastLayersAreDisabledInSender) {
333 auto local = CreatePeerConnectionWrapper();
334 auto remote = CreatePeerConnectionWrapper();
335 auto layers = CreateLayers({"f", "h", "q"}, {true, false, true});
336 auto server_layers = CreateLayers({"f", "h", "q"}, {true, false, false});
337 RTC_DCHECK_EQ(layers.size(), server_layers.size());
338 auto transceiver = AddTransceiver(local.get(), layers);
339 auto offer = local->CreateOfferAndSetAsLocal();
Amit Hilbuche2a284d2019-03-05 20:36:31340 {
341 SCOPED_TRACE("after create offer");
342 ValidateTransceiverParameters(transceiver, layers);
343 }
Amit Hilbuchaa584152019-02-07 01:09:52344
345 // Remove simulcast as the second peer connection won't support it.
346 RemoveSimulcast(offer.get());
347 std::string error;
348 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
349 auto answer = remote->CreateAnswerAndSetAsLocal();
350
351 // Setup an answer that mimics a server accepting simulcast.
352 auto mcd_answer = answer->description()->contents()[0].media_description();
353 mcd_answer->mutable_streams().clear();
354 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
355 for (const SimulcastLayer& layer : server_layers) {
356 receive_layers.AddLayer(layer);
357 }
358 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuche2a284d2019-03-05 20:36:31359 {
360 SCOPED_TRACE("after set remote");
361 ValidateTransceiverParameters(transceiver, server_layers);
362 }
Amit Hilbuchaa584152019-02-07 01:09:52363}
364
365// Checks that when Simulcast is not supported by the remote party, then all
Amit Hilbuch2297d332019-02-19 20:49:22366// the layers (except the first) are removed.
367TEST_F(PeerConnectionSimulcastTests, SimulcastRejectedRemovesExtraLayers) {
Amit Hilbuchaa584152019-02-07 01:09:52368 auto local = CreatePeerConnectionWrapper();
369 auto remote = CreatePeerConnectionWrapper();
370 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
Amit Hilbuchaa584152019-02-07 01:09:52371 auto transceiver = AddTransceiver(local.get(), layers);
Amit Hilbuch619b2942019-02-26 23:55:19372 ExchangeOfferAnswer(local.get(), remote.get(), {});
Amit Hilbuch2297d332019-02-19 20:49:22373 auto parameters = transceiver->sender()->GetParameters();
374 // Should only have the first layer.
375 EXPECT_THAT(parameters.encodings,
376 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq("1"))));
Amit Hilbuchaa584152019-02-07 01:09:52377}
378
Amit Hilbuch2297d332019-02-19 20:49:22379// Checks that if Simulcast is supported by remote party, but some layers are
380// rejected, then only rejected layers are removed from the sender.
Amit Hilbuchaa584152019-02-07 01:09:52381TEST_F(PeerConnectionSimulcastTests, RejectedSimulcastLayersAreDeactivated) {
382 auto local = CreatePeerConnectionWrapper();
383 auto remote = CreatePeerConnectionWrapper();
Florent Castelli3fbf1e22019-07-04 15:09:05384 auto layers = CreateLayers({"1", "2", "3"}, true);
385 auto expected_layers = CreateLayers({"2", "3"}, true);
Amit Hilbuchaa584152019-02-07 01:09:52386 auto transceiver = AddTransceiver(local.get(), layers);
387 auto offer = local->CreateOfferAndSetAsLocal();
Amit Hilbuche2a284d2019-03-05 20:36:31388 {
389 SCOPED_TRACE("after create offer");
390 ValidateTransceiverParameters(transceiver, layers);
391 }
Amit Hilbuchaa584152019-02-07 01:09:52392 // Remove simulcast as the second peer connection won't support it.
393 auto removed_simulcast = RemoveSimulcast(offer.get());
394 std::string error;
395 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
396 auto answer = remote->CreateAnswerAndSetAsLocal();
397 auto mcd_answer = answer->description()->contents()[0].media_description();
398 // Setup the answer to look like a server response.
399 // Remove one of the layers to reject it in the answer.
400 auto simulcast_layers = removed_simulcast.send_layers().GetAllLayers();
401 simulcast_layers.erase(simulcast_layers.begin());
402 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
403 for (const auto& layer : simulcast_layers) {
404 receive_layers.AddLayer(layer);
405 }
406 ASSERT_TRUE(mcd_answer->HasSimulcast());
407 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuche2a284d2019-03-05 20:36:31408 {
409 SCOPED_TRACE("after set remote");
410 ValidateTransceiverParameters(transceiver, expected_layers);
411 }
Amit Hilbuchaa584152019-02-07 01:09:52412}
413
414// Checks that simulcast is set up correctly when the server sends an offer
415// requesting to receive simulcast.
416TEST_F(PeerConnectionSimulcastTests, ServerSendsOfferToReceiveSimulcast) {
417 auto local = CreatePeerConnectionWrapper();
418 auto remote = CreatePeerConnectionWrapper();
419 auto layers = CreateLayers({"f", "h", "q"}, true);
420 AddTransceiver(local.get(), layers);
421 auto offer = local->CreateOfferAndSetAsLocal();
422 // Remove simulcast as a sender and set it up as a receiver.
423 RemoveSimulcast(offer.get());
424 AddRequestToReceiveSimulcast(layers, offer.get());
425 std::string error;
426 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
427 auto transceiver = remote->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 07:54:02428 transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
Amit Hilbuchaa584152019-02-07 01:09:52429 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
Amit Hilbuche2a284d2019-03-05 20:36:31430 ValidateTransceiverParameters(transceiver, layers);
Amit Hilbuchaa584152019-02-07 01:09:52431}
432
433// Checks that SetRemoteDescription doesn't attempt to associate a transceiver
434// when simulcast is requested by the server.
435TEST_F(PeerConnectionSimulcastTests, TransceiverIsNotRecycledWithSimulcast) {
436 auto local = CreatePeerConnectionWrapper();
437 auto remote = CreatePeerConnectionWrapper();
438 auto layers = CreateLayers({"f", "h", "q"}, true);
439 AddTransceiver(local.get(), layers);
440 auto offer = local->CreateOfferAndSetAsLocal();
441 // Remove simulcast as a sender and set it up as a receiver.
442 RemoveSimulcast(offer.get());
443 AddRequestToReceiveSimulcast(layers, offer.get());
444 // Call AddTrack so that a transceiver is created.
445 remote->AddVideoTrack("fake_track");
446 std::string error;
447 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
448 auto transceivers = remote->pc()->GetTransceivers();
449 ASSERT_EQ(2u, transceivers.size());
450 auto transceiver = transceivers[1];
Harald Alvestrand6060df52020-08-11 07:54:02451 transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
Amit Hilbuchaa584152019-02-07 01:09:52452 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
Amit Hilbuche2a284d2019-03-05 20:36:31453 ValidateTransceiverParameters(transceiver, layers);
Amit Hilbuchaa584152019-02-07 01:09:52454}
455
Amit Hilbuch619b2942019-02-26 23:55:19456// Checks that if the number of layers changes during negotiation, then any
457// outstanding get/set parameters transaction is invalidated.
458TEST_F(PeerConnectionSimulcastTests, ParametersAreInvalidatedWhenLayersChange) {
459 auto local = CreatePeerConnectionWrapper();
460 auto remote = CreatePeerConnectionWrapper();
461 auto layers = CreateLayers({"1", "2", "3"}, true);
462 auto transceiver = AddTransceiver(local.get(), layers);
463 auto parameters = transceiver->sender()->GetParameters();
464 ASSERT_EQ(3u, parameters.encodings.size());
465 // Response will reject simulcast altogether.
466 ExchangeOfferAnswer(local.get(), remote.get(), {});
467 auto result = transceiver->sender()->SetParameters(parameters);
468 EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type());
469}
470
471// Checks that even though negotiation modifies the sender's parameters, an
472// outstanding get/set parameters transaction is not invalidated.
473// This test negotiates twice because initial parameters before negotiation
474// is missing critical information and cannot be set on the sender.
475TEST_F(PeerConnectionSimulcastTests,
476 NegotiationDoesNotInvalidateParameterTransactions) {
477 auto local = CreatePeerConnectionWrapper();
478 auto remote = CreatePeerConnectionWrapper();
479 auto layers = CreateLayers({"1", "2", "3"}, true);
480 auto expected_layers = CreateLayers({"1", "2", "3"}, false);
481 auto transceiver = AddTransceiver(local.get(), layers);
482 ExchangeOfferAnswer(local.get(), remote.get(), expected_layers);
483
484 // Verify that negotiation does not invalidate the parameters.
485 auto parameters = transceiver->sender()->GetParameters();
486 ExchangeOfferAnswer(local.get(), remote.get(), expected_layers);
487
488 auto result = transceiver->sender()->SetParameters(parameters);
489 EXPECT_TRUE(result.ok());
Amit Hilbuche2a284d2019-03-05 20:36:31490 ValidateTransceiverParameters(transceiver, expected_layers);
Amit Hilbuch619b2942019-02-26 23:55:19491}
492
Philipp Hancke34887262023-06-01 17:07:50493// Tests that a simulcast answer is rejected if the RID extension is not
494// negotiated.
495TEST_F(PeerConnectionSimulcastTests, NegotiationDoesNotHaveRidExtensionFails) {
Amit Hilbuchaabd0362019-03-01 21:14:46496 auto local = CreatePeerConnectionWrapper();
497 auto remote = CreatePeerConnectionWrapper();
498 auto layers = CreateLayers({"1", "2", "3"}, true);
499 auto expected_layers = CreateLayers({"1"}, true);
500 auto transceiver = AddTransceiver(local.get(), layers);
501 auto offer = local->CreateOfferAndSetAsLocal();
502 // Remove simulcast as the second peer connection won't support it.
503 RemoveSimulcast(offer.get());
504 std::string err;
505 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &err)) << err;
506 auto answer = remote->CreateAnswerAndSetAsLocal();
507 // Setup the answer to look like a server response.
508 // Drop the RID header extension.
509 auto mcd_answer = answer->description()->contents()[0].media_description();
510 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
511 for (const SimulcastLayer& layer : layers) {
512 receive_layers.AddLayer(layer);
513 }
514 cricket::RtpHeaderExtensions extensions;
515 for (auto extension : mcd_answer->rtp_header_extensions()) {
516 if (extension.uri != RtpExtension::kRidUri) {
517 extensions.push_back(extension);
518 }
519 }
520 mcd_answer->set_rtp_header_extensions(extensions);
521 EXPECT_EQ(layers.size(), mcd_answer->simulcast_description()
522 .receive_layers()
523 .GetAllLayers()
524 .size());
Philipp Hancke34887262023-06-01 17:07:50525 EXPECT_FALSE(local->SetRemoteDescription(std::move(answer), &err)) << err;
Amit Hilbuchaabd0362019-03-01 21:14:46526}
Ying Wangef3998f2019-12-09 12:06:53527
Florent Castellie1b685a2021-04-30 17:11:37528TEST_F(PeerConnectionSimulcastTests, SimulcastAudioRejected) {
529 auto local = CreatePeerConnectionWrapper();
530 auto remote = CreatePeerConnectionWrapper();
531 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
532 auto transceiver =
533 AddTransceiver(local.get(), layers, cricket::MEDIA_TYPE_AUDIO);
534 // Should only have the first layer.
535 auto parameters = transceiver->sender()->GetParameters();
536 EXPECT_EQ(1u, parameters.encodings.size());
537 EXPECT_THAT(parameters.encodings,
538 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
539 ExchangeOfferAnswer(local.get(), remote.get(), {});
540 // Still have a single layer after negotiation
541 parameters = transceiver->sender()->GetParameters();
542 EXPECT_EQ(1u, parameters.encodings.size());
543 EXPECT_THAT(parameters.encodings,
544 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
545}
546
Harald Alvestrand1c580812022-07-04 09:41:24547// Check that modifying the offer to remove simulcast and at the same
548// time leaving in a RID line does not cause an exception.
549TEST_F(PeerConnectionSimulcastTests, SimulcastSldModificationRejected) {
550 auto local = CreatePeerConnectionWrapper();
551 auto remote = CreatePeerConnectionWrapper();
552 auto layers = CreateLayers({"1", "2", "3"}, true);
553 AddTransceiver(local.get(), layers);
554 auto offer = local->CreateOffer();
555 std::string as_string;
556 EXPECT_TRUE(offer->ToString(&as_string));
557 auto simulcast_marker = "a=rid:3 send\r\na=simulcast:send 1;2;3\r\n";
558 auto pos = as_string.find(simulcast_marker);
559 EXPECT_NE(pos, std::string::npos);
560 as_string.erase(pos, strlen(simulcast_marker));
561 SdpParseError parse_error;
562 auto modified_offer =
563 CreateSessionDescription(SdpType::kOffer, as_string, &parse_error);
564 EXPECT_TRUE(modified_offer);
565 EXPECT_TRUE(local->SetLocalDescription(std::move(modified_offer)));
566}
Amit Hilbuchaa584152019-02-07 01:09:52567} // namespace webrtc