blob: 695d249cd94f2acac2569e14b9abcd0e998ea569 [file] [log] [blame]
Amit Hilbuchaa584152019-02-06 17:09:52 -08001/*
2 * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <ostream> // no-presubmit-check TODO(webrtc:8982)
12
13#include "absl/algorithm/container.h"
14#include "absl/memory/memory.h"
15#include "api/audio_codecs/builtin_audio_decoder_factory.h"
16#include "api/audio_codecs/builtin_audio_encoder_factory.h"
17#include "api/create_peerconnection_factory.h"
18#include "api/rtp_transceiver_interface.h"
19#include "api/video_codecs/builtin_video_decoder_factory.h"
20#include "api/video_codecs/builtin_video_encoder_factory.h"
21#include "pc/peer_connection.h"
22#include "pc/peer_connection_wrapper.h"
23#include "pc/test/fake_audio_capture_module.h"
24#include "pc/test/mock_peer_connection_observers.h"
25#include "rtc_base/gunit.h"
26#include "test/gmock.h"
27
28using ::testing::Contains;
29using ::testing::Each;
30using ::testing::ElementsAre;
31using ::testing::ElementsAreArray;
32using ::testing::Eq;
33using ::testing::Field;
34using ::testing::IsEmpty;
35using ::testing::Ne;
36using ::testing::Property;
37using ::testing::SizeIs;
38
39using cricket::MediaContentDescription;
40using cricket::RidDescription;
41using cricket::SimulcastDescription;
42using cricket::SimulcastLayer;
43using cricket::StreamParams;
44
45namespace cricket {
46
47std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
48 std::ostream& os, // no-presubmit-check TODO(webrtc:8982)
49 const SimulcastLayer& layer) {
50 if (layer.is_paused) {
51 os << "~";
52 }
53 return os << layer.rid;
54}
55
56} // namespace cricket
57
58namespace {
59
60std::vector<SimulcastLayer> CreateLayers(const std::vector<std::string>& rids,
61 const std::vector<bool>& active) {
62 RTC_DCHECK_EQ(rids.size(), active.size());
63 std::vector<SimulcastLayer> result;
64 absl::c_transform(rids, active, std::back_inserter(result),
65 [](const std::string& rid, bool is_active) {
66 return SimulcastLayer(rid, !is_active);
67 });
68 return result;
69}
70std::vector<SimulcastLayer> CreateLayers(const std::vector<std::string>& rids,
71 bool active) {
72 return CreateLayers(rids, std::vector<bool>(rids.size(), active));
73}
74
75} // namespace
76namespace webrtc {
77
78class PeerConnectionSimulcastTests : public testing::Test {
79 public:
80 PeerConnectionSimulcastTests()
81 : pc_factory_(
82 CreatePeerConnectionFactory(rtc::Thread::Current(),
83 rtc::Thread::Current(),
84 rtc::Thread::Current(),
85 FakeAudioCaptureModule::Create(),
86 CreateBuiltinAudioEncoderFactory(),
87 CreateBuiltinAudioDecoderFactory(),
88 CreateBuiltinVideoEncoderFactory(),
89 CreateBuiltinVideoDecoderFactory(),
90 nullptr,
91 nullptr)) {}
92
93 rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
94 MockPeerConnectionObserver* observer) {
95 PeerConnectionInterface::RTCConfiguration config;
96 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
97 PeerConnectionDependencies pcd(observer);
98 auto pc = pc_factory_->CreatePeerConnection(config, std::move(pcd));
99 EXPECT_TRUE(pc);
100 observer->SetPeerConnectionInterface(pc);
101 return pc;
102 }
103
104 std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWrapper() {
105 auto observer = absl::make_unique<MockPeerConnectionObserver>();
106 auto pc = CreatePeerConnection(observer.get());
107 return absl::make_unique<PeerConnectionWrapper>(pc_factory_, pc,
108 std::move(observer));
109 }
110
111 RtpTransceiverInit CreateTransceiverInit(
112 const std::vector<SimulcastLayer>& layers) {
113 RtpTransceiverInit init;
114 for (const SimulcastLayer& layer : layers) {
115 RtpEncodingParameters encoding;
116 encoding.rid = layer.rid;
117 encoding.active = !layer.is_paused;
118 init.send_encodings.push_back(encoding);
119 }
120 return init;
121 }
122
123 rtc::scoped_refptr<RtpTransceiverInterface> AddTransceiver(
124 PeerConnectionWrapper* pc,
125 const std::vector<SimulcastLayer>& layers) {
126 auto init = CreateTransceiverInit(layers);
127 return pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
128 }
129
130 SimulcastDescription RemoveSimulcast(SessionDescriptionInterface* sd) {
131 auto mcd = sd->description()->contents()[0].media_description();
132 auto result = mcd->simulcast_description();
133 mcd->set_simulcast_description(SimulcastDescription());
134 return result;
135 }
136
137 void AddRequestToReceiveSimulcast(const std::vector<SimulcastLayer>& layers,
138 SessionDescriptionInterface* sd) {
139 auto mcd = sd->description()->contents()[0].media_description();
140 SimulcastDescription simulcast;
141 auto& receive_layers = simulcast.receive_layers();
142 for (const SimulcastLayer& layer : layers) {
143 receive_layers.AddLayer(layer);
144 }
145 mcd->set_simulcast_description(simulcast);
146 }
147
148 bool ValidateTransceiverParameters(
149 rtc::scoped_refptr<RtpTransceiverInterface> transceiver,
150 const std::vector<SimulcastLayer>& layers) {
151 bool errors_before = ::testing::Test::HasFailure();
152 auto parameters = transceiver->sender()->GetParameters();
153 std::vector<SimulcastLayer> result_layers;
154 absl::c_transform(parameters.encodings, std::back_inserter(result_layers),
155 [](const RtpEncodingParameters& encoding) {
156 return SimulcastLayer(encoding.rid, !encoding.active);
157 });
158 EXPECT_THAT(result_layers, ElementsAreArray(layers));
159 // If there were errors before this code ran, we cannot tell if this
160 // validation succeeded or not.
161 return errors_before || !::testing::Test::HasFailure();
162 }
163
164 private:
165 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
166};
167
168// Validates that RIDs are supported arguments when adding a transceiver.
169TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithRid) {
170 auto pc = CreatePeerConnectionWrapper();
171 auto layers = CreateLayers({"f"}, true);
172 auto transceiver = AddTransceiver(pc.get(), layers);
173 ASSERT_TRUE(transceiver);
174 auto parameters = transceiver->sender()->GetParameters();
175 // Single RID should be removed.
176 EXPECT_THAT(parameters.encodings,
Amit Hilbuch2297d332019-02-19 12:49:22 -0800177 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq(""))));
Amit Hilbuchaa584152019-02-06 17:09:52 -0800178}
179
180TEST_F(PeerConnectionSimulcastTests, CanCreateTransceiverWithSimulcast) {
181 auto pc = CreatePeerConnectionWrapper();
182 auto layers = CreateLayers({"f", "h", "q"}, true);
183 auto transceiver = AddTransceiver(pc.get(), layers);
184 ASSERT_TRUE(transceiver);
185 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
186}
187
188TEST_F(PeerConnectionSimulcastTests, RidsAreAutogeneratedIfNotProvided) {
189 auto pc = CreatePeerConnectionWrapper();
190 auto init = CreateTransceiverInit(CreateLayers({"f", "h", "q"}, true));
191 for (RtpEncodingParameters& parameters : init.send_encodings) {
192 parameters.rid = "";
193 }
194 auto transceiver = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
195 auto parameters = transceiver->sender()->GetParameters();
196 ASSERT_EQ(3u, parameters.encodings.size());
197 EXPECT_THAT(parameters.encodings,
Amit Hilbuch2297d332019-02-19 12:49:22 -0800198 Each(Field("rid", &RtpEncodingParameters::rid, Ne(""))));
Amit Hilbuchaa584152019-02-06 17:09:52 -0800199}
200
201// Validates that an error is returned when there is a mix of supplied and not
202// supplied RIDs in a call to AddTransceiver.
203TEST_F(PeerConnectionSimulcastTests, MustSupplyAllOrNoRidsInSimulcast) {
204 auto pc_wrapper = CreatePeerConnectionWrapper();
205 auto pc = pc_wrapper->pc();
206 // Cannot create a layer with empty RID. Remove the RID after init is created.
207 auto layers = CreateLayers({"f", "h", "remove"}, true);
208 auto init = CreateTransceiverInit(layers);
209 init.send_encodings[2].rid = "";
210 auto error = pc->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
211 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.error().type());
212}
213
Amit Hilbuch2297d332019-02-19 12:49:22 -0800214// Validates that a single RID is removed from the encoding layer.
Amit Hilbuchaa584152019-02-06 17:09:52 -0800215TEST_F(PeerConnectionSimulcastTests, SingleRidIsRemovedFromSessionDescription) {
216 auto pc = CreatePeerConnectionWrapper();
217 auto transceiver = AddTransceiver(pc.get(), CreateLayers({"1"}, true));
218 auto offer = pc->CreateOfferAndSetAsLocal();
219 ASSERT_TRUE(offer);
220 auto contents = offer->description()->contents();
221 ASSERT_EQ(1u, contents.size());
222 EXPECT_THAT(contents[0].media_description()->streams(),
223 ElementsAre(Property(&StreamParams::has_rids, false)));
224}
225
226TEST_F(PeerConnectionSimulcastTests, SimulcastLayersRemovedFromTail) {
227 static_assert(
228 kMaxSimulcastStreams < 8,
229 "Test assumes that the platform does not allow 8 simulcast layers");
230 auto pc = CreatePeerConnectionWrapper();
231 auto layers = CreateLayers({"1", "2", "3", "4", "5", "6", "7", "8"}, true);
232 std::vector<SimulcastLayer> expected_layers;
233 std::copy_n(layers.begin(), kMaxSimulcastStreams,
234 std::back_inserter(expected_layers));
235 auto transceiver = AddTransceiver(pc.get(), layers);
236 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, expected_layers));
237}
238
239// Checks that an offfer to send simulcast contains a SimulcastDescription.
240TEST_F(PeerConnectionSimulcastTests, SimulcastAppearsInSessionDescription) {
241 auto pc = CreatePeerConnectionWrapper();
242 std::vector<std::string> rids({"f", "h", "q"});
243 auto layers = CreateLayers(rids, true);
244 auto transceiver = AddTransceiver(pc.get(), layers);
245 auto offer = pc->CreateOffer();
246 ASSERT_TRUE(offer);
247 auto contents = offer->description()->contents();
248 ASSERT_EQ(1u, contents.size());
249 auto content = contents[0];
250 auto mcd = content.media_description();
251 ASSERT_TRUE(mcd->HasSimulcast());
252 auto simulcast = mcd->simulcast_description();
253 EXPECT_THAT(simulcast.receive_layers(), IsEmpty());
254 // The size is validated separately because GetAllLayers() flattens the list.
255 EXPECT_THAT(simulcast.send_layers(), SizeIs(3));
256 std::vector<SimulcastLayer> result = simulcast.send_layers().GetAllLayers();
257 EXPECT_THAT(result, ElementsAreArray(layers));
258 auto streams = mcd->streams();
259 ASSERT_EQ(1u, streams.size());
260 auto stream = streams[0];
261 EXPECT_FALSE(stream.has_ssrcs());
262 EXPECT_TRUE(stream.has_rids());
263 std::vector<std::string> result_rids;
264 absl::c_transform(stream.rids(), std::back_inserter(result_rids),
265 [](const RidDescription& rid) { return rid.rid; });
266 EXPECT_THAT(result_rids, ElementsAreArray(rids));
267}
268
269// Checks that Simulcast layers propagate to the sender parameters.
270TEST_F(PeerConnectionSimulcastTests, SimulcastLayersAreSetInSender) {
271 auto local = CreatePeerConnectionWrapper();
272 auto remote = CreatePeerConnectionWrapper();
273 auto layers = CreateLayers({"f", "h", "q"}, true);
274 auto transceiver = AddTransceiver(local.get(), layers);
275 auto offer = local->CreateOfferAndSetAsLocal();
276 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
277
278 // Remove simulcast as the second peer connection won't support it.
279 auto simulcast = RemoveSimulcast(offer.get());
280 std::string error;
281 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
282 auto answer = remote->CreateAnswerAndSetAsLocal();
283
284 // Setup an answer that mimics a server accepting simulcast.
285 auto mcd_answer = answer->description()->contents()[0].media_description();
286 mcd_answer->mutable_streams().clear();
287 auto simulcast_layers = simulcast.send_layers().GetAllLayers();
288 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
289 for (const auto& layer : simulcast_layers) {
290 receive_layers.AddLayer(layer);
291 }
292 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
293 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
294}
295
296// Checks that paused Simulcast layers propagate to the sender parameters.
297TEST_F(PeerConnectionSimulcastTests, PausedSimulcastLayersAreDisabledInSender) {
298 auto local = CreatePeerConnectionWrapper();
299 auto remote = CreatePeerConnectionWrapper();
300 auto layers = CreateLayers({"f", "h", "q"}, {true, false, true});
301 auto server_layers = CreateLayers({"f", "h", "q"}, {true, false, false});
302 RTC_DCHECK_EQ(layers.size(), server_layers.size());
303 auto transceiver = AddTransceiver(local.get(), layers);
304 auto offer = local->CreateOfferAndSetAsLocal();
305 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
306
307 // Remove simulcast as the second peer connection won't support it.
308 RemoveSimulcast(offer.get());
309 std::string error;
310 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
311 auto answer = remote->CreateAnswerAndSetAsLocal();
312
313 // Setup an answer that mimics a server accepting simulcast.
314 auto mcd_answer = answer->description()->contents()[0].media_description();
315 mcd_answer->mutable_streams().clear();
316 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
317 for (const SimulcastLayer& layer : server_layers) {
318 receive_layers.AddLayer(layer);
319 }
320 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
321 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, server_layers));
322}
323
324// Checks that when Simulcast is not supported by the remote party, then all
Amit Hilbuch2297d332019-02-19 12:49:22 -0800325// the layers (except the first) are removed.
326TEST_F(PeerConnectionSimulcastTests, SimulcastRejectedRemovesExtraLayers) {
Amit Hilbuchaa584152019-02-06 17:09:52 -0800327 auto local = CreatePeerConnectionWrapper();
328 auto remote = CreatePeerConnectionWrapper();
329 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
330 // The number of layers does not change.
331 auto expected_layers = CreateLayers({"1", "2", "3", "4"}, false);
332 RTC_DCHECK_EQ(layers.size(), expected_layers.size());
333 expected_layers[0].is_paused = false;
334 auto transceiver = AddTransceiver(local.get(), layers);
335 auto offer = local->CreateOfferAndSetAsLocal();
336 // Remove simulcast as the second peer connection won't support it.
337 RemoveSimulcast(offer.get());
338 std::string error;
339 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
340 auto answer = remote->CreateAnswerAndSetAsLocal();
341 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuch2297d332019-02-19 12:49:22 -0800342 auto parameters = transceiver->sender()->GetParameters();
343 // Should only have the first layer.
344 EXPECT_THAT(parameters.encodings,
345 ElementsAre(Field("rid", &RtpEncodingParameters::rid, Eq("1"))));
Amit Hilbuchaa584152019-02-06 17:09:52 -0800346}
347
Amit Hilbuch2297d332019-02-19 12:49:22 -0800348// Checks that if Simulcast is supported by remote party, but some layers are
349// rejected, then only rejected layers are removed from the sender.
Amit Hilbuchaa584152019-02-06 17:09:52 -0800350TEST_F(PeerConnectionSimulcastTests, RejectedSimulcastLayersAreDeactivated) {
351 auto local = CreatePeerConnectionWrapper();
352 auto remote = CreatePeerConnectionWrapper();
353 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
Amit Hilbuch2297d332019-02-19 12:49:22 -0800354 auto expected_layers = CreateLayers({"2", "3", "4"}, true);
Amit Hilbuchaa584152019-02-06 17:09:52 -0800355 auto transceiver = AddTransceiver(local.get(), layers);
356 auto offer = local->CreateOfferAndSetAsLocal();
357 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
358 // Remove simulcast as the second peer connection won't support it.
359 auto removed_simulcast = RemoveSimulcast(offer.get());
360 std::string error;
361 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
362 auto answer = remote->CreateAnswerAndSetAsLocal();
363 auto mcd_answer = answer->description()->contents()[0].media_description();
364 // Setup the answer to look like a server response.
365 // Remove one of the layers to reject it in the answer.
366 auto simulcast_layers = removed_simulcast.send_layers().GetAllLayers();
367 simulcast_layers.erase(simulcast_layers.begin());
368 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
369 for (const auto& layer : simulcast_layers) {
370 receive_layers.AddLayer(layer);
371 }
372 ASSERT_TRUE(mcd_answer->HasSimulcast());
373 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
Amit Hilbuch2297d332019-02-19 12:49:22 -0800374 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, expected_layers));
Amit Hilbuchaa584152019-02-06 17:09:52 -0800375}
376
377// Checks that simulcast is set up correctly when the server sends an offer
378// requesting to receive simulcast.
379TEST_F(PeerConnectionSimulcastTests, ServerSendsOfferToReceiveSimulcast) {
380 auto local = CreatePeerConnectionWrapper();
381 auto remote = CreatePeerConnectionWrapper();
382 auto layers = CreateLayers({"f", "h", "q"}, true);
383 AddTransceiver(local.get(), layers);
384 auto offer = local->CreateOfferAndSetAsLocal();
385 // Remove simulcast as a sender and set it up as a receiver.
386 RemoveSimulcast(offer.get());
387 AddRequestToReceiveSimulcast(layers, offer.get());
388 std::string error;
389 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
390 auto transceiver = remote->pc()->GetTransceivers()[0];
391 transceiver->SetDirection(RtpTransceiverDirection::kSendRecv);
392 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
393 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
394}
395
396// Checks that SetRemoteDescription doesn't attempt to associate a transceiver
397// when simulcast is requested by the server.
398TEST_F(PeerConnectionSimulcastTests, TransceiverIsNotRecycledWithSimulcast) {
399 auto local = CreatePeerConnectionWrapper();
400 auto remote = CreatePeerConnectionWrapper();
401 auto layers = CreateLayers({"f", "h", "q"}, true);
402 AddTransceiver(local.get(), layers);
403 auto offer = local->CreateOfferAndSetAsLocal();
404 // Remove simulcast as a sender and set it up as a receiver.
405 RemoveSimulcast(offer.get());
406 AddRequestToReceiveSimulcast(layers, offer.get());
407 // Call AddTrack so that a transceiver is created.
408 remote->AddVideoTrack("fake_track");
409 std::string error;
410 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
411 auto transceivers = remote->pc()->GetTransceivers();
412 ASSERT_EQ(2u, transceivers.size());
413 auto transceiver = transceivers[1];
414 transceiver->SetDirection(RtpTransceiverDirection::kSendRecv);
415 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
416 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
417}
418
419} // namespace webrtc