blob: 067dc14c50cea9f531a67c413a458338188b7c64 [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>
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -070016#include <set>
Steve Anton8d3444d2017-10-20 15:30:51 -070017#include <tuple>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 15:38:50 +020020#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "api/call/call_factory_interface.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020022#include "api/rtc_event_log/rtc_event_log_factory.h"
23#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "media/base/fake_media_engine.h"
25#include "p2p/base/fake_port_allocator.h"
26#include "pc/media_session.h"
27#include "pc/peer_connection_wrapper.h"
28#include "pc/rtp_media_utils.h"
29#include "pc/sdp_utils.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070030#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080031#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070032#endif
Steve Anton10542f22019-01-11 09:11:00 -080033#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070034#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070036#include "test/gmock.h"
37
38namespace webrtc {
39
40using cricket::FakeMediaEngine;
41using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
42using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
43using ::testing::Bool;
44using ::testing::Combine;
Steve Anton8d3444d2017-10-20 15:30:51 -070045using ::testing::ElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020046using ::testing::Values;
Steve Anton8d3444d2017-10-20 15:30:51 -070047
48class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
49 public:
50 using PeerConnectionWrapper::PeerConnectionWrapper;
51
52 FakeMediaEngine* media_engine() { return media_engine_; }
53 void set_media_engine(FakeMediaEngine* media_engine) {
54 media_engine_ = media_engine;
55 }
56
57 private:
58 FakeMediaEngine* media_engine_;
59};
60
Steve Antonad7bffc2018-01-22 10:21:56 -080061class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070062 protected:
63 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
64
Steve Antonad7bffc2018-01-22 10:21:56 -080065 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
66 : vss_(new rtc::VirtualSocketServer()),
67 main_(vss_.get()),
68 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -070069#ifdef WEBRTC_ANDROID
70 InitializeAndroidObjects();
71#endif
72 }
73
74 WrapperPtr CreatePeerConnection() {
75 return CreatePeerConnection(RTCConfiguration());
76 }
77
Florent Castelli2d9d82e2019-04-23 19:25:51 +020078 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020079 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 19:25:51 +020080 }
81
82 WrapperPtr CreatePeerConnection(
83 std::unique_ptr<FakeMediaEngine> media_engine) {
84 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
85 }
86
Anton Sukhanov98a462c2018-10-17 13:15:42 -070087 // Creates PeerConnectionFactory and PeerConnection for given configuration.
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();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020098 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070099 factory_dependencies.media_engine = std::move(media_engine);
100 factory_dependencies.call_factory = CreateCallFactory();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200101 factory_dependencies.event_log_factory =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200102 std::make_unique<RtcEventLogFactory>(
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200103 factory_dependencies.task_queue_factory.get());
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700104
105 auto pc_factory =
106 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -0700107
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200108 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700109 rtc::Thread::Current(), nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200110 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 10:21:56 -0800111 auto modified_config = config;
112 modified_config.sdp_semantics = sdp_semantics_;
113 auto pc = pc_factory->CreatePeerConnection(modified_config,
114 std::move(fake_port_allocator),
115 nullptr, observer.get());
Steve Anton8d3444d2017-10-20 15:30:51 -0700116 if (!pc) {
117 return nullptr;
118 }
119
Yves Gerey4e933292018-10-31 15:36:05 +0100120 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200121 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700122 pc_factory, pc, std::move(observer));
123 wrapper->set_media_engine(media_engine_ptr);
124 return wrapper;
125 }
126
127 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800128 // track (but no video).
129 template <typename... Args>
130 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
131 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
132 if (!wrapper) {
133 return nullptr;
134 }
135 wrapper->AddAudioTrack("a");
136 return wrapper;
137 }
138
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200139 // Accepts the same arguments as CreatePeerConnection and adds default video
140 // track (but no audio).
141 template <typename... Args>
142 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
143 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
144 if (!wrapper) {
145 return nullptr;
146 }
147 wrapper->AddVideoTrack("v");
148 return wrapper;
149 }
150
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800151 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 15:30:51 -0700152 // and video tracks.
153 template <typename... Args>
154 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
155 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
156 if (!wrapper) {
157 return nullptr;
158 }
159 wrapper->AddAudioTrack("a");
160 wrapper->AddVideoTrack("v");
161 return wrapper;
162 }
163
Steve Anton4e70a722017-11-28 14:57:10 -0800164 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700165 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800166 cricket::MediaType media_type) {
167 auto* content =
168 cricket::GetFirstMediaContent(sdesc->description(), media_type);
169 RTC_DCHECK(content);
170 return content->media_description()->direction();
171 }
172
173 bool IsUnifiedPlan() const {
174 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700175 }
176
177 std::unique_ptr<rtc::VirtualSocketServer> vss_;
178 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800179 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700180};
181
Steve Antonad7bffc2018-01-22 10:21:56 -0800182class PeerConnectionMediaTest
183 : public PeerConnectionMediaBaseTest,
184 public ::testing::WithParamInterface<SdpSemantics> {
185 protected:
186 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
187};
188
189class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
190 protected:
191 PeerConnectionMediaTestUnifiedPlan()
192 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
193};
194
195class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
196 protected:
197 PeerConnectionMediaTestPlanB()
198 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
199};
200
201TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700202 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
203 auto caller = CreatePeerConnectionWithAudioVideo();
204 auto callee = CreatePeerConnectionWithAudioVideo();
205 callee->media_engine()->set_fail_create_channel(true);
206
207 std::string error;
208 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800209 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
210 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700211}
212
Steve Antonad7bffc2018-01-22 10:21:56 -0800213TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700214 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
215 auto caller = CreatePeerConnectionWithAudioVideo();
216 caller->media_engine()->set_fail_create_channel(true);
217
218 std::string error;
219 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800220 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
221 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700222}
223
224std::vector<std::string> GetIds(
225 const std::vector<cricket::StreamParams>& streams) {
226 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100227 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700228 for (const auto& stream : streams) {
229 ids.push_back(stream.id);
230 }
231 return ids;
232}
233
234// Test that exchanging an offer and answer with each side having an audio and
235// video stream creates the appropriate send/recv streams in the underlying
236// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800237TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700238 const std::string kCallerAudioId = "caller_a";
239 const std::string kCallerVideoId = "caller_v";
240 const std::string kCalleeAudioId = "callee_a";
241 const std::string kCalleeVideoId = "callee_v";
242
243 auto caller = CreatePeerConnection();
244 caller->AddAudioTrack(kCallerAudioId);
245 caller->AddVideoTrack(kCallerVideoId);
246
247 auto callee = CreatePeerConnection();
248 callee->AddAudioTrack(kCalleeAudioId);
249 callee->AddVideoTrack(kCalleeVideoId);
250
251 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
252 ASSERT_TRUE(
253 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
254
255 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
256 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
257 ElementsAre(kCalleeAudioId));
258 EXPECT_THAT(GetIds(caller_voice->send_streams()),
259 ElementsAre(kCallerAudioId));
260
261 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
262 EXPECT_THAT(GetIds(caller_video->recv_streams()),
263 ElementsAre(kCalleeVideoId));
264 EXPECT_THAT(GetIds(caller_video->send_streams()),
265 ElementsAre(kCallerVideoId));
266
267 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
268 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
269 ElementsAre(kCallerAudioId));
270 EXPECT_THAT(GetIds(callee_voice->send_streams()),
271 ElementsAre(kCalleeAudioId));
272
273 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
274 EXPECT_THAT(GetIds(callee_video->recv_streams()),
275 ElementsAre(kCallerVideoId));
276 EXPECT_THAT(GetIds(callee_video->send_streams()),
277 ElementsAre(kCalleeVideoId));
278}
279
Steve Antonad7bffc2018-01-22 10:21:56 -0800280// Test that stopping the caller transceivers causes the media channels on the
281// callee to be destroyed after calling SetRemoteDescription on the generated
282// offer.
283// See next test for equivalent behavior with Plan B semantics.
284TEST_F(PeerConnectionMediaTestUnifiedPlan,
285 StoppedRemoteTransceiversRemovesMediaChannels) {
286 auto caller = CreatePeerConnectionWithAudioVideo();
287 auto callee = CreatePeerConnection();
288
289 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
290
291 // Stop both audio and video transceivers on the caller.
292 auto transceivers = caller->pc()->GetTransceivers();
293 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200294 transceivers[0]->StopInternal();
295 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 10:21:56 -0800296
297 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
298
299 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
300 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
301}
302
Steve Anton8d3444d2017-10-20 15:30:51 -0700303// Test that removing streams from a subsequent offer causes the receive streams
304// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800305// See previous test for equivalent behavior with Unified Plan semantics.
306TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700307 auto caller = CreatePeerConnection();
308 auto caller_audio_track = caller->AddAudioTrack("a");
309 auto caller_video_track = caller->AddVideoTrack("v");
310 auto callee = CreatePeerConnectionWithAudioVideo();
311
Steve Antonad7bffc2018-01-22 10:21:56 -0800312 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700313
314 // Remove both tracks from caller.
315 caller->pc()->RemoveTrack(caller_audio_track);
316 caller->pc()->RemoveTrack(caller_video_track);
317
Steve Antonad7bffc2018-01-22 10:21:56 -0800318 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700319
320 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800321 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700322 EXPECT_EQ(1u, callee_voice->send_streams().size());
323 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700324 EXPECT_EQ(1u, callee_video->send_streams().size());
325 EXPECT_EQ(0u, callee_video->recv_streams().size());
326}
327
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200328// Test enabling of simulcast with Plan B semantics.
329// This test creating an offer.
330TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
331 auto caller = CreatePeerConnection();
332 auto caller_video_track = caller->AddVideoTrack("v");
333 RTCOfferAnswerOptions options;
334 options.num_simulcast_layers = 3;
335 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 19:08:33 +0200336 auto* description = cricket::GetFirstMediaContent(offer->description(),
337 cricket::MEDIA_TYPE_VIDEO)
338 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200339 ASSERT_EQ(1u, description->streams().size());
340 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
341 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
342
343 // Check that it actually creates simulcast aswell.
344 caller->SetLocalDescription(std::move(offer));
345 auto senders = caller->pc()->GetSenders();
346 ASSERT_EQ(1u, senders.size());
347 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
348 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
349}
350
351// Test enabling of simulcast with Plan B semantics.
352// This test creating an answer.
353TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
354 auto caller = CreatePeerConnection();
355 caller->AddVideoTrack("v0");
356 auto offer = caller->CreateOffer();
357 auto callee = CreatePeerConnection();
358 auto callee_video_track = callee->AddVideoTrack("v1");
359 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
360 RTCOfferAnswerOptions options;
361 options.num_simulcast_layers = 3;
362 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 19:08:33 +0200363 auto* description = cricket::GetFirstMediaContent(answer->description(),
364 cricket::MEDIA_TYPE_VIDEO)
365 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200366 ASSERT_EQ(1u, description->streams().size());
367 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
368 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
369
370 // Check that it actually creates simulcast aswell.
371 callee->SetLocalDescription(std::move(answer));
372 auto senders = callee->pc()->GetSenders();
373 ASSERT_EQ(1u, senders.size());
374 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
375 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
376}
377
Steve Antonad7bffc2018-01-22 10:21:56 -0800378// Test that stopping the callee transceivers causes the media channels to be
379// destroyed on the callee after calling SetLocalDescription on the local
380// answer.
381// See next test for equivalent behavior with Plan B semantics.
382TEST_F(PeerConnectionMediaTestUnifiedPlan,
383 StoppedLocalTransceiversRemovesMediaChannels) {
384 auto caller = CreatePeerConnectionWithAudioVideo();
385 auto callee = CreatePeerConnectionWithAudioVideo();
386
387 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
388
389 // Stop both audio and video transceivers on the callee.
390 auto transceivers = callee->pc()->GetTransceivers();
391 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200392 transceivers[0]->StopInternal();
393 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 10:21:56 -0800394
395 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
396
397 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
398 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
399}
400
Steve Anton8d3444d2017-10-20 15:30:51 -0700401// Test that removing streams from a subsequent answer causes the send streams
402// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800403// See previous test for equivalent behavior with Unified Plan semantics.
404TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700405 auto caller = CreatePeerConnectionWithAudioVideo();
406 auto callee = CreatePeerConnection();
407 auto callee_audio_track = callee->AddAudioTrack("a");
408 auto callee_video_track = callee->AddVideoTrack("v");
409
Steve Antonad7bffc2018-01-22 10:21:56 -0800410 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700411
412 // Remove both tracks from callee.
413 callee->pc()->RemoveTrack(callee_audio_track);
414 callee->pc()->RemoveTrack(callee_video_track);
415
Steve Antonad7bffc2018-01-22 10:21:56 -0800416 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700417
418 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800419 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700420 EXPECT_EQ(0u, callee_voice->send_streams().size());
421 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700422 EXPECT_EQ(0u, callee_video->send_streams().size());
423 EXPECT_EQ(1u, callee_video->recv_streams().size());
424}
425
426// Test that a new stream in a subsequent offer causes a new receive stream to
427// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800428TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700429 auto caller = CreatePeerConnectionWithAudioVideo();
430 auto callee = CreatePeerConnection();
431
Steve Antonad7bffc2018-01-22 10:21:56 -0800432 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700433
434 // Add second set of tracks to the caller.
435 caller->AddAudioTrack("a2");
436 caller->AddVideoTrack("v2");
437
Steve Antonad7bffc2018-01-22 10:21:56 -0800438 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700439
Steve Antonad7bffc2018-01-22 10:21:56 -0800440 auto a1 = callee->media_engine()->GetVoiceChannel(0);
441 auto a2 = callee->media_engine()->GetVoiceChannel(1);
442 auto v1 = callee->media_engine()->GetVideoChannel(0);
443 auto v2 = callee->media_engine()->GetVideoChannel(1);
444 if (IsUnifiedPlan()) {
445 ASSERT_TRUE(a1);
446 EXPECT_EQ(1u, a1->recv_streams().size());
447 ASSERT_TRUE(a2);
448 EXPECT_EQ(1u, a2->recv_streams().size());
449 ASSERT_TRUE(v1);
450 EXPECT_EQ(1u, v1->recv_streams().size());
451 ASSERT_TRUE(v2);
452 EXPECT_EQ(1u, v2->recv_streams().size());
453 } else {
454 ASSERT_TRUE(a1);
455 EXPECT_EQ(2u, a1->recv_streams().size());
456 ASSERT_FALSE(a2);
457 ASSERT_TRUE(v1);
458 EXPECT_EQ(2u, v1->recv_streams().size());
459 ASSERT_FALSE(v2);
460 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700461}
462
463// Test that a new stream in a subsequent answer causes a new send stream to be
464// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800465TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700466 auto caller = CreatePeerConnection();
467 auto callee = CreatePeerConnectionWithAudioVideo();
468
Steve Anton22da89f2018-01-25 13:58:07 -0800469 RTCOfferAnswerOptions offer_options;
470 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700471 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800472 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700473 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800474 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700475
Steve Anton22da89f2018-01-25 13:58:07 -0800476 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
477 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700478
479 // Add second set of tracks to the callee.
480 callee->AddAudioTrack("a2");
481 callee->AddVideoTrack("v2");
482
Steve Anton22da89f2018-01-25 13:58:07 -0800483 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
484 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700485
486 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800487 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700488 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800489 ASSERT_TRUE(callee_video);
490
491 if (IsUnifiedPlan()) {
492 EXPECT_EQ(1u, callee_voice->send_streams().size());
493 EXPECT_EQ(1u, callee_video->send_streams().size());
494 } else {
495 EXPECT_EQ(2u, callee_voice->send_streams().size());
496 EXPECT_EQ(2u, callee_video->send_streams().size());
497 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700498}
499
500// A PeerConnection with no local streams and no explicit answer constraints
501// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800502TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700503 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
504 auto caller = CreatePeerConnectionWithAudioVideo();
505 auto callee = CreatePeerConnection();
506 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
507 auto answer = callee->CreateAnswer();
508
509 const auto* audio_content =
510 cricket::GetFirstAudioContent(answer->description());
511 ASSERT_TRUE(audio_content);
512 EXPECT_FALSE(audio_content->rejected);
513
514 const auto* video_content =
515 cricket::GetFirstVideoContent(answer->description());
516 ASSERT_TRUE(video_content);
517 EXPECT_FALSE(video_content->rejected);
518}
519
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200520// Test that raw packetization is not set in the offer by default.
521TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
522 std::vector<cricket::VideoCodec> fake_codecs;
523 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
524 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
525 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
526 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
527 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
528 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200529 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200530 caller_fake_engine->SetVideoCodecs(fake_codecs);
531
532 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
533 auto offer = caller->CreateOfferAndSetAsLocal();
534 auto* offer_description =
535 cricket::GetFirstVideoContentDescription(offer->description());
536 for (const auto& codec : offer_description->codecs()) {
537 EXPECT_EQ(codec.packetization, absl::nullopt);
538 }
539}
540
541// Test that raw packetization is set in the offer and answer for all
542// video payload when raw_packetization_for_video is true.
543TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
544 std::vector<cricket::VideoCodec> fake_codecs;
545 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
546 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
547 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
548 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
549 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
550 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200551 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200552 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200553 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200554 callee_fake_engine->SetVideoCodecs(fake_codecs);
555
556 RTCOfferAnswerOptions options;
557 options.raw_packetization_for_video = true;
558
559 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
560 auto offer = caller->CreateOfferAndSetAsLocal(options);
561 auto* offer_description =
562 cricket::GetFirstVideoContentDescription(offer->description());
563 for (const auto& codec : offer_description->codecs()) {
564 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
565 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
566 }
567 }
568
569 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
570 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
571 auto answer = callee->CreateAnswerAndSetAsLocal(options);
572 auto* answer_description =
573 cricket::GetFirstVideoContentDescription(answer->description());
574 for (const auto& codec : answer_description->codecs()) {
575 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
576 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
577 }
578 }
579
580 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
581}
582
583// Test that raw packetization is not set in the answer when
584// raw_packetization_for_video is true if it was not set in the offer.
585TEST_P(PeerConnectionMediaTest,
586 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
587 std::vector<cricket::VideoCodec> fake_codecs;
588 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
589 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
590 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
591 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
592 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
593 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200594 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200595 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200596 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200597 callee_fake_engine->SetVideoCodecs(fake_codecs);
598
599 RTCOfferAnswerOptions caller_options;
600 caller_options.raw_packetization_for_video = false;
601 RTCOfferAnswerOptions callee_options;
602 callee_options.raw_packetization_for_video = true;
603
604 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
605 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
606
607 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
608 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
609 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
610
611 auto* answer_description =
612 cricket::GetFirstVideoContentDescription(answer->description());
613 for (const auto& codec : answer_description->codecs()) {
614 EXPECT_EQ(codec.packetization, absl::nullopt);
615 }
616
617 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
618}
619
Steve Anton8d3444d2017-10-20 15:30:51 -0700620class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800621 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700622 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800623 std::tuple<SdpSemantics,
624 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700625 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800626 PeerConnectionMediaOfferDirectionTest()
627 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
628 auto param = std::get<1>(GetParam());
629 send_media_ = std::get<0>(param);
630 offer_to_receive_ = std::get<1>(param);
631 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700632 }
633
634 bool send_media_;
635 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800636 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700637};
638
639// Tests that the correct direction is set on the media description according
640// to the presence of a local media track and the offer_to_receive setting.
641TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
642 auto caller = CreatePeerConnection();
643 if (send_media_) {
644 caller->AddAudioTrack("a");
645 }
646
647 RTCOfferAnswerOptions options;
648 options.offer_to_receive_audio = offer_to_receive_;
649 auto offer = caller->CreateOffer(options);
650
Steve Antonad7bffc2018-01-22 10:21:56 -0800651 auto* content = cricket::GetFirstMediaContent(offer->description(),
652 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800653 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800654 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700655 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800656 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700657 }
658}
659
660// Note that in these tests, MD_INACTIVE indicates that no media section is
661// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100662INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 14:57:10 -0800663 PeerConnectionMediaTest,
664 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800665 Combine(
666 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
667 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
668 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
669 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
670 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
671 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
672 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700673
674class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800675 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700676 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800677 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700678 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800679 PeerConnectionMediaAnswerDirectionTest()
680 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
681 offer_direction_ = std::get<1>(GetParam());
682 send_media_ = std::get<2>(GetParam());
683 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700684 }
685
Steve Anton4e70a722017-11-28 14:57:10 -0800686 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700687 bool send_media_;
688 int offer_to_receive_;
689};
690
691// Tests that the direction in an answer is correct according to direction sent
692// in the offer, the presence of a local media track on the receive side and the
693// offer_to_receive setting.
694TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800695 if (IsUnifiedPlan() &&
696 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
697 // offer_to_receive_ is not implemented when creating answers with Unified
698 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800699 return;
700 }
Steve Anton22da89f2018-01-25 13:58:07 -0800701
Steve Anton8d3444d2017-10-20 15:30:51 -0700702 auto caller = CreatePeerConnection();
703 caller->AddAudioTrack("a");
704
705 // Create the offer with an audio section and set its direction.
706 auto offer = caller->CreateOffer();
707 cricket::GetFirstAudioContentDescription(offer->description())
708 ->set_direction(offer_direction_);
709
710 auto callee = CreatePeerConnection();
711 if (send_media_) {
712 callee->AddAudioTrack("a");
713 }
714 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
715
716 // Create the answer according to the test parameters.
717 RTCOfferAnswerOptions options;
718 options.offer_to_receive_audio = offer_to_receive_;
719 auto answer = callee->CreateAnswer(options);
720
721 // The expected direction in the answer is the intersection of each side's
722 // capability to send/recv media.
723 // For the offerer, the direction is given in the offer (offer_direction_).
724 // For the answerer, the direction has two components:
725 // 1. Send if the answerer has a local track to send.
726 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
727 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800728 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
729 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700730
731 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800732 bool negotiate_send = (send_media_ && offer_recv);
733 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700734
735 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800736 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700737 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800738 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700739}
740
741// Tests that the media section is rejected if and only if the callee has no
742// local media track and has set offer_to_receive to 0, no matter which
743// direction the caller indicated in the offer.
744TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800745 if (IsUnifiedPlan() &&
746 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
747 // offer_to_receive_ is not implemented when creating answers with Unified
748 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800749 return;
750 }
Steve Anton22da89f2018-01-25 13:58:07 -0800751
Steve Anton8d3444d2017-10-20 15:30:51 -0700752 auto caller = CreatePeerConnection();
753 caller->AddAudioTrack("a");
754
755 // Create the offer with an audio section and set its direction.
756 auto offer = caller->CreateOffer();
757 cricket::GetFirstAudioContentDescription(offer->description())
758 ->set_direction(offer_direction_);
759
760 auto callee = CreatePeerConnection();
761 if (send_media_) {
762 callee->AddAudioTrack("a");
763 }
764 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
765
766 // Create the answer according to the test parameters.
767 RTCOfferAnswerOptions options;
768 options.offer_to_receive_audio = offer_to_receive_;
769 auto answer = callee->CreateAnswer(options);
770
771 // The media section is rejected if and only if offer_to_receive is explicitly
772 // set to 0 and there is no media to send.
773 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
774 ASSERT_TRUE(audio_content);
775 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
776}
777
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100778INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
779 PeerConnectionMediaAnswerDirectionTest,
780 Combine(Values(SdpSemantics::kPlanB,
781 SdpSemantics::kUnifiedPlan),
782 Values(RtpTransceiverDirection::kInactive,
783 RtpTransceiverDirection::kSendOnly,
784 RtpTransceiverDirection::kRecvOnly,
785 RtpTransceiverDirection::kSendRecv),
786 Bool(),
787 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 15:30:51 -0700788
Steve Antonad7bffc2018-01-22 10:21:56 -0800789TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700790 auto caller = CreatePeerConnection();
791 caller->AddVideoTrack("v");
792
793 RTCOfferAnswerOptions options;
794 options.offer_to_receive_audio = 1;
795 options.offer_to_receive_video = 0;
796 auto offer = caller->CreateOffer(options);
797
Steve Anton4e70a722017-11-28 14:57:10 -0800798 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800799 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800800 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800801 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700802}
803
Steve Antonad7bffc2018-01-22 10:21:56 -0800804TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800805 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800806 // offer_to_receive_ is not implemented when creating answers with Unified
807 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800808 return;
809 }
810
Steve Anton8d3444d2017-10-20 15:30:51 -0700811 auto caller = CreatePeerConnectionWithAudioVideo();
812 auto callee = CreatePeerConnection();
813 callee->AddVideoTrack("v");
814
815 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
816
817 RTCOfferAnswerOptions options;
818 options.offer_to_receive_audio = 1;
819 options.offer_to_receive_video = 0;
820 auto answer = callee->CreateAnswer(options);
821
Steve Anton4e70a722017-11-28 14:57:10 -0800822 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800823 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800824 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800825 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700826}
827
828void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Philipp Hancke8498c252020-06-05 13:28:57 +0200829 const cricket::AudioCodec kComfortNoiseCodec8k(102, cricket::kCnCodecName,
830 8000, 0, 1);
831 const cricket::AudioCodec kComfortNoiseCodec16k(103, cricket::kCnCodecName,
832 16000, 0, 1);
Steve Anton8d3444d2017-10-20 15:30:51 -0700833
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100834 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700835 codecs.push_back(kComfortNoiseCodec8k);
836 codecs.push_back(kComfortNoiseCodec16k);
837 media_engine->SetAudioCodecs(codecs);
838}
839
840bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
841 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
842 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 13:28:57 +0200843 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700844 return true;
845 }
846 }
847 return false;
848}
849
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -0700850bool HasPayloadTypeConflict(const cricket::SessionDescription* desc) {
851 std::set<int> payload_types;
852 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
853 if (audio_desc) {
854 for (const auto& codec : audio_desc->codecs()) {
855 if (payload_types.count(codec.id) > 0) {
856 return true;
857 }
858 payload_types.insert(codec.id);
859 }
860 }
861 const auto* video_desc = cricket::GetFirstVideoContentDescription(desc);
862 if (video_desc) {
863 for (const auto& codec : video_desc->codecs()) {
864 if (payload_types.count(codec.id) > 0) {
865 return true;
866 }
867 payload_types.insert(codec.id);
868 }
869 }
870 return false;
871}
872
Steve Antonad7bffc2018-01-22 10:21:56 -0800873TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700874 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Philipp Hancke718acf62021-05-12 14:18:03 +0200875 auto fake_engine = std::make_unique<FakeMediaEngine>();
876 AddComfortNoiseCodecsToSend(fake_engine.get());
877 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
Steve Anton8d3444d2017-10-20 15:30:51 -0700878
879 RTCOfferAnswerOptions options;
880 options.voice_activity_detection = false;
881 auto offer = caller->CreateOffer(options);
882
883 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
884}
885
Steve Antonad7bffc2018-01-22 10:21:56 -0800886TEST_P(PeerConnectionMediaTest,
Philipp Hancke718acf62021-05-12 14:18:03 +0200887 CreateOfferWithVoiceActivityDetectionIncludesComfortNoiseCodecs) {
888 auto fake_engine = std::make_unique<FakeMediaEngine>();
889 AddComfortNoiseCodecsToSend(fake_engine.get());
890 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
891
892 RTCOfferAnswerOptions options;
893 options.voice_activity_detection = true;
894 auto offer = caller->CreateOffer(options);
895
896 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
897}
898
899TEST_P(PeerConnectionMediaTest,
900 CreateAnswerWithVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700901 auto caller = CreatePeerConnectionWithAudioVideo();
Philipp Hancke718acf62021-05-12 14:18:03 +0200902
903 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
904 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
905 auto callee =
906 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
907
908 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
909
910 RTCOfferAnswerOptions options;
911 options.voice_activity_detection = true;
912 auto answer = callee->CreateAnswer(options);
913
914 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
915}
916
917TEST_P(PeerConnectionMediaTest,
918 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
919 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
920 AddComfortNoiseCodecsToSend(caller_fake_engine.get());
921 auto caller =
922 CreatePeerConnectionWithAudioVideo(std::move(caller_fake_engine));
923
924 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
925 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
926 auto callee =
927 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
Steve Anton8d3444d2017-10-20 15:30:51 -0700928
929 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
930
931 RTCOfferAnswerOptions options;
932 options.voice_activity_detection = false;
933 auto answer = callee->CreateAnswer(options);
934
935 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
936}
937
938// The following test group verifies that we reject answers with invalid media
939// sections as per RFC 3264.
940
941class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800942 : public PeerConnectionMediaBaseTest,
943 public ::testing::WithParamInterface<std::tuple<
944 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700945 std::tuple<std::string,
946 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800947 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700948 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800949 PeerConnectionMediaInvalidMediaTest()
950 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
951 auto param = std::get<1>(GetParam());
952 mutator_ = std::get<1>(param);
953 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700954 }
955
956 std::function<void(cricket::SessionDescription*)> mutator_;
957 std::string expected_error_;
958};
959
960TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
961 auto caller = CreatePeerConnectionWithAudioVideo();
962 auto callee = CreatePeerConnectionWithAudioVideo();
963
964 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
965
966 auto answer = callee->CreateAnswer();
967 mutator_(answer->description());
968
969 std::string error;
970 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
971 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
972}
973
974TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
975 auto caller = CreatePeerConnectionWithAudioVideo();
976 auto callee = CreatePeerConnectionWithAudioVideo();
977
978 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
979
980 auto answer = callee->CreateAnswer();
981 mutator_(answer->description());
982
983 std::string error;
984 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
985 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
986}
987
988void RemoveVideoContent(cricket::SessionDescription* desc) {
989 auto content_name = cricket::GetFirstVideoContent(desc)->name;
990 desc->RemoveContentByName(content_name);
991 desc->RemoveTransportInfoByName(content_name);
992}
993
994void RenameVideoContent(cricket::SessionDescription* desc) {
995 auto* video_content = cricket::GetFirstVideoContent(desc);
996 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
997 video_content->name = "video_renamed";
998 transport_info->content_name = video_content->name;
999}
1000
1001void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -08001002 absl::c_reverse(desc->contents());
1003 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -07001004}
1005
1006void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001007 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
1008 desc->RemoveContentByName(audio_mid);
1009 auto* video_content = cricket::GetFirstVideoContent(desc);
1010 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001011 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 15:30:51 -07001012}
1013
1014constexpr char kMLinesOutOfOrder[] =
1015 "The order of m-lines in answer doesn't match order in offer. Rejecting "
1016 "answer.";
1017
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001018INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -07001019 PeerConnectionMediaTest,
1020 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -08001021 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
1022 Values(std::make_tuple("remove video",
1023 RemoveVideoContent,
1024 kMLinesOutOfOrder),
1025 std::make_tuple("rename video",
1026 RenameVideoContent,
1027 kMLinesOutOfOrder),
1028 std::make_tuple("reverse media sections",
1029 ReverseMediaContent,
1030 kMLinesOutOfOrder),
1031 std::make_tuple("change audio type to video type",
1032 ChangeMediaTypeAudioToVideo,
1033 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -07001034
1035// Test that the correct media engine send/recv streams are created when doing
1036// a series of offer/answers where audio/video are both sent, then audio is
1037// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001038TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001039 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001040 // offer_to_receive_ is not implemented when creating answers with Unified
1041 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001042 return;
1043 }
1044
Steve Anton8d3444d2017-10-20 15:30:51 -07001045 RTCOfferAnswerOptions options_reject_video;
1046 options_reject_video.offer_to_receive_audio =
1047 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
1048 options_reject_video.offer_to_receive_video = 0;
1049
1050 auto caller = CreatePeerConnection();
1051 caller->AddAudioTrack("a");
1052 caller->AddVideoTrack("v");
1053 auto callee = CreatePeerConnection();
1054
1055 // Caller initially offers to send/recv audio and video.
1056 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1057 // Callee accepts the audio as recv only but rejects the video.
1058 ASSERT_TRUE(caller->SetRemoteDescription(
1059 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
1060
1061 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1062 ASSERT_TRUE(caller_voice);
1063 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1064 EXPECT_EQ(1u, caller_voice->send_streams().size());
1065 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1066 EXPECT_FALSE(caller_video);
1067
1068 // Callee adds its own audio/video stream and offers to receive audio/video
1069 // too.
1070 callee->AddAudioTrack("a");
1071 auto callee_video_track = callee->AddVideoTrack("v");
1072 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1073 ASSERT_TRUE(
1074 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1075
1076 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1077 ASSERT_TRUE(callee_voice);
1078 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1079 EXPECT_EQ(1u, callee_voice->send_streams().size());
1080 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1081 ASSERT_TRUE(callee_video);
1082 EXPECT_EQ(1u, callee_video->recv_streams().size());
1083 EXPECT_EQ(1u, callee_video->send_streams().size());
1084
1085 // Callee removes video but keeps audio and rejects the video once again.
1086 callee->pc()->RemoveTrack(callee_video_track);
1087 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1088 ASSERT_TRUE(
1089 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1090
1091 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1092 ASSERT_TRUE(callee_voice);
1093 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1094 EXPECT_EQ(1u, callee_voice->send_streams().size());
1095 callee_video = callee->media_engine()->GetVideoChannel(0);
1096 EXPECT_FALSE(callee_video);
1097}
1098
1099// Test that the correct media engine send/recv streams are created when doing
1100// a series of offer/answers where audio/video are both sent, then video is
1101// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001102TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001103 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001104 // offer_to_receive_ is not implemented when creating answers with Unified
1105 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001106 return;
1107 }
1108
Steve Anton8d3444d2017-10-20 15:30:51 -07001109 // Disable the bundling here. If the media is bundled on audio
1110 // transport, then we can't reject the audio because switching the bundled
1111 // transport is not currently supported.
1112 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1113 RTCOfferAnswerOptions options_no_bundle;
1114 options_no_bundle.use_rtp_mux = false;
1115 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1116 options_reject_audio.offer_to_receive_audio = 0;
1117 options_reject_audio.offer_to_receive_video =
1118 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1119
1120 auto caller = CreatePeerConnection();
1121 caller->AddAudioTrack("a");
1122 caller->AddVideoTrack("v");
1123 auto callee = CreatePeerConnection();
1124
1125 // Caller initially offers to send/recv audio and video.
1126 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1127 // Callee accepts the video as recv only but rejects the audio.
1128 ASSERT_TRUE(caller->SetRemoteDescription(
1129 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1130
1131 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1132 EXPECT_FALSE(caller_voice);
1133 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1134 ASSERT_TRUE(caller_video);
1135 EXPECT_EQ(0u, caller_video->recv_streams().size());
1136 EXPECT_EQ(1u, caller_video->send_streams().size());
1137
1138 // Callee adds its own audio/video stream and offers to receive audio/video
1139 // too.
1140 auto callee_audio_track = callee->AddAudioTrack("a");
1141 callee->AddVideoTrack("v");
1142 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1143 ASSERT_TRUE(caller->SetRemoteDescription(
1144 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1145
1146 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1147 ASSERT_TRUE(callee_voice);
1148 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1149 EXPECT_EQ(1u, callee_voice->send_streams().size());
1150 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1151 ASSERT_TRUE(callee_video);
1152 EXPECT_EQ(1u, callee_video->recv_streams().size());
1153 EXPECT_EQ(1u, callee_video->send_streams().size());
1154
1155 // Callee removes audio but keeps video and rejects the audio once again.
1156 callee->pc()->RemoveTrack(callee_audio_track);
1157 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1158 ASSERT_TRUE(
1159 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1160
1161 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1162 EXPECT_FALSE(callee_voice);
1163 callee_video = callee->media_engine()->GetVideoChannel(0);
1164 ASSERT_TRUE(callee_video);
1165 EXPECT_EQ(1u, callee_video->recv_streams().size());
1166 EXPECT_EQ(1u, callee_video->send_streams().size());
1167}
1168
1169// Tests that if the underlying video encoder fails to be initialized (signaled
1170// by failing to set send codecs), the PeerConnection signals the error to the
1171// client.
Steve Antonad7bffc2018-01-22 10:21:56 -08001172TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001173 auto caller = CreatePeerConnectionWithAudioVideo();
1174 auto callee = CreatePeerConnectionWithAudioVideo();
1175
1176 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1177
1178 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1179 video_channel->set_fail_set_send_codecs(true);
1180
1181 std::string error;
1182 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1183 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:22 +00001184 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1185 "video description "
1186 "send parameters for m-section with mid='") +
1187 (IsUnifiedPlan() ? "1" : "video") + "'.",
1188 error);
Steve Anton8d3444d2017-10-20 15:30:51 -07001189}
1190
1191// Tests that if the underlying video encoder fails once then subsequent
1192// attempts at setting the local/remote description will also fail, even if
1193// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001194TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001195 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1196 auto caller = CreatePeerConnectionWithAudioVideo();
1197 auto callee = CreatePeerConnectionWithAudioVideo();
1198
1199 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1200
1201 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1202 video_channel->set_fail_set_send_codecs(true);
1203
1204 EXPECT_FALSE(
1205 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1206
1207 video_channel->set_fail_set_send_codecs(false);
1208
1209 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1210 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1211}
1212
1213void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001214 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001215 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001216 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001217 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001218 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001219 content->name = new_name;
1220 auto* transport = desc->GetTransportInfoByName(old_name);
1221 RTC_DCHECK(transport);
1222 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001223
1224 // Rename the content name in the BUNDLE group.
1225 cricket::ContentGroup new_bundle_group =
1226 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1227 new_bundle_group.RemoveContentName(old_name);
1228 new_bundle_group.AddContentName(new_name);
1229 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1230 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001231}
1232
1233// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001234TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001235 const std::string kAudioMid = "notdefault1";
1236 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001237
1238 auto caller = CreatePeerConnectionWithAudioVideo();
1239 auto callee = CreatePeerConnectionWithAudioVideo();
1240
1241 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001242 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1243 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001244 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1245
1246 auto answer = callee->CreateAnswer();
1247 EXPECT_EQ(kAudioMid,
1248 cricket::GetFirstAudioContent(answer->description())->name);
1249 EXPECT_EQ(kVideoMid,
1250 cricket::GetFirstVideoContent(answer->description())->name);
1251}
1252
1253// Test that if the callee creates a re-offer, the MIDs are the same as the
1254// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001255TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001256 const std::string kAudioMid = "notdefault1";
1257 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001258
1259 auto caller = CreatePeerConnectionWithAudioVideo();
1260 auto callee = CreatePeerConnectionWithAudioVideo();
1261
1262 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001263 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1264 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001265 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1266 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1267
1268 auto reoffer = callee->CreateOffer();
1269 EXPECT_EQ(kAudioMid,
1270 cricket::GetFirstAudioContent(reoffer->description())->name);
1271 EXPECT_EQ(kVideoMid,
1272 cricket::GetFirstVideoContent(reoffer->description())->name);
1273}
1274
Steve Anton06817cd2018-12-18 15:55:30 -08001275// Test that SetRemoteDescription returns an error if there are two m= sections
1276// with the same MID value.
1277TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1278 auto caller = CreatePeerConnectionWithAudioVideo();
1279 auto callee = CreatePeerConnectionWithAudioVideo();
1280
1281 auto offer = caller->CreateOffer();
1282 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1283 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1284
1285 std::string error;
1286 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1287 EXPECT_EQ(error,
1288 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1289}
1290
Steve Antonad7bffc2018-01-22 10:21:56 -08001291TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001292 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1293 RTCConfiguration config;
1294 config.combined_audio_video_bwe.emplace(true);
1295 auto caller = CreatePeerConnectionWithAudioVideo(config);
1296
1297 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1298
1299 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1300 ASSERT_TRUE(caller_voice);
1301 const cricket::AudioOptions& audio_options = caller_voice->options();
1302 EXPECT_EQ(config.combined_audio_video_bwe,
1303 audio_options.combined_audio_video_bwe);
1304}
1305
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001306template <typename C>
1307bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1308 const std::vector<C>& codecs) {
1309 bool capability_has_rtx =
1310 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1311 return codec.name == cricket::kRtxCodecName;
1312 });
1313 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1314 return codec.name == cricket::kRtxCodecName;
1315 });
1316
1317 std::vector<C> codecs_no_rtx;
1318 absl::c_copy_if(
1319 codecs, std::back_inserter(codecs_no_rtx),
1320 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1321
1322 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1323 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1324 [](const webrtc::RtpCodecCapability& codec) {
1325 return codec.name != cricket::kRtxCodecName;
1326 });
1327
1328 return capability_has_rtx == codecs_has_rtx &&
1329 absl::c_equal(
1330 capabilities_no_rtx, codecs_no_rtx,
1331 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1332 return codec.MatchesCapability(capability);
1333 });
1334}
1335
1336TEST_F(PeerConnectionMediaTestUnifiedPlan,
1337 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001338 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001339 auto send_codecs = fake_engine->voice().send_codecs();
1340 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1341 "send_only_codec", 0, 0, 1));
1342 fake_engine->SetAudioSendCodecs(send_codecs);
1343
1344 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1345
1346 auto transceiver = caller->pc()->GetTransceivers().front();
1347 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1348 cricket::MediaType::MEDIA_TYPE_AUDIO);
1349
1350 std::vector<webrtc::RtpCodecCapability> codecs;
1351 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1352 [](const webrtc::RtpCodecCapability& codec) {
1353 return codec.name.find("_only_") != std::string::npos;
1354 });
1355
1356 auto result = transceiver->SetCodecPreferences(codecs);
1357 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1358}
1359
1360TEST_F(PeerConnectionMediaTestUnifiedPlan,
1361 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001362 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001363 auto recv_codecs = fake_engine->voice().recv_codecs();
1364 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1365 "recv_only_codec", 0, 0, 1));
1366 fake_engine->SetAudioRecvCodecs(recv_codecs);
1367 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1368
1369 auto transceiver = caller->pc()->GetTransceivers().front();
1370 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1371 cricket::MediaType::MEDIA_TYPE_AUDIO);
1372
1373 std::vector<webrtc::RtpCodecCapability> codecs;
1374 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1375 [](const webrtc::RtpCodecCapability& codec) {
1376 return codec.name.find("_only_") != std::string::npos;
1377 });
1378
1379 auto result = transceiver->SetCodecPreferences(codecs);
1380 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1381}
1382
1383TEST_F(PeerConnectionMediaTestUnifiedPlan,
1384 SetCodecPreferencesAudioRejectsVideoCodec) {
1385 auto caller = CreatePeerConnectionWithAudio();
1386
1387 auto transceiver = caller->pc()->GetTransceivers().front();
1388 auto video_codecs =
1389 caller->pc_factory()
1390 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1391 .codecs;
1392 auto codecs =
1393 caller->pc_factory()
1394 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1395 .codecs;
1396 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1397 auto result = transceiver->SetCodecPreferences(codecs);
1398 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1399}
1400
1401TEST_F(PeerConnectionMediaTestUnifiedPlan,
1402 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001403 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001404 auto audio_codecs = fake_engine->voice().send_codecs();
1405 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1406 cricket::kRtxCodecName, 0, 0, 1));
1407 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1408 std::to_string(audio_codecs.back().id - 1);
1409 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1410 cricket::kRedCodecName, 0, 0, 1));
1411 audio_codecs.push_back(cricket::AudioCodec(
1412 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1413 fake_engine->SetAudioCodecs(audio_codecs);
1414
1415 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1416
1417 auto transceiver = caller->pc()->GetTransceivers().front();
1418 auto codecs =
1419 caller->pc_factory()
1420 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1421 .codecs;
1422 auto codecs_only_rtx_red_fec = codecs;
1423 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1424 codecs_only_rtx_red_fec.end(),
1425 [](const webrtc::RtpCodecCapability& codec) {
1426 return !(codec.name == cricket::kRtxCodecName ||
1427 codec.name == cricket::kRedCodecName ||
1428 codec.name == cricket::kUlpfecCodecName);
1429 });
1430 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1431
1432 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1433 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1434}
1435
1436TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1437 auto caller = CreatePeerConnectionWithAudio();
1438
1439 auto sender_audio_codecs =
1440 caller->pc_factory()
1441 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1442 .codecs;
1443
1444 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1445
1446 // Normal case, set all capabilities as preferences
1447 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1448 auto offer = caller->CreateOffer();
1449 auto codecs = offer->description()
1450 ->contents()[0]
1451 .media_description()
1452 ->as_audio()
1453 ->codecs();
1454 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1455}
1456
1457TEST_F(PeerConnectionMediaTestUnifiedPlan,
1458 SetCodecPreferencesResetAudioCodecs) {
1459 auto caller = CreatePeerConnectionWithAudio();
1460
1461 auto sender_audio_codecs =
1462 caller->pc_factory()
1463 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1464 .codecs;
1465 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1466
1467 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1468
1469 // Normal case, reset codec preferences
1470 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1471 auto offer = caller->CreateOffer();
1472 auto codecs = offer->description()
1473 ->contents()[0]
1474 .media_description()
1475 ->as_audio()
1476 ->codecs();
1477 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1478}
1479
1480TEST_F(PeerConnectionMediaTestUnifiedPlan,
1481 SetCodecPreferencesVideoRejectsAudioCodec) {
1482 auto caller = CreatePeerConnectionWithVideo();
1483
1484 auto transceiver = caller->pc()->GetTransceivers().front();
1485 auto audio_codecs =
1486 caller->pc_factory()
1487 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1488 .codecs;
1489 auto codecs =
1490 caller->pc_factory()
1491 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1492 .codecs;
1493 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1494 auto result = transceiver->SetCodecPreferences(codecs);
1495 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1496}
1497
1498TEST_F(PeerConnectionMediaTestUnifiedPlan,
1499 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001500 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001501 auto video_codecs = fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001502 video_codecs.push_back(
1503 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
Johannes Kron3e983682020-03-29 22:17:00 +02001504 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1505 std::to_string(video_codecs.back().id - 1);
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001506 video_codecs.push_back(
1507 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1508 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1509 cricket::kUlpfecCodecName));
1510 fake_engine->SetVideoCodecs(video_codecs);
1511
1512 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1513
1514 auto transceiver = caller->pc()->GetTransceivers().front();
1515 auto codecs =
1516 caller->pc_factory()
1517 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1518 .codecs;
1519 auto codecs_only_rtx_red_fec = codecs;
1520 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1521 codecs_only_rtx_red_fec.end(),
1522 [](const webrtc::RtpCodecCapability& codec) {
1523 return !(codec.name == cricket::kRtxCodecName ||
1524 codec.name == cricket::kRedCodecName ||
1525 codec.name == cricket::kUlpfecCodecName);
1526 });
1527 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1528
1529 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1530 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1531}
1532
1533TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1534 auto caller = CreatePeerConnectionWithVideo();
1535
1536 auto sender_video_codecs =
1537 caller->pc_factory()
1538 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1539 .codecs;
1540
1541 auto video_transceiver = caller->pc()->GetTransceivers().front();
1542
1543 // Normal case, setting preferences to normal capabilities
1544 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1545 auto offer = caller->CreateOffer();
1546 auto codecs = offer->description()
1547 ->contents()[0]
1548 .media_description()
1549 ->as_video()
1550 ->codecs();
1551 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1552}
1553
1554TEST_F(PeerConnectionMediaTestUnifiedPlan,
1555 SetCodecPreferencesResetVideoCodecs) {
1556 auto caller = CreatePeerConnectionWithVideo();
1557
1558 auto sender_video_codecs =
1559 caller->pc_factory()
1560 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1561 .codecs;
1562
1563 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1564
1565 auto video_transceiver = caller->pc()->GetTransceivers().front();
1566
1567 // Normal case, resetting preferences with empty list of codecs
1568 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1569 auto offer = caller->CreateOffer();
1570 auto codecs = offer->description()
1571 ->contents()[0]
1572 .media_description()
1573 ->as_video()
1574 ->codecs();
1575 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1576}
1577
1578TEST_F(PeerConnectionMediaTestUnifiedPlan,
1579 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1580 auto caller = CreatePeerConnectionWithVideo();
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 duplicates are removed
1590 auto single_codec = sender_video_codecs;
1591 single_codec.resize(1);
1592 auto duplicate_codec = single_codec;
1593 duplicate_codec.push_back(duplicate_codec.front());
1594 duplicate_codec.push_back(duplicate_codec.front());
1595 duplicate_codec.push_back(duplicate_codec.front());
1596
1597 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1598 auto offer = caller->CreateOffer();
1599 auto codecs = offer->description()
1600 ->contents()[0]
1601 .media_description()
1602 ->as_video()
1603 ->codecs();
1604 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1605}
1606
1607TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001608 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001609 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001610 caller_video_codecs.push_back(cricket::VideoCodec(
1611 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1612 caller_video_codecs.push_back(cricket::VideoCodec(
1613 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1614 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1615 std::to_string(caller_video_codecs.back().id - 1);
1616 caller_video_codecs.push_back(cricket::VideoCodec(
1617 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1618 caller_video_codecs.push_back(cricket::VideoCodec(
1619 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1620 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1621 std::to_string(caller_video_codecs.back().id - 1);
1622 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1623
1624 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1625
1626 auto sender_video_codecs =
1627 caller->pc_factory()
1628 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1629 .codecs;
1630
1631 auto video_transceiver = caller->pc()->GetTransceivers().front();
1632
1633 // Check that RTX codec is properly added
1634 auto video_codecs_vpx_rtx = sender_video_codecs;
1635 auto it =
1636 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1637 [](const webrtc::RtpCodecCapability& codec) {
1638 return codec.name != cricket::kRtxCodecName &&
1639 codec.name != cricket::kVp8CodecName &&
1640 codec.name != cricket::kVp9CodecName;
1641 });
1642 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1643 absl::c_reverse(video_codecs_vpx_rtx);
1644 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1645 EXPECT_TRUE(
1646 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1647 auto offer = caller->CreateOffer();
1648 auto codecs = offer->description()
1649 ->contents()[0]
1650 .media_description()
1651 ->as_video()
1652 ->codecs();
1653
1654 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1655 EXPECT_EQ(codecs.size(), 4u);
1656}
1657
1658TEST_F(PeerConnectionMediaTestUnifiedPlan,
1659 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001660 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001661 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001662 caller_video_codecs.push_back(cricket::VideoCodec(
1663 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1664 caller_video_codecs.push_back(cricket::VideoCodec(
1665 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1666 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1667 std::to_string(caller_video_codecs.back().id - 1);
1668 caller_video_codecs.push_back(cricket::VideoCodec(
1669 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1670 caller_video_codecs.push_back(cricket::VideoCodec(
1671 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1672 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1673 std::to_string(caller_video_codecs.back().id - 1);
1674 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1675
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001676 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001677 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1678
1679 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1680 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1681
1682 auto video_codecs = caller->pc_factory()
1683 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1684 .codecs;
1685
1686 auto send_transceiver = caller->pc()->GetTransceivers().front();
1687
1688 auto video_codecs_vpx = video_codecs;
1689 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1690 [](const webrtc::RtpCodecCapability& codec) {
1691 return codec.name != cricket::kVp8CodecName &&
1692 codec.name != cricket::kVp9CodecName;
1693 });
1694 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1695 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1696 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1697
1698 auto offer = caller->CreateOfferAndSetAsLocal();
1699 auto codecs = offer->description()
1700 ->contents()[0]
1701 .media_description()
1702 ->as_video()
1703 ->codecs();
1704
1705 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1706 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1707
1708 callee->SetRemoteDescription(std::move(offer));
1709
1710 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1711 auto video_codecs_vp8_rtx = video_codecs;
1712 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1713 [](const webrtc::RtpCodecCapability& codec) {
1714 bool r = codec.name != cricket::kVp8CodecName &&
1715 codec.name != cricket::kRtxCodecName;
1716 return r;
1717 });
1718 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1719 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1720 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1721
1722 auto answer = callee->CreateAnswerAndSetAsLocal();
1723
1724 auto recv_codecs = answer->description()
1725 ->contents()[0]
1726 .media_description()
1727 ->as_video()
1728 ->codecs();
1729 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1730}
1731
1732TEST_F(PeerConnectionMediaTestUnifiedPlan,
1733 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001734 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001735 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001736 caller_video_codecs.push_back(cricket::VideoCodec(
1737 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1738 caller_video_codecs.push_back(cricket::VideoCodec(
1739 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1740 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1741 std::to_string(caller_video_codecs.back().id - 1);
1742 caller_video_codecs.push_back(cricket::VideoCodec(
1743 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1744 caller_video_codecs.push_back(cricket::VideoCodec(
1745 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1746 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1747 std::to_string(caller_video_codecs.back().id - 1);
1748 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1749
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001750 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001751 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1752
1753 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1754 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1755
1756 auto video_codecs = caller->pc_factory()
1757 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1758 .codecs;
1759
1760 auto send_transceiver = caller->pc()->GetTransceivers().front();
1761
1762 auto video_codecs_vpx = video_codecs;
1763 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1764 [](const webrtc::RtpCodecCapability& codec) {
1765 return codec.name != cricket::kVp8CodecName &&
1766 codec.name != cricket::kVp9CodecName;
1767 });
1768 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1769 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1770 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1771
1772 auto video_codecs_vpx_reverse = video_codecs_vpx;
1773 absl::c_reverse(video_codecs_vpx_reverse);
1774
1775 auto offer = caller->CreateOfferAndSetAsLocal();
1776 auto codecs = offer->description()
1777 ->contents()[0]
1778 .media_description()
1779 ->as_video()
1780 ->codecs();
1781 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1782 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1783
1784 callee->SetRemoteDescription(std::move(offer));
1785
1786 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1787 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1788
1789 auto answer = callee->CreateAnswerAndSetAsLocal();
1790
1791 auto recv_codecs = answer->description()
1792 ->contents()[0]
1793 .media_description()
1794 ->as_video()
1795 ->codecs();
1796
1797 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1798}
1799
Philipp Hancke3ac73bd2021-05-11 14:13:06 +02001800TEST_F(PeerConnectionMediaTestUnifiedPlan,
1801 SetCodecPreferencesVoiceActivityDetection) {
1802 auto fake_engine = std::make_unique<FakeMediaEngine>();
1803 AddComfortNoiseCodecsToSend(fake_engine.get());
1804 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1805
1806 RTCOfferAnswerOptions options;
1807 auto offer = caller->CreateOffer(options);
1808 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
1809
1810 auto transceiver = caller->pc()->GetTransceivers().front();
1811 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1812 cricket::MediaType::MEDIA_TYPE_AUDIO);
1813 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
1814
1815 options.voice_activity_detection = false;
1816 offer = caller->CreateOffer(options);
1817 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
1818}
1819
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -07001820// If the "default" payload types of audio/video codecs are the same, and
1821// audio/video are bundled (as is the default), payload types should be
1822// remapped to avoid conflict, as normally happens without using
1823// SetCodecPreferences.
1824TEST_F(PeerConnectionMediaTestUnifiedPlan,
1825 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
1826 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
1827
1828 std::vector<cricket::AudioCodec> audio_codecs;
1829 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
1830 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
1831 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
1832 fake_engine->SetAudioCodecs(audio_codecs);
1833
1834 std::vector<cricket::VideoCodec> video_codecs;
1835 video_codecs.emplace_back(100, "bar");
1836 video_codecs.emplace_back(101, cricket::kRtxCodecName);
1837 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
1838 fake_engine->SetVideoCodecs(video_codecs);
1839
1840 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
1841 auto transceivers = caller->pc()->GetTransceivers();
1842 ASSERT_EQ(2u, transceivers.size());
1843
1844 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
1845 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1846 cricket::MediaType::MEDIA_TYPE_AUDIO);
1847 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1848
1849 auto video_transceiver = caller->pc()->GetTransceivers()[1];
1850 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1851 cricket::MediaType::MEDIA_TYPE_VIDEO);
1852 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1853
1854 RTCOfferAnswerOptions options;
1855 auto offer = caller->CreateOffer(options);
1856 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
1857 // Sanity check that we got the primary codec and RTX.
1858 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
1859 ->codecs()
1860 .size());
1861 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
1862 ->codecs()
1863 .size());
1864}
1865
1866// Same as above, but preferences set for the answer.
1867TEST_F(PeerConnectionMediaTestUnifiedPlan,
1868 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
1869 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
1870
1871 std::vector<cricket::AudioCodec> audio_codecs;
1872 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
1873 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
1874 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
1875 fake_engine->SetAudioCodecs(audio_codecs);
1876
1877 std::vector<cricket::VideoCodec> video_codecs;
1878 video_codecs.emplace_back(100, "bar");
1879 video_codecs.emplace_back(101, cricket::kRtxCodecName);
1880 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
1881 fake_engine->SetVideoCodecs(video_codecs);
1882
1883 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
1884
1885 RTCOfferAnswerOptions options;
1886 caller->SetRemoteDescription(caller->CreateOffer(options));
1887
1888 auto transceivers = caller->pc()->GetTransceivers();
1889 ASSERT_EQ(2u, transceivers.size());
1890
1891 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
1892 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1893 cricket::MediaType::MEDIA_TYPE_AUDIO);
1894 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1895
1896 auto video_transceiver = caller->pc()->GetTransceivers()[1];
1897 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1898 cricket::MediaType::MEDIA_TYPE_VIDEO);
1899 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1900
1901 auto answer = caller->CreateAnswer(options);
1902
1903 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
1904 // Sanity check that we got the primary codec and RTX.
1905 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
1906 ->codecs()
1907 .size());
1908 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
1909 ->codecs()
1910 .size());
1911}
1912
1913// Same as above, but preferences set for a subsequent offer.
1914TEST_F(PeerConnectionMediaTestUnifiedPlan,
1915 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
1916 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
1917
1918 std::vector<cricket::AudioCodec> audio_codecs;
1919 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
1920 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
1921 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
1922 fake_engine->SetAudioCodecs(audio_codecs);
1923
1924 std::vector<cricket::VideoCodec> video_codecs;
1925 video_codecs.emplace_back(100, "bar");
1926 video_codecs.emplace_back(101, cricket::kRtxCodecName);
1927 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
1928 fake_engine->SetVideoCodecs(video_codecs);
1929
1930 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
1931
1932 RTCOfferAnswerOptions options;
1933 caller->SetRemoteDescription(caller->CreateOffer(options));
1934 caller->SetLocalDescription(caller->CreateAnswer(options));
1935
1936 auto transceivers = caller->pc()->GetTransceivers();
1937 ASSERT_EQ(2u, transceivers.size());
1938
1939 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
1940 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1941 cricket::MediaType::MEDIA_TYPE_AUDIO);
1942 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1943
1944 auto video_transceiver = caller->pc()->GetTransceivers()[1];
1945 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1946 cricket::MediaType::MEDIA_TYPE_VIDEO);
1947 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1948
1949 auto reoffer = caller->CreateOffer(options);
1950
1951 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
1952 // Sanity check that we got the primary codec and RTX.
1953 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
1954 ->codecs()
1955 .size());
1956 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
1957 ->codecs()
1958 .size());
1959}
1960
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001961INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
1962 PeerConnectionMediaTest,
1963 Values(SdpSemantics::kPlanB,
1964 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08001965
Steve Anton8d3444d2017-10-20 15:30:51 -07001966} // namespace webrtc