blob: f078144d4f2852c985e6fc89d3f7de8d237ec2a0 [file] [log] [blame]
Steve Anton8d3444d2017-10-20 22:30:511/*
2 * Copyright 2017 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// This file contains tests that check the interaction between the
12// PeerConnection and the underlying media engine, as well as tests that check
13// the media-related aspects of SDP.
14
Mirko Bonadei317a1f02019-09-17 15:06:1815#include <memory>
Steve Anton8d3444d2017-10-20 22:30:5116#include <tuple>
17
Steve Anton64b626b2019-01-29 01:25:2618#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 13:38:5019#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 17:11:0020#include "api/call/call_factory_interface.h"
Danil Chapovalov9da25bd2019-06-20 08:19:4221#include "api/rtc_event_log/rtc_event_log_factory.h"
22#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 17:11:0023#include "media/base/fake_media_engine.h"
24#include "p2p/base/fake_port_allocator.h"
25#include "pc/media_session.h"
26#include "pc/peer_connection_wrapper.h"
27#include "pc/rtp_media_utils.h"
28#include "pc/sdp_utils.h"
Steve Anton8d3444d2017-10-20 22:30:5129#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0030#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 22:30:5131#endif
Steve Anton10542f22019-01-11 17:11:0032#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 22:30:5133#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0034#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 22:30:5135#include "test/gmock.h"
36
37namespace webrtc {
38
39using cricket::FakeMediaEngine;
40using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
41using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
42using ::testing::Bool;
43using ::testing::Combine;
Steve Anton8d3444d2017-10-20 22:30:5144using ::testing::ElementsAre;
Jonas Olssona4d87372019-07-05 17:08:3345using ::testing::Values;
Steve Anton8d3444d2017-10-20 22:30:5146
47class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
48 public:
49 using PeerConnectionWrapper::PeerConnectionWrapper;
50
51 FakeMediaEngine* media_engine() { return media_engine_; }
52 void set_media_engine(FakeMediaEngine* media_engine) {
53 media_engine_ = media_engine;
54 }
55
56 private:
57 FakeMediaEngine* media_engine_;
58};
59
Steve Antonad7bffc2018-01-22 18:21:5660class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 22:30:5161 protected:
62 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
63
Steve Antonad7bffc2018-01-22 18:21:5664 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
65 : vss_(new rtc::VirtualSocketServer()),
66 main_(vss_.get()),
67 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 22:30:5168#ifdef WEBRTC_ANDROID
69 InitializeAndroidObjects();
70#endif
71 }
72
73 WrapperPtr CreatePeerConnection() {
74 return CreatePeerConnection(RTCConfiguration());
75 }
76
Florent Castelli2d9d82e2019-04-23 17:25:5177 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 15:06:1878 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 17:25:5179 }
80
81 WrapperPtr CreatePeerConnection(
82 std::unique_ptr<FakeMediaEngine> media_engine) {
83 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
84 }
85
Anton Sukhanov98a462c2018-10-17 20:15:4286 // Creates PeerConnectionFactory and PeerConnection for given configuration.
Florent Castelli2d9d82e2019-04-23 17:25:5187 WrapperPtr CreatePeerConnection(
88 const RTCConfiguration& config,
89 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 22:30:5190 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 20:15:4291
92 PeerConnectionFactoryDependencies factory_dependencies;
93
94 factory_dependencies.network_thread = rtc::Thread::Current();
95 factory_dependencies.worker_thread = rtc::Thread::Current();
96 factory_dependencies.signaling_thread = rtc::Thread::Current();
Danil Chapovalov9da25bd2019-06-20 08:19:4297 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Anton Sukhanov98a462c2018-10-17 20:15:4298 factory_dependencies.media_engine = std::move(media_engine);
99 factory_dependencies.call_factory = CreateCallFactory();
Danil Chapovalov9da25bd2019-06-20 08:19:42100 factory_dependencies.event_log_factory =
Mirko Bonadei317a1f02019-09-17 15:06:18101 std::make_unique<RtcEventLogFactory>(
Danil Chapovalov9da25bd2019-06-20 08:19:42102 factory_dependencies.task_queue_factory.get());
Anton Sukhanov98a462c2018-10-17 20:15:42103
104 auto pc_factory =
105 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 22:30:51106
Mirko Bonadei317a1f02019-09-17 15:06:18107 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 22:30:51108 rtc::Thread::Current(), nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:18109 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 18:21:56110 auto modified_config = config;
111 modified_config.sdp_semantics = sdp_semantics_;
112 auto pc = pc_factory->CreatePeerConnection(modified_config,
113 std::move(fake_port_allocator),
114 nullptr, observer.get());
Steve Anton8d3444d2017-10-20 22:30:51115 if (!pc) {
116 return nullptr;
117 }
118
Yves Gerey4e933292018-10-31 14:36:05119 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 15:06:18120 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 22:30:51121 pc_factory, pc, std::move(observer));
122 wrapper->set_media_engine(media_engine_ptr);
123 return wrapper;
124 }
125
126 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24127 // track (but no video).
128 template <typename... Args>
129 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
130 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
131 if (!wrapper) {
132 return nullptr;
133 }
134 wrapper->AddAudioTrack("a");
135 return wrapper;
136 }
137
Florent Castelli2d9d82e2019-04-23 17:25:51138 // Accepts the same arguments as CreatePeerConnection and adds default video
139 // track (but no audio).
140 template <typename... Args>
141 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
142 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
143 if (!wrapper) {
144 return nullptr;
145 }
146 wrapper->AddVideoTrack("v");
147 return wrapper;
148 }
149
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24150 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 22:30:51151 // and video tracks.
152 template <typename... Args>
153 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
154 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
155 if (!wrapper) {
156 return nullptr;
157 }
158 wrapper->AddAudioTrack("a");
159 wrapper->AddVideoTrack("v");
160 return wrapper;
161 }
162
Steve Anton4e70a722017-11-28 22:57:10163 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 22:30:51164 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 18:21:56165 cricket::MediaType media_type) {
166 auto* content =
167 cricket::GetFirstMediaContent(sdesc->description(), media_type);
168 RTC_DCHECK(content);
169 return content->media_description()->direction();
170 }
171
172 bool IsUnifiedPlan() const {
173 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 22:30:51174 }
175
176 std::unique_ptr<rtc::VirtualSocketServer> vss_;
177 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 18:21:56178 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 22:30:51179};
180
Steve Antonad7bffc2018-01-22 18:21:56181class PeerConnectionMediaTest
182 : public PeerConnectionMediaBaseTest,
183 public ::testing::WithParamInterface<SdpSemantics> {
184 protected:
185 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
186};
187
188class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
189 protected:
190 PeerConnectionMediaTestUnifiedPlan()
191 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
192};
193
194class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
195 protected:
196 PeerConnectionMediaTestPlanB()
197 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
198};
199
200TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51201 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
202 auto caller = CreatePeerConnectionWithAudioVideo();
203 auto callee = CreatePeerConnectionWithAudioVideo();
204 callee->media_engine()->set_fail_create_channel(true);
205
206 std::string error;
207 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56208 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
209 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51210}
211
Steve Antonad7bffc2018-01-22 18:21:56212TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51213 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
214 auto caller = CreatePeerConnectionWithAudioVideo();
215 caller->media_engine()->set_fail_create_channel(true);
216
217 std::string error;
218 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56219 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
220 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51221}
222
223std::vector<std::string> GetIds(
224 const std::vector<cricket::StreamParams>& streams) {
225 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 09:11:53226 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 22:30:51227 for (const auto& stream : streams) {
228 ids.push_back(stream.id);
229 }
230 return ids;
231}
232
233// Test that exchanging an offer and answer with each side having an audio and
234// video stream creates the appropriate send/recv streams in the underlying
235// media engine on both sides.
Steve Antonad7bffc2018-01-22 18:21:56236TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51237 const std::string kCallerAudioId = "caller_a";
238 const std::string kCallerVideoId = "caller_v";
239 const std::string kCalleeAudioId = "callee_a";
240 const std::string kCalleeVideoId = "callee_v";
241
242 auto caller = CreatePeerConnection();
243 caller->AddAudioTrack(kCallerAudioId);
244 caller->AddVideoTrack(kCallerVideoId);
245
246 auto callee = CreatePeerConnection();
247 callee->AddAudioTrack(kCalleeAudioId);
248 callee->AddVideoTrack(kCalleeVideoId);
249
250 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
251 ASSERT_TRUE(
252 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
253
254 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
255 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
256 ElementsAre(kCalleeAudioId));
257 EXPECT_THAT(GetIds(caller_voice->send_streams()),
258 ElementsAre(kCallerAudioId));
259
260 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
261 EXPECT_THAT(GetIds(caller_video->recv_streams()),
262 ElementsAre(kCalleeVideoId));
263 EXPECT_THAT(GetIds(caller_video->send_streams()),
264 ElementsAre(kCallerVideoId));
265
266 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
267 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
268 ElementsAre(kCallerAudioId));
269 EXPECT_THAT(GetIds(callee_voice->send_streams()),
270 ElementsAre(kCalleeAudioId));
271
272 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
273 EXPECT_THAT(GetIds(callee_video->recv_streams()),
274 ElementsAre(kCallerVideoId));
275 EXPECT_THAT(GetIds(callee_video->send_streams()),
276 ElementsAre(kCalleeVideoId));
277}
278
Steve Antonad7bffc2018-01-22 18:21:56279// Test that stopping the caller transceivers causes the media channels on the
280// callee to be destroyed after calling SetRemoteDescription on the generated
281// offer.
282// See next test for equivalent behavior with Plan B semantics.
283TEST_F(PeerConnectionMediaTestUnifiedPlan,
284 StoppedRemoteTransceiversRemovesMediaChannels) {
285 auto caller = CreatePeerConnectionWithAudioVideo();
286 auto callee = CreatePeerConnection();
287
288 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
289
290 // Stop both audio and video transceivers on the caller.
291 auto transceivers = caller->pc()->GetTransceivers();
292 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02293 transceivers[0]->StopInternal();
294 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56295
296 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
297
298 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
299 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
300}
301
Steve Anton8d3444d2017-10-20 22:30:51302// Test that removing streams from a subsequent offer causes the receive streams
303// on the callee to be removed.
Steve Antonad7bffc2018-01-22 18:21:56304// See previous test for equivalent behavior with Unified Plan semantics.
305TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51306 auto caller = CreatePeerConnection();
307 auto caller_audio_track = caller->AddAudioTrack("a");
308 auto caller_video_track = caller->AddVideoTrack("v");
309 auto callee = CreatePeerConnectionWithAudioVideo();
310
Steve Antonad7bffc2018-01-22 18:21:56311 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51312
313 // Remove both tracks from caller.
314 caller->pc()->RemoveTrack(caller_audio_track);
315 caller->pc()->RemoveTrack(caller_video_track);
316
Steve Antonad7bffc2018-01-22 18:21:56317 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51318
319 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 18:21:56320 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 22:30:51321 EXPECT_EQ(1u, callee_voice->send_streams().size());
322 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 22:30:51323 EXPECT_EQ(1u, callee_video->send_streams().size());
324 EXPECT_EQ(0u, callee_video->recv_streams().size());
325}
326
Jonas Orelandfc1acd22018-08-24 08:58:37327// Test enabling of simulcast with Plan B semantics.
328// This test creating an offer.
329TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
330 auto caller = CreatePeerConnection();
331 auto caller_video_track = caller->AddVideoTrack("v");
332 RTCOfferAnswerOptions options;
333 options.num_simulcast_layers = 3;
334 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 17:08:33335 auto* description = cricket::GetFirstMediaContent(offer->description(),
336 cricket::MEDIA_TYPE_VIDEO)
337 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37338 ASSERT_EQ(1u, description->streams().size());
339 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
340 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
341
342 // Check that it actually creates simulcast aswell.
343 caller->SetLocalDescription(std::move(offer));
344 auto senders = caller->pc()->GetSenders();
345 ASSERT_EQ(1u, senders.size());
346 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
347 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
348}
349
350// Test enabling of simulcast with Plan B semantics.
351// This test creating an answer.
352TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
353 auto caller = CreatePeerConnection();
354 caller->AddVideoTrack("v0");
355 auto offer = caller->CreateOffer();
356 auto callee = CreatePeerConnection();
357 auto callee_video_track = callee->AddVideoTrack("v1");
358 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
359 RTCOfferAnswerOptions options;
360 options.num_simulcast_layers = 3;
361 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 17:08:33362 auto* description = cricket::GetFirstMediaContent(answer->description(),
363 cricket::MEDIA_TYPE_VIDEO)
364 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37365 ASSERT_EQ(1u, description->streams().size());
366 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
367 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
368
369 // Check that it actually creates simulcast aswell.
370 callee->SetLocalDescription(std::move(answer));
371 auto senders = callee->pc()->GetSenders();
372 ASSERT_EQ(1u, senders.size());
373 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
374 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
375}
376
Steve Antonad7bffc2018-01-22 18:21:56377// Test that stopping the callee transceivers causes the media channels to be
378// destroyed on the callee after calling SetLocalDescription on the local
379// answer.
380// See next test for equivalent behavior with Plan B semantics.
381TEST_F(PeerConnectionMediaTestUnifiedPlan,
382 StoppedLocalTransceiversRemovesMediaChannels) {
383 auto caller = CreatePeerConnectionWithAudioVideo();
384 auto callee = CreatePeerConnectionWithAudioVideo();
385
386 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
387
388 // Stop both audio and video transceivers on the callee.
389 auto transceivers = callee->pc()->GetTransceivers();
390 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02391 transceivers[0]->StopInternal();
392 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56393
394 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
395
396 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
397 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
398}
399
Steve Anton8d3444d2017-10-20 22:30:51400// Test that removing streams from a subsequent answer causes the send streams
401// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 18:21:56402// See previous test for equivalent behavior with Unified Plan semantics.
403TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51404 auto caller = CreatePeerConnectionWithAudioVideo();
405 auto callee = CreatePeerConnection();
406 auto callee_audio_track = callee->AddAudioTrack("a");
407 auto callee_video_track = callee->AddVideoTrack("v");
408
Steve Antonad7bffc2018-01-22 18:21:56409 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51410
411 // Remove both tracks from callee.
412 callee->pc()->RemoveTrack(callee_audio_track);
413 callee->pc()->RemoveTrack(callee_video_track);
414
Steve Antonad7bffc2018-01-22 18:21:56415 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51416
417 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 18:21:56418 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 22:30:51419 EXPECT_EQ(0u, callee_voice->send_streams().size());
420 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 22:30:51421 EXPECT_EQ(0u, callee_video->send_streams().size());
422 EXPECT_EQ(1u, callee_video->recv_streams().size());
423}
424
425// Test that a new stream in a subsequent offer causes a new receive stream to
426// be created on the callee.
Steve Antonad7bffc2018-01-22 18:21:56427TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51428 auto caller = CreatePeerConnectionWithAudioVideo();
429 auto callee = CreatePeerConnection();
430
Steve Antonad7bffc2018-01-22 18:21:56431 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51432
433 // Add second set of tracks to the caller.
434 caller->AddAudioTrack("a2");
435 caller->AddVideoTrack("v2");
436
Steve Antonad7bffc2018-01-22 18:21:56437 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51438
Steve Antonad7bffc2018-01-22 18:21:56439 auto a1 = callee->media_engine()->GetVoiceChannel(0);
440 auto a2 = callee->media_engine()->GetVoiceChannel(1);
441 auto v1 = callee->media_engine()->GetVideoChannel(0);
442 auto v2 = callee->media_engine()->GetVideoChannel(1);
443 if (IsUnifiedPlan()) {
444 ASSERT_TRUE(a1);
445 EXPECT_EQ(1u, a1->recv_streams().size());
446 ASSERT_TRUE(a2);
447 EXPECT_EQ(1u, a2->recv_streams().size());
448 ASSERT_TRUE(v1);
449 EXPECT_EQ(1u, v1->recv_streams().size());
450 ASSERT_TRUE(v2);
451 EXPECT_EQ(1u, v2->recv_streams().size());
452 } else {
453 ASSERT_TRUE(a1);
454 EXPECT_EQ(2u, a1->recv_streams().size());
455 ASSERT_FALSE(a2);
456 ASSERT_TRUE(v1);
457 EXPECT_EQ(2u, v1->recv_streams().size());
458 ASSERT_FALSE(v2);
459 }
Steve Anton8d3444d2017-10-20 22:30:51460}
461
462// Test that a new stream in a subsequent answer causes a new send stream to be
463// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 18:21:56464TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51465 auto caller = CreatePeerConnection();
466 auto callee = CreatePeerConnectionWithAudioVideo();
467
Steve Anton22da89f2018-01-25 21:58:07468 RTCOfferAnswerOptions offer_options;
469 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 22:30:51470 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07471 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 22:30:51472 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07473 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 22:30:51474
Steve Anton22da89f2018-01-25 21:58:07475 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
476 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51477
478 // Add second set of tracks to the callee.
479 callee->AddAudioTrack("a2");
480 callee->AddVideoTrack("v2");
481
Steve Anton22da89f2018-01-25 21:58:07482 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
483 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51484
485 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 21:58:07486 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 22:30:51487 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 21:58:07488 ASSERT_TRUE(callee_video);
489
490 if (IsUnifiedPlan()) {
491 EXPECT_EQ(1u, callee_voice->send_streams().size());
492 EXPECT_EQ(1u, callee_video->send_streams().size());
493 } else {
494 EXPECT_EQ(2u, callee_voice->send_streams().size());
495 EXPECT_EQ(2u, callee_video->send_streams().size());
496 }
Steve Anton8d3444d2017-10-20 22:30:51497}
498
499// A PeerConnection with no local streams and no explicit answer constraints
500// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 18:21:56501TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51502 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
503 auto caller = CreatePeerConnectionWithAudioVideo();
504 auto callee = CreatePeerConnection();
505 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
506 auto answer = callee->CreateAnswer();
507
508 const auto* audio_content =
509 cricket::GetFirstAudioContent(answer->description());
510 ASSERT_TRUE(audio_content);
511 EXPECT_FALSE(audio_content->rejected);
512
513 const auto* video_content =
514 cricket::GetFirstVideoContent(answer->description());
515 ASSERT_TRUE(video_content);
516 EXPECT_FALSE(video_content->rejected);
517}
518
Mirta Dvornicic479a3c02019-06-04 13:38:50519// Test that raw packetization is not set in the offer by default.
520TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
521 std::vector<cricket::VideoCodec> fake_codecs;
522 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
523 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
524 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
525 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
526 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
527 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18528 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50529 caller_fake_engine->SetVideoCodecs(fake_codecs);
530
531 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
532 auto offer = caller->CreateOfferAndSetAsLocal();
533 auto* offer_description =
534 cricket::GetFirstVideoContentDescription(offer->description());
535 for (const auto& codec : offer_description->codecs()) {
536 EXPECT_EQ(codec.packetization, absl::nullopt);
537 }
538}
539
540// Test that raw packetization is set in the offer and answer for all
541// video payload when raw_packetization_for_video is true.
542TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
543 std::vector<cricket::VideoCodec> fake_codecs;
544 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
545 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
546 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
547 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
548 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
549 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18550 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50551 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18552 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50553 callee_fake_engine->SetVideoCodecs(fake_codecs);
554
555 RTCOfferAnswerOptions options;
556 options.raw_packetization_for_video = true;
557
558 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
559 auto offer = caller->CreateOfferAndSetAsLocal(options);
560 auto* offer_description =
561 cricket::GetFirstVideoContentDescription(offer->description());
562 for (const auto& codec : offer_description->codecs()) {
563 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
564 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
565 }
566 }
567
568 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
569 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
570 auto answer = callee->CreateAnswerAndSetAsLocal(options);
571 auto* answer_description =
572 cricket::GetFirstVideoContentDescription(answer->description());
573 for (const auto& codec : answer_description->codecs()) {
574 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
575 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
576 }
577 }
578
579 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
580}
581
582// Test that raw packetization is not set in the answer when
583// raw_packetization_for_video is true if it was not set in the offer.
584TEST_P(PeerConnectionMediaTest,
585 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
586 std::vector<cricket::VideoCodec> fake_codecs;
587 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
588 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
589 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
590 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
591 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
592 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18593 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50594 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18595 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50596 callee_fake_engine->SetVideoCodecs(fake_codecs);
597
598 RTCOfferAnswerOptions caller_options;
599 caller_options.raw_packetization_for_video = false;
600 RTCOfferAnswerOptions callee_options;
601 callee_options.raw_packetization_for_video = true;
602
603 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
604 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
605
606 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
607 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
608 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
609
610 auto* answer_description =
611 cricket::GetFirstVideoContentDescription(answer->description());
612 for (const auto& codec : answer_description->codecs()) {
613 EXPECT_EQ(codec.packetization, absl::nullopt);
614 }
615
616 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
617}
618
Steve Anton8d3444d2017-10-20 22:30:51619class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56620 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51621 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56622 std::tuple<SdpSemantics,
623 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 22:30:51624 protected:
Steve Antonad7bffc2018-01-22 18:21:56625 PeerConnectionMediaOfferDirectionTest()
626 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
627 auto param = std::get<1>(GetParam());
628 send_media_ = std::get<0>(param);
629 offer_to_receive_ = std::get<1>(param);
630 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51631 }
632
633 bool send_media_;
634 int offer_to_receive_;
Steve Anton4e70a722017-11-28 22:57:10635 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 22:30:51636};
637
638// Tests that the correct direction is set on the media description according
639// to the presence of a local media track and the offer_to_receive setting.
640TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
641 auto caller = CreatePeerConnection();
642 if (send_media_) {
643 caller->AddAudioTrack("a");
644 }
645
646 RTCOfferAnswerOptions options;
647 options.offer_to_receive_audio = offer_to_receive_;
648 auto offer = caller->CreateOffer(options);
649
Steve Antonad7bffc2018-01-22 18:21:56650 auto* content = cricket::GetFirstMediaContent(offer->description(),
651 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 22:57:10652 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 18:21:56653 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 22:30:51654 } else {
Steve Antonad7bffc2018-01-22 18:21:56655 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 22:30:51656 }
657}
658
659// Note that in these tests, MD_INACTIVE indicates that no media section is
660// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 11:20:57661INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 22:57:10662 PeerConnectionMediaTest,
663 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 18:21:56664 Combine(
665 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
666 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
667 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
668 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
669 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
670 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
671 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 22:30:51672
673class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56674 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51675 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56676 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 22:30:51677 protected:
Steve Antonad7bffc2018-01-22 18:21:56678 PeerConnectionMediaAnswerDirectionTest()
679 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
680 offer_direction_ = std::get<1>(GetParam());
681 send_media_ = std::get<2>(GetParam());
682 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 22:30:51683 }
684
Steve Anton4e70a722017-11-28 22:57:10685 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 22:30:51686 bool send_media_;
687 int offer_to_receive_;
688};
689
690// Tests that the direction in an answer is correct according to direction sent
691// in the offer, the presence of a local media track on the receive side and the
692// offer_to_receive setting.
693TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 21:58:07694 if (IsUnifiedPlan() &&
695 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
696 // offer_to_receive_ is not implemented when creating answers with Unified
697 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56698 return;
699 }
Steve Anton22da89f2018-01-25 21:58:07700
Steve Anton8d3444d2017-10-20 22:30:51701 auto caller = CreatePeerConnection();
702 caller->AddAudioTrack("a");
703
704 // Create the offer with an audio section and set its direction.
705 auto offer = caller->CreateOffer();
706 cricket::GetFirstAudioContentDescription(offer->description())
707 ->set_direction(offer_direction_);
708
709 auto callee = CreatePeerConnection();
710 if (send_media_) {
711 callee->AddAudioTrack("a");
712 }
713 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
714
715 // Create the answer according to the test parameters.
716 RTCOfferAnswerOptions options;
717 options.offer_to_receive_audio = offer_to_receive_;
718 auto answer = callee->CreateAnswer(options);
719
720 // The expected direction in the answer is the intersection of each side's
721 // capability to send/recv media.
722 // For the offerer, the direction is given in the offer (offer_direction_).
723 // For the answerer, the direction has two components:
724 // 1. Send if the answerer has a local track to send.
725 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
726 // if it has been left as default.
Steve Anton4e70a722017-11-28 22:57:10727 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
728 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 22:30:51729
730 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 22:30:09731 bool negotiate_send = (send_media_ && offer_recv);
732 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 22:30:51733
734 auto expected_direction =
Steve Anton4e70a722017-11-28 22:57:10735 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 22:30:51736 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 18:21:56737 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 22:30:51738}
739
740// Tests that the media section is rejected if and only if the callee has no
741// local media track and has set offer_to_receive to 0, no matter which
742// direction the caller indicated in the offer.
743TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 21:58:07744 if (IsUnifiedPlan() &&
745 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
746 // offer_to_receive_ is not implemented when creating answers with Unified
747 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56748 return;
749 }
Steve Anton22da89f2018-01-25 21:58:07750
Steve Anton8d3444d2017-10-20 22:30:51751 auto caller = CreatePeerConnection();
752 caller->AddAudioTrack("a");
753
754 // Create the offer with an audio section and set its direction.
755 auto offer = caller->CreateOffer();
756 cricket::GetFirstAudioContentDescription(offer->description())
757 ->set_direction(offer_direction_);
758
759 auto callee = CreatePeerConnection();
760 if (send_media_) {
761 callee->AddAudioTrack("a");
762 }
763 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
764
765 // Create the answer according to the test parameters.
766 RTCOfferAnswerOptions options;
767 options.offer_to_receive_audio = offer_to_receive_;
768 auto answer = callee->CreateAnswer(options);
769
770 // The media section is rejected if and only if offer_to_receive is explicitly
771 // set to 0 and there is no media to send.
772 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
773 ASSERT_TRUE(audio_content);
774 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
775}
776
Mirko Bonadeic84f6612019-01-31 11:20:57777INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
778 PeerConnectionMediaAnswerDirectionTest,
779 Combine(Values(SdpSemantics::kPlanB,
780 SdpSemantics::kUnifiedPlan),
781 Values(RtpTransceiverDirection::kInactive,
782 RtpTransceiverDirection::kSendOnly,
783 RtpTransceiverDirection::kRecvOnly,
784 RtpTransceiverDirection::kSendRecv),
785 Bool(),
786 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 22:30:51787
Steve Antonad7bffc2018-01-22 18:21:56788TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 22:30:51789 auto caller = CreatePeerConnection();
790 caller->AddVideoTrack("v");
791
792 RTCOfferAnswerOptions options;
793 options.offer_to_receive_audio = 1;
794 options.offer_to_receive_video = 0;
795 auto offer = caller->CreateOffer(options);
796
Steve Anton4e70a722017-11-28 22:57:10797 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56798 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10799 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56800 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51801}
802
Steve Antonad7bffc2018-01-22 18:21:56803TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 18:21:56804 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:07805 // offer_to_receive_ is not implemented when creating answers with Unified
806 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56807 return;
808 }
809
Steve Anton8d3444d2017-10-20 22:30:51810 auto caller = CreatePeerConnectionWithAudioVideo();
811 auto callee = CreatePeerConnection();
812 callee->AddVideoTrack("v");
813
814 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
815
816 RTCOfferAnswerOptions options;
817 options.offer_to_receive_audio = 1;
818 options.offer_to_receive_video = 0;
819 auto answer = callee->CreateAnswer(options);
820
Steve Anton4e70a722017-11-28 22:57:10821 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56822 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10823 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56824 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51825}
826
827void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Philipp Hancke8498c252020-06-05 11:28:57828 const cricket::AudioCodec kComfortNoiseCodec8k(102, cricket::kCnCodecName,
829 8000, 0, 1);
830 const cricket::AudioCodec kComfortNoiseCodec16k(103, cricket::kCnCodecName,
831 16000, 0, 1);
Steve Anton8d3444d2017-10-20 22:30:51832
Sebastian Jansson6eb8a162018-11-16 10:29:55833 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 22:30:51834 codecs.push_back(kComfortNoiseCodec8k);
835 codecs.push_back(kComfortNoiseCodec16k);
836 media_engine->SetAudioCodecs(codecs);
837}
838
839bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
840 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
841 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 11:28:57842 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 22:30:51843 return true;
844 }
845 }
846 return false;
847}
848
Steve Antonad7bffc2018-01-22 18:21:56849TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51850 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
851 auto caller = CreatePeerConnectionWithAudioVideo();
852 AddComfortNoiseCodecsToSend(caller->media_engine());
853
854 RTCOfferAnswerOptions options;
855 options.voice_activity_detection = false;
856 auto offer = caller->CreateOffer(options);
857
858 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
859}
860
Steve Antonad7bffc2018-01-22 18:21:56861TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51862 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
863 auto caller = CreatePeerConnectionWithAudioVideo();
864 AddComfortNoiseCodecsToSend(caller->media_engine());
865 auto callee = CreatePeerConnectionWithAudioVideo();
866 AddComfortNoiseCodecsToSend(callee->media_engine());
867
868 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
869
870 RTCOfferAnswerOptions options;
871 options.voice_activity_detection = false;
872 auto answer = callee->CreateAnswer(options);
873
874 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
875}
876
877// The following test group verifies that we reject answers with invalid media
878// sections as per RFC 3264.
879
880class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 18:21:56881 : public PeerConnectionMediaBaseTest,
882 public ::testing::WithParamInterface<std::tuple<
883 SdpSemantics,
Steve Anton8d3444d2017-10-20 22:30:51884 std::tuple<std::string,
885 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 18:21:56886 std::string>>> {
Steve Anton8d3444d2017-10-20 22:30:51887 protected:
Steve Antonad7bffc2018-01-22 18:21:56888 PeerConnectionMediaInvalidMediaTest()
889 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
890 auto param = std::get<1>(GetParam());
891 mutator_ = std::get<1>(param);
892 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51893 }
894
895 std::function<void(cricket::SessionDescription*)> mutator_;
896 std::string expected_error_;
897};
898
899TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
900 auto caller = CreatePeerConnectionWithAudioVideo();
901 auto callee = CreatePeerConnectionWithAudioVideo();
902
903 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
904
905 auto answer = callee->CreateAnswer();
906 mutator_(answer->description());
907
908 std::string error;
909 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
910 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
911}
912
913TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
914 auto caller = CreatePeerConnectionWithAudioVideo();
915 auto callee = CreatePeerConnectionWithAudioVideo();
916
917 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
918
919 auto answer = callee->CreateAnswer();
920 mutator_(answer->description());
921
922 std::string error;
923 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
924 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
925}
926
927void RemoveVideoContent(cricket::SessionDescription* desc) {
928 auto content_name = cricket::GetFirstVideoContent(desc)->name;
929 desc->RemoveContentByName(content_name);
930 desc->RemoveTransportInfoByName(content_name);
931}
932
933void RenameVideoContent(cricket::SessionDescription* desc) {
934 auto* video_content = cricket::GetFirstVideoContent(desc);
935 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
936 video_content->name = "video_renamed";
937 transport_info->content_name = video_content->name;
938}
939
940void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-29 01:25:26941 absl::c_reverse(desc->contents());
942 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 22:30:51943}
944
945void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 18:21:56946 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
947 desc->RemoveContentByName(audio_mid);
948 auto* video_content = cricket::GetFirstVideoContent(desc);
949 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 18:35:45950 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 22:30:51951}
952
953constexpr char kMLinesOutOfOrder[] =
954 "The order of m-lines in answer doesn't match order in offer. Rejecting "
955 "answer.";
956
Mirko Bonadeic84f6612019-01-31 11:20:57957INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 22:30:51958 PeerConnectionMediaTest,
959 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 18:21:56960 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
961 Values(std::make_tuple("remove video",
962 RemoveVideoContent,
963 kMLinesOutOfOrder),
964 std::make_tuple("rename video",
965 RenameVideoContent,
966 kMLinesOutOfOrder),
967 std::make_tuple("reverse media sections",
968 ReverseMediaContent,
969 kMLinesOutOfOrder),
970 std::make_tuple("change audio type to video type",
971 ChangeMediaTypeAudioToVideo,
972 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 22:30:51973
974// Test that the correct media engine send/recv streams are created when doing
975// a series of offer/answers where audio/video are both sent, then audio is
976// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 18:21:56977TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 18:21:56978 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:07979 // offer_to_receive_ is not implemented when creating answers with Unified
980 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56981 return;
982 }
983
Steve Anton8d3444d2017-10-20 22:30:51984 RTCOfferAnswerOptions options_reject_video;
985 options_reject_video.offer_to_receive_audio =
986 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
987 options_reject_video.offer_to_receive_video = 0;
988
989 auto caller = CreatePeerConnection();
990 caller->AddAudioTrack("a");
991 caller->AddVideoTrack("v");
992 auto callee = CreatePeerConnection();
993
994 // Caller initially offers to send/recv audio and video.
995 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
996 // Callee accepts the audio as recv only but rejects the video.
997 ASSERT_TRUE(caller->SetRemoteDescription(
998 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
999
1000 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1001 ASSERT_TRUE(caller_voice);
1002 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1003 EXPECT_EQ(1u, caller_voice->send_streams().size());
1004 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1005 EXPECT_FALSE(caller_video);
1006
1007 // Callee adds its own audio/video stream and offers to receive audio/video
1008 // too.
1009 callee->AddAudioTrack("a");
1010 auto callee_video_track = callee->AddVideoTrack("v");
1011 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1012 ASSERT_TRUE(
1013 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1014
1015 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1016 ASSERT_TRUE(callee_voice);
1017 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1018 EXPECT_EQ(1u, callee_voice->send_streams().size());
1019 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1020 ASSERT_TRUE(callee_video);
1021 EXPECT_EQ(1u, callee_video->recv_streams().size());
1022 EXPECT_EQ(1u, callee_video->send_streams().size());
1023
1024 // Callee removes video but keeps audio and rejects the video once again.
1025 callee->pc()->RemoveTrack(callee_video_track);
1026 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1027 ASSERT_TRUE(
1028 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1029
1030 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1031 ASSERT_TRUE(callee_voice);
1032 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1033 EXPECT_EQ(1u, callee_voice->send_streams().size());
1034 callee_video = callee->media_engine()->GetVideoChannel(0);
1035 EXPECT_FALSE(callee_video);
1036}
1037
1038// Test that the correct media engine send/recv streams are created when doing
1039// a series of offer/answers where audio/video are both sent, then video is
1040// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 18:21:561041TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 18:21:561042 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:071043 // offer_to_receive_ is not implemented when creating answers with Unified
1044 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:561045 return;
1046 }
1047
Steve Anton8d3444d2017-10-20 22:30:511048 // Disable the bundling here. If the media is bundled on audio
1049 // transport, then we can't reject the audio because switching the bundled
1050 // transport is not currently supported.
1051 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1052 RTCOfferAnswerOptions options_no_bundle;
1053 options_no_bundle.use_rtp_mux = false;
1054 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1055 options_reject_audio.offer_to_receive_audio = 0;
1056 options_reject_audio.offer_to_receive_video =
1057 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1058
1059 auto caller = CreatePeerConnection();
1060 caller->AddAudioTrack("a");
1061 caller->AddVideoTrack("v");
1062 auto callee = CreatePeerConnection();
1063
1064 // Caller initially offers to send/recv audio and video.
1065 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1066 // Callee accepts the video as recv only but rejects the audio.
1067 ASSERT_TRUE(caller->SetRemoteDescription(
1068 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1069
1070 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1071 EXPECT_FALSE(caller_voice);
1072 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1073 ASSERT_TRUE(caller_video);
1074 EXPECT_EQ(0u, caller_video->recv_streams().size());
1075 EXPECT_EQ(1u, caller_video->send_streams().size());
1076
1077 // Callee adds its own audio/video stream and offers to receive audio/video
1078 // too.
1079 auto callee_audio_track = callee->AddAudioTrack("a");
1080 callee->AddVideoTrack("v");
1081 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1082 ASSERT_TRUE(caller->SetRemoteDescription(
1083 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1084
1085 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1086 ASSERT_TRUE(callee_voice);
1087 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1088 EXPECT_EQ(1u, callee_voice->send_streams().size());
1089 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1090 ASSERT_TRUE(callee_video);
1091 EXPECT_EQ(1u, callee_video->recv_streams().size());
1092 EXPECT_EQ(1u, callee_video->send_streams().size());
1093
1094 // Callee removes audio but keeps video and rejects the audio once again.
1095 callee->pc()->RemoveTrack(callee_audio_track);
1096 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1097 ASSERT_TRUE(
1098 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1099
1100 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1101 EXPECT_FALSE(callee_voice);
1102 callee_video = callee->media_engine()->GetVideoChannel(0);
1103 ASSERT_TRUE(callee_video);
1104 EXPECT_EQ(1u, callee_video->recv_streams().size());
1105 EXPECT_EQ(1u, callee_video->send_streams().size());
1106}
1107
1108// Tests that if the underlying video encoder fails to be initialized (signaled
1109// by failing to set send codecs), the PeerConnection signals the error to the
1110// client.
Steve Antonad7bffc2018-01-22 18:21:561111TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 22:30:511112 auto caller = CreatePeerConnectionWithAudioVideo();
1113 auto callee = CreatePeerConnectionWithAudioVideo();
1114
1115 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1116
1117 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1118 video_channel->set_fail_set_send_codecs(true);
1119
1120 std::string error;
1121 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1122 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:221123 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1124 "video description "
1125 "send parameters for m-section with mid='") +
1126 (IsUnifiedPlan() ? "1" : "video") + "'.",
1127 error);
Steve Anton8d3444d2017-10-20 22:30:511128}
1129
1130// Tests that if the underlying video encoder fails once then subsequent
1131// attempts at setting the local/remote description will also fail, even if
1132// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 18:21:561133TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:511134 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1135 auto caller = CreatePeerConnectionWithAudioVideo();
1136 auto callee = CreatePeerConnectionWithAudioVideo();
1137
1138 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1139
1140 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1141 video_channel->set_fail_set_send_codecs(true);
1142
1143 EXPECT_FALSE(
1144 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1145
1146 video_channel->set_fail_set_send_codecs(false);
1147
1148 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1149 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1150}
1151
1152void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 18:21:561153 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 22:30:511154 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 18:21:561155 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 22:30:511156 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 18:21:561157 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 22:30:511158 content->name = new_name;
1159 auto* transport = desc->GetTransportInfoByName(old_name);
1160 RTC_DCHECK(transport);
1161 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 21:41:031162
1163 // Rename the content name in the BUNDLE group.
1164 cricket::ContentGroup new_bundle_group =
1165 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1166 new_bundle_group.RemoveContentName(old_name);
1167 new_bundle_group.AddContentName(new_name);
1168 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1169 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 22:30:511170}
1171
1172// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 18:21:561173TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 23:44:341174 const std::string kAudioMid = "notdefault1";
1175 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511176
1177 auto caller = CreatePeerConnectionWithAudioVideo();
1178 auto callee = CreatePeerConnectionWithAudioVideo();
1179
1180 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561181 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1182 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511183 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1184
1185 auto answer = callee->CreateAnswer();
1186 EXPECT_EQ(kAudioMid,
1187 cricket::GetFirstAudioContent(answer->description())->name);
1188 EXPECT_EQ(kVideoMid,
1189 cricket::GetFirstVideoContent(answer->description())->name);
1190}
1191
1192// Test that if the callee creates a re-offer, the MIDs are the same as the
1193// original offer.
Steve Antonad7bffc2018-01-22 18:21:561194TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 23:44:341195 const std::string kAudioMid = "notdefault1";
1196 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511197
1198 auto caller = CreatePeerConnectionWithAudioVideo();
1199 auto callee = CreatePeerConnectionWithAudioVideo();
1200
1201 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561202 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1203 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511204 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1205 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1206
1207 auto reoffer = callee->CreateOffer();
1208 EXPECT_EQ(kAudioMid,
1209 cricket::GetFirstAudioContent(reoffer->description())->name);
1210 EXPECT_EQ(kVideoMid,
1211 cricket::GetFirstVideoContent(reoffer->description())->name);
1212}
1213
Steve Anton06817cd2018-12-18 23:55:301214// Test that SetRemoteDescription returns an error if there are two m= sections
1215// with the same MID value.
1216TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1217 auto caller = CreatePeerConnectionWithAudioVideo();
1218 auto callee = CreatePeerConnectionWithAudioVideo();
1219
1220 auto offer = caller->CreateOffer();
1221 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1222 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1223
1224 std::string error;
1225 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1226 EXPECT_EQ(error,
1227 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1228}
1229
Steve Antonad7bffc2018-01-22 18:21:561230TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:511231 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1232 RTCConfiguration config;
1233 config.combined_audio_video_bwe.emplace(true);
1234 auto caller = CreatePeerConnectionWithAudioVideo(config);
1235
1236 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1237
1238 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1239 ASSERT_TRUE(caller_voice);
1240 const cricket::AudioOptions& audio_options = caller_voice->options();
1241 EXPECT_EQ(config.combined_audio_video_bwe,
1242 audio_options.combined_audio_video_bwe);
1243}
1244
Florent Castelli2d9d82e2019-04-23 17:25:511245template <typename C>
1246bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1247 const std::vector<C>& codecs) {
1248 bool capability_has_rtx =
1249 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1250 return codec.name == cricket::kRtxCodecName;
1251 });
1252 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1253 return codec.name == cricket::kRtxCodecName;
1254 });
1255
1256 std::vector<C> codecs_no_rtx;
1257 absl::c_copy_if(
1258 codecs, std::back_inserter(codecs_no_rtx),
1259 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1260
1261 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1262 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1263 [](const webrtc::RtpCodecCapability& codec) {
1264 return codec.name != cricket::kRtxCodecName;
1265 });
1266
1267 return capability_has_rtx == codecs_has_rtx &&
1268 absl::c_equal(
1269 capabilities_no_rtx, codecs_no_rtx,
1270 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1271 return codec.MatchesCapability(capability);
1272 });
1273}
1274
1275TEST_F(PeerConnectionMediaTestUnifiedPlan,
1276 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181277 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511278 auto send_codecs = fake_engine->voice().send_codecs();
1279 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1280 "send_only_codec", 0, 0, 1));
1281 fake_engine->SetAudioSendCodecs(send_codecs);
1282
1283 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1284
1285 auto transceiver = caller->pc()->GetTransceivers().front();
1286 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1287 cricket::MediaType::MEDIA_TYPE_AUDIO);
1288
1289 std::vector<webrtc::RtpCodecCapability> codecs;
1290 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1291 [](const webrtc::RtpCodecCapability& codec) {
1292 return codec.name.find("_only_") != std::string::npos;
1293 });
1294
1295 auto result = transceiver->SetCodecPreferences(codecs);
1296 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1297}
1298
1299TEST_F(PeerConnectionMediaTestUnifiedPlan,
1300 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181301 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511302 auto recv_codecs = fake_engine->voice().recv_codecs();
1303 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1304 "recv_only_codec", 0, 0, 1));
1305 fake_engine->SetAudioRecvCodecs(recv_codecs);
1306 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1307
1308 auto transceiver = caller->pc()->GetTransceivers().front();
1309 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1310 cricket::MediaType::MEDIA_TYPE_AUDIO);
1311
1312 std::vector<webrtc::RtpCodecCapability> codecs;
1313 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1314 [](const webrtc::RtpCodecCapability& codec) {
1315 return codec.name.find("_only_") != std::string::npos;
1316 });
1317
1318 auto result = transceiver->SetCodecPreferences(codecs);
1319 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1320}
1321
1322TEST_F(PeerConnectionMediaTestUnifiedPlan,
1323 SetCodecPreferencesAudioRejectsVideoCodec) {
1324 auto caller = CreatePeerConnectionWithAudio();
1325
1326 auto transceiver = caller->pc()->GetTransceivers().front();
1327 auto video_codecs =
1328 caller->pc_factory()
1329 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1330 .codecs;
1331 auto codecs =
1332 caller->pc_factory()
1333 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1334 .codecs;
1335 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1336 auto result = transceiver->SetCodecPreferences(codecs);
1337 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1338}
1339
1340TEST_F(PeerConnectionMediaTestUnifiedPlan,
1341 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181342 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511343 auto audio_codecs = fake_engine->voice().send_codecs();
1344 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1345 cricket::kRtxCodecName, 0, 0, 1));
1346 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1347 std::to_string(audio_codecs.back().id - 1);
1348 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1349 cricket::kRedCodecName, 0, 0, 1));
1350 audio_codecs.push_back(cricket::AudioCodec(
1351 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1352 fake_engine->SetAudioCodecs(audio_codecs);
1353
1354 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1355
1356 auto transceiver = caller->pc()->GetTransceivers().front();
1357 auto codecs =
1358 caller->pc_factory()
1359 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1360 .codecs;
1361 auto codecs_only_rtx_red_fec = codecs;
1362 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1363 codecs_only_rtx_red_fec.end(),
1364 [](const webrtc::RtpCodecCapability& codec) {
1365 return !(codec.name == cricket::kRtxCodecName ||
1366 codec.name == cricket::kRedCodecName ||
1367 codec.name == cricket::kUlpfecCodecName);
1368 });
1369 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1370
1371 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1372 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1373}
1374
1375TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1376 auto caller = CreatePeerConnectionWithAudio();
1377
1378 auto sender_audio_codecs =
1379 caller->pc_factory()
1380 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1381 .codecs;
1382
1383 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1384
1385 // Normal case, set all capabilities as preferences
1386 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1387 auto offer = caller->CreateOffer();
1388 auto codecs = offer->description()
1389 ->contents()[0]
1390 .media_description()
1391 ->as_audio()
1392 ->codecs();
1393 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1394}
1395
1396TEST_F(PeerConnectionMediaTestUnifiedPlan,
1397 SetCodecPreferencesResetAudioCodecs) {
1398 auto caller = CreatePeerConnectionWithAudio();
1399
1400 auto sender_audio_codecs =
1401 caller->pc_factory()
1402 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1403 .codecs;
1404 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1405
1406 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1407
1408 // Normal case, reset codec preferences
1409 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1410 auto offer = caller->CreateOffer();
1411 auto codecs = offer->description()
1412 ->contents()[0]
1413 .media_description()
1414 ->as_audio()
1415 ->codecs();
1416 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1417}
1418
1419TEST_F(PeerConnectionMediaTestUnifiedPlan,
1420 SetCodecPreferencesVideoRejectsAudioCodec) {
1421 auto caller = CreatePeerConnectionWithVideo();
1422
1423 auto transceiver = caller->pc()->GetTransceivers().front();
1424 auto audio_codecs =
1425 caller->pc_factory()
1426 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1427 .codecs;
1428 auto codecs =
1429 caller->pc_factory()
1430 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1431 .codecs;
1432 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1433 auto result = transceiver->SetCodecPreferences(codecs);
1434 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1435}
1436
1437TEST_F(PeerConnectionMediaTestUnifiedPlan,
1438 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181439 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001440 auto video_codecs = fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511441 video_codecs.push_back(
1442 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
Johannes Kron3e983682020-03-29 20:17:001443 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1444 std::to_string(video_codecs.back().id - 1);
Florent Castelli2d9d82e2019-04-23 17:25:511445 video_codecs.push_back(
1446 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1447 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1448 cricket::kUlpfecCodecName));
1449 fake_engine->SetVideoCodecs(video_codecs);
1450
1451 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1452
1453 auto transceiver = caller->pc()->GetTransceivers().front();
1454 auto codecs =
1455 caller->pc_factory()
1456 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1457 .codecs;
1458 auto codecs_only_rtx_red_fec = codecs;
1459 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1460 codecs_only_rtx_red_fec.end(),
1461 [](const webrtc::RtpCodecCapability& codec) {
1462 return !(codec.name == cricket::kRtxCodecName ||
1463 codec.name == cricket::kRedCodecName ||
1464 codec.name == cricket::kUlpfecCodecName);
1465 });
1466 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1467
1468 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1469 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1470}
1471
1472TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1473 auto caller = CreatePeerConnectionWithVideo();
1474
1475 auto sender_video_codecs =
1476 caller->pc_factory()
1477 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1478 .codecs;
1479
1480 auto video_transceiver = caller->pc()->GetTransceivers().front();
1481
1482 // Normal case, setting preferences to normal capabilities
1483 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1484 auto offer = caller->CreateOffer();
1485 auto codecs = offer->description()
1486 ->contents()[0]
1487 .media_description()
1488 ->as_video()
1489 ->codecs();
1490 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1491}
1492
1493TEST_F(PeerConnectionMediaTestUnifiedPlan,
1494 SetCodecPreferencesResetVideoCodecs) {
1495 auto caller = CreatePeerConnectionWithVideo();
1496
1497 auto sender_video_codecs =
1498 caller->pc_factory()
1499 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1500 .codecs;
1501
1502 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1503
1504 auto video_transceiver = caller->pc()->GetTransceivers().front();
1505
1506 // Normal case, resetting preferences with empty list of codecs
1507 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1508 auto offer = caller->CreateOffer();
1509 auto codecs = offer->description()
1510 ->contents()[0]
1511 .media_description()
1512 ->as_video()
1513 ->codecs();
1514 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1515}
1516
1517TEST_F(PeerConnectionMediaTestUnifiedPlan,
1518 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1519 auto caller = CreatePeerConnectionWithVideo();
1520
1521 auto sender_video_codecs =
1522 caller->pc_factory()
1523 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1524 .codecs;
1525
1526 auto video_transceiver = caller->pc()->GetTransceivers().front();
1527
1528 // Check duplicates are removed
1529 auto single_codec = sender_video_codecs;
1530 single_codec.resize(1);
1531 auto duplicate_codec = single_codec;
1532 duplicate_codec.push_back(duplicate_codec.front());
1533 duplicate_codec.push_back(duplicate_codec.front());
1534 duplicate_codec.push_back(duplicate_codec.front());
1535
1536 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1537 auto offer = caller->CreateOffer();
1538 auto codecs = offer->description()
1539 ->contents()[0]
1540 .media_description()
1541 ->as_video()
1542 ->codecs();
1543 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1544}
1545
1546TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 15:06:181547 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001548 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511549 caller_video_codecs.push_back(cricket::VideoCodec(
1550 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1551 caller_video_codecs.push_back(cricket::VideoCodec(
1552 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1553 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1554 std::to_string(caller_video_codecs.back().id - 1);
1555 caller_video_codecs.push_back(cricket::VideoCodec(
1556 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1557 caller_video_codecs.push_back(cricket::VideoCodec(
1558 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1559 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1560 std::to_string(caller_video_codecs.back().id - 1);
1561 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1562
1563 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1564
1565 auto sender_video_codecs =
1566 caller->pc_factory()
1567 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1568 .codecs;
1569
1570 auto video_transceiver = caller->pc()->GetTransceivers().front();
1571
1572 // Check that RTX codec is properly added
1573 auto video_codecs_vpx_rtx = sender_video_codecs;
1574 auto it =
1575 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1576 [](const webrtc::RtpCodecCapability& codec) {
1577 return codec.name != cricket::kRtxCodecName &&
1578 codec.name != cricket::kVp8CodecName &&
1579 codec.name != cricket::kVp9CodecName;
1580 });
1581 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1582 absl::c_reverse(video_codecs_vpx_rtx);
1583 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1584 EXPECT_TRUE(
1585 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1586 auto offer = caller->CreateOffer();
1587 auto codecs = offer->description()
1588 ->contents()[0]
1589 .media_description()
1590 ->as_video()
1591 ->codecs();
1592
1593 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1594 EXPECT_EQ(codecs.size(), 4u);
1595}
1596
1597TEST_F(PeerConnectionMediaTestUnifiedPlan,
1598 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 15:06:181599 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001600 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511601 caller_video_codecs.push_back(cricket::VideoCodec(
1602 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1603 caller_video_codecs.push_back(cricket::VideoCodec(
1604 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1605 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1606 std::to_string(caller_video_codecs.back().id - 1);
1607 caller_video_codecs.push_back(cricket::VideoCodec(
1608 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1609 caller_video_codecs.push_back(cricket::VideoCodec(
1610 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1611 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1612 std::to_string(caller_video_codecs.back().id - 1);
1613 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1614
Mirko Bonadei317a1f02019-09-17 15:06:181615 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511616 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1617
1618 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1619 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1620
1621 auto video_codecs = caller->pc_factory()
1622 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1623 .codecs;
1624
1625 auto send_transceiver = caller->pc()->GetTransceivers().front();
1626
1627 auto video_codecs_vpx = video_codecs;
1628 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1629 [](const webrtc::RtpCodecCapability& codec) {
1630 return codec.name != cricket::kVp8CodecName &&
1631 codec.name != cricket::kVp9CodecName;
1632 });
1633 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1634 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1635 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1636
1637 auto offer = caller->CreateOfferAndSetAsLocal();
1638 auto codecs = offer->description()
1639 ->contents()[0]
1640 .media_description()
1641 ->as_video()
1642 ->codecs();
1643
1644 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1645 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1646
1647 callee->SetRemoteDescription(std::move(offer));
1648
1649 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1650 auto video_codecs_vp8_rtx = video_codecs;
1651 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1652 [](const webrtc::RtpCodecCapability& codec) {
1653 bool r = codec.name != cricket::kVp8CodecName &&
1654 codec.name != cricket::kRtxCodecName;
1655 return r;
1656 });
1657 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1658 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1659 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1660
1661 auto answer = callee->CreateAnswerAndSetAsLocal();
1662
1663 auto recv_codecs = answer->description()
1664 ->contents()[0]
1665 .media_description()
1666 ->as_video()
1667 ->codecs();
1668 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1669}
1670
1671TEST_F(PeerConnectionMediaTestUnifiedPlan,
1672 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 15:06:181673 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001674 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511675 caller_video_codecs.push_back(cricket::VideoCodec(
1676 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1677 caller_video_codecs.push_back(cricket::VideoCodec(
1678 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1679 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1680 std::to_string(caller_video_codecs.back().id - 1);
1681 caller_video_codecs.push_back(cricket::VideoCodec(
1682 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1683 caller_video_codecs.push_back(cricket::VideoCodec(
1684 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1685 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1686 std::to_string(caller_video_codecs.back().id - 1);
1687 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1688
Mirko Bonadei317a1f02019-09-17 15:06:181689 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511690 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1691
1692 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1693 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1694
1695 auto video_codecs = caller->pc_factory()
1696 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1697 .codecs;
1698
1699 auto send_transceiver = caller->pc()->GetTransceivers().front();
1700
1701 auto video_codecs_vpx = video_codecs;
1702 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1703 [](const webrtc::RtpCodecCapability& codec) {
1704 return codec.name != cricket::kVp8CodecName &&
1705 codec.name != cricket::kVp9CodecName;
1706 });
1707 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1708 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1709 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1710
1711 auto video_codecs_vpx_reverse = video_codecs_vpx;
1712 absl::c_reverse(video_codecs_vpx_reverse);
1713
1714 auto offer = caller->CreateOfferAndSetAsLocal();
1715 auto codecs = offer->description()
1716 ->contents()[0]
1717 .media_description()
1718 ->as_video()
1719 ->codecs();
1720 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1721 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1722
1723 callee->SetRemoteDescription(std::move(offer));
1724
1725 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1726 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1727
1728 auto answer = callee->CreateAnswerAndSetAsLocal();
1729
1730 auto recv_codecs = answer->description()
1731 ->contents()[0]
1732 .media_description()
1733 ->as_video()
1734 ->codecs();
1735
1736 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1737}
1738
Mirko Bonadeic84f6612019-01-31 11:20:571739INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
1740 PeerConnectionMediaTest,
1741 Values(SdpSemantics::kPlanB,
1742 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 18:21:561743
Steve Anton8d3444d2017-10-20 22:30:511744} // namespace webrtc