blob: 53dcd2d9dc459639b6ee4ea581ab05d98d8d6d50 [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>
Amit Hilbuchaa584152019-02-07 01:09:5215#include <ostream> // no-presubmit-check TODO(webrtc:8982)
Harald Alvestrandc24a2182022-02-23 13:44:5916#include <string>
17#include <utility>
18#include <vector>
Amit Hilbuchaa584152019-02-07 01:09:5219
20#include "absl/algorithm/container.h"
Henrik Boström88ddfdb2023-02-08 13:42:1221#include "absl/strings/match.h"
Harald Alvestrandc24a2182022-02-23 13:44:5922#include "absl/strings/string_view.h"
Florent Castellif4673f92024-04-19 19:46:0323#include "api/audio/audio_device.h"
Harald Alvestrandc24a2182022-02-23 13:44:5924#include "api/audio/audio_mixer.h"
Florent Castelli0afde762024-04-19 15:07:0825#include "api/audio/audio_processing.h"
Amit Hilbuchaa584152019-02-07 01:09:5226#include "api/audio_codecs/builtin_audio_decoder_factory.h"
27#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Henrik Boströmfd4ddd12023-02-08 10:29:2028#include "api/audio_codecs/opus_audio_decoder_factory.h"
29#include "api/audio_codecs/opus_audio_encoder_factory.h"
Amit Hilbuchaa584152019-02-07 01:09:5230#include "api/create_peerconnection_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5931#include "api/jsep.h"
Amit Hilbuchf4770402019-04-08 21:11:5732#include "api/media_types.h"
Harald Alvestrandc24a2182022-02-23 13:44:5933#include "api/peer_connection_interface.h"
Amit Hilbuchf4770402019-04-08 21:11:5734#include "api/rtc_error.h"
Harald Alvestrandc24a2182022-02-23 13:44:5935#include "api/rtp_parameters.h"
36#include "api/rtp_sender_interface.h"
37#include "api/rtp_transceiver_direction.h"
Amit Hilbuchaa584152019-02-07 01:09:5238#include "api/rtp_transceiver_interface.h"
Harald Alvestrandc24a2182022-02-23 13:44:5939#include "api/scoped_refptr.h"
Amit Hilbuche2a284d2019-03-05 20:36:3140#include "api/uma_metrics.h"
Harald Alvestrandc24a2182022-02-23 13:44:5941#include "api/video/video_codec_constants.h"
Åsa Persson0587aae2023-03-31 14:49:1442#include "api/video_codecs/video_decoder_factory_template.h"
43#include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h"
44#include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h"
45#include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h"
46#include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h"
47#include "api/video_codecs/video_encoder_factory_template.h"
48#include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h"
49#include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h"
50#include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h"
51#include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h"
Henrik Boström88ddfdb2023-02-08 13:42:1252#include "media/base/media_constants.h"
Harald Alvestrandc24a2182022-02-23 13:44:5953#include "media/base/rid_description.h"
54#include "media/base/stream_params.h"
Harald Alvestrandc24a2182022-02-23 13:44:5955#include "pc/channel_interface.h"
Amit Hilbuchaa584152019-02-07 01:09:5256#include "pc/peer_connection_wrapper.h"
Henrik Boströmfd4ddd12023-02-08 10:29:2057#include "pc/sdp_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:5958#include "pc/session_description.h"
59#include "pc/simulcast_description.h"
Amit Hilbuchaa584152019-02-07 01:09:5260#include "pc/test/fake_audio_capture_module.h"
61#include "pc/test/mock_peer_connection_observers.h"
Henrik Boströmda9e2842023-04-06 13:27:3362#include "pc/test/simulcast_layer_util.h"
Harald Alvestrandc24a2182022-02-23 13:44:5963#include "rtc_base/checks.h"
Henrik Boströmfd4ddd12023-02-08 10:29:2064#include "rtc_base/gunit.h"
Harald Alvestrandc24a2182022-02-23 13:44:5965#include "rtc_base/strings/string_builder.h"
66#include "rtc_base/thread.h"
67#include "rtc_base/unique_id_generator.h"
Amit Hilbuche2a284d2019-03-05 20:36:3168#include "system_wrappers/include/metrics.h"
Amit Hilbuchaa584152019-02-07 01:09:5269#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:5970#include "test/gtest.h"
Amit Hilbuchaa584152019-02-07 01:09:5271
72using ::testing::Contains;
73using ::testing::Each;
74using ::testing::ElementsAre;
75using ::testing::ElementsAreArray;
76using ::testing::Eq;
77using ::testing::Field;
78using ::testing::IsEmpty;
Henrik Boström95250db2023-02-28 13:40:2479using ::testing::Le;
Amit Hilbuchaa584152019-02-07 01:09:5280using ::testing::Ne;
Amit Hilbuche2a284d2019-03-05 20:36:3181using ::testing::Pair;
Amit Hilbuchaa584152019-02-07 01:09:5282using ::testing::Property;
83using ::testing::SizeIs;
Henrik Boström88ddfdb2023-02-08 13:42:1284using ::testing::StartsWith;
Amit Hilbuchaa584152019-02-07 01:09:5285
86using cricket::MediaContentDescription;
87using cricket::RidDescription;
88using cricket::SimulcastDescription;
89using cricket::SimulcastLayer;
90using cricket::StreamParams;
91
92namespace cricket {
93
94std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
95 std::ostream& os, // no-presubmit-check TODO(webrtc:8982)
96 const SimulcastLayer& layer) {
97 if (layer.is_paused) {
98 os << "~";
99 }
100 return os << layer.rid;
101}
102
103} // namespace cricket
104
Amit Hilbuchaa584152019-02-07 01:09:52105namespace webrtc {
106
Mirko Bonadei6a489f22019-04-09 13:11:12107class PeerConnectionSimulcastTests : public ::testing::Test {
Amit Hilbuchaa584152019-02-07 01:09:52108 public:
109 PeerConnectionSimulcastTests()
Åsa Persson0587aae2023-03-31 14:49:14110 : pc_factory_(CreatePeerConnectionFactory(
111 rtc::Thread::Current(),
112 rtc::Thread::Current(),
113 rtc::Thread::Current(),
114 FakeAudioCaptureModule::Create(),
115 CreateBuiltinAudioEncoderFactory(),
116 CreateBuiltinAudioDecoderFactory(),
117 std::make_unique<
118 VideoEncoderFactoryTemplate<LibvpxVp8EncoderTemplateAdapter,
119 LibvpxVp9EncoderTemplateAdapter,
120 OpenH264EncoderTemplateAdapter,
121 LibaomAv1EncoderTemplateAdapter>>(),
122 std::make_unique<
123 VideoDecoderFactoryTemplate<LibvpxVp8DecoderTemplateAdapter,
124 LibvpxVp9DecoderTemplateAdapter,
125 OpenH264DecoderTemplateAdapter,
126 Dav1dDecoderTemplateAdapter>>(),
127 nullptr,
128 nullptr)) {}
Amit Hilbuchaa584152019-02-07 01:09:52129
130 rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
131 MockPeerConnectionObserver* observer) {
132 PeerConnectionInterface::RTCConfiguration config;
133 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
134 PeerConnectionDependencies pcd(observer);
Florent Castelli72424402022-04-06 01:45:10135 auto result =
136 pc_factory_->CreatePeerConnectionOrError(config, std::move(pcd));
137 EXPECT_TRUE(result.ok());
Niels Möllerafb246b2022-04-20 12:26:50138 observer->SetPeerConnectionInterface(result.value().get());
Florent Castelli72424402022-04-06 01:45:10139 return result.MoveValue();
Amit Hilbuchaa584152019-02-07 01:09:52140 }
141
142 std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWrapper() {
Mirko Bonadei317a1f02019-09-17 15:06:18143 auto observer = std::make_unique<MockPeerConnectionObserver>();
Amit Hilbuchaa584152019-02-07 01:09:52144 auto pc = CreatePeerConnection(observer.get());
Mirko Bonadei317a1f02019-09-17 15:06:18145 return std::make_unique<PeerConnectionWrapper>(pc_factory_, pc,
146 std::move(observer));
Amit Hilbuchaa584152019-02-07 01:09:52147 }
148
Amit Hilbuch619b2942019-02-26 23:55:19149 void ExchangeOfferAnswer(PeerConnectionWrapper* local,
150 PeerConnectionWrapper* remote,
151 const std::vector<SimulcastLayer>& answer_layers) {
152 auto offer = local->CreateOfferAndSetAsLocal();
153 // Remove simulcast as the second peer connection won't support it.
Amit Hilbuchaabd0362019-03-01 21:14:46154 RemoveSimulcast(offer.get());
Amit Hilbuch619b2942019-02-26 23:55:19155 std::string err;
156 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &err)) << err;
157 auto answer = remote->CreateAnswerAndSetAsLocal();
158 // Setup the answer to look like a server response.
159 auto mcd_answer = answer->description()->contents()[0].media_description();
160 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
161 for (const SimulcastLayer& layer : answer_layers) {
162 receive_layers.AddLayer(layer);
163 }
164 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &err)) << err;
165 }
166
Amit Hilbuchaa584152019-02-07 01:09:52167 rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
168 PeerConnectionWrapper* pc,
Florent Castellie1b685a2021-04-30 17:11:37169 const std::vector<SimulcastLayer>& layers,
170 cricket::MediaType media_type = cricket::MEDIA_TYPE_VIDEO) {
Amit Hilbuchaa584152019-02-07 01:09:52171 auto init = CreateTransceiverInit(layers);
Florent Castellie1b685a2021-04-30 17:11:37172 return pc->AddTransceiver(media_type, init);
Amit Hilbuchaa584152019-02-07 01:09:52173 }
174
Amit Hilbuchaa584152019-02-07 01:09:52175 void AddRequestToReceiveSimulcast(const std::vector<SimulcastLayer>& layers,
176 SessionDescriptionInterface* sd) {
177 auto mcd = sd->description()->contents()[0].media_description();
178 SimulcastDescription simulcast;
179 auto& receive_layers = simulcast.receive_layers();
180 for (const SimulcastLayer& layer : layers) {
181 receive_layers.AddLayer(layer);
182 }
183 mcd->set_simulcast_description(simulcast);
184 }
185
Amit Hilbuche2a284d2019-03-05 20:36:31186 void ValidateTransceiverParameters(
Amit Hilbuchaa584152019-02-07 01:09:52187 rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
188 const std::vector<SimulcastLayer>& layers) {
Amit Hilbuchaa584152019-02-07 01:09:52189 auto parameters = transceiver->sender()->GetParameters();
190 std::vector<SimulcastLayer> result_layers;
191 absl::c_transform(parameters.encodings, std::back_inserter(result_layers),
192 [](const RtpEncodingParameters& encoding) {
193 return SimulcastLayer(encoding.rid, !encoding.active);
194 });
195 EXPECT_THAT(result_layers, ElementsAreArray(layers));
Amit Hilbuchaa584152019-02-07 01:09:52196 }
197
198 private:
199 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
200};
201
202// Validates that RIDs are supported arguments when adding a transceiver.
203TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithRid) {
204 auto pc = CreatePeerConnectionWrapper();
205 auto layers = CreateLayers({"f"}, true);
206 auto transceiver = AddTransceiver(pc.get(), layers);
207 ASSERT_TRUE(transceiver);
208 auto parameters = transceiver->sender()->GetParameters();
209 // Single RID should be removed.
210 EXPECT_THAT(parameters.encodings,
Amit Hilbuch2297d332019-02-19 20:49:22211 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
Amit Hilbuchaa584152019-02-07 01:09:52212}
213
214TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithSimulcast) {
215 auto pc = CreatePeerConnectionWrapper();
216 auto layers = CreateLayers({"f", "h", "q"}, true);
217 auto transceiver = AddTransceiver(pc.get(), layers);
218 ASSERT_TRUE(transceiver);
Amit Hilbuche2a284d2019-03-05 20:36:31219 ValidateTransceiverParameters(transceiver, layers);
Amit Hilbuchaa584152019-02-07 01:09:52220}
221
222TEST_F(PeerConnectionSimulcastTests, RidsAreAutogeneratedIfNotProvided) {
223 auto pc = CreatePeerConnectionWrapper();
224 auto init = CreateTransceiverInit(CreateLayers({"f", "h", "q"}, true));
225 for (RtpEncodingParameters& parameters : init.send_encodings) {
226 parameters.rid = "";
227 }
228 auto transceiver = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
229 auto parameters = transceiver->sender()->GetParameters();
230 ASSERT_EQ(3u, parameters.encodings.size());
231 EXPECT_THAT(parameters.encodings,
Amit Hilbuch2297d332019-02-19 20:49:22232 Each(Field("rid", &RtpEncodingParameters::rid, Ne(""))));
Amit Hilbuchaa584152019-02-07 01:09:52233}
234
235// Validates that an error is returned when there is a mix of supplied and not
236// supplied RIDs in a call to AddTransceiver.
237TEST_F(PeerConnectionSimulcastTests, MustSupplyAllOrNoRidsInSimulcast) {
238 auto pc_wrapper = CreatePeerConnectionWrapper();
239 auto pc = pc_wrapper->pc();
240 // Cannot create a layer with empty RID. Remove the RID after init is created.
241 auto layers = CreateLayers({"f", "h", "remove"}, true);
242 auto init = CreateTransceiverInit(layers);
243 init.send_encodings[2].rid = "";
244 auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
245 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
246}
247
Amit Hilbuchf4770402019-04-08 21:11:57248// Validates that an error is returned when illegal RIDs are supplied.
249TEST_F(PeerConnectionSimulcastTests, ChecksForIllegalRidValues) {
250 auto pc_wrapper = CreatePeerConnectionWrapper();
251 auto pc = pc_wrapper->pc();
252 auto layers = CreateLayers({"f", "h", "~q"}, true);
253 auto init = CreateTransceiverInit(layers);
254 auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
255 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
256}
257
Amit Hilbuch2297d332019-02-19 20:49:22258// Validates that a single RID is removed from the encoding layer.
Amit Hilbuchaa584152019-02-07 01:09:52259TEST_F(PeerConnectionSimulcastTests, SingleRidIsRemovedFromSessionDescription) {
260 auto pc = CreatePeerConnectionWrapper();
261 auto transceiver = AddTransceiver(pc.get(), CreateLayers({"1"}, true));
262 auto offer = pc->CreateOfferAndSetAsLocal();
263 ASSERT_TRUE(offer);
264 auto contents = offer->description()->contents();
265 ASSERT_EQ(1u, contents.size());
266 EXPECT_THAT(contents[0].media_description()->streams(),
267 ElementsAre(Property(&StreamParams::has_rids, false)));
268}
269
270TEST_F(PeerConnectionSimulcastTests, SimulcastLayersRemovedFromTail) {
271 static_assert(
272 kMaxSimulcastStreams < 8,
273 "Test assumes that the platform does not allow 8 simulcast layers");
274 auto pc = CreatePeerConnectionWrapper();
275 auto layers = CreateLayers({"1", "2", "3", "4", "5", "6", "7", "8"}, true);
276 std::vector<SimulcastLayer> expected_layers;
277 std::copy_n(layers.begin(), kMaxSimulcastStreams,
278 std::back_inserter(expected_layers));
279 auto transceiver = AddTransceiver(pc.get(), layers);
Amit Hilbuche2a284d2019-03-05 20:36:31280 ValidateTransceiverParameters(transceiver, expected_layers);
Amit Hilbuchaa584152019-02-07 01:09:52281}
282
283// Checks that an offfer to send simulcast contains a SimulcastDescription.
284TEST_F(PeerConnectionSimulcastTests, SimulcastAppearsInSessionDescription) {
285 auto pc = CreatePeerConnectionWrapper();
286 std::vector<std::string> rids({"f", "h", "q"});
287 auto layers = CreateLayers(rids, true);
288 auto transceiver = AddTransceiver(pc.get(), layers);
289 auto offer = pc->CreateOffer();
290 ASSERT_TRUE(offer);
291 auto contents = offer->description()->contents();
292 ASSERT_EQ(1u, contents.size());
293 auto content = contents[0];
294 auto mcd = content.media_description();
295 ASSERT_TRUE(mcd->HasSimulcast());
296 auto simulcast = mcd->simulcast_description();
297 EXPECT_THAT(simulcast.receive_layers(), IsEmpty());
298 // The size is validated separately because GetAllLayers() flattens the list.
299 EXPECT_THAT(simulcast.send_layers(), SizeIs(3));
300 std::vector<SimulcastLayer> result = simulcast.send_layers().GetAllLayers();
301 EXPECT_THAT(result, ElementsAreArray(layers));
302 auto streams = mcd->streams();
303 ASSERT_EQ(1u, streams.size());
304 auto stream = streams[0];
305 EXPECT_FALSE(stream.has_ssrcs());
306 EXPECT_TRUE(stream.has_rids());
307 std::vector<std::string> result_rids;
308 absl::c_transform(stream.rids(), std::back_inserter(result_rids),
309 [](const RidDescription& rid) { return rid.rid; });
310 EXPECT_THAT(result_rids, ElementsAreArray(rids));
311}
312
313// Checks that Simulcast layers propagate to the sender parameters.
314TEST_F(PeerConnectionSimulcastTests, SimulcastLayersAreSetInSender) {
315 auto local = CreatePeerConnectionWrapper();
316 auto remote = CreatePeerConnectionWrapper();
317 auto layers = CreateLayers({"f", "h", "q"}, true);
318 auto transceiver = AddTransceiver(local.get(), layers);
319 auto offer = local->CreateOfferAndSetAsLocal();
Amit Hilbuche2a284d2019-03-05 20:36:31320 {
321 SCOPED_TRACE("after create offer");
322 ValidateTransceiverParameters(transceiver, layers);
323 }
Amit Hilbuchaa584152019-02-07 01:09:52324 // Remove simulcast as the second peer connection won't support it.
325 auto simulcast = RemoveSimulcast(offer.get());
326 std::string error;
327 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
328 auto answer = remote->CreateAnswerAndSetAsLocal();
329
330 // Setup an answer that mimics a server accepting simulcast.
331 auto mcd_answer = answer->description()->contents()[0].media_description();
332 mcd_answer->mutable_streams().clear();
333 auto simulcast_layers = simulcast.send_layers().GetAllLayers();
334 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
335 for (const auto& layer : simulcast_layers) {
336 receive_layers.AddLayer(layer);
337 }
338 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuche2a284d2019-03-05 20:36:31339 {
340 SCOPED_TRACE("after set remote");
341 ValidateTransceiverParameters(transceiver, layers);
342 }
Amit Hilbuchaa584152019-02-07 01:09:52343}
344
345// Checks that paused Simulcast layers propagate to the sender parameters.
346TEST_F(PeerConnectionSimulcastTests, PausedSimulcastLayersAreDisabledInSender) {
347 auto local = CreatePeerConnectionWrapper();
348 auto remote = CreatePeerConnectionWrapper();
349 auto layers = CreateLayers({"f", "h", "q"}, {true, false, true});
350 auto server_layers = CreateLayers({"f", "h", "q"}, {true, false, false});
351 RTC_DCHECK_EQ(layers.size(), server_layers.size());
352 auto transceiver = AddTransceiver(local.get(), layers);
353 auto offer = local->CreateOfferAndSetAsLocal();
Amit Hilbuche2a284d2019-03-05 20:36:31354 {
355 SCOPED_TRACE("after create offer");
356 ValidateTransceiverParameters(transceiver, layers);
357 }
Amit Hilbuchaa584152019-02-07 01:09:52358
359 // Remove simulcast as the second peer connection won't support it.
360 RemoveSimulcast(offer.get());
361 std::string error;
362 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
363 auto answer = remote->CreateAnswerAndSetAsLocal();
364
365 // Setup an answer that mimics a server accepting simulcast.
366 auto mcd_answer = answer->description()->contents()[0].media_description();
367 mcd_answer->mutable_streams().clear();
368 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
369 for (const SimulcastLayer& layer : server_layers) {
370 receive_layers.AddLayer(layer);
371 }
372 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuche2a284d2019-03-05 20:36:31373 {
374 SCOPED_TRACE("after set remote");
375 ValidateTransceiverParameters(transceiver, server_layers);
376 }
Amit Hilbuchaa584152019-02-07 01:09:52377}
378
379// Checks that when Simulcast is not supported by the remote party, then all
Amit Hilbuch2297d332019-02-19 20:49:22380// the layers (except the first) are removed.
381TEST_F(PeerConnectionSimulcastTests, SimulcastRejectedRemovesExtraLayers) {
Amit Hilbuchaa584152019-02-07 01:09:52382 auto local = CreatePeerConnectionWrapper();
383 auto remote = CreatePeerConnectionWrapper();
384 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
Amit Hilbuchaa584152019-02-07 01:09:52385 auto transceiver = AddTransceiver(local.get(), layers);
Amit Hilbuch619b2942019-02-26 23:55:19386 ExchangeOfferAnswer(local.get(), remote.get(), {});
Amit Hilbuch2297d332019-02-19 20:49:22387 auto parameters = transceiver->sender()->GetParameters();
388 // Should only have the first layer.
389 EXPECT_THAT(parameters.encodings,
390 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq("1"))));
Amit Hilbuchaa584152019-02-07 01:09:52391}
392
Amit Hilbuch2297d332019-02-19 20:49:22393// Checks that if Simulcast is supported by remote party, but some layers are
394// rejected, then only rejected layers are removed from the sender.
Amit Hilbuchaa584152019-02-07 01:09:52395TEST_F(PeerConnectionSimulcastTests, RejectedSimulcastLayersAreDeactivated) {
396 auto local = CreatePeerConnectionWrapper();
397 auto remote = CreatePeerConnectionWrapper();
Florent Castelli3fbf1e22019-07-04 15:09:05398 auto layers = CreateLayers({"1", "2", "3"}, true);
399 auto expected_layers = CreateLayers({"2", "3"}, true);
Amit Hilbuchaa584152019-02-07 01:09:52400 auto transceiver = AddTransceiver(local.get(), layers);
401 auto offer = local->CreateOfferAndSetAsLocal();
Amit Hilbuche2a284d2019-03-05 20:36:31402 {
403 SCOPED_TRACE("after create offer");
404 ValidateTransceiverParameters(transceiver, layers);
405 }
Amit Hilbuchaa584152019-02-07 01:09:52406 // Remove simulcast as the second peer connection won't support it.
407 auto removed_simulcast = RemoveSimulcast(offer.get());
408 std::string error;
409 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
410 auto answer = remote->CreateAnswerAndSetAsLocal();
411 auto mcd_answer = answer->description()->contents()[0].media_description();
412 // Setup the answer to look like a server response.
413 // Remove one of the layers to reject it in the answer.
414 auto simulcast_layers = removed_simulcast.send_layers().GetAllLayers();
415 simulcast_layers.erase(simulcast_layers.begin());
416 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
417 for (const auto& layer : simulcast_layers) {
418 receive_layers.AddLayer(layer);
419 }
420 ASSERT_TRUE(mcd_answer->HasSimulcast());
421 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuche2a284d2019-03-05 20:36:31422 {
423 SCOPED_TRACE("after set remote");
424 ValidateTransceiverParameters(transceiver, expected_layers);
425 }
Amit Hilbuchaa584152019-02-07 01:09:52426}
427
428// Checks that simulcast is set up correctly when the server sends an offer
429// requesting to receive simulcast.
430TEST_F(PeerConnectionSimulcastTests, ServerSendsOfferToReceiveSimulcast) {
431 auto local = CreatePeerConnectionWrapper();
432 auto remote = CreatePeerConnectionWrapper();
433 auto layers = CreateLayers({"f", "h", "q"}, true);
434 AddTransceiver(local.get(), layers);
435 auto offer = local->CreateOfferAndSetAsLocal();
436 // Remove simulcast as a sender and set it up as a receiver.
437 RemoveSimulcast(offer.get());
438 AddRequestToReceiveSimulcast(layers, offer.get());
439 std::string error;
440 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
441 auto transceiver = remote->pc()->GetTransceivers()[0];
Harald Alvestrand6060df52020-08-11 07:54:02442 transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
Amit Hilbuchaa584152019-02-07 01:09:52443 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
Amit Hilbuche2a284d2019-03-05 20:36:31444 ValidateTransceiverParameters(transceiver, layers);
Amit Hilbuchaa584152019-02-07 01:09:52445}
446
447// Checks that SetRemoteDescription doesn't attempt to associate a transceiver
448// when simulcast is requested by the server.
449TEST_F(PeerConnectionSimulcastTests, TransceiverIsNotRecycledWithSimulcast) {
450 auto local = CreatePeerConnectionWrapper();
451 auto remote = CreatePeerConnectionWrapper();
452 auto layers = CreateLayers({"f", "h", "q"}, true);
453 AddTransceiver(local.get(), layers);
454 auto offer = local->CreateOfferAndSetAsLocal();
455 // Remove simulcast as a sender and set it up as a receiver.
456 RemoveSimulcast(offer.get());
457 AddRequestToReceiveSimulcast(layers, offer.get());
458 // Call AddTrack so that a transceiver is created.
459 remote->AddVideoTrack("fake_track");
460 std::string error;
461 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
462 auto transceivers = remote->pc()->GetTransceivers();
463 ASSERT_EQ(2u, transceivers.size());
464 auto transceiver = transceivers[1];
Harald Alvestrand6060df52020-08-11 07:54:02465 transceiver->SetDirectionWithError(RtpTransceiverDirection::kSendRecv);
Amit Hilbuchaa584152019-02-07 01:09:52466 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
Amit Hilbuche2a284d2019-03-05 20:36:31467 ValidateTransceiverParameters(transceiver, layers);
Amit Hilbuchaa584152019-02-07 01:09:52468}
469
Amit Hilbuch619b2942019-02-26 23:55:19470// Checks that if the number of layers changes during negotiation, then any
471// outstanding get/set parameters transaction is invalidated.
472TEST_F(PeerConnectionSimulcastTests, ParametersAreInvalidatedWhenLayersChange) {
473 auto local = CreatePeerConnectionWrapper();
474 auto remote = CreatePeerConnectionWrapper();
475 auto layers = CreateLayers({"1", "2", "3"}, true);
476 auto transceiver = AddTransceiver(local.get(), layers);
477 auto parameters = transceiver->sender()->GetParameters();
478 ASSERT_EQ(3u, parameters.encodings.size());
479 // Response will reject simulcast altogether.
480 ExchangeOfferAnswer(local.get(), remote.get(), {});
481 auto result = transceiver->sender()->SetParameters(parameters);
482 EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type());
483}
484
485// Checks that even though negotiation modifies the sender's parameters, an
486// outstanding get/set parameters transaction is not invalidated.
487// This test negotiates twice because initial parameters before negotiation
488// is missing critical information and cannot be set on the sender.
489TEST_F(PeerConnectionSimulcastTests,
490 NegotiationDoesNotInvalidateParameterTransactions) {
491 auto local = CreatePeerConnectionWrapper();
492 auto remote = CreatePeerConnectionWrapper();
493 auto layers = CreateLayers({"1", "2", "3"}, true);
494 auto expected_layers = CreateLayers({"1", "2", "3"}, false);
495 auto transceiver = AddTransceiver(local.get(), layers);
496 ExchangeOfferAnswer(local.get(), remote.get(), expected_layers);
497
498 // Verify that negotiation does not invalidate the parameters.
499 auto parameters = transceiver->sender()->GetParameters();
500 ExchangeOfferAnswer(local.get(), remote.get(), expected_layers);
501
502 auto result = transceiver->sender()->SetParameters(parameters);
503 EXPECT_TRUE(result.ok());
Amit Hilbuche2a284d2019-03-05 20:36:31504 ValidateTransceiverParameters(transceiver, expected_layers);
Amit Hilbuch619b2942019-02-26 23:55:19505}
506
Philipp Hancke34887262023-06-01 17:07:50507// Tests that a simulcast answer is rejected if the RID extension is not
508// negotiated.
509TEST_F(PeerConnectionSimulcastTests, NegotiationDoesNotHaveRidExtensionFails) {
Amit Hilbuchaabd0362019-03-01 21:14:46510 auto local = CreatePeerConnectionWrapper();
511 auto remote = CreatePeerConnectionWrapper();
512 auto layers = CreateLayers({"1", "2", "3"}, true);
513 auto expected_layers = CreateLayers({"1"}, true);
514 auto transceiver = AddTransceiver(local.get(), layers);
515 auto offer = local->CreateOfferAndSetAsLocal();
516 // Remove simulcast as the second peer connection won't support it.
517 RemoveSimulcast(offer.get());
518 std::string err;
519 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &err)) << err;
520 auto answer = remote->CreateAnswerAndSetAsLocal();
521 // Setup the answer to look like a server response.
522 // Drop the RID header extension.
523 auto mcd_answer = answer->description()->contents()[0].media_description();
524 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
525 for (const SimulcastLayer& layer : layers) {
526 receive_layers.AddLayer(layer);
527 }
528 cricket::RtpHeaderExtensions extensions;
529 for (auto extension : mcd_answer->rtp_header_extensions()) {
530 if (extension.uri != RtpExtension::kRidUri) {
531 extensions.push_back(extension);
532 }
533 }
534 mcd_answer->set_rtp_header_extensions(extensions);
535 EXPECT_EQ(layers.size(), mcd_answer->simulcast_description()
536 .receive_layers()
537 .GetAllLayers()
538 .size());
Philipp Hancke34887262023-06-01 17:07:50539 EXPECT_FALSE(local->SetRemoteDescription(std::move(answer), &err)) << err;
Amit Hilbuchaabd0362019-03-01 21:14:46540}
Ying Wangef3998f2019-12-09 12:06:53541
Florent Castellie1b685a2021-04-30 17:11:37542TEST_F(PeerConnectionSimulcastTests, SimulcastAudioRejected) {
543 auto local = CreatePeerConnectionWrapper();
544 auto remote = CreatePeerConnectionWrapper();
545 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
546 auto transceiver =
547 AddTransceiver(local.get(), layers, cricket::MEDIA_TYPE_AUDIO);
548 // Should only have the first layer.
549 auto parameters = transceiver->sender()->GetParameters();
550 EXPECT_EQ(1u, parameters.encodings.size());
551 EXPECT_THAT(parameters.encodings,
552 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
553 ExchangeOfferAnswer(local.get(), remote.get(), {});
554 // Still have a single layer after negotiation
555 parameters = transceiver->sender()->GetParameters();
556 EXPECT_EQ(1u, parameters.encodings.size());
557 EXPECT_THAT(parameters.encodings,
558 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
559}
560
Harald Alvestrand1c580812022-07-04 09:41:24561// Check that modifying the offer to remove simulcast and at the same
562// time leaving in a RID line does not cause an exception.
563TEST_F(PeerConnectionSimulcastTests, SimulcastSldModificationRejected) {
564 auto local = CreatePeerConnectionWrapper();
565 auto remote = CreatePeerConnectionWrapper();
566 auto layers = CreateLayers({"1", "2", "3"}, true);
567 AddTransceiver(local.get(), layers);
568 auto offer = local->CreateOffer();
569 std::string as_string;
570 EXPECT_TRUE(offer->ToString(&as_string));
571 auto simulcast_marker = "a=rid:3 send\r\na=simulcast:send 1;2;3\r\n";
572 auto pos = as_string.find(simulcast_marker);
573 EXPECT_NE(pos, std::string::npos);
574 as_string.erase(pos, strlen(simulcast_marker));
575 SdpParseError parse_error;
576 auto modified_offer =
577 CreateSessionDescription(SdpType::kOffer, as_string, &parse_error);
578 EXPECT_TRUE(modified_offer);
579 EXPECT_TRUE(local->SetLocalDescription(std::move(modified_offer)));
580}
Amit Hilbuchaa584152019-02-07 01:09:52581} // namespace webrtc