blob: ac2563d5fd03fd25961fa67a1b8aa332b7b01cb7 [file] [log] [blame]
Steve Anton8d3444d2017-10-20 15:30:51 -07001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11// This file contains tests that check the interaction between the
12// PeerConnection and the underlying media engine, as well as tests that check
13// the media-related aspects of SDP.
14
15#include <tuple>
16
Steve Anton64b626b2019-01-28 17:25:26 -080017#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 15:38:50 +020018#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "api/call/call_factory_interface.h"
Anton Sukhanov98a462c2018-10-17 13:15:42 -070020#include "api/test/fake_media_transport.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070021#include "logging/rtc_event_log/rtc_event_log_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/fake_media_engine.h"
23#include "p2p/base/fake_port_allocator.h"
24#include "pc/media_session.h"
25#include "pc/peer_connection_wrapper.h"
26#include "pc/rtp_media_utils.h"
27#include "pc/sdp_utils.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070028#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080029#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070030#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020031#include "absl/memory/memory.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070033#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080034#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070035#include "test/gmock.h"
36
37namespace webrtc {
38
39using cricket::FakeMediaEngine;
40using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
41using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
42using ::testing::Bool;
43using ::testing::Combine;
44using ::testing::Values;
45using ::testing::ElementsAre;
46
47class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
48 public:
49 using PeerConnectionWrapper::PeerConnectionWrapper;
50
51 FakeMediaEngine* media_engine() { return media_engine_; }
52 void set_media_engine(FakeMediaEngine* media_engine) {
53 media_engine_ = media_engine;
54 }
55
56 private:
57 FakeMediaEngine* media_engine_;
58};
59
Steve Antonad7bffc2018-01-22 10:21:56 -080060class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070061 protected:
62 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
63
Steve Antonad7bffc2018-01-22 10:21:56 -080064 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
65 : vss_(new rtc::VirtualSocketServer()),
66 main_(vss_.get()),
67 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -070068#ifdef WEBRTC_ANDROID
69 InitializeAndroidObjects();
70#endif
71 }
72
73 WrapperPtr CreatePeerConnection() {
74 return CreatePeerConnection(RTCConfiguration());
75 }
76
Florent Castelli2d9d82e2019-04-23 19:25:51 +020077 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
78 return CreatePeerConnection(config, absl::make_unique<FakeMediaEngine>());
79 }
80
81 WrapperPtr CreatePeerConnection(
82 std::unique_ptr<FakeMediaEngine> media_engine) {
83 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
84 }
85
Anton Sukhanov98a462c2018-10-17 13:15:42 -070086 // Creates PeerConnectionFactory and PeerConnection for given configuration.
87 // Note that PeerConnectionFactory is created with MediaTransportFactory,
88 // because some tests pass config.use_media_transport = true.
Florent Castelli2d9d82e2019-04-23 19:25:51 +020089 WrapperPtr CreatePeerConnection(
90 const RTCConfiguration& config,
91 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 15:30:51 -070092 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070093
94 PeerConnectionFactoryDependencies factory_dependencies;
95
96 factory_dependencies.network_thread = rtc::Thread::Current();
97 factory_dependencies.worker_thread = rtc::Thread::Current();
98 factory_dependencies.signaling_thread = rtc::Thread::Current();
99 factory_dependencies.media_engine = std::move(media_engine);
100 factory_dependencies.call_factory = CreateCallFactory();
101 factory_dependencies.event_log_factory = CreateRtcEventLogFactory();
102 factory_dependencies.media_transport_factory =
103 absl::make_unique<FakeMediaTransportFactory>();
104
105 auto pc_factory =
106 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -0700107
Karl Wiberg918f50c2018-07-05 11:40:33 +0200108 auto fake_port_allocator = absl::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700109 rtc::Thread::Current(), nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +0200110 auto observer = absl::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());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200121 auto wrapper = absl::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());
294 transceivers[0]->Stop();
295 transceivers[1]->Stop();
296
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);
336 auto* description = cricket::GetFirstMediaContent(
337 offer->description(),
338 cricket::MEDIA_TYPE_VIDEO)->media_description();
339 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);
363 auto* description = cricket::GetFirstMediaContent(
364 answer->description(),
365 cricket::MEDIA_TYPE_VIDEO)->media_description();
366 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());
392 transceivers[0]->Stop();
393 transceivers[1]->Stop();
394
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"));
529 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
530 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"));
551 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
552 caller_fake_engine->SetVideoCodecs(fake_codecs);
553 auto callee_fake_engine = absl::make_unique<FakeMediaEngine>();
554 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"));
594 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
595 caller_fake_engine->SetVideoCodecs(fake_codecs);
596 auto callee_fake_engine = absl::make_unique<FakeMediaEngine>();
597 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) {
829 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
830 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
831
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100832 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700833 codecs.push_back(kComfortNoiseCodec8k);
834 codecs.push_back(kComfortNoiseCodec16k);
835 media_engine->SetAudioCodecs(codecs);
836}
837
838bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
839 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
840 for (const auto& codec : audio_desc->codecs()) {
841 if (codec.name == "CN") {
842 return true;
843 }
844 }
845 return false;
846}
847
Steve Antonad7bffc2018-01-22 10:21:56 -0800848TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700849 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
850 auto caller = CreatePeerConnectionWithAudioVideo();
851 AddComfortNoiseCodecsToSend(caller->media_engine());
852
853 RTCOfferAnswerOptions options;
854 options.voice_activity_detection = false;
855 auto offer = caller->CreateOffer(options);
856
857 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
858}
859
Steve Antonad7bffc2018-01-22 10:21:56 -0800860TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700861 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
862 auto caller = CreatePeerConnectionWithAudioVideo();
863 AddComfortNoiseCodecsToSend(caller->media_engine());
864 auto callee = CreatePeerConnectionWithAudioVideo();
865 AddComfortNoiseCodecsToSend(callee->media_engine());
866
867 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
868
869 RTCOfferAnswerOptions options;
870 options.voice_activity_detection = false;
871 auto answer = callee->CreateAnswer(options);
872
873 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
874}
875
876// The following test group verifies that we reject answers with invalid media
877// sections as per RFC 3264.
878
879class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800880 : public PeerConnectionMediaBaseTest,
881 public ::testing::WithParamInterface<std::tuple<
882 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700883 std::tuple<std::string,
884 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800885 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700886 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800887 PeerConnectionMediaInvalidMediaTest()
888 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
889 auto param = std::get<1>(GetParam());
890 mutator_ = std::get<1>(param);
891 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700892 }
893
894 std::function<void(cricket::SessionDescription*)> mutator_;
895 std::string expected_error_;
896};
897
898TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
899 auto caller = CreatePeerConnectionWithAudioVideo();
900 auto callee = CreatePeerConnectionWithAudioVideo();
901
902 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
903
904 auto answer = callee->CreateAnswer();
905 mutator_(answer->description());
906
907 std::string error;
908 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
909 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
910}
911
912TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
913 auto caller = CreatePeerConnectionWithAudioVideo();
914 auto callee = CreatePeerConnectionWithAudioVideo();
915
916 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
917
918 auto answer = callee->CreateAnswer();
919 mutator_(answer->description());
920
921 std::string error;
922 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
923 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
924}
925
926void RemoveVideoContent(cricket::SessionDescription* desc) {
927 auto content_name = cricket::GetFirstVideoContent(desc)->name;
928 desc->RemoveContentByName(content_name);
929 desc->RemoveTransportInfoByName(content_name);
930}
931
932void RenameVideoContent(cricket::SessionDescription* desc) {
933 auto* video_content = cricket::GetFirstVideoContent(desc);
934 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
935 video_content->name = "video_renamed";
936 transport_info->content_name = video_content->name;
937}
938
939void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -0800940 absl::c_reverse(desc->contents());
941 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -0700942}
943
944void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800945 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
946 desc->RemoveContentByName(audio_mid);
947 auto* video_content = cricket::GetFirstVideoContent(desc);
948 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +0200949 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 15:30:51 -0700950}
951
952constexpr char kMLinesOutOfOrder[] =
953 "The order of m-lines in answer doesn't match order in offer. Rejecting "
954 "answer.";
955
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100956INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -0700957 PeerConnectionMediaTest,
958 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800959 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
960 Values(std::make_tuple("remove video",
961 RemoveVideoContent,
962 kMLinesOutOfOrder),
963 std::make_tuple("rename video",
964 RenameVideoContent,
965 kMLinesOutOfOrder),
966 std::make_tuple("reverse media sections",
967 ReverseMediaContent,
968 kMLinesOutOfOrder),
969 std::make_tuple("change audio type to video type",
970 ChangeMediaTypeAudioToVideo,
971 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700972
973// Test that the correct media engine send/recv streams are created when doing
974// a series of offer/answers where audio/video are both sent, then audio is
975// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800976TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800977 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800978 // offer_to_receive_ is not implemented when creating answers with Unified
979 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800980 return;
981 }
982
Steve Anton8d3444d2017-10-20 15:30:51 -0700983 RTCOfferAnswerOptions options_reject_video;
984 options_reject_video.offer_to_receive_audio =
985 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
986 options_reject_video.offer_to_receive_video = 0;
987
988 auto caller = CreatePeerConnection();
989 caller->AddAudioTrack("a");
990 caller->AddVideoTrack("v");
991 auto callee = CreatePeerConnection();
992
993 // Caller initially offers to send/recv audio and video.
994 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
995 // Callee accepts the audio as recv only but rejects the video.
996 ASSERT_TRUE(caller->SetRemoteDescription(
997 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
998
999 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1000 ASSERT_TRUE(caller_voice);
1001 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1002 EXPECT_EQ(1u, caller_voice->send_streams().size());
1003 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1004 EXPECT_FALSE(caller_video);
1005
1006 // Callee adds its own audio/video stream and offers to receive audio/video
1007 // too.
1008 callee->AddAudioTrack("a");
1009 auto callee_video_track = callee->AddVideoTrack("v");
1010 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1011 ASSERT_TRUE(
1012 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1013
1014 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1015 ASSERT_TRUE(callee_voice);
1016 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1017 EXPECT_EQ(1u, callee_voice->send_streams().size());
1018 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1019 ASSERT_TRUE(callee_video);
1020 EXPECT_EQ(1u, callee_video->recv_streams().size());
1021 EXPECT_EQ(1u, callee_video->send_streams().size());
1022
1023 // Callee removes video but keeps audio and rejects the video once again.
1024 callee->pc()->RemoveTrack(callee_video_track);
1025 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1026 ASSERT_TRUE(
1027 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1028
1029 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1030 ASSERT_TRUE(callee_voice);
1031 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1032 EXPECT_EQ(1u, callee_voice->send_streams().size());
1033 callee_video = callee->media_engine()->GetVideoChannel(0);
1034 EXPECT_FALSE(callee_video);
1035}
1036
1037// Test that the correct media engine send/recv streams are created when doing
1038// a series of offer/answers where audio/video are both sent, then video is
1039// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001040TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001041 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001042 // offer_to_receive_ is not implemented when creating answers with Unified
1043 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001044 return;
1045 }
1046
Steve Anton8d3444d2017-10-20 15:30:51 -07001047 // Disable the bundling here. If the media is bundled on audio
1048 // transport, then we can't reject the audio because switching the bundled
1049 // transport is not currently supported.
1050 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1051 RTCOfferAnswerOptions options_no_bundle;
1052 options_no_bundle.use_rtp_mux = false;
1053 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1054 options_reject_audio.offer_to_receive_audio = 0;
1055 options_reject_audio.offer_to_receive_video =
1056 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1057
1058 auto caller = CreatePeerConnection();
1059 caller->AddAudioTrack("a");
1060 caller->AddVideoTrack("v");
1061 auto callee = CreatePeerConnection();
1062
1063 // Caller initially offers to send/recv audio and video.
1064 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1065 // Callee accepts the video as recv only but rejects the audio.
1066 ASSERT_TRUE(caller->SetRemoteDescription(
1067 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1068
1069 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1070 EXPECT_FALSE(caller_voice);
1071 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1072 ASSERT_TRUE(caller_video);
1073 EXPECT_EQ(0u, caller_video->recv_streams().size());
1074 EXPECT_EQ(1u, caller_video->send_streams().size());
1075
1076 // Callee adds its own audio/video stream and offers to receive audio/video
1077 // too.
1078 auto callee_audio_track = callee->AddAudioTrack("a");
1079 callee->AddVideoTrack("v");
1080 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1081 ASSERT_TRUE(caller->SetRemoteDescription(
1082 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1083
1084 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1085 ASSERT_TRUE(callee_voice);
1086 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1087 EXPECT_EQ(1u, callee_voice->send_streams().size());
1088 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1089 ASSERT_TRUE(callee_video);
1090 EXPECT_EQ(1u, callee_video->recv_streams().size());
1091 EXPECT_EQ(1u, callee_video->send_streams().size());
1092
1093 // Callee removes audio but keeps video and rejects the audio once again.
1094 callee->pc()->RemoveTrack(callee_audio_track);
1095 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1096 ASSERT_TRUE(
1097 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1098
1099 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1100 EXPECT_FALSE(callee_voice);
1101 callee_video = callee->media_engine()->GetVideoChannel(0);
1102 ASSERT_TRUE(callee_video);
1103 EXPECT_EQ(1u, callee_video->recv_streams().size());
1104 EXPECT_EQ(1u, callee_video->send_streams().size());
1105}
1106
1107// Tests that if the underlying video encoder fails to be initialized (signaled
1108// by failing to set send codecs), the PeerConnection signals the error to the
1109// client.
Steve Antonad7bffc2018-01-22 10:21:56 -08001110TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001111 auto caller = CreatePeerConnectionWithAudioVideo();
1112 auto callee = CreatePeerConnectionWithAudioVideo();
1113
1114 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1115
1116 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1117 video_channel->set_fail_set_send_codecs(true);
1118
1119 std::string error;
1120 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1121 &error));
1122 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -08001123 "Failed to set remote answer sdp: Failed to set remote video description "
1124 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -07001125 error);
1126}
1127
1128// Tests that if the underlying video encoder fails once then subsequent
1129// attempts at setting the local/remote description will also fail, even if
1130// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001131TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001132 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1133 auto caller = CreatePeerConnectionWithAudioVideo();
1134 auto callee = CreatePeerConnectionWithAudioVideo();
1135
1136 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1137
1138 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1139 video_channel->set_fail_set_send_codecs(true);
1140
1141 EXPECT_FALSE(
1142 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1143
1144 video_channel->set_fail_set_send_codecs(false);
1145
1146 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1147 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1148}
1149
1150void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001151 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001152 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001153 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001154 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001155 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001156 content->name = new_name;
1157 auto* transport = desc->GetTransportInfoByName(old_name);
1158 RTC_DCHECK(transport);
1159 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001160
1161 // Rename the content name in the BUNDLE group.
1162 cricket::ContentGroup new_bundle_group =
1163 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1164 new_bundle_group.RemoveContentName(old_name);
1165 new_bundle_group.AddContentName(new_name);
1166 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1167 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001168}
1169
1170// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001171TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001172 const std::string kAudioMid = "notdefault1";
1173 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001174
1175 auto caller = CreatePeerConnectionWithAudioVideo();
1176 auto callee = CreatePeerConnectionWithAudioVideo();
1177
1178 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001179 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1180 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001181 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1182
1183 auto answer = callee->CreateAnswer();
1184 EXPECT_EQ(kAudioMid,
1185 cricket::GetFirstAudioContent(answer->description())->name);
1186 EXPECT_EQ(kVideoMid,
1187 cricket::GetFirstVideoContent(answer->description())->name);
1188}
1189
1190// Test that if the callee creates a re-offer, the MIDs are the same as the
1191// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001192TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001193 const std::string kAudioMid = "notdefault1";
1194 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001195
1196 auto caller = CreatePeerConnectionWithAudioVideo();
1197 auto callee = CreatePeerConnectionWithAudioVideo();
1198
1199 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001200 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1201 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001202 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1203 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1204
1205 auto reoffer = callee->CreateOffer();
1206 EXPECT_EQ(kAudioMid,
1207 cricket::GetFirstAudioContent(reoffer->description())->name);
1208 EXPECT_EQ(kVideoMid,
1209 cricket::GetFirstVideoContent(reoffer->description())->name);
1210}
1211
Steve Anton06817cd2018-12-18 15:55:30 -08001212// Test that SetRemoteDescription returns an error if there are two m= sections
1213// with the same MID value.
1214TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1215 auto caller = CreatePeerConnectionWithAudioVideo();
1216 auto callee = CreatePeerConnectionWithAudioVideo();
1217
1218 auto offer = caller->CreateOffer();
1219 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1220 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1221
1222 std::string error;
1223 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1224 EXPECT_EQ(error,
1225 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1226}
1227
Steve Antonad7bffc2018-01-22 10:21:56 -08001228TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001229 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1230 RTCConfiguration config;
1231 config.combined_audio_video_bwe.emplace(true);
1232 auto caller = CreatePeerConnectionWithAudioVideo(config);
1233
1234 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1235
1236 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1237 ASSERT_TRUE(caller_voice);
1238 const cricket::AudioOptions& audio_options = caller_voice->options();
1239 EXPECT_EQ(config.combined_audio_video_bwe,
1240 audio_options.combined_audio_video_bwe);
1241}
1242
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001243TEST_P(PeerConnectionMediaTest, MediaTransportPropagatedToVoiceEngine) {
1244 RTCConfiguration config;
1245
1246 // Setup PeerConnection to use media transport.
1247 config.use_media_transport = true;
1248
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001249 // Force SDES.
1250 config.enable_dtls_srtp = false;
1251
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001252 auto caller = CreatePeerConnectionWithAudio(config);
1253 auto callee = CreatePeerConnectionWithAudio(config);
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001254
1255 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1256 auto answer = callee->CreateAnswer();
1257 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1258
1259 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1260 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1261 ASSERT_TRUE(caller_voice);
1262 ASSERT_TRUE(callee_voice);
1263
1264 // Make sure media transport is propagated to voice channel.
1265 FakeMediaTransport* caller_voice_media_transport =
1266 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1267 FakeMediaTransport* callee_voice_media_transport =
1268 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1269 ASSERT_NE(nullptr, caller_voice_media_transport);
1270 ASSERT_NE(nullptr, callee_voice_media_transport);
1271
1272 // Make sure media transport is created with correct is_caller.
1273 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1274 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1275
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001276 // TODO(sukhanov): Propagate media transport to video channel.
1277 // This test does NOT set up video channels, because currently it causes
1278 // us to create two media transports.
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001279}
1280
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001281TEST_P(PeerConnectionMediaTest, MediaTransportOnlyForDataChannels) {
1282 RTCConfiguration config;
1283
1284 // Setup PeerConnection to use media transport for data channels.
1285 config.use_media_transport_for_data_channels = true;
1286
1287 // Force SDES.
1288 config.enable_dtls_srtp = false;
1289
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001290 auto caller = CreatePeerConnectionWithAudio(config);
1291 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001292
1293 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1294 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1295
1296 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1297 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1298 ASSERT_TRUE(caller_voice);
1299 ASSERT_TRUE(callee_voice);
1300
1301 // Make sure media transport is not propagated to voice channel.
1302 EXPECT_EQ(nullptr, caller_voice->media_transport());
1303 EXPECT_EQ(nullptr, callee_voice->media_transport());
1304}
1305
1306TEST_P(PeerConnectionMediaTest, MediaTransportForMediaAndDataChannels) {
1307 RTCConfiguration config;
1308
1309 // Setup PeerConnection to use media transport for both media and data
1310 // channels.
1311 config.use_media_transport = true;
1312 config.use_media_transport_for_data_channels = true;
1313
1314 // Force SDES.
1315 config.enable_dtls_srtp = false;
1316
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001317 auto caller = CreatePeerConnectionWithAudio(config);
1318 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001319
1320 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1321 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1322
1323 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1324 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1325 ASSERT_TRUE(caller_voice);
1326 ASSERT_TRUE(callee_voice);
1327
1328 // Make sure media transport is propagated to voice channel.
1329 FakeMediaTransport* caller_voice_media_transport =
1330 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1331 FakeMediaTransport* callee_voice_media_transport =
1332 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1333 ASSERT_NE(nullptr, caller_voice_media_transport);
1334 ASSERT_NE(nullptr, callee_voice_media_transport);
1335
1336 // Make sure media transport is created with correct is_caller.
1337 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1338 EXPECT_FALSE(callee_voice_media_transport->is_caller());
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001339}
1340
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001341TEST_P(PeerConnectionMediaTest, MediaTransportNotPropagatedToVoiceEngine) {
1342 auto caller = CreatePeerConnectionWithAudioVideo();
1343 auto callee = CreatePeerConnectionWithAudioVideo();
1344
1345 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1346 auto answer = callee->CreateAnswer();
1347 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1348
1349 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1350 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1351 ASSERT_TRUE(caller_voice);
1352 ASSERT_TRUE(callee_voice);
1353
1354 // Since we did not setup PeerConnection to use media transport, media
1355 // transport should not be created / propagated to the voice engine.
1356 ASSERT_EQ(nullptr, caller_voice->media_transport());
1357 ASSERT_EQ(nullptr, callee_voice->media_transport());
1358
1359 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1360 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1361 ASSERT_EQ(nullptr, caller_video->media_transport());
1362 ASSERT_EQ(nullptr, callee_video->media_transport());
1363}
1364
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001365template <typename C>
1366bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1367 const std::vector<C>& codecs) {
1368 bool capability_has_rtx =
1369 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1370 return codec.name == cricket::kRtxCodecName;
1371 });
1372 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1373 return codec.name == cricket::kRtxCodecName;
1374 });
1375
1376 std::vector<C> codecs_no_rtx;
1377 absl::c_copy_if(
1378 codecs, std::back_inserter(codecs_no_rtx),
1379 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1380
1381 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1382 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1383 [](const webrtc::RtpCodecCapability& codec) {
1384 return codec.name != cricket::kRtxCodecName;
1385 });
1386
1387 return capability_has_rtx == codecs_has_rtx &&
1388 absl::c_equal(
1389 capabilities_no_rtx, codecs_no_rtx,
1390 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1391 return codec.MatchesCapability(capability);
1392 });
1393}
1394
1395TEST_F(PeerConnectionMediaTestUnifiedPlan,
1396 SetCodecPreferencesAudioMissingRecvCodec) {
1397 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1398 auto send_codecs = fake_engine->voice().send_codecs();
1399 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1400 "send_only_codec", 0, 0, 1));
1401 fake_engine->SetAudioSendCodecs(send_codecs);
1402
1403 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1404
1405 auto transceiver = caller->pc()->GetTransceivers().front();
1406 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1407 cricket::MediaType::MEDIA_TYPE_AUDIO);
1408
1409 std::vector<webrtc::RtpCodecCapability> codecs;
1410 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1411 [](const webrtc::RtpCodecCapability& codec) {
1412 return codec.name.find("_only_") != std::string::npos;
1413 });
1414
1415 auto result = transceiver->SetCodecPreferences(codecs);
1416 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1417}
1418
1419TEST_F(PeerConnectionMediaTestUnifiedPlan,
1420 SetCodecPreferencesAudioMissingSendCodec) {
1421 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1422 auto recv_codecs = fake_engine->voice().recv_codecs();
1423 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1424 "recv_only_codec", 0, 0, 1));
1425 fake_engine->SetAudioRecvCodecs(recv_codecs);
1426 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1427
1428 auto transceiver = caller->pc()->GetTransceivers().front();
1429 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1430 cricket::MediaType::MEDIA_TYPE_AUDIO);
1431
1432 std::vector<webrtc::RtpCodecCapability> codecs;
1433 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1434 [](const webrtc::RtpCodecCapability& codec) {
1435 return codec.name.find("_only_") != std::string::npos;
1436 });
1437
1438 auto result = transceiver->SetCodecPreferences(codecs);
1439 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1440}
1441
1442TEST_F(PeerConnectionMediaTestUnifiedPlan,
1443 SetCodecPreferencesAudioRejectsVideoCodec) {
1444 auto caller = CreatePeerConnectionWithAudio();
1445
1446 auto transceiver = caller->pc()->GetTransceivers().front();
1447 auto video_codecs =
1448 caller->pc_factory()
1449 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1450 .codecs;
1451 auto codecs =
1452 caller->pc_factory()
1453 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1454 .codecs;
1455 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1456 auto result = transceiver->SetCodecPreferences(codecs);
1457 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1458}
1459
1460TEST_F(PeerConnectionMediaTestUnifiedPlan,
1461 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
1462 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1463 auto audio_codecs = fake_engine->voice().send_codecs();
1464 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1465 cricket::kRtxCodecName, 0, 0, 1));
1466 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1467 std::to_string(audio_codecs.back().id - 1);
1468 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1469 cricket::kRedCodecName, 0, 0, 1));
1470 audio_codecs.push_back(cricket::AudioCodec(
1471 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1472 fake_engine->SetAudioCodecs(audio_codecs);
1473
1474 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1475
1476 auto transceiver = caller->pc()->GetTransceivers().front();
1477 auto codecs =
1478 caller->pc_factory()
1479 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1480 .codecs;
1481 auto codecs_only_rtx_red_fec = codecs;
1482 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1483 codecs_only_rtx_red_fec.end(),
1484 [](const webrtc::RtpCodecCapability& codec) {
1485 return !(codec.name == cricket::kRtxCodecName ||
1486 codec.name == cricket::kRedCodecName ||
1487 codec.name == cricket::kUlpfecCodecName);
1488 });
1489 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1490
1491 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1492 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1493}
1494
1495TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1496 auto caller = CreatePeerConnectionWithAudio();
1497
1498 auto sender_audio_codecs =
1499 caller->pc_factory()
1500 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1501 .codecs;
1502
1503 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1504
1505 // Normal case, set all capabilities as preferences
1506 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1507 auto offer = caller->CreateOffer();
1508 auto codecs = offer->description()
1509 ->contents()[0]
1510 .media_description()
1511 ->as_audio()
1512 ->codecs();
1513 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1514}
1515
1516TEST_F(PeerConnectionMediaTestUnifiedPlan,
1517 SetCodecPreferencesResetAudioCodecs) {
1518 auto caller = CreatePeerConnectionWithAudio();
1519
1520 auto sender_audio_codecs =
1521 caller->pc_factory()
1522 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1523 .codecs;
1524 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1525
1526 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1527
1528 // Normal case, reset codec preferences
1529 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1530 auto offer = caller->CreateOffer();
1531 auto codecs = offer->description()
1532 ->contents()[0]
1533 .media_description()
1534 ->as_audio()
1535 ->codecs();
1536 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1537}
1538
1539TEST_F(PeerConnectionMediaTestUnifiedPlan,
1540 SetCodecPreferencesVideoRejectsAudioCodec) {
1541 auto caller = CreatePeerConnectionWithVideo();
1542
1543 auto transceiver = caller->pc()->GetTransceivers().front();
1544 auto audio_codecs =
1545 caller->pc_factory()
1546 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1547 .codecs;
1548 auto codecs =
1549 caller->pc_factory()
1550 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1551 .codecs;
1552 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1553 auto result = transceiver->SetCodecPreferences(codecs);
1554 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1555}
1556
1557TEST_F(PeerConnectionMediaTestUnifiedPlan,
1558 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
1559 auto fake_engine = absl::make_unique<FakeMediaEngine>();
1560 auto video_codecs = fake_engine->video().codecs();
1561 video_codecs.push_back(
1562 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
1563 video_codecs.push_back(
1564 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1565 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1566 cricket::kUlpfecCodecName));
1567 fake_engine->SetVideoCodecs(video_codecs);
1568
1569 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1570
1571 auto transceiver = caller->pc()->GetTransceivers().front();
1572 auto codecs =
1573 caller->pc_factory()
1574 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1575 .codecs;
1576 auto codecs_only_rtx_red_fec = codecs;
1577 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1578 codecs_only_rtx_red_fec.end(),
1579 [](const webrtc::RtpCodecCapability& codec) {
1580 return !(codec.name == cricket::kRtxCodecName ||
1581 codec.name == cricket::kRedCodecName ||
1582 codec.name == cricket::kUlpfecCodecName);
1583 });
1584 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1585
1586 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1587 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1588}
1589
1590TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1591 auto caller = CreatePeerConnectionWithVideo();
1592
1593 auto sender_video_codecs =
1594 caller->pc_factory()
1595 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1596 .codecs;
1597
1598 auto video_transceiver = caller->pc()->GetTransceivers().front();
1599
1600 // Normal case, setting preferences to normal capabilities
1601 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1602 auto offer = caller->CreateOffer();
1603 auto codecs = offer->description()
1604 ->contents()[0]
1605 .media_description()
1606 ->as_video()
1607 ->codecs();
1608 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1609}
1610
1611TEST_F(PeerConnectionMediaTestUnifiedPlan,
1612 SetCodecPreferencesResetVideoCodecs) {
1613 auto caller = CreatePeerConnectionWithVideo();
1614
1615 auto sender_video_codecs =
1616 caller->pc_factory()
1617 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1618 .codecs;
1619
1620 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1621
1622 auto video_transceiver = caller->pc()->GetTransceivers().front();
1623
1624 // Normal case, resetting preferences with empty list of codecs
1625 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1626 auto offer = caller->CreateOffer();
1627 auto codecs = offer->description()
1628 ->contents()[0]
1629 .media_description()
1630 ->as_video()
1631 ->codecs();
1632 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1633}
1634
1635TEST_F(PeerConnectionMediaTestUnifiedPlan,
1636 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1637 auto caller = CreatePeerConnectionWithVideo();
1638
1639 auto sender_video_codecs =
1640 caller->pc_factory()
1641 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1642 .codecs;
1643
1644 auto video_transceiver = caller->pc()->GetTransceivers().front();
1645
1646 // Check duplicates are removed
1647 auto single_codec = sender_video_codecs;
1648 single_codec.resize(1);
1649 auto duplicate_codec = single_codec;
1650 duplicate_codec.push_back(duplicate_codec.front());
1651 duplicate_codec.push_back(duplicate_codec.front());
1652 duplicate_codec.push_back(duplicate_codec.front());
1653
1654 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1655 auto offer = caller->CreateOffer();
1656 auto codecs = offer->description()
1657 ->contents()[0]
1658 .media_description()
1659 ->as_video()
1660 ->codecs();
1661 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1662}
1663
1664TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
1665 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
1666 auto caller_video_codecs = caller_fake_engine->video().codecs();
1667 caller_video_codecs.push_back(cricket::VideoCodec(
1668 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1669 caller_video_codecs.push_back(cricket::VideoCodec(
1670 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1671 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1672 std::to_string(caller_video_codecs.back().id - 1);
1673 caller_video_codecs.push_back(cricket::VideoCodec(
1674 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1675 caller_video_codecs.push_back(cricket::VideoCodec(
1676 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1677 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1678 std::to_string(caller_video_codecs.back().id - 1);
1679 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1680
1681 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1682
1683 auto sender_video_codecs =
1684 caller->pc_factory()
1685 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1686 .codecs;
1687
1688 auto video_transceiver = caller->pc()->GetTransceivers().front();
1689
1690 // Check that RTX codec is properly added
1691 auto video_codecs_vpx_rtx = sender_video_codecs;
1692 auto it =
1693 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1694 [](const webrtc::RtpCodecCapability& codec) {
1695 return codec.name != cricket::kRtxCodecName &&
1696 codec.name != cricket::kVp8CodecName &&
1697 codec.name != cricket::kVp9CodecName;
1698 });
1699 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1700 absl::c_reverse(video_codecs_vpx_rtx);
1701 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1702 EXPECT_TRUE(
1703 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1704 auto offer = caller->CreateOffer();
1705 auto codecs = offer->description()
1706 ->contents()[0]
1707 .media_description()
1708 ->as_video()
1709 ->codecs();
1710
1711 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1712 EXPECT_EQ(codecs.size(), 4u);
1713}
1714
1715TEST_F(PeerConnectionMediaTestUnifiedPlan,
1716 SetCodecPreferencesVideoCodecsNegotiation) {
1717 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
1718 auto caller_video_codecs = caller_fake_engine->video().codecs();
1719 caller_video_codecs.push_back(cricket::VideoCodec(
1720 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1721 caller_video_codecs.push_back(cricket::VideoCodec(
1722 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1723 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1724 std::to_string(caller_video_codecs.back().id - 1);
1725 caller_video_codecs.push_back(cricket::VideoCodec(
1726 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1727 caller_video_codecs.push_back(cricket::VideoCodec(
1728 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1729 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1730 std::to_string(caller_video_codecs.back().id - 1);
1731 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1732
1733 auto callee_fake_engine = absl::make_unique<FakeMediaEngine>();
1734 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1735
1736 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1737 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1738
1739 auto video_codecs = caller->pc_factory()
1740 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1741 .codecs;
1742
1743 auto send_transceiver = caller->pc()->GetTransceivers().front();
1744
1745 auto video_codecs_vpx = video_codecs;
1746 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1747 [](const webrtc::RtpCodecCapability& codec) {
1748 return codec.name != cricket::kVp8CodecName &&
1749 codec.name != cricket::kVp9CodecName;
1750 });
1751 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1752 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1753 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1754
1755 auto offer = caller->CreateOfferAndSetAsLocal();
1756 auto codecs = offer->description()
1757 ->contents()[0]
1758 .media_description()
1759 ->as_video()
1760 ->codecs();
1761
1762 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1763 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1764
1765 callee->SetRemoteDescription(std::move(offer));
1766
1767 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1768 auto video_codecs_vp8_rtx = video_codecs;
1769 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1770 [](const webrtc::RtpCodecCapability& codec) {
1771 bool r = codec.name != cricket::kVp8CodecName &&
1772 codec.name != cricket::kRtxCodecName;
1773 return r;
1774 });
1775 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1776 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1777 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1778
1779 auto answer = callee->CreateAnswerAndSetAsLocal();
1780
1781 auto recv_codecs = answer->description()
1782 ->contents()[0]
1783 .media_description()
1784 ->as_video()
1785 ->codecs();
1786 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1787}
1788
1789TEST_F(PeerConnectionMediaTestUnifiedPlan,
1790 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
1791 auto caller_fake_engine = absl::make_unique<FakeMediaEngine>();
1792 auto caller_video_codecs = caller_fake_engine->video().codecs();
1793 caller_video_codecs.push_back(cricket::VideoCodec(
1794 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1795 caller_video_codecs.push_back(cricket::VideoCodec(
1796 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1797 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1798 std::to_string(caller_video_codecs.back().id - 1);
1799 caller_video_codecs.push_back(cricket::VideoCodec(
1800 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1801 caller_video_codecs.push_back(cricket::VideoCodec(
1802 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1803 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1804 std::to_string(caller_video_codecs.back().id - 1);
1805 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1806
1807 auto callee_fake_engine = absl::make_unique<FakeMediaEngine>();
1808 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1809
1810 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1811 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1812
1813 auto video_codecs = caller->pc_factory()
1814 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1815 .codecs;
1816
1817 auto send_transceiver = caller->pc()->GetTransceivers().front();
1818
1819 auto video_codecs_vpx = video_codecs;
1820 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1821 [](const webrtc::RtpCodecCapability& codec) {
1822 return codec.name != cricket::kVp8CodecName &&
1823 codec.name != cricket::kVp9CodecName;
1824 });
1825 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1826 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1827 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1828
1829 auto video_codecs_vpx_reverse = video_codecs_vpx;
1830 absl::c_reverse(video_codecs_vpx_reverse);
1831
1832 auto offer = caller->CreateOfferAndSetAsLocal();
1833 auto codecs = offer->description()
1834 ->contents()[0]
1835 .media_description()
1836 ->as_video()
1837 ->codecs();
1838 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1839 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1840
1841 callee->SetRemoteDescription(std::move(offer));
1842
1843 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1844 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1845
1846 auto answer = callee->CreateAnswerAndSetAsLocal();
1847
1848 auto recv_codecs = answer->description()
1849 ->contents()[0]
1850 .media_description()
1851 ->as_video()
1852 ->codecs();
1853
1854 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1855}
1856
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001857INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
1858 PeerConnectionMediaTest,
1859 Values(SdpSemantics::kPlanB,
1860 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08001861
Steve Anton8d3444d2017-10-20 15:30:51 -07001862} // namespace webrtc