blob: f9e3d932e22c861360f2d21e7b917c4314f9d288 [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,
177 ElementsAre(Field(&RtpEncodingParameters::rid, Eq(""))));
178}
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,
198 Each(Field(&RtpEncodingParameters::rid, Ne(""))));
199}
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
214// Validates that a single RID does not get negotiated.
215// This test is currently disabled because a single RID is not supported.
216TEST_F(PeerConnectionSimulcastTests, SingleRidIsRemovedFromSessionDescription) {
217 auto pc = CreatePeerConnectionWrapper();
218 auto transceiver = AddTransceiver(pc.get(), CreateLayers({"1"}, true));
219 auto offer = pc->CreateOfferAndSetAsLocal();
220 ASSERT_TRUE(offer);
221 auto contents = offer->description()->contents();
222 ASSERT_EQ(1u, contents.size());
223 EXPECT_THAT(contents[0].media_description()->streams(),
224 ElementsAre(Property(&StreamParams::has_rids, false)));
225}
226
227TEST_F(PeerConnectionSimulcastTests, SimulcastLayersRemovedFromTail) {
228 static_assert(
229 kMaxSimulcastStreams < 8,
230 "Test assumes that the platform does not allow 8 simulcast layers");
231 auto pc = CreatePeerConnectionWrapper();
232 auto layers = CreateLayers({"1", "2", "3", "4", "5", "6", "7", "8"}, true);
233 std::vector<SimulcastLayer> expected_layers;
234 std::copy_n(layers.begin(), kMaxSimulcastStreams,
235 std::back_inserter(expected_layers));
236 auto transceiver = AddTransceiver(pc.get(), layers);
237 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, expected_layers));
238}
239
240// Checks that an offfer to send simulcast contains a SimulcastDescription.
241TEST_F(PeerConnectionSimulcastTests, SimulcastAppearsInSessionDescription) {
242 auto pc = CreatePeerConnectionWrapper();
243 std::vector<std::string> rids({"f", "h", "q"});
244 auto layers = CreateLayers(rids, true);
245 auto transceiver = AddTransceiver(pc.get(), layers);
246 auto offer = pc->CreateOffer();
247 ASSERT_TRUE(offer);
248 auto contents = offer->description()->contents();
249 ASSERT_EQ(1u, contents.size());
250 auto content = contents[0];
251 auto mcd = content.media_description();
252 ASSERT_TRUE(mcd->HasSimulcast());
253 auto simulcast = mcd->simulcast_description();
254 EXPECT_THAT(simulcast.receive_layers(), IsEmpty());
255 // The size is validated separately because GetAllLayers() flattens the list.
256 EXPECT_THAT(simulcast.send_layers(), SizeIs(3));
257 std::vector<SimulcastLayer> result = simulcast.send_layers().GetAllLayers();
258 EXPECT_THAT(result, ElementsAreArray(layers));
259 auto streams = mcd->streams();
260 ASSERT_EQ(1u, streams.size());
261 auto stream = streams[0];
262 EXPECT_FALSE(stream.has_ssrcs());
263 EXPECT_TRUE(stream.has_rids());
264 std::vector<std::string> result_rids;
265 absl::c_transform(stream.rids(), std::back_inserter(result_rids),
266 [](const RidDescription& rid) { return rid.rid; });
267 EXPECT_THAT(result_rids, ElementsAreArray(rids));
268}
269
270// Checks that Simulcast layers propagate to the sender parameters.
271TEST_F(PeerConnectionSimulcastTests, SimulcastLayersAreSetInSender) {
272 auto local = CreatePeerConnectionWrapper();
273 auto remote = CreatePeerConnectionWrapper();
274 auto layers = CreateLayers({"f", "h", "q"}, true);
275 auto transceiver = AddTransceiver(local.get(), layers);
276 auto offer = local->CreateOfferAndSetAsLocal();
277 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
278
279 // Remove simulcast as the second peer connection won't support it.
280 auto simulcast = RemoveSimulcast(offer.get());
281 std::string error;
282 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
283 auto answer = remote->CreateAnswerAndSetAsLocal();
284
285 // Setup an answer that mimics a server accepting simulcast.
286 auto mcd_answer = answer->description()->contents()[0].media_description();
287 mcd_answer->mutable_streams().clear();
288 auto simulcast_layers = simulcast.send_layers().GetAllLayers();
289 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
290 for (const auto& layer : simulcast_layers) {
291 receive_layers.AddLayer(layer);
292 }
293 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
294 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
295}
296
297// Checks that paused Simulcast layers propagate to the sender parameters.
298TEST_F(PeerConnectionSimulcastTests, PausedSimulcastLayersAreDisabledInSender) {
299 auto local = CreatePeerConnectionWrapper();
300 auto remote = CreatePeerConnectionWrapper();
301 auto layers = CreateLayers({"f", "h", "q"}, {true, false, true});
302 auto server_layers = CreateLayers({"f", "h", "q"}, {true, false, false});
303 RTC_DCHECK_EQ(layers.size(), server_layers.size());
304 auto transceiver = AddTransceiver(local.get(), layers);
305 auto offer = local->CreateOfferAndSetAsLocal();
306 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
307
308 // Remove simulcast as the second peer connection won't support it.
309 RemoveSimulcast(offer.get());
310 std::string error;
311 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
312 auto answer = remote->CreateAnswerAndSetAsLocal();
313
314 // Setup an answer that mimics a server accepting simulcast.
315 auto mcd_answer = answer->description()->contents()[0].media_description();
316 mcd_answer->mutable_streams().clear();
317 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
318 for (const SimulcastLayer& layer : server_layers) {
319 receive_layers.AddLayer(layer);
320 }
321 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
322 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, server_layers));
323}
324
325// Checks that when Simulcast is not supported by the remote party, then all
326// the layers (except the first) are marked as disabled.
327TEST_F(PeerConnectionSimulcastTests, SimulcastRejectedDisablesExtraLayers) {
328 auto local = CreatePeerConnectionWrapper();
329 auto remote = CreatePeerConnectionWrapper();
330 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
331 // The number of layers does not change.
332 auto expected_layers = CreateLayers({"1", "2", "3", "4"}, false);
333 RTC_DCHECK_EQ(layers.size(), expected_layers.size());
334 expected_layers[0].is_paused = false;
335 auto transceiver = AddTransceiver(local.get(), layers);
336 auto offer = local->CreateOfferAndSetAsLocal();
337 // Remove simulcast as the second peer connection won't support it.
338 RemoveSimulcast(offer.get());
339 std::string error;
340 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
341 auto answer = remote->CreateAnswerAndSetAsLocal();
342 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
343 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, expected_layers));
344}
345
346// Checks that if Simulcast is supported by remote party, but some layer is
347// rejected, then only that layer is marked as disabled.
348TEST_F(PeerConnectionSimulcastTests, RejectedSimulcastLayersAreDeactivated) {
349 auto local = CreatePeerConnectionWrapper();
350 auto remote = CreatePeerConnectionWrapper();
351 auto layers = CreateLayers({"1", "2", "3", "4"}, true);
352 auto transceiver = AddTransceiver(local.get(), layers);
353 auto offer = local->CreateOfferAndSetAsLocal();
354 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
355 // Remove simulcast as the second peer connection won't support it.
356 auto removed_simulcast = RemoveSimulcast(offer.get());
357 std::string error;
358 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
359 auto answer = remote->CreateAnswerAndSetAsLocal();
360 auto mcd_answer = answer->description()->contents()[0].media_description();
361 // Setup the answer to look like a server response.
362 // Remove one of the layers to reject it in the answer.
363 auto simulcast_layers = removed_simulcast.send_layers().GetAllLayers();
364 simulcast_layers.erase(simulcast_layers.begin());
365 auto& receive_layers = mcd_answer->simulcast_description().receive_layers();
366 for (const auto& layer : simulcast_layers) {
367 receive_layers.AddLayer(layer);
368 }
369 ASSERT_TRUE(mcd_answer->HasSimulcast());
370 EXPECT_TRUE(local->SetRemoteDescription(std::move(answer), &error)) << error;
371 layers[0].is_paused = true;
372 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
373}
374
375// Checks that simulcast is set up correctly when the server sends an offer
376// requesting to receive simulcast.
377TEST_F(PeerConnectionSimulcastTests, ServerSendsOfferToReceiveSimulcast) {
378 auto local = CreatePeerConnectionWrapper();
379 auto remote = CreatePeerConnectionWrapper();
380 auto layers = CreateLayers({"f", "h", "q"}, true);
381 AddTransceiver(local.get(), layers);
382 auto offer = local->CreateOfferAndSetAsLocal();
383 // Remove simulcast as a sender and set it up as a receiver.
384 RemoveSimulcast(offer.get());
385 AddRequestToReceiveSimulcast(layers, offer.get());
386 std::string error;
387 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
388 auto transceiver = remote->pc()->GetTransceivers()[0];
389 transceiver->SetDirection(RtpTransceiverDirection::kSendRecv);
390 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
391 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
392}
393
394// Checks that SetRemoteDescription doesn't attempt to associate a transceiver
395// when simulcast is requested by the server.
396TEST_F(PeerConnectionSimulcastTests, TransceiverIsNotRecycledWithSimulcast) {
397 auto local = CreatePeerConnectionWrapper();
398 auto remote = CreatePeerConnectionWrapper();
399 auto layers = CreateLayers({"f", "h", "q"}, true);
400 AddTransceiver(local.get(), layers);
401 auto offer = local->CreateOfferAndSetAsLocal();
402 // Remove simulcast as a sender and set it up as a receiver.
403 RemoveSimulcast(offer.get());
404 AddRequestToReceiveSimulcast(layers, offer.get());
405 // Call AddTrack so that a transceiver is created.
406 remote->AddVideoTrack("fake_track");
407 std::string error;
408 EXPECT_TRUE(remote->SetRemoteDescription(std::move(offer), &error)) << error;
409 auto transceivers = remote->pc()->GetTransceivers();
410 ASSERT_EQ(2u, transceivers.size());
411 auto transceiver = transceivers[1];
412 transceiver->SetDirection(RtpTransceiverDirection::kSendRecv);
413 EXPECT_TRUE(remote->CreateAnswerAndSetAsLocal());
414 EXPECT_TRUE(ValidateTransceiverParameters(transceiver, layers));
415}
416
417} // namespace webrtc