blob: e9e3a00a13f00750e921f6a48981f2118305a14e [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
15#include <tuple>
16
Steve Anton64b626b2019-01-28 17:25:26 -080017#include "absl/algorithm/container.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "api/call/call_factory_interface.h"
Anton Sukhanov98a462c2018-10-17 13:15:42 -070019#include "api/test/fake_media_transport.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070020#include "logging/rtc_event_log/rtc_event_log_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "media/base/fake_media_engine.h"
22#include "p2p/base/fake_port_allocator.h"
23#include "pc/media_session.h"
24#include "pc/peer_connection_wrapper.h"
25#include "pc/rtp_media_utils.h"
26#include "pc/sdp_utils.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070027#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070029#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020030#include "absl/memory/memory.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070032#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070034#include "test/gmock.h"
35
36namespace webrtc {
37
38using cricket::FakeMediaEngine;
39using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
40using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
41using ::testing::Bool;
42using ::testing::Combine;
43using ::testing::Values;
44using ::testing::ElementsAre;
45
46class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
47 public:
48 using PeerConnectionWrapper::PeerConnectionWrapper;
49
50 FakeMediaEngine* media_engine() { return media_engine_; }
51 void set_media_engine(FakeMediaEngine* media_engine) {
52 media_engine_ = media_engine;
53 }
54
55 private:
56 FakeMediaEngine* media_engine_;
57};
58
Steve Antonad7bffc2018-01-22 10:21:56 -080059class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070060 protected:
61 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
62
Steve Antonad7bffc2018-01-22 10:21:56 -080063 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
64 : vss_(new rtc::VirtualSocketServer()),
65 main_(vss_.get()),
66 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -070067#ifdef WEBRTC_ANDROID
68 InitializeAndroidObjects();
69#endif
70 }
71
72 WrapperPtr CreatePeerConnection() {
73 return CreatePeerConnection(RTCConfiguration());
74 }
75
Florent Castelli2d9d82e2019-04-23 19:25:51 +020076 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
77 return CreatePeerConnection(config, absl::make_unique<FakeMediaEngine>());
78 }
79
80 WrapperPtr CreatePeerConnection(
81 std::unique_ptr<FakeMediaEngine> media_engine) {
82 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
83 }
84
Anton Sukhanov98a462c2018-10-17 13:15:42 -070085 // Creates PeerConnectionFactory and PeerConnection for given configuration.
86 // Note that PeerConnectionFactory is created with MediaTransportFactory,
87 // because some tests pass config.use_media_transport = true.
Florent Castelli2d9d82e2019-04-23 19:25:51 +020088 WrapperPtr CreatePeerConnection(
89 const RTCConfiguration& config,
90 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 15:30:51 -070091 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070092
93 PeerConnectionFactoryDependencies factory_dependencies;
94
95 factory_dependencies.network_thread = rtc::Thread::Current();
96 factory_dependencies.worker_thread = rtc::Thread::Current();
97 factory_dependencies.signaling_thread = rtc::Thread::Current();
98 factory_dependencies.media_engine = std::move(media_engine);
99 factory_dependencies.call_factory = CreateCallFactory();
100 factory_dependencies.event_log_factory = CreateRtcEventLogFactory();
101 factory_dependencies.media_transport_factory =
102 absl::make_unique<FakeMediaTransportFactory>();
103
104 auto pc_factory =
105 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -0700106
Karl Wiberg918f50c2018-07-05 11:40:33 +0200107 auto fake_port_allocator = absl::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700108 rtc::Thread::Current(), nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200109 auto observer = absl::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());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200120 auto wrapper = absl::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);
335 auto* description = cricket::GetFirstMediaContent(
336 offer->description(),
337 cricket::MEDIA_TYPE_VIDEO)->media_description();
338 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);
362 auto* description = cricket::GetFirstMediaContent(
363 answer->description(),
364 cricket::MEDIA_TYPE_VIDEO)->media_description();
365 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
519class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800520 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700521 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800522 std::tuple<SdpSemantics,
523 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700524 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800525 PeerConnectionMediaOfferDirectionTest()
526 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
527 auto param = std::get<1>(GetParam());
528 send_media_ = std::get<0>(param);
529 offer_to_receive_ = std::get<1>(param);
530 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700531 }
532
533 bool send_media_;
534 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800535 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700536};
537
538// Tests that the correct direction is set on the media description according
539// to the presence of a local media track and the offer_to_receive setting.
540TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
541 auto caller = CreatePeerConnection();
542 if (send_media_) {
543 caller->AddAudioTrack("a");
544 }
545
546 RTCOfferAnswerOptions options;
547 options.offer_to_receive_audio = offer_to_receive_;
548 auto offer = caller->CreateOffer(options);
549
Steve Antonad7bffc2018-01-22 10:21:56 -0800550 auto* content = cricket::GetFirstMediaContent(offer->description(),
551 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800552 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800553 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700554 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800555 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700556 }
557}
558
559// Note that in these tests, MD_INACTIVE indicates that no media section is
560// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100561INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 14:57:10 -0800562 PeerConnectionMediaTest,
563 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800564 Combine(
565 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
566 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
567 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
568 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
569 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
570 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
571 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700572
573class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800574 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700575 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800576 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700577 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800578 PeerConnectionMediaAnswerDirectionTest()
579 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
580 offer_direction_ = std::get<1>(GetParam());
581 send_media_ = std::get<2>(GetParam());
582 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700583 }
584
Steve Anton4e70a722017-11-28 14:57:10 -0800585 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700586 bool send_media_;
587 int offer_to_receive_;
588};
589
590// Tests that the direction in an answer is correct according to direction sent
591// in the offer, the presence of a local media track on the receive side and the
592// offer_to_receive setting.
593TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800594 if (IsUnifiedPlan() &&
595 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
596 // offer_to_receive_ is not implemented when creating answers with Unified
597 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800598 return;
599 }
Steve Anton22da89f2018-01-25 13:58:07 -0800600
Steve Anton8d3444d2017-10-20 15:30:51 -0700601 auto caller = CreatePeerConnection();
602 caller->AddAudioTrack("a");
603
604 // Create the offer with an audio section and set its direction.
605 auto offer = caller->CreateOffer();
606 cricket::GetFirstAudioContentDescription(offer->description())
607 ->set_direction(offer_direction_);
608
609 auto callee = CreatePeerConnection();
610 if (send_media_) {
611 callee->AddAudioTrack("a");
612 }
613 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
614
615 // Create the answer according to the test parameters.
616 RTCOfferAnswerOptions options;
617 options.offer_to_receive_audio = offer_to_receive_;
618 auto answer = callee->CreateAnswer(options);
619
620 // The expected direction in the answer is the intersection of each side's
621 // capability to send/recv media.
622 // For the offerer, the direction is given in the offer (offer_direction_).
623 // For the answerer, the direction has two components:
624 // 1. Send if the answerer has a local track to send.
625 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
626 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800627 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
628 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700629
630 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800631 bool negotiate_send = (send_media_ && offer_recv);
632 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700633
634 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800635 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700636 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800637 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700638}
639
640// Tests that the media section is rejected if and only if the callee has no
641// local media track and has set offer_to_receive to 0, no matter which
642// direction the caller indicated in the offer.
643TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800644 if (IsUnifiedPlan() &&
645 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
646 // offer_to_receive_ is not implemented when creating answers with Unified
647 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800648 return;
649 }
Steve Anton22da89f2018-01-25 13:58:07 -0800650
Steve Anton8d3444d2017-10-20 15:30:51 -0700651 auto caller = CreatePeerConnection();
652 caller->AddAudioTrack("a");
653
654 // Create the offer with an audio section and set its direction.
655 auto offer = caller->CreateOffer();
656 cricket::GetFirstAudioContentDescription(offer->description())
657 ->set_direction(offer_direction_);
658
659 auto callee = CreatePeerConnection();
660 if (send_media_) {
661 callee->AddAudioTrack("a");
662 }
663 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
664
665 // Create the answer according to the test parameters.
666 RTCOfferAnswerOptions options;
667 options.offer_to_receive_audio = offer_to_receive_;
668 auto answer = callee->CreateAnswer(options);
669
670 // The media section is rejected if and only if offer_to_receive is explicitly
671 // set to 0 and there is no media to send.
672 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
673 ASSERT_TRUE(audio_content);
674 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
675}
676
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100677INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
678 PeerConnectionMediaAnswerDirectionTest,
679 Combine(Values(SdpSemantics::kPlanB,
680 SdpSemantics::kUnifiedPlan),
681 Values(RtpTransceiverDirection::kInactive,
682 RtpTransceiverDirection::kSendOnly,
683 RtpTransceiverDirection::kRecvOnly,
684 RtpTransceiverDirection::kSendRecv),
685 Bool(),
686 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 15:30:51 -0700687
Steve Antonad7bffc2018-01-22 10:21:56 -0800688TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700689 auto caller = CreatePeerConnection();
690 caller->AddVideoTrack("v");
691
692 RTCOfferAnswerOptions options;
693 options.offer_to_receive_audio = 1;
694 options.offer_to_receive_video = 0;
695 auto offer = caller->CreateOffer(options);
696
Steve Anton4e70a722017-11-28 14:57:10 -0800697 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800698 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800699 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800700 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700701}
702
Steve Antonad7bffc2018-01-22 10:21:56 -0800703TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800704 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800705 // offer_to_receive_ is not implemented when creating answers with Unified
706 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800707 return;
708 }
709
Steve Anton8d3444d2017-10-20 15:30:51 -0700710 auto caller = CreatePeerConnectionWithAudioVideo();
711 auto callee = CreatePeerConnection();
712 callee->AddVideoTrack("v");
713
714 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
715
716 RTCOfferAnswerOptions options;
717 options.offer_to_receive_audio = 1;
718 options.offer_to_receive_video = 0;
719 auto answer = callee->CreateAnswer(options);
720
Steve Anton4e70a722017-11-28 14:57:10 -0800721 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800722 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800723 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800724 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700725}
726
727void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
728 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
729 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
730
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100731 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700732 codecs.push_back(kComfortNoiseCodec8k);
733 codecs.push_back(kComfortNoiseCodec16k);
734 media_engine->SetAudioCodecs(codecs);
735}
736
737bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
738 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
739 for (const auto& codec : audio_desc->codecs()) {
740 if (codec.name == "CN") {
741 return true;
742 }
743 }
744 return false;
745}
746
Steve Antonad7bffc2018-01-22 10:21:56 -0800747TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700748 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
749 auto caller = CreatePeerConnectionWithAudioVideo();
750 AddComfortNoiseCodecsToSend(caller->media_engine());
751
752 RTCOfferAnswerOptions options;
753 options.voice_activity_detection = false;
754 auto offer = caller->CreateOffer(options);
755
756 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
757}
758
Steve Antonad7bffc2018-01-22 10:21:56 -0800759TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700760 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
761 auto caller = CreatePeerConnectionWithAudioVideo();
762 AddComfortNoiseCodecsToSend(caller->media_engine());
763 auto callee = CreatePeerConnectionWithAudioVideo();
764 AddComfortNoiseCodecsToSend(callee->media_engine());
765
766 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
767
768 RTCOfferAnswerOptions options;
769 options.voice_activity_detection = false;
770 auto answer = callee->CreateAnswer(options);
771
772 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
773}
774
775// The following test group verifies that we reject answers with invalid media
776// sections as per RFC 3264.
777
778class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800779 : public PeerConnectionMediaBaseTest,
780 public ::testing::WithParamInterface<std::tuple<
781 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700782 std::tuple<std::string,
783 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800784 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700785 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800786 PeerConnectionMediaInvalidMediaTest()
787 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
788 auto param = std::get<1>(GetParam());
789 mutator_ = std::get<1>(param);
790 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700791 }
792
793 std::function<void(cricket::SessionDescription*)> mutator_;
794 std::string expected_error_;
795};
796
797TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
798 auto caller = CreatePeerConnectionWithAudioVideo();
799 auto callee = CreatePeerConnectionWithAudioVideo();
800
801 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
802
803 auto answer = callee->CreateAnswer();
804 mutator_(answer->description());
805
806 std::string error;
807 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
808 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
809}
810
811TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
812 auto caller = CreatePeerConnectionWithAudioVideo();
813 auto callee = CreatePeerConnectionWithAudioVideo();
814
815 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
816
817 auto answer = callee->CreateAnswer();
818 mutator_(answer->description());
819
820 std::string error;
821 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
822 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
823}
824
825void RemoveVideoContent(cricket::SessionDescription* desc) {
826 auto content_name = cricket::GetFirstVideoContent(desc)->name;
827 desc->RemoveContentByName(content_name);
828 desc->RemoveTransportInfoByName(content_name);
829}
830
831void RenameVideoContent(cricket::SessionDescription* desc) {
832 auto* video_content = cricket::GetFirstVideoContent(desc);
833 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
834 video_content->name = "video_renamed";
835 transport_info->content_name = video_content->name;
836}
837
838void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -0800839 absl::c_reverse(desc->contents());
840 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -0700841}
842
843void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800844 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
845 desc->RemoveContentByName(audio_mid);
846 auto* video_content = cricket::GetFirstVideoContent(desc);
847 desc->AddContent(audio_mid, video_content->type,
Steve Antonb1c1de12017-12-21 15:14:30 -0800848 video_content->media_description()->Copy());
Steve Anton8d3444d2017-10-20 15:30:51 -0700849}
850
851constexpr char kMLinesOutOfOrder[] =
852 "The order of m-lines in answer doesn't match order in offer. Rejecting "
853 "answer.";
854
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100855INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -0700856 PeerConnectionMediaTest,
857 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800858 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
859 Values(std::make_tuple("remove video",
860 RemoveVideoContent,
861 kMLinesOutOfOrder),
862 std::make_tuple("rename video",
863 RenameVideoContent,
864 kMLinesOutOfOrder),
865 std::make_tuple("reverse media sections",
866 ReverseMediaContent,
867 kMLinesOutOfOrder),
868 std::make_tuple("change audio type to video type",
869 ChangeMediaTypeAudioToVideo,
870 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700871
872// Test that the correct media engine send/recv streams are created when doing
873// a series of offer/answers where audio/video are both sent, then audio is
874// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800875TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800876 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800877 // offer_to_receive_ is not implemented when creating answers with Unified
878 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800879 return;
880 }
881
Steve Anton8d3444d2017-10-20 15:30:51 -0700882 RTCOfferAnswerOptions options_reject_video;
883 options_reject_video.offer_to_receive_audio =
884 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
885 options_reject_video.offer_to_receive_video = 0;
886
887 auto caller = CreatePeerConnection();
888 caller->AddAudioTrack("a");
889 caller->AddVideoTrack("v");
890 auto callee = CreatePeerConnection();
891
892 // Caller initially offers to send/recv audio and video.
893 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
894 // Callee accepts the audio as recv only but rejects the video.
895 ASSERT_TRUE(caller->SetRemoteDescription(
896 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
897
898 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
899 ASSERT_TRUE(caller_voice);
900 EXPECT_EQ(0u, caller_voice->recv_streams().size());
901 EXPECT_EQ(1u, caller_voice->send_streams().size());
902 auto caller_video = caller->media_engine()->GetVideoChannel(0);
903 EXPECT_FALSE(caller_video);
904
905 // Callee adds its own audio/video stream and offers to receive audio/video
906 // too.
907 callee->AddAudioTrack("a");
908 auto callee_video_track = callee->AddVideoTrack("v");
909 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
910 ASSERT_TRUE(
911 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
912
913 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
914 ASSERT_TRUE(callee_voice);
915 EXPECT_EQ(1u, callee_voice->recv_streams().size());
916 EXPECT_EQ(1u, callee_voice->send_streams().size());
917 auto callee_video = callee->media_engine()->GetVideoChannel(0);
918 ASSERT_TRUE(callee_video);
919 EXPECT_EQ(1u, callee_video->recv_streams().size());
920 EXPECT_EQ(1u, callee_video->send_streams().size());
921
922 // Callee removes video but keeps audio and rejects the video once again.
923 callee->pc()->RemoveTrack(callee_video_track);
924 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
925 ASSERT_TRUE(
926 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
927
928 callee_voice = callee->media_engine()->GetVoiceChannel(0);
929 ASSERT_TRUE(callee_voice);
930 EXPECT_EQ(1u, callee_voice->recv_streams().size());
931 EXPECT_EQ(1u, callee_voice->send_streams().size());
932 callee_video = callee->media_engine()->GetVideoChannel(0);
933 EXPECT_FALSE(callee_video);
934}
935
936// Test that the correct media engine send/recv streams are created when doing
937// a series of offer/answers where audio/video are both sent, then video is
938// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800939TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800940 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800941 // offer_to_receive_ is not implemented when creating answers with Unified
942 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800943 return;
944 }
945
Steve Anton8d3444d2017-10-20 15:30:51 -0700946 // Disable the bundling here. If the media is bundled on audio
947 // transport, then we can't reject the audio because switching the bundled
948 // transport is not currently supported.
949 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
950 RTCOfferAnswerOptions options_no_bundle;
951 options_no_bundle.use_rtp_mux = false;
952 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
953 options_reject_audio.offer_to_receive_audio = 0;
954 options_reject_audio.offer_to_receive_video =
955 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
956
957 auto caller = CreatePeerConnection();
958 caller->AddAudioTrack("a");
959 caller->AddVideoTrack("v");
960 auto callee = CreatePeerConnection();
961
962 // Caller initially offers to send/recv audio and video.
963 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
964 // Callee accepts the video as recv only but rejects the audio.
965 ASSERT_TRUE(caller->SetRemoteDescription(
966 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
967
968 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
969 EXPECT_FALSE(caller_voice);
970 auto caller_video = caller->media_engine()->GetVideoChannel(0);
971 ASSERT_TRUE(caller_video);
972 EXPECT_EQ(0u, caller_video->recv_streams().size());
973 EXPECT_EQ(1u, caller_video->send_streams().size());
974
975 // Callee adds its own audio/video stream and offers to receive audio/video
976 // too.
977 auto callee_audio_track = callee->AddAudioTrack("a");
978 callee->AddVideoTrack("v");
979 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
980 ASSERT_TRUE(caller->SetRemoteDescription(
981 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
982
983 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
984 ASSERT_TRUE(callee_voice);
985 EXPECT_EQ(1u, callee_voice->recv_streams().size());
986 EXPECT_EQ(1u, callee_voice->send_streams().size());
987 auto callee_video = callee->media_engine()->GetVideoChannel(0);
988 ASSERT_TRUE(callee_video);
989 EXPECT_EQ(1u, callee_video->recv_streams().size());
990 EXPECT_EQ(1u, callee_video->send_streams().size());
991
992 // Callee removes audio but keeps video and rejects the audio once again.
993 callee->pc()->RemoveTrack(callee_audio_track);
994 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
995 ASSERT_TRUE(
996 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
997
998 callee_voice = callee->media_engine()->GetVoiceChannel(0);
999 EXPECT_FALSE(callee_voice);
1000 callee_video = callee->media_engine()->GetVideoChannel(0);
1001 ASSERT_TRUE(callee_video);
1002 EXPECT_EQ(1u, callee_video->recv_streams().size());
1003 EXPECT_EQ(1u, callee_video->send_streams().size());
1004}
1005
1006// Tests that if the underlying video encoder fails to be initialized (signaled
1007// by failing to set send codecs), the PeerConnection signals the error to the
1008// client.
Steve Antonad7bffc2018-01-22 10:21:56 -08001009TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001010 auto caller = CreatePeerConnectionWithAudioVideo();
1011 auto callee = CreatePeerConnectionWithAudioVideo();
1012
1013 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1014
1015 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1016 video_channel->set_fail_set_send_codecs(true);
1017
1018 std::string error;
1019 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1020 &error));
1021 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -08001022 "Failed to set remote answer sdp: Failed to set remote video description "
1023 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -07001024 error);
1025}
1026
1027// Tests that if the underlying video encoder fails once then subsequent
1028// attempts at setting the local/remote description will also fail, even if
1029// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001030TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001031 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1032 auto caller = CreatePeerConnectionWithAudioVideo();
1033 auto callee = CreatePeerConnectionWithAudioVideo();
1034
1035 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1036
1037 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1038 video_channel->set_fail_set_send_codecs(true);
1039
1040 EXPECT_FALSE(
1041 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1042
1043 video_channel->set_fail_set_send_codecs(false);
1044
1045 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1046 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1047}
1048
1049void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001050 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001051 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001052 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001053 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001054 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001055 content->name = new_name;
1056 auto* transport = desc->GetTransportInfoByName(old_name);
1057 RTC_DCHECK(transport);
1058 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001059
1060 // Rename the content name in the BUNDLE group.
1061 cricket::ContentGroup new_bundle_group =
1062 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1063 new_bundle_group.RemoveContentName(old_name);
1064 new_bundle_group.AddContentName(new_name);
1065 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1066 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001067}
1068
1069// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001070TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001071 const std::string kAudioMid = "notdefault1";
1072 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001073
1074 auto caller = CreatePeerConnectionWithAudioVideo();
1075 auto callee = CreatePeerConnectionWithAudioVideo();
1076
1077 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001078 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1079 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001080 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1081
1082 auto answer = callee->CreateAnswer();
1083 EXPECT_EQ(kAudioMid,
1084 cricket::GetFirstAudioContent(answer->description())->name);
1085 EXPECT_EQ(kVideoMid,
1086 cricket::GetFirstVideoContent(answer->description())->name);
1087}
1088
1089// Test that if the callee creates a re-offer, the MIDs are the same as the
1090// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001091TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001092 const std::string kAudioMid = "notdefault1";
1093 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001094
1095 auto caller = CreatePeerConnectionWithAudioVideo();
1096 auto callee = CreatePeerConnectionWithAudioVideo();
1097
1098 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001099 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1100 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001101 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1102 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1103
1104 auto reoffer = callee->CreateOffer();
1105 EXPECT_EQ(kAudioMid,
1106 cricket::GetFirstAudioContent(reoffer->description())->name);
1107 EXPECT_EQ(kVideoMid,
1108 cricket::GetFirstVideoContent(reoffer->description())->name);
1109}
1110
Steve Anton06817cd2018-12-18 15:55:30 -08001111// Test that SetRemoteDescription returns an error if there are two m= sections
1112// with the same MID value.
1113TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1114 auto caller = CreatePeerConnectionWithAudioVideo();
1115 auto callee = CreatePeerConnectionWithAudioVideo();
1116
1117 auto offer = caller->CreateOffer();
1118 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1119 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1120
1121 std::string error;
1122 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1123 EXPECT_EQ(error,
1124 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1125}
1126
Steve Antonad7bffc2018-01-22 10:21:56 -08001127TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001128 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1129 RTCConfiguration config;
1130 config.combined_audio_video_bwe.emplace(true);
1131 auto caller = CreatePeerConnectionWithAudioVideo(config);
1132
1133 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1134
1135 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1136 ASSERT_TRUE(caller_voice);
1137 const cricket::AudioOptions& audio_options = caller_voice->options();
1138 EXPECT_EQ(config.combined_audio_video_bwe,
1139 audio_options.combined_audio_video_bwe);
1140}
1141
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001142TEST_P(PeerConnectionMediaTest, MediaTransportPropagatedToVoiceEngine) {
1143 RTCConfiguration config;
1144
1145 // Setup PeerConnection to use media transport.
1146 config.use_media_transport = true;
1147
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001148 // Force SDES.
1149 config.enable_dtls_srtp = false;
1150
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001151 auto caller = CreatePeerConnectionWithAudio(config);
1152 auto callee = CreatePeerConnectionWithAudio(config);
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001153
1154 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1155 auto answer = callee->CreateAnswer();
1156 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1157
1158 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1159 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1160 ASSERT_TRUE(caller_voice);
1161 ASSERT_TRUE(callee_voice);
1162
1163 // Make sure media transport is propagated to voice channel.
1164 FakeMediaTransport* caller_voice_media_transport =
1165 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1166 FakeMediaTransport* callee_voice_media_transport =
1167 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1168 ASSERT_NE(nullptr, caller_voice_media_transport);
1169 ASSERT_NE(nullptr, callee_voice_media_transport);
1170
1171 // Make sure media transport is created with correct is_caller.
1172 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1173 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1174
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001175 // TODO(sukhanov): Propagate media transport to video channel.
1176 // This test does NOT set up video channels, because currently it causes
1177 // us to create two media transports.
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001178}
1179
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001180TEST_P(PeerConnectionMediaTest, MediaTransportOnlyForDataChannels) {
1181 RTCConfiguration config;
1182
1183 // Setup PeerConnection to use media transport for data channels.
1184 config.use_media_transport_for_data_channels = true;
1185
1186 // Force SDES.
1187 config.enable_dtls_srtp = false;
1188
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001189 auto caller = CreatePeerConnectionWithAudio(config);
1190 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001191
1192 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1193 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1194
1195 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1196 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1197 ASSERT_TRUE(caller_voice);
1198 ASSERT_TRUE(callee_voice);
1199
1200 // Make sure media transport is not propagated to voice channel.
1201 EXPECT_EQ(nullptr, caller_voice->media_transport());
1202 EXPECT_EQ(nullptr, callee_voice->media_transport());
1203}
1204
1205TEST_P(PeerConnectionMediaTest, MediaTransportForMediaAndDataChannels) {
1206 RTCConfiguration config;
1207
1208 // Setup PeerConnection to use media transport for both media and data
1209 // channels.
1210 config.use_media_transport = true;
1211 config.use_media_transport_for_data_channels = true;
1212
1213 // Force SDES.
1214 config.enable_dtls_srtp = false;
1215
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001216 auto caller = CreatePeerConnectionWithAudio(config);
1217 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001218
1219 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1220 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1221
1222 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1223 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1224 ASSERT_TRUE(caller_voice);
1225 ASSERT_TRUE(callee_voice);
1226
1227 // Make sure media transport is propagated to voice channel.
1228 FakeMediaTransport* caller_voice_media_transport =
1229 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1230 FakeMediaTransport* callee_voice_media_transport =
1231 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1232 ASSERT_NE(nullptr, caller_voice_media_transport);
1233 ASSERT_NE(nullptr, callee_voice_media_transport);
1234
1235 // Make sure media transport is created with correct is_caller.
1236 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1237 EXPECT_FALSE(callee_voice_media_transport->is_caller());
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001238}
1239
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001240TEST_P(PeerConnectionMediaTest, MediaTransportNotPropagatedToVoiceEngine) {
1241 auto caller = CreatePeerConnectionWithAudioVideo();
1242 auto callee = CreatePeerConnectionWithAudioVideo();
1243
1244 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1245 auto answer = callee->CreateAnswer();
1246 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1247
1248 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1249 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1250 ASSERT_TRUE(caller_voice);
1251 ASSERT_TRUE(callee_voice);
1252
1253 // Since we did not setup PeerConnection to use media transport, media
1254 // transport should not be created / propagated to the voice engine.
1255 ASSERT_EQ(nullptr, caller_voice->media_transport());
1256 ASSERT_EQ(nullptr, callee_voice->media_transport());
1257
1258 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1259 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1260 ASSERT_EQ(nullptr, caller_video->media_transport());
1261 ASSERT_EQ(nullptr, callee_video->media_transport());
1262}
1263
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001264template <typename C>
1265bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1266 const std::vector<C>& codecs) {
1267 bool capability_has_rtx =
1268 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1269 return codec.name == cricket::kRtxCodecName;
1270 });
1271 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1272 return codec.name == cricket::kRtxCodecName;
1273 });
1274
1275 std::vector<C> codecs_no_rtx;
1276 absl::c_copy_if(
1277 codecs, std::back_inserter(codecs_no_rtx),
1278 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1279
1280 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1281 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1282 [](const webrtc::RtpCodecCapability& codec) {
1283 return codec.name != cricket::kRtxCodecName;
1284 });
1285
1286 return capability_has_rtx == codecs_has_rtx &&
1287 absl::c_equal(
1288 capabilities_no_rtx, codecs_no_rtx,
1289 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1290 return codec.MatchesCapability(capability);
1291 });
1292}
1293
1294TEST_F(PeerConnectionMediaTestUnifiedPlan,
1295 SetCodecPreferencesAudioMissingRecvCodec) {
1296 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1297 auto send_codecs = fake_engine->voice().send_codecs();
1298 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1299 "send_only_codec", 0, 0, 1));
1300 fake_engine->SetAudioSendCodecs(send_codecs);
1301
1302 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1303
1304 auto transceiver = caller->pc()->GetTransceivers().front();
1305 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1306 cricket::MediaType::MEDIA_TYPE_AUDIO);
1307
1308 std::vector<webrtc::RtpCodecCapability> codecs;
1309 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1310 [](const webrtc::RtpCodecCapability& codec) {
1311 return codec.name.find("_only_") != std::string::npos;
1312 });
1313
1314 auto result = transceiver->SetCodecPreferences(codecs);
1315 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1316}
1317
1318TEST_F(PeerConnectionMediaTestUnifiedPlan,
1319 SetCodecPreferencesAudioMissingSendCodec) {
1320 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1321 auto recv_codecs = fake_engine->voice().recv_codecs();
1322 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1323 "recv_only_codec", 0, 0, 1));
1324 fake_engine->SetAudioRecvCodecs(recv_codecs);
1325 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1326
1327 auto transceiver = caller->pc()->GetTransceivers().front();
1328 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1329 cricket::MediaType::MEDIA_TYPE_AUDIO);
1330
1331 std::vector<webrtc::RtpCodecCapability> codecs;
1332 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1333 [](const webrtc::RtpCodecCapability& codec) {
1334 return codec.name.find("_only_") != std::string::npos;
1335 });
1336
1337 auto result = transceiver->SetCodecPreferences(codecs);
1338 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1339}
1340
1341TEST_F(PeerConnectionMediaTestUnifiedPlan,
1342 SetCodecPreferencesAudioRejectsVideoCodec) {
1343 auto caller = CreatePeerConnectionWithAudio();
1344
1345 auto transceiver = caller->pc()->GetTransceivers().front();
1346 auto video_codecs =
1347 caller->pc_factory()
1348 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1349 .codecs;
1350 auto codecs =
1351 caller->pc_factory()
1352 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1353 .codecs;
1354 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1355 auto result = transceiver->SetCodecPreferences(codecs);
1356 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1357}
1358
1359TEST_F(PeerConnectionMediaTestUnifiedPlan,
1360 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
1361 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1362 auto audio_codecs = fake_engine->voice().send_codecs();
1363 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1364 cricket::kRtxCodecName, 0, 0, 1));
1365 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1366 std::to_string(audio_codecs.back().id - 1);
1367 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1368 cricket::kRedCodecName, 0, 0, 1));
1369 audio_codecs.push_back(cricket::AudioCodec(
1370 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1371 fake_engine->SetAudioCodecs(audio_codecs);
1372
1373 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1374
1375 auto transceiver = caller->pc()->GetTransceivers().front();
1376 auto codecs =
1377 caller->pc_factory()
1378 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1379 .codecs;
1380 auto codecs_only_rtx_red_fec = codecs;
1381 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1382 codecs_only_rtx_red_fec.end(),
1383 [](const webrtc::RtpCodecCapability& codec) {
1384 return !(codec.name == cricket::kRtxCodecName ||
1385 codec.name == cricket::kRedCodecName ||
1386 codec.name == cricket::kUlpfecCodecName);
1387 });
1388 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1389
1390 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1391 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1392}
1393
1394TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1395 auto caller = CreatePeerConnectionWithAudio();
1396
1397 auto sender_audio_codecs =
1398 caller->pc_factory()
1399 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1400 .codecs;
1401
1402 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1403
1404 // Normal case, set all capabilities as preferences
1405 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1406 auto offer = caller->CreateOffer();
1407 auto codecs = offer->description()
1408 ->contents()[0]
1409 .media_description()
1410 ->as_audio()
1411 ->codecs();
1412 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1413}
1414
1415TEST_F(PeerConnectionMediaTestUnifiedPlan,
1416 SetCodecPreferencesResetAudioCodecs) {
1417 auto caller = CreatePeerConnectionWithAudio();
1418
1419 auto sender_audio_codecs =
1420 caller->pc_factory()
1421 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1422 .codecs;
1423 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1424
1425 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1426
1427 // Normal case, reset codec preferences
1428 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1429 auto offer = caller->CreateOffer();
1430 auto codecs = offer->description()
1431 ->contents()[0]
1432 .media_description()
1433 ->as_audio()
1434 ->codecs();
1435 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1436}
1437
1438TEST_F(PeerConnectionMediaTestUnifiedPlan,
1439 SetCodecPreferencesVideoRejectsAudioCodec) {
1440 auto caller = CreatePeerConnectionWithVideo();
1441
1442 auto transceiver = caller->pc()->GetTransceivers().front();
1443 auto audio_codecs =
1444 caller->pc_factory()
1445 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1446 .codecs;
1447 auto codecs =
1448 caller->pc_factory()
1449 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1450 .codecs;
1451 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1452 auto result = transceiver->SetCodecPreferences(codecs);
1453 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1454}
1455
1456TEST_F(PeerConnectionMediaTestUnifiedPlan,
1457 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
1458 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1459 auto video_codecs = fake_engine->video().codecs();
1460 video_codecs.push_back(
1461 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
1462 video_codecs.push_back(
1463 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1464 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1465 cricket::kUlpfecCodecName));
1466 fake_engine->SetVideoCodecs(video_codecs);
1467
1468 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1469
1470 auto transceiver = caller->pc()->GetTransceivers().front();
1471 auto codecs =
1472 caller->pc_factory()
1473 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1474 .codecs;
1475 auto codecs_only_rtx_red_fec = codecs;
1476 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1477 codecs_only_rtx_red_fec.end(),
1478 [](const webrtc::RtpCodecCapability& codec) {
1479 return !(codec.name == cricket::kRtxCodecName ||
1480 codec.name == cricket::kRedCodecName ||
1481 codec.name == cricket::kUlpfecCodecName);
1482 });
1483 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1484
1485 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1486 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1487}
1488
1489TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1490 auto caller = CreatePeerConnectionWithVideo();
1491
1492 auto sender_video_codecs =
1493 caller->pc_factory()
1494 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1495 .codecs;
1496
1497 auto video_transceiver = caller->pc()->GetTransceivers().front();
1498
1499 // Normal case, setting preferences to normal capabilities
1500 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1501 auto offer = caller->CreateOffer();
1502 auto codecs = offer->description()
1503 ->contents()[0]
1504 .media_description()
1505 ->as_video()
1506 ->codecs();
1507 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1508}
1509
1510TEST_F(PeerConnectionMediaTestUnifiedPlan,
1511 SetCodecPreferencesResetVideoCodecs) {
1512 auto caller = CreatePeerConnectionWithVideo();
1513
1514 auto sender_video_codecs =
1515 caller->pc_factory()
1516 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1517 .codecs;
1518
1519 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1520
1521 auto video_transceiver = caller->pc()->GetTransceivers().front();
1522
1523 // Normal case, resetting preferences with empty list of codecs
1524 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1525 auto offer = caller->CreateOffer();
1526 auto codecs = offer->description()
1527 ->contents()[0]
1528 .media_description()
1529 ->as_video()
1530 ->codecs();
1531 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1532}
1533
1534TEST_F(PeerConnectionMediaTestUnifiedPlan,
1535 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1536 auto caller = CreatePeerConnectionWithVideo();
1537
1538 auto sender_video_codecs =
1539 caller->pc_factory()
1540 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1541 .codecs;
1542
1543 auto video_transceiver = caller->pc()->GetTransceivers().front();
1544
1545 // Check duplicates are removed
1546 auto single_codec = sender_video_codecs;
1547 single_codec.resize(1);
1548 auto duplicate_codec = single_codec;
1549 duplicate_codec.push_back(duplicate_codec.front());
1550 duplicate_codec.push_back(duplicate_codec.front());
1551 duplicate_codec.push_back(duplicate_codec.front());
1552
1553 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1554 auto offer = caller->CreateOffer();
1555 auto codecs = offer->description()
1556 ->contents()[0]
1557 .media_description()
1558 ->as_video()
1559 ->codecs();
1560 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1561}
1562
1563TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
1564 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
1565 auto caller_video_codecs = caller_fake_engine->video().codecs();
1566 caller_video_codecs.push_back(cricket::VideoCodec(
1567 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1568 caller_video_codecs.push_back(cricket::VideoCodec(
1569 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1570 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1571 std::to_string(caller_video_codecs.back().id - 1);
1572 caller_video_codecs.push_back(cricket::VideoCodec(
1573 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1574 caller_video_codecs.push_back(cricket::VideoCodec(
1575 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1576 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1577 std::to_string(caller_video_codecs.back().id - 1);
1578 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1579
1580 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1581
1582 auto sender_video_codecs =
1583 caller->pc_factory()
1584 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1585 .codecs;
1586
1587 auto video_transceiver = caller->pc()->GetTransceivers().front();
1588
1589 // Check that RTX codec is properly added
1590 auto video_codecs_vpx_rtx = sender_video_codecs;
1591 auto it =
1592 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1593 [](const webrtc::RtpCodecCapability& codec) {
1594 return codec.name != cricket::kRtxCodecName &&
1595 codec.name != cricket::kVp8CodecName &&
1596 codec.name != cricket::kVp9CodecName;
1597 });
1598 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1599 absl::c_reverse(video_codecs_vpx_rtx);
1600 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1601 EXPECT_TRUE(
1602 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1603 auto offer = caller->CreateOffer();
1604 auto codecs = offer->description()
1605 ->contents()[0]
1606 .media_description()
1607 ->as_video()
1608 ->codecs();
1609
1610 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1611 EXPECT_EQ(codecs.size(), 4u);
1612}
1613
1614TEST_F(PeerConnectionMediaTestUnifiedPlan,
1615 SetCodecPreferencesVideoCodecsNegotiation) {
1616 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
1617 auto caller_video_codecs = caller_fake_engine->video().codecs();
1618 caller_video_codecs.push_back(cricket::VideoCodec(
1619 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1620 caller_video_codecs.push_back(cricket::VideoCodec(
1621 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1622 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1623 std::to_string(caller_video_codecs.back().id - 1);
1624 caller_video_codecs.push_back(cricket::VideoCodec(
1625 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1626 caller_video_codecs.push_back(cricket::VideoCodec(
1627 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1628 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1629 std::to_string(caller_video_codecs.back().id - 1);
1630 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1631
1632 auto callee_fake_engine = absl::make_unique<FakeMediaEngine>();
1633 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1634
1635 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1636 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1637
1638 auto video_codecs = caller->pc_factory()
1639 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1640 .codecs;
1641
1642 auto send_transceiver = caller->pc()->GetTransceivers().front();
1643
1644 auto video_codecs_vpx = video_codecs;
1645 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1646 [](const webrtc::RtpCodecCapability& codec) {
1647 return codec.name != cricket::kVp8CodecName &&
1648 codec.name != cricket::kVp9CodecName;
1649 });
1650 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1651 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1652 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1653
1654 auto offer = caller->CreateOfferAndSetAsLocal();
1655 auto codecs = offer->description()
1656 ->contents()[0]
1657 .media_description()
1658 ->as_video()
1659 ->codecs();
1660
1661 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1662 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1663
1664 callee->SetRemoteDescription(std::move(offer));
1665
1666 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1667 auto video_codecs_vp8_rtx = video_codecs;
1668 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1669 [](const webrtc::RtpCodecCapability& codec) {
1670 bool r = codec.name != cricket::kVp8CodecName &&
1671 codec.name != cricket::kRtxCodecName;
1672 return r;
1673 });
1674 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1675 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1676 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1677
1678 auto answer = callee->CreateAnswerAndSetAsLocal();
1679
1680 auto recv_codecs = answer->description()
1681 ->contents()[0]
1682 .media_description()
1683 ->as_video()
1684 ->codecs();
1685 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1686}
1687
1688TEST_F(PeerConnectionMediaTestUnifiedPlan,
1689 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
1690 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
1691 auto caller_video_codecs = caller_fake_engine->video().codecs();
1692 caller_video_codecs.push_back(cricket::VideoCodec(
1693 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1694 caller_video_codecs.push_back(cricket::VideoCodec(
1695 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1696 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1697 std::to_string(caller_video_codecs.back().id - 1);
1698 caller_video_codecs.push_back(cricket::VideoCodec(
1699 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1700 caller_video_codecs.push_back(cricket::VideoCodec(
1701 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1702 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1703 std::to_string(caller_video_codecs.back().id - 1);
1704 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1705
1706 auto callee_fake_engine = absl::make_unique<FakeMediaEngine>();
1707 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1708
1709 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1710 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1711
1712 auto video_codecs = caller->pc_factory()
1713 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1714 .codecs;
1715
1716 auto send_transceiver = caller->pc()->GetTransceivers().front();
1717
1718 auto video_codecs_vpx = video_codecs;
1719 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1720 [](const webrtc::RtpCodecCapability& codec) {
1721 return codec.name != cricket::kVp8CodecName &&
1722 codec.name != cricket::kVp9CodecName;
1723 });
1724 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1725 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1726 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1727
1728 auto video_codecs_vpx_reverse = video_codecs_vpx;
1729 absl::c_reverse(video_codecs_vpx_reverse);
1730
1731 auto offer = caller->CreateOfferAndSetAsLocal();
1732 auto codecs = offer->description()
1733 ->contents()[0]
1734 .media_description()
1735 ->as_video()
1736 ->codecs();
1737 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1738 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1739
1740 callee->SetRemoteDescription(std::move(offer));
1741
1742 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1743 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1744
1745 auto answer = callee->CreateAnswerAndSetAsLocal();
1746
1747 auto recv_codecs = answer->description()
1748 ->contents()[0]
1749 .media_description()
1750 ->as_video()
1751 ->codecs();
1752
1753 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1754}
1755
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001756INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
1757 PeerConnectionMediaTest,
1758 Values(SdpSemantics::kPlanB,
1759 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08001760
Steve Anton8d3444d2017-10-20 15:30:51 -07001761} // namespace webrtc