blob: 077c4a3e43de6209ba6112f8e078c00e1bcfe649 [file] [log] [blame]
Steve Anton8d3444d2017-10-20 15:30:51 -07001/*
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 17:06:18 +020015#include <memory>
Steve Anton8d3444d2017-10-20 15:30:51 -070016#include <tuple>
17
Steve Anton64b626b2019-01-28 17:25:26 -080018#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 15:38:50 +020019#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "api/call/call_factory_interface.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020021#include "api/rtc_event_log/rtc_event_log_factory.h"
22#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#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 15:30:51 -070029#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080030#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070031#endif
Steve Anton10542f22019-01-11 09:11:00 -080032#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070033#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080034#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070035#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 15:30:51 -070044using ::testing::ElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020045using ::testing::Values;
Steve Anton8d3444d2017-10-20 15:30:51 -070046
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 10:21:56 -080060class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070061 protected:
62 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
63
Steve Antonad7bffc2018-01-22 10:21:56 -080064 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
65 : vss_(new rtc::VirtualSocketServer()),
66 main_(vss_.get()),
67 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -070068#ifdef WEBRTC_ANDROID
69 InitializeAndroidObjects();
70#endif
71 }
72
73 WrapperPtr CreatePeerConnection() {
74 return CreatePeerConnection(RTCConfiguration());
75 }
76
Florent Castelli2d9d82e2019-04-23 19:25:51 +020077 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020078 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 19:25:51 +020079 }
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 13:15:42 -070086 // Creates PeerConnectionFactory and PeerConnection for given configuration.
Florent Castelli2d9d82e2019-04-23 19:25:51 +020087 WrapperPtr CreatePeerConnection(
88 const RTCConfiguration& config,
89 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 15:30:51 -070090 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070091
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 10:19:42 +020097 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070098 factory_dependencies.media_engine = std::move(media_engine);
99 factory_dependencies.call_factory = CreateCallFactory();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200100 factory_dependencies.event_log_factory =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200101 std::make_unique<RtcEventLogFactory>(
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200102 factory_dependencies.task_queue_factory.get());
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700103
104 auto pc_factory =
105 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -0700106
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200107 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700108 rtc::Thread::Current(), nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200109 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 10:21:56 -0800110 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 15:30:51 -0700115 if (!pc) {
116 return nullptr;
117 }
118
Yves Gerey4e933292018-10-31 15:36:05 +0100119 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200120 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700121 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 10:57:24 -0800127 // 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 19:25:51 +0200138 // 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 10:57:24 -0800150 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 15:30:51 -0700151 // 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 14:57:10 -0800163 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700164 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800165 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 15:30:51 -0700174 }
175
176 std::unique_ptr<rtc::VirtualSocketServer> vss_;
177 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800178 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700179};
180
Steve Antonad7bffc2018-01-22 10:21:56 -0800181class 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 15:30:51 -0700201 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 10:21:56 -0800208 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
209 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700210}
211
Steve Antonad7bffc2018-01-22 10:21:56 -0800212TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700213 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 10:21:56 -0800219 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
220 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700221}
222
223std::vector<std::string> GetIds(
224 const std::vector<cricket::StreamParams>& streams) {
225 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100226 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700227 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 10:21:56 -0800236TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700237 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 10:21:56 -0800279// 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());
293 transceivers[0]->Stop();
294 transceivers[1]->Stop();
295
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 15:30:51 -0700302// Test that removing streams from a subsequent offer causes the receive streams
303// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800304// See previous test for equivalent behavior with Unified Plan semantics.
305TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700306 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 10:21:56 -0800311 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700312
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 10:21:56 -0800317 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700318
319 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800320 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700321 EXPECT_EQ(1u, callee_voice->send_streams().size());
322 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700323 EXPECT_EQ(1u, callee_video->send_streams().size());
324 EXPECT_EQ(0u, callee_video->recv_streams().size());
325}
326
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200327// 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 19:08:33 +0200335 auto* description = cricket::GetFirstMediaContent(offer->description(),
336 cricket::MEDIA_TYPE_VIDEO)
337 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200338 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 19:08:33 +0200362 auto* description = cricket::GetFirstMediaContent(answer->description(),
363 cricket::MEDIA_TYPE_VIDEO)
364 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200365 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 10:21:56 -0800377// 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());
391 transceivers[0]->Stop();
392 transceivers[1]->Stop();
393
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 15:30:51 -0700400// 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 10:21:56 -0800402// See previous test for equivalent behavior with Unified Plan semantics.
403TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700404 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 10:21:56 -0800409 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700410
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 10:21:56 -0800415 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700416
417 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800418 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700419 EXPECT_EQ(0u, callee_voice->send_streams().size());
420 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700421 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 10:21:56 -0800427TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700428 auto caller = CreatePeerConnectionWithAudioVideo();
429 auto callee = CreatePeerConnection();
430
Steve Antonad7bffc2018-01-22 10:21:56 -0800431 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700432
433 // Add second set of tracks to the caller.
434 caller->AddAudioTrack("a2");
435 caller->AddVideoTrack("v2");
436
Steve Antonad7bffc2018-01-22 10:21:56 -0800437 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700438
Steve Antonad7bffc2018-01-22 10:21:56 -0800439 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 15:30:51 -0700460}
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 10:21:56 -0800464TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700465 auto caller = CreatePeerConnection();
466 auto callee = CreatePeerConnectionWithAudioVideo();
467
Steve Anton22da89f2018-01-25 13:58:07 -0800468 RTCOfferAnswerOptions offer_options;
469 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700470 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800471 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700472 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800473 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700474
Steve Anton22da89f2018-01-25 13:58:07 -0800475 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
476 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700477
478 // Add second set of tracks to the callee.
479 callee->AddAudioTrack("a2");
480 callee->AddVideoTrack("v2");
481
Steve Anton22da89f2018-01-25 13:58:07 -0800482 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
483 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700484
485 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800486 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700487 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800488 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 15:30:51 -0700497}
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 10:21:56 -0800501TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700502 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 15:38:50 +0200519// 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 17:06:18 +0200528 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200529 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 17:06:18 +0200550 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200551 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200552 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200553 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 17:06:18 +0200593 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200594 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200595 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200596 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 15:30:51 -0700619class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800620 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700621 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800622 std::tuple<SdpSemantics,
623 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700624 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800625 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 15:30:51 -0700631 }
632
633 bool send_media_;
634 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800635 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700636};
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 10:21:56 -0800650 auto* content = cricket::GetFirstMediaContent(offer->description(),
651 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800652 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800653 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700654 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800655 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700656 }
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 12:20:57 +0100661INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 14:57:10 -0800662 PeerConnectionMediaTest,
663 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800664 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 15:30:51 -0700672
673class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800674 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700675 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800676 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700677 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800678 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 15:30:51 -0700683 }
684
Steve Anton4e70a722017-11-28 14:57:10 -0800685 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700686 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 13:58:07 -0800694 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 10:21:56 -0800698 return;
699 }
Steve Anton22da89f2018-01-25 13:58:07 -0800700
Steve Anton8d3444d2017-10-20 15:30:51 -0700701 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 14:57:10 -0800727 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
728 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700729
730 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800731 bool negotiate_send = (send_media_ && offer_recv);
732 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700733
734 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800735 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700736 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800737 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700738}
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 13:58:07 -0800744 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 10:21:56 -0800748 return;
749 }
Steve Anton22da89f2018-01-25 13:58:07 -0800750
Steve Anton8d3444d2017-10-20 15:30:51 -0700751 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 12:20:57 +0100777INSTANTIATE_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 15:30:51 -0700787
Steve Antonad7bffc2018-01-22 10:21:56 -0800788TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700789 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 14:57:10 -0800797 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800798 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800799 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800800 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700801}
802
Steve Antonad7bffc2018-01-22 10:21:56 -0800803TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800804 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800805 // offer_to_receive_ is not implemented when creating answers with Unified
806 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800807 return;
808 }
809
Steve Anton8d3444d2017-10-20 15:30:51 -0700810 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 14:57:10 -0800821 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800822 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800823 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800824 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700825}
826
827void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
828 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
829 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
830
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100831 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700832 codecs.push_back(kComfortNoiseCodec8k);
833 codecs.push_back(kComfortNoiseCodec16k);
834 media_engine->SetAudioCodecs(codecs);
835}
836
837bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
838 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
839 for (const auto& codec : audio_desc->codecs()) {
840 if (codec.name == "CN") {
841 return true;
842 }
843 }
844 return false;
845}
846
Steve Antonad7bffc2018-01-22 10:21:56 -0800847TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700848 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
849 auto caller = CreatePeerConnectionWithAudioVideo();
850 AddComfortNoiseCodecsToSend(caller->media_engine());
851
852 RTCOfferAnswerOptions options;
853 options.voice_activity_detection = false;
854 auto offer = caller->CreateOffer(options);
855
856 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
857}
858
Steve Antonad7bffc2018-01-22 10:21:56 -0800859TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700860 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
861 auto caller = CreatePeerConnectionWithAudioVideo();
862 AddComfortNoiseCodecsToSend(caller->media_engine());
863 auto callee = CreatePeerConnectionWithAudioVideo();
864 AddComfortNoiseCodecsToSend(callee->media_engine());
865
866 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
867
868 RTCOfferAnswerOptions options;
869 options.voice_activity_detection = false;
870 auto answer = callee->CreateAnswer(options);
871
872 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
873}
874
875// The following test group verifies that we reject answers with invalid media
876// sections as per RFC 3264.
877
878class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800879 : public PeerConnectionMediaBaseTest,
880 public ::testing::WithParamInterface<std::tuple<
881 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700882 std::tuple<std::string,
883 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800884 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700885 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800886 PeerConnectionMediaInvalidMediaTest()
887 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
888 auto param = std::get<1>(GetParam());
889 mutator_ = std::get<1>(param);
890 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700891 }
892
893 std::function<void(cricket::SessionDescription*)> mutator_;
894 std::string expected_error_;
895};
896
897TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
898 auto caller = CreatePeerConnectionWithAudioVideo();
899 auto callee = CreatePeerConnectionWithAudioVideo();
900
901 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
902
903 auto answer = callee->CreateAnswer();
904 mutator_(answer->description());
905
906 std::string error;
907 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
908 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
909}
910
911TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
912 auto caller = CreatePeerConnectionWithAudioVideo();
913 auto callee = CreatePeerConnectionWithAudioVideo();
914
915 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
916
917 auto answer = callee->CreateAnswer();
918 mutator_(answer->description());
919
920 std::string error;
921 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
922 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
923}
924
925void RemoveVideoContent(cricket::SessionDescription* desc) {
926 auto content_name = cricket::GetFirstVideoContent(desc)->name;
927 desc->RemoveContentByName(content_name);
928 desc->RemoveTransportInfoByName(content_name);
929}
930
931void RenameVideoContent(cricket::SessionDescription* desc) {
932 auto* video_content = cricket::GetFirstVideoContent(desc);
933 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
934 video_content->name = "video_renamed";
935 transport_info->content_name = video_content->name;
936}
937
938void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -0800939 absl::c_reverse(desc->contents());
940 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -0700941}
942
943void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800944 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
945 desc->RemoveContentByName(audio_mid);
946 auto* video_content = cricket::GetFirstVideoContent(desc);
947 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200948 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 15:30:51 -0700949}
950
951constexpr char kMLinesOutOfOrder[] =
952 "The order of m-lines in answer doesn't match order in offer. Rejecting "
953 "answer.";
954
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100955INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -0700956 PeerConnectionMediaTest,
957 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800958 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
959 Values(std::make_tuple("remove video",
960 RemoveVideoContent,
961 kMLinesOutOfOrder),
962 std::make_tuple("rename video",
963 RenameVideoContent,
964 kMLinesOutOfOrder),
965 std::make_tuple("reverse media sections",
966 ReverseMediaContent,
967 kMLinesOutOfOrder),
968 std::make_tuple("change audio type to video type",
969 ChangeMediaTypeAudioToVideo,
970 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700971
972// Test that the correct media engine send/recv streams are created when doing
973// a series of offer/answers where audio/video are both sent, then audio is
974// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800975TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800976 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800977 // offer_to_receive_ is not implemented when creating answers with Unified
978 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800979 return;
980 }
981
Steve Anton8d3444d2017-10-20 15:30:51 -0700982 RTCOfferAnswerOptions options_reject_video;
983 options_reject_video.offer_to_receive_audio =
984 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
985 options_reject_video.offer_to_receive_video = 0;
986
987 auto caller = CreatePeerConnection();
988 caller->AddAudioTrack("a");
989 caller->AddVideoTrack("v");
990 auto callee = CreatePeerConnection();
991
992 // Caller initially offers to send/recv audio and video.
993 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
994 // Callee accepts the audio as recv only but rejects the video.
995 ASSERT_TRUE(caller->SetRemoteDescription(
996 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
997
998 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
999 ASSERT_TRUE(caller_voice);
1000 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1001 EXPECT_EQ(1u, caller_voice->send_streams().size());
1002 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1003 EXPECT_FALSE(caller_video);
1004
1005 // Callee adds its own audio/video stream and offers to receive audio/video
1006 // too.
1007 callee->AddAudioTrack("a");
1008 auto callee_video_track = callee->AddVideoTrack("v");
1009 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1010 ASSERT_TRUE(
1011 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1012
1013 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1014 ASSERT_TRUE(callee_voice);
1015 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1016 EXPECT_EQ(1u, callee_voice->send_streams().size());
1017 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1018 ASSERT_TRUE(callee_video);
1019 EXPECT_EQ(1u, callee_video->recv_streams().size());
1020 EXPECT_EQ(1u, callee_video->send_streams().size());
1021
1022 // Callee removes video but keeps audio and rejects the video once again.
1023 callee->pc()->RemoveTrack(callee_video_track);
1024 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1025 ASSERT_TRUE(
1026 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1027
1028 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1029 ASSERT_TRUE(callee_voice);
1030 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1031 EXPECT_EQ(1u, callee_voice->send_streams().size());
1032 callee_video = callee->media_engine()->GetVideoChannel(0);
1033 EXPECT_FALSE(callee_video);
1034}
1035
1036// Test that the correct media engine send/recv streams are created when doing
1037// a series of offer/answers where audio/video are both sent, then video is
1038// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001039TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001040 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001041 // offer_to_receive_ is not implemented when creating answers with Unified
1042 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001043 return;
1044 }
1045
Steve Anton8d3444d2017-10-20 15:30:51 -07001046 // Disable the bundling here. If the media is bundled on audio
1047 // transport, then we can't reject the audio because switching the bundled
1048 // transport is not currently supported.
1049 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1050 RTCOfferAnswerOptions options_no_bundle;
1051 options_no_bundle.use_rtp_mux = false;
1052 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1053 options_reject_audio.offer_to_receive_audio = 0;
1054 options_reject_audio.offer_to_receive_video =
1055 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1056
1057 auto caller = CreatePeerConnection();
1058 caller->AddAudioTrack("a");
1059 caller->AddVideoTrack("v");
1060 auto callee = CreatePeerConnection();
1061
1062 // Caller initially offers to send/recv audio and video.
1063 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1064 // Callee accepts the video as recv only but rejects the audio.
1065 ASSERT_TRUE(caller->SetRemoteDescription(
1066 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1067
1068 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1069 EXPECT_FALSE(caller_voice);
1070 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1071 ASSERT_TRUE(caller_video);
1072 EXPECT_EQ(0u, caller_video->recv_streams().size());
1073 EXPECT_EQ(1u, caller_video->send_streams().size());
1074
1075 // Callee adds its own audio/video stream and offers to receive audio/video
1076 // too.
1077 auto callee_audio_track = callee->AddAudioTrack("a");
1078 callee->AddVideoTrack("v");
1079 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1080 ASSERT_TRUE(caller->SetRemoteDescription(
1081 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1082
1083 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1084 ASSERT_TRUE(callee_voice);
1085 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1086 EXPECT_EQ(1u, callee_voice->send_streams().size());
1087 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1088 ASSERT_TRUE(callee_video);
1089 EXPECT_EQ(1u, callee_video->recv_streams().size());
1090 EXPECT_EQ(1u, callee_video->send_streams().size());
1091
1092 // Callee removes audio but keeps video and rejects the audio once again.
1093 callee->pc()->RemoveTrack(callee_audio_track);
1094 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1095 ASSERT_TRUE(
1096 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1097
1098 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1099 EXPECT_FALSE(callee_voice);
1100 callee_video = callee->media_engine()->GetVideoChannel(0);
1101 ASSERT_TRUE(callee_video);
1102 EXPECT_EQ(1u, callee_video->recv_streams().size());
1103 EXPECT_EQ(1u, callee_video->send_streams().size());
1104}
1105
1106// Tests that if the underlying video encoder fails to be initialized (signaled
1107// by failing to set send codecs), the PeerConnection signals the error to the
1108// client.
Steve Antonad7bffc2018-01-22 10:21:56 -08001109TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001110 auto caller = CreatePeerConnectionWithAudioVideo();
1111 auto callee = CreatePeerConnectionWithAudioVideo();
1112
1113 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1114
1115 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1116 video_channel->set_fail_set_send_codecs(true);
1117
1118 std::string error;
1119 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1120 &error));
1121 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -08001122 "Failed to set remote answer sdp: Failed to set remote video description "
1123 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -07001124 error);
1125}
1126
1127// Tests that if the underlying video encoder fails once then subsequent
1128// attempts at setting the local/remote description will also fail, even if
1129// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001130TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001131 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1132 auto caller = CreatePeerConnectionWithAudioVideo();
1133 auto callee = CreatePeerConnectionWithAudioVideo();
1134
1135 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1136
1137 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1138 video_channel->set_fail_set_send_codecs(true);
1139
1140 EXPECT_FALSE(
1141 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1142
1143 video_channel->set_fail_set_send_codecs(false);
1144
1145 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1146 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1147}
1148
1149void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001150 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001151 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001152 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001153 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001154 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001155 content->name = new_name;
1156 auto* transport = desc->GetTransportInfoByName(old_name);
1157 RTC_DCHECK(transport);
1158 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001159
1160 // Rename the content name in the BUNDLE group.
1161 cricket::ContentGroup new_bundle_group =
1162 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1163 new_bundle_group.RemoveContentName(old_name);
1164 new_bundle_group.AddContentName(new_name);
1165 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1166 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001167}
1168
1169// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001170TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001171 const std::string kAudioMid = "notdefault1";
1172 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001173
1174 auto caller = CreatePeerConnectionWithAudioVideo();
1175 auto callee = CreatePeerConnectionWithAudioVideo();
1176
1177 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001178 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1179 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001180 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1181
1182 auto answer = callee->CreateAnswer();
1183 EXPECT_EQ(kAudioMid,
1184 cricket::GetFirstAudioContent(answer->description())->name);
1185 EXPECT_EQ(kVideoMid,
1186 cricket::GetFirstVideoContent(answer->description())->name);
1187}
1188
1189// Test that if the callee creates a re-offer, the MIDs are the same as the
1190// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001191TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001192 const std::string kAudioMid = "notdefault1";
1193 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001194
1195 auto caller = CreatePeerConnectionWithAudioVideo();
1196 auto callee = CreatePeerConnectionWithAudioVideo();
1197
1198 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001199 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1200 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001201 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1202 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1203
1204 auto reoffer = callee->CreateOffer();
1205 EXPECT_EQ(kAudioMid,
1206 cricket::GetFirstAudioContent(reoffer->description())->name);
1207 EXPECT_EQ(kVideoMid,
1208 cricket::GetFirstVideoContent(reoffer->description())->name);
1209}
1210
Steve Anton06817cd2018-12-18 15:55:30 -08001211// Test that SetRemoteDescription returns an error if there are two m= sections
1212// with the same MID value.
1213TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1214 auto caller = CreatePeerConnectionWithAudioVideo();
1215 auto callee = CreatePeerConnectionWithAudioVideo();
1216
1217 auto offer = caller->CreateOffer();
1218 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1219 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1220
1221 std::string error;
1222 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1223 EXPECT_EQ(error,
1224 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1225}
1226
Steve Antonad7bffc2018-01-22 10:21:56 -08001227TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001228 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1229 RTCConfiguration config;
1230 config.combined_audio_video_bwe.emplace(true);
1231 auto caller = CreatePeerConnectionWithAudioVideo(config);
1232
1233 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1234
1235 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1236 ASSERT_TRUE(caller_voice);
1237 const cricket::AudioOptions& audio_options = caller_voice->options();
1238 EXPECT_EQ(config.combined_audio_video_bwe,
1239 audio_options.combined_audio_video_bwe);
1240}
1241
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001242template <typename C>
1243bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1244 const std::vector<C>& codecs) {
1245 bool capability_has_rtx =
1246 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1247 return codec.name == cricket::kRtxCodecName;
1248 });
1249 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1250 return codec.name == cricket::kRtxCodecName;
1251 });
1252
1253 std::vector<C> codecs_no_rtx;
1254 absl::c_copy_if(
1255 codecs, std::back_inserter(codecs_no_rtx),
1256 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1257
1258 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1259 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1260 [](const webrtc::RtpCodecCapability& codec) {
1261 return codec.name != cricket::kRtxCodecName;
1262 });
1263
1264 return capability_has_rtx == codecs_has_rtx &&
1265 absl::c_equal(
1266 capabilities_no_rtx, codecs_no_rtx,
1267 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1268 return codec.MatchesCapability(capability);
1269 });
1270}
1271
1272TEST_F(PeerConnectionMediaTestUnifiedPlan,
1273 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001274 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001275 auto send_codecs = fake_engine->voice().send_codecs();
1276 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1277 "send_only_codec", 0, 0, 1));
1278 fake_engine->SetAudioSendCodecs(send_codecs);
1279
1280 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1281
1282 auto transceiver = caller->pc()->GetTransceivers().front();
1283 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1284 cricket::MediaType::MEDIA_TYPE_AUDIO);
1285
1286 std::vector<webrtc::RtpCodecCapability> codecs;
1287 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1288 [](const webrtc::RtpCodecCapability& codec) {
1289 return codec.name.find("_only_") != std::string::npos;
1290 });
1291
1292 auto result = transceiver->SetCodecPreferences(codecs);
1293 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1294}
1295
1296TEST_F(PeerConnectionMediaTestUnifiedPlan,
1297 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001298 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001299 auto recv_codecs = fake_engine->voice().recv_codecs();
1300 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1301 "recv_only_codec", 0, 0, 1));
1302 fake_engine->SetAudioRecvCodecs(recv_codecs);
1303 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1304
1305 auto transceiver = caller->pc()->GetTransceivers().front();
1306 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1307 cricket::MediaType::MEDIA_TYPE_AUDIO);
1308
1309 std::vector<webrtc::RtpCodecCapability> codecs;
1310 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1311 [](const webrtc::RtpCodecCapability& codec) {
1312 return codec.name.find("_only_") != std::string::npos;
1313 });
1314
1315 auto result = transceiver->SetCodecPreferences(codecs);
1316 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1317}
1318
1319TEST_F(PeerConnectionMediaTestUnifiedPlan,
1320 SetCodecPreferencesAudioRejectsVideoCodec) {
1321 auto caller = CreatePeerConnectionWithAudio();
1322
1323 auto transceiver = caller->pc()->GetTransceivers().front();
1324 auto video_codecs =
1325 caller->pc_factory()
1326 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1327 .codecs;
1328 auto codecs =
1329 caller->pc_factory()
1330 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1331 .codecs;
1332 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1333 auto result = transceiver->SetCodecPreferences(codecs);
1334 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1335}
1336
1337TEST_F(PeerConnectionMediaTestUnifiedPlan,
1338 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001339 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001340 auto audio_codecs = fake_engine->voice().send_codecs();
1341 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1342 cricket::kRtxCodecName, 0, 0, 1));
1343 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1344 std::to_string(audio_codecs.back().id - 1);
1345 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1346 cricket::kRedCodecName, 0, 0, 1));
1347 audio_codecs.push_back(cricket::AudioCodec(
1348 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1349 fake_engine->SetAudioCodecs(audio_codecs);
1350
1351 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1352
1353 auto transceiver = caller->pc()->GetTransceivers().front();
1354 auto codecs =
1355 caller->pc_factory()
1356 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1357 .codecs;
1358 auto codecs_only_rtx_red_fec = codecs;
1359 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1360 codecs_only_rtx_red_fec.end(),
1361 [](const webrtc::RtpCodecCapability& codec) {
1362 return !(codec.name == cricket::kRtxCodecName ||
1363 codec.name == cricket::kRedCodecName ||
1364 codec.name == cricket::kUlpfecCodecName);
1365 });
1366 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1367
1368 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1369 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1370}
1371
1372TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1373 auto caller = CreatePeerConnectionWithAudio();
1374
1375 auto sender_audio_codecs =
1376 caller->pc_factory()
1377 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1378 .codecs;
1379
1380 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1381
1382 // Normal case, set all capabilities as preferences
1383 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1384 auto offer = caller->CreateOffer();
1385 auto codecs = offer->description()
1386 ->contents()[0]
1387 .media_description()
1388 ->as_audio()
1389 ->codecs();
1390 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1391}
1392
1393TEST_F(PeerConnectionMediaTestUnifiedPlan,
1394 SetCodecPreferencesResetAudioCodecs) {
1395 auto caller = CreatePeerConnectionWithAudio();
1396
1397 auto sender_audio_codecs =
1398 caller->pc_factory()
1399 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1400 .codecs;
1401 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1402
1403 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1404
1405 // Normal case, reset codec preferences
1406 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1407 auto offer = caller->CreateOffer();
1408 auto codecs = offer->description()
1409 ->contents()[0]
1410 .media_description()
1411 ->as_audio()
1412 ->codecs();
1413 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1414}
1415
1416TEST_F(PeerConnectionMediaTestUnifiedPlan,
1417 SetCodecPreferencesVideoRejectsAudioCodec) {
1418 auto caller = CreatePeerConnectionWithVideo();
1419
1420 auto transceiver = caller->pc()->GetTransceivers().front();
1421 auto audio_codecs =
1422 caller->pc_factory()
1423 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1424 .codecs;
1425 auto codecs =
1426 caller->pc_factory()
1427 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1428 .codecs;
1429 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1430 auto result = transceiver->SetCodecPreferences(codecs);
1431 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1432}
1433
1434TEST_F(PeerConnectionMediaTestUnifiedPlan,
1435 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001436 auto fake_engine = std::make_unique<FakeMediaEngine>();
Mirko Bonadeif5ecb5f2020-01-13 08:12:47 +00001437 auto video_codecs = fake_engine->video().codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001438 video_codecs.push_back(
1439 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
1440 video_codecs.push_back(
1441 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1442 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1443 cricket::kUlpfecCodecName));
1444 fake_engine->SetVideoCodecs(video_codecs);
1445
1446 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1447
1448 auto transceiver = caller->pc()->GetTransceivers().front();
1449 auto codecs =
1450 caller->pc_factory()
1451 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1452 .codecs;
1453 auto codecs_only_rtx_red_fec = codecs;
1454 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1455 codecs_only_rtx_red_fec.end(),
1456 [](const webrtc::RtpCodecCapability& codec) {
1457 return !(codec.name == cricket::kRtxCodecName ||
1458 codec.name == cricket::kRedCodecName ||
1459 codec.name == cricket::kUlpfecCodecName);
1460 });
1461 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1462
1463 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1464 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1465}
1466
1467TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1468 auto caller = CreatePeerConnectionWithVideo();
1469
1470 auto sender_video_codecs =
1471 caller->pc_factory()
1472 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1473 .codecs;
1474
1475 auto video_transceiver = caller->pc()->GetTransceivers().front();
1476
1477 // Normal case, setting preferences to normal capabilities
1478 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1479 auto offer = caller->CreateOffer();
1480 auto codecs = offer->description()
1481 ->contents()[0]
1482 .media_description()
1483 ->as_video()
1484 ->codecs();
1485 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1486}
1487
1488TEST_F(PeerConnectionMediaTestUnifiedPlan,
1489 SetCodecPreferencesResetVideoCodecs) {
1490 auto caller = CreatePeerConnectionWithVideo();
1491
1492 auto sender_video_codecs =
1493 caller->pc_factory()
1494 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1495 .codecs;
1496
1497 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1498
1499 auto video_transceiver = caller->pc()->GetTransceivers().front();
1500
1501 // Normal case, resetting preferences with empty list of codecs
1502 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1503 auto offer = caller->CreateOffer();
1504 auto codecs = offer->description()
1505 ->contents()[0]
1506 .media_description()
1507 ->as_video()
1508 ->codecs();
1509 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1510}
1511
1512TEST_F(PeerConnectionMediaTestUnifiedPlan,
1513 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1514 auto caller = CreatePeerConnectionWithVideo();
1515
1516 auto sender_video_codecs =
1517 caller->pc_factory()
1518 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1519 .codecs;
1520
1521 auto video_transceiver = caller->pc()->GetTransceivers().front();
1522
1523 // Check duplicates are removed
1524 auto single_codec = sender_video_codecs;
1525 single_codec.resize(1);
1526 auto duplicate_codec = single_codec;
1527 duplicate_codec.push_back(duplicate_codec.front());
1528 duplicate_codec.push_back(duplicate_codec.front());
1529 duplicate_codec.push_back(duplicate_codec.front());
1530
1531 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1532 auto offer = caller->CreateOffer();
1533 auto codecs = offer->description()
1534 ->contents()[0]
1535 .media_description()
1536 ->as_video()
1537 ->codecs();
1538 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1539}
1540
1541TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001542 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirko Bonadeif5ecb5f2020-01-13 08:12:47 +00001543 auto caller_video_codecs = caller_fake_engine->video().codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001544 caller_video_codecs.push_back(cricket::VideoCodec(
1545 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1546 caller_video_codecs.push_back(cricket::VideoCodec(
1547 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1548 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1549 std::to_string(caller_video_codecs.back().id - 1);
1550 caller_video_codecs.push_back(cricket::VideoCodec(
1551 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1552 caller_video_codecs.push_back(cricket::VideoCodec(
1553 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1554 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1555 std::to_string(caller_video_codecs.back().id - 1);
1556 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1557
1558 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1559
1560 auto sender_video_codecs =
1561 caller->pc_factory()
1562 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1563 .codecs;
1564
1565 auto video_transceiver = caller->pc()->GetTransceivers().front();
1566
1567 // Check that RTX codec is properly added
1568 auto video_codecs_vpx_rtx = sender_video_codecs;
1569 auto it =
1570 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1571 [](const webrtc::RtpCodecCapability& codec) {
1572 return codec.name != cricket::kRtxCodecName &&
1573 codec.name != cricket::kVp8CodecName &&
1574 codec.name != cricket::kVp9CodecName;
1575 });
1576 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1577 absl::c_reverse(video_codecs_vpx_rtx);
1578 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1579 EXPECT_TRUE(
1580 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1581 auto offer = caller->CreateOffer();
1582 auto codecs = offer->description()
1583 ->contents()[0]
1584 .media_description()
1585 ->as_video()
1586 ->codecs();
1587
1588 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1589 EXPECT_EQ(codecs.size(), 4u);
1590}
1591
1592TEST_F(PeerConnectionMediaTestUnifiedPlan,
1593 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001594 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirko Bonadeif5ecb5f2020-01-13 08:12:47 +00001595 auto caller_video_codecs = caller_fake_engine->video().codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001596 caller_video_codecs.push_back(cricket::VideoCodec(
1597 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1598 caller_video_codecs.push_back(cricket::VideoCodec(
1599 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1600 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1601 std::to_string(caller_video_codecs.back().id - 1);
1602 caller_video_codecs.push_back(cricket::VideoCodec(
1603 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1604 caller_video_codecs.push_back(cricket::VideoCodec(
1605 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1606 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1607 std::to_string(caller_video_codecs.back().id - 1);
1608 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1609
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001610 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001611 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1612
1613 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1614 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1615
1616 auto video_codecs = caller->pc_factory()
1617 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1618 .codecs;
1619
1620 auto send_transceiver = caller->pc()->GetTransceivers().front();
1621
1622 auto video_codecs_vpx = video_codecs;
1623 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1624 [](const webrtc::RtpCodecCapability& codec) {
1625 return codec.name != cricket::kVp8CodecName &&
1626 codec.name != cricket::kVp9CodecName;
1627 });
1628 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1629 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1630 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1631
1632 auto offer = caller->CreateOfferAndSetAsLocal();
1633 auto codecs = offer->description()
1634 ->contents()[0]
1635 .media_description()
1636 ->as_video()
1637 ->codecs();
1638
1639 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1640 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1641
1642 callee->SetRemoteDescription(std::move(offer));
1643
1644 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1645 auto video_codecs_vp8_rtx = video_codecs;
1646 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1647 [](const webrtc::RtpCodecCapability& codec) {
1648 bool r = codec.name != cricket::kVp8CodecName &&
1649 codec.name != cricket::kRtxCodecName;
1650 return r;
1651 });
1652 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1653 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1654 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1655
1656 auto answer = callee->CreateAnswerAndSetAsLocal();
1657
1658 auto recv_codecs = answer->description()
1659 ->contents()[0]
1660 .media_description()
1661 ->as_video()
1662 ->codecs();
1663 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1664}
1665
1666TEST_F(PeerConnectionMediaTestUnifiedPlan,
1667 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001668 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirko Bonadeif5ecb5f2020-01-13 08:12:47 +00001669 auto caller_video_codecs = caller_fake_engine->video().codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001670 caller_video_codecs.push_back(cricket::VideoCodec(
1671 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1672 caller_video_codecs.push_back(cricket::VideoCodec(
1673 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1674 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1675 std::to_string(caller_video_codecs.back().id - 1);
1676 caller_video_codecs.push_back(cricket::VideoCodec(
1677 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1678 caller_video_codecs.push_back(cricket::VideoCodec(
1679 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1680 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1681 std::to_string(caller_video_codecs.back().id - 1);
1682 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1683
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001684 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001685 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1686
1687 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1688 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1689
1690 auto video_codecs = caller->pc_factory()
1691 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1692 .codecs;
1693
1694 auto send_transceiver = caller->pc()->GetTransceivers().front();
1695
1696 auto video_codecs_vpx = video_codecs;
1697 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1698 [](const webrtc::RtpCodecCapability& codec) {
1699 return codec.name != cricket::kVp8CodecName &&
1700 codec.name != cricket::kVp9CodecName;
1701 });
1702 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1703 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1704 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1705
1706 auto video_codecs_vpx_reverse = video_codecs_vpx;
1707 absl::c_reverse(video_codecs_vpx_reverse);
1708
1709 auto offer = caller->CreateOfferAndSetAsLocal();
1710 auto codecs = offer->description()
1711 ->contents()[0]
1712 .media_description()
1713 ->as_video()
1714 ->codecs();
1715 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1716 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1717
1718 callee->SetRemoteDescription(std::move(offer));
1719
1720 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1721 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1722
1723 auto answer = callee->CreateAnswerAndSetAsLocal();
1724
1725 auto recv_codecs = answer->description()
1726 ->contents()[0]
1727 .media_description()
1728 ->as_video()
1729 ->codecs();
1730
1731 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1732}
1733
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001734INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
1735 PeerConnectionMediaTest,
1736 Values(SdpSemantics::kPlanB,
1737 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08001738
Steve Anton8d3444d2017-10-20 15:30:51 -07001739} // namespace webrtc