blob: 6af0c9887e6e2dfe4a1c07cad220ebd120e56486 [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
Niels Möller8366e172018-02-14 12:20:13 +010017#include "api/call/callfactoryinterface.h"
Anton Sukhanov98a462c2018-10-17 13:15:42 -070018#include "api/test/fake_media_transport.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070019#include "logging/rtc_event_log/rtc_event_log_factory.h"
20#include "media/base/fakemediaengine.h"
21#include "p2p/base/fakeportallocator.h"
22#include "pc/mediasession.h"
23#include "pc/peerconnectionwrapper.h"
Steve Anton1d03a752017-11-27 14:30:09 -080024#include "pc/rtpmediautils.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070025#include "pc/sdputils.h"
26#ifdef WEBRTC_ANDROID
27#include "pc/test/androidtestinitializer.h"
28#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020029#include "absl/memory/memory.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070030#include "pc/test/fakertccertificategenerator.h"
31#include "rtc_base/gunit.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070032#include "rtc_base/virtualsocketserver.h"
33#include "test/gmock.h"
34
35namespace webrtc {
36
37using cricket::FakeMediaEngine;
38using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
39using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
40using ::testing::Bool;
41using ::testing::Combine;
42using ::testing::Values;
43using ::testing::ElementsAre;
44
45class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
46 public:
47 using PeerConnectionWrapper::PeerConnectionWrapper;
48
49 FakeMediaEngine* media_engine() { return media_engine_; }
50 void set_media_engine(FakeMediaEngine* media_engine) {
51 media_engine_ = media_engine;
52 }
53
54 private:
55 FakeMediaEngine* media_engine_;
56};
57
Steve Antonad7bffc2018-01-22 10:21:56 -080058class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070059 protected:
60 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
61
Steve Antonad7bffc2018-01-22 10:21:56 -080062 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
63 : vss_(new rtc::VirtualSocketServer()),
64 main_(vss_.get()),
65 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -070066#ifdef WEBRTC_ANDROID
67 InitializeAndroidObjects();
68#endif
69 }
70
71 WrapperPtr CreatePeerConnection() {
72 return CreatePeerConnection(RTCConfiguration());
73 }
74
Anton Sukhanov98a462c2018-10-17 13:15:42 -070075 // Creates PeerConnectionFactory and PeerConnection for given configuration.
76 // Note that PeerConnectionFactory is created with MediaTransportFactory,
77 // because some tests pass config.use_media_transport = true.
Steve Anton8d3444d2017-10-20 15:30:51 -070078 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020079 auto media_engine = absl::make_unique<FakeMediaEngine>();
Steve Anton8d3444d2017-10-20 15:30:51 -070080 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070081
82 PeerConnectionFactoryDependencies factory_dependencies;
83
84 factory_dependencies.network_thread = rtc::Thread::Current();
85 factory_dependencies.worker_thread = rtc::Thread::Current();
86 factory_dependencies.signaling_thread = rtc::Thread::Current();
87 factory_dependencies.media_engine = std::move(media_engine);
88 factory_dependencies.call_factory = CreateCallFactory();
89 factory_dependencies.event_log_factory = CreateRtcEventLogFactory();
90 factory_dependencies.media_transport_factory =
91 absl::make_unique<FakeMediaTransportFactory>();
92
93 auto pc_factory =
94 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -070095
Karl Wiberg918f50c2018-07-05 11:40:33 +020096 auto fake_port_allocator = absl::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -070097 rtc::Thread::Current(), nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +020098 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 10:21:56 -080099 auto modified_config = config;
100 modified_config.sdp_semantics = sdp_semantics_;
101 auto pc = pc_factory->CreatePeerConnection(modified_config,
102 std::move(fake_port_allocator),
103 nullptr, observer.get());
Steve Anton8d3444d2017-10-20 15:30:51 -0700104 if (!pc) {
105 return nullptr;
106 }
107
Yves Gerey4e933292018-10-31 15:36:05 +0100108 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200109 auto wrapper = absl::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700110 pc_factory, pc, std::move(observer));
111 wrapper->set_media_engine(media_engine_ptr);
112 return wrapper;
113 }
114
115 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800116 // track (but no video).
117 template <typename... Args>
118 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
119 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
120 if (!wrapper) {
121 return nullptr;
122 }
123 wrapper->AddAudioTrack("a");
124 return wrapper;
125 }
126
127 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 15:30:51 -0700128 // and video tracks.
129 template <typename... Args>
130 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
131 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
132 if (!wrapper) {
133 return nullptr;
134 }
135 wrapper->AddAudioTrack("a");
136 wrapper->AddVideoTrack("v");
137 return wrapper;
138 }
139
Steve Anton4e70a722017-11-28 14:57:10 -0800140 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700141 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800142 cricket::MediaType media_type) {
143 auto* content =
144 cricket::GetFirstMediaContent(sdesc->description(), media_type);
145 RTC_DCHECK(content);
146 return content->media_description()->direction();
147 }
148
149 bool IsUnifiedPlan() const {
150 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700151 }
152
153 std::unique_ptr<rtc::VirtualSocketServer> vss_;
154 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800155 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700156};
157
Steve Antonad7bffc2018-01-22 10:21:56 -0800158class PeerConnectionMediaTest
159 : public PeerConnectionMediaBaseTest,
160 public ::testing::WithParamInterface<SdpSemantics> {
161 protected:
162 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
163};
164
165class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
166 protected:
167 PeerConnectionMediaTestUnifiedPlan()
168 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
169};
170
171class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
172 protected:
173 PeerConnectionMediaTestPlanB()
174 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
175};
176
177TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700178 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
179 auto caller = CreatePeerConnectionWithAudioVideo();
180 auto callee = CreatePeerConnectionWithAudioVideo();
181 callee->media_engine()->set_fail_create_channel(true);
182
183 std::string error;
184 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800185 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
186 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700187}
188
Steve Antonad7bffc2018-01-22 10:21:56 -0800189TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700190 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
191 auto caller = CreatePeerConnectionWithAudioVideo();
192 caller->media_engine()->set_fail_create_channel(true);
193
194 std::string error;
195 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800196 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
197 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700198}
199
200std::vector<std::string> GetIds(
201 const std::vector<cricket::StreamParams>& streams) {
202 std::vector<std::string> ids;
203 for (const auto& stream : streams) {
204 ids.push_back(stream.id);
205 }
206 return ids;
207}
208
209// Test that exchanging an offer and answer with each side having an audio and
210// video stream creates the appropriate send/recv streams in the underlying
211// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800212TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700213 const std::string kCallerAudioId = "caller_a";
214 const std::string kCallerVideoId = "caller_v";
215 const std::string kCalleeAudioId = "callee_a";
216 const std::string kCalleeVideoId = "callee_v";
217
218 auto caller = CreatePeerConnection();
219 caller->AddAudioTrack(kCallerAudioId);
220 caller->AddVideoTrack(kCallerVideoId);
221
222 auto callee = CreatePeerConnection();
223 callee->AddAudioTrack(kCalleeAudioId);
224 callee->AddVideoTrack(kCalleeVideoId);
225
226 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
227 ASSERT_TRUE(
228 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
229
230 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
231 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
232 ElementsAre(kCalleeAudioId));
233 EXPECT_THAT(GetIds(caller_voice->send_streams()),
234 ElementsAre(kCallerAudioId));
235
236 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
237 EXPECT_THAT(GetIds(caller_video->recv_streams()),
238 ElementsAre(kCalleeVideoId));
239 EXPECT_THAT(GetIds(caller_video->send_streams()),
240 ElementsAre(kCallerVideoId));
241
242 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
243 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
244 ElementsAre(kCallerAudioId));
245 EXPECT_THAT(GetIds(callee_voice->send_streams()),
246 ElementsAre(kCalleeAudioId));
247
248 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
249 EXPECT_THAT(GetIds(callee_video->recv_streams()),
250 ElementsAre(kCallerVideoId));
251 EXPECT_THAT(GetIds(callee_video->send_streams()),
252 ElementsAre(kCalleeVideoId));
253}
254
Steve Antonad7bffc2018-01-22 10:21:56 -0800255// Test that stopping the caller transceivers causes the media channels on the
256// callee to be destroyed after calling SetRemoteDescription on the generated
257// offer.
258// See next test for equivalent behavior with Plan B semantics.
259TEST_F(PeerConnectionMediaTestUnifiedPlan,
260 StoppedRemoteTransceiversRemovesMediaChannels) {
261 auto caller = CreatePeerConnectionWithAudioVideo();
262 auto callee = CreatePeerConnection();
263
264 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
265
266 // Stop both audio and video transceivers on the caller.
267 auto transceivers = caller->pc()->GetTransceivers();
268 ASSERT_EQ(2u, transceivers.size());
269 transceivers[0]->Stop();
270 transceivers[1]->Stop();
271
272 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
273
274 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
275 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
276}
277
Steve Anton8d3444d2017-10-20 15:30:51 -0700278// Test that removing streams from a subsequent offer causes the receive streams
279// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800280// See previous test for equivalent behavior with Unified Plan semantics.
281TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700282 auto caller = CreatePeerConnection();
283 auto caller_audio_track = caller->AddAudioTrack("a");
284 auto caller_video_track = caller->AddVideoTrack("v");
285 auto callee = CreatePeerConnectionWithAudioVideo();
286
Steve Antonad7bffc2018-01-22 10:21:56 -0800287 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700288
289 // Remove both tracks from caller.
290 caller->pc()->RemoveTrack(caller_audio_track);
291 caller->pc()->RemoveTrack(caller_video_track);
292
Steve Antonad7bffc2018-01-22 10:21:56 -0800293 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700294
295 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800296 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700297 EXPECT_EQ(1u, callee_voice->send_streams().size());
298 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700299 EXPECT_EQ(1u, callee_video->send_streams().size());
300 EXPECT_EQ(0u, callee_video->recv_streams().size());
301}
302
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200303// Test enabling of simulcast with Plan B semantics.
304// This test creating an offer.
305TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
306 auto caller = CreatePeerConnection();
307 auto caller_video_track = caller->AddVideoTrack("v");
308 RTCOfferAnswerOptions options;
309 options.num_simulcast_layers = 3;
310 auto offer = caller->CreateOffer(options);
311 auto* description = cricket::GetFirstMediaContent(
312 offer->description(),
313 cricket::MEDIA_TYPE_VIDEO)->media_description();
314 ASSERT_EQ(1u, description->streams().size());
315 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
316 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
317
318 // Check that it actually creates simulcast aswell.
319 caller->SetLocalDescription(std::move(offer));
320 auto senders = caller->pc()->GetSenders();
321 ASSERT_EQ(1u, senders.size());
322 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
323 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
324}
325
326// Test enabling of simulcast with Plan B semantics.
327// This test creating an answer.
328TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
329 auto caller = CreatePeerConnection();
330 caller->AddVideoTrack("v0");
331 auto offer = caller->CreateOffer();
332 auto callee = CreatePeerConnection();
333 auto callee_video_track = callee->AddVideoTrack("v1");
334 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
335 RTCOfferAnswerOptions options;
336 options.num_simulcast_layers = 3;
337 auto answer = callee->CreateAnswer(options);
338 auto* description = cricket::GetFirstMediaContent(
339 answer->description(),
340 cricket::MEDIA_TYPE_VIDEO)->media_description();
341 ASSERT_EQ(1u, description->streams().size());
342 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
343 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
344
345 // Check that it actually creates simulcast aswell.
346 callee->SetLocalDescription(std::move(answer));
347 auto senders = callee->pc()->GetSenders();
348 ASSERT_EQ(1u, senders.size());
349 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
350 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
351}
352
Steve Antonad7bffc2018-01-22 10:21:56 -0800353// Test that stopping the callee transceivers causes the media channels to be
354// destroyed on the callee after calling SetLocalDescription on the local
355// answer.
356// See next test for equivalent behavior with Plan B semantics.
357TEST_F(PeerConnectionMediaTestUnifiedPlan,
358 StoppedLocalTransceiversRemovesMediaChannels) {
359 auto caller = CreatePeerConnectionWithAudioVideo();
360 auto callee = CreatePeerConnectionWithAudioVideo();
361
362 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
363
364 // Stop both audio and video transceivers on the callee.
365 auto transceivers = callee->pc()->GetTransceivers();
366 ASSERT_EQ(2u, transceivers.size());
367 transceivers[0]->Stop();
368 transceivers[1]->Stop();
369
370 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
371
372 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
373 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
374}
375
Steve Anton8d3444d2017-10-20 15:30:51 -0700376// Test that removing streams from a subsequent answer causes the send streams
377// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800378// See previous test for equivalent behavior with Unified Plan semantics.
379TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700380 auto caller = CreatePeerConnectionWithAudioVideo();
381 auto callee = CreatePeerConnection();
382 auto callee_audio_track = callee->AddAudioTrack("a");
383 auto callee_video_track = callee->AddVideoTrack("v");
384
Steve Antonad7bffc2018-01-22 10:21:56 -0800385 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700386
387 // Remove both tracks from callee.
388 callee->pc()->RemoveTrack(callee_audio_track);
389 callee->pc()->RemoveTrack(callee_video_track);
390
Steve Antonad7bffc2018-01-22 10:21:56 -0800391 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700392
393 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800394 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700395 EXPECT_EQ(0u, callee_voice->send_streams().size());
396 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700397 EXPECT_EQ(0u, callee_video->send_streams().size());
398 EXPECT_EQ(1u, callee_video->recv_streams().size());
399}
400
401// Test that a new stream in a subsequent offer causes a new receive stream to
402// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800403TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700404 auto caller = CreatePeerConnectionWithAudioVideo();
405 auto callee = CreatePeerConnection();
406
Steve Antonad7bffc2018-01-22 10:21:56 -0800407 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700408
409 // Add second set of tracks to the caller.
410 caller->AddAudioTrack("a2");
411 caller->AddVideoTrack("v2");
412
Steve Antonad7bffc2018-01-22 10:21:56 -0800413 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700414
Steve Antonad7bffc2018-01-22 10:21:56 -0800415 auto a1 = callee->media_engine()->GetVoiceChannel(0);
416 auto a2 = callee->media_engine()->GetVoiceChannel(1);
417 auto v1 = callee->media_engine()->GetVideoChannel(0);
418 auto v2 = callee->media_engine()->GetVideoChannel(1);
419 if (IsUnifiedPlan()) {
420 ASSERT_TRUE(a1);
421 EXPECT_EQ(1u, a1->recv_streams().size());
422 ASSERT_TRUE(a2);
423 EXPECT_EQ(1u, a2->recv_streams().size());
424 ASSERT_TRUE(v1);
425 EXPECT_EQ(1u, v1->recv_streams().size());
426 ASSERT_TRUE(v2);
427 EXPECT_EQ(1u, v2->recv_streams().size());
428 } else {
429 ASSERT_TRUE(a1);
430 EXPECT_EQ(2u, a1->recv_streams().size());
431 ASSERT_FALSE(a2);
432 ASSERT_TRUE(v1);
433 EXPECT_EQ(2u, v1->recv_streams().size());
434 ASSERT_FALSE(v2);
435 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700436}
437
438// Test that a new stream in a subsequent answer causes a new send stream to be
439// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800440TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700441 auto caller = CreatePeerConnection();
442 auto callee = CreatePeerConnectionWithAudioVideo();
443
Steve Anton22da89f2018-01-25 13:58:07 -0800444 RTCOfferAnswerOptions offer_options;
445 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700446 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800447 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700448 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800449 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700450
Steve Anton22da89f2018-01-25 13:58:07 -0800451 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
452 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700453
454 // Add second set of tracks to the callee.
455 callee->AddAudioTrack("a2");
456 callee->AddVideoTrack("v2");
457
Steve Anton22da89f2018-01-25 13:58:07 -0800458 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
459 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700460
461 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800462 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700463 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800464 ASSERT_TRUE(callee_video);
465
466 if (IsUnifiedPlan()) {
467 EXPECT_EQ(1u, callee_voice->send_streams().size());
468 EXPECT_EQ(1u, callee_video->send_streams().size());
469 } else {
470 EXPECT_EQ(2u, callee_voice->send_streams().size());
471 EXPECT_EQ(2u, callee_video->send_streams().size());
472 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700473}
474
475// A PeerConnection with no local streams and no explicit answer constraints
476// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800477TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700478 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
479 auto caller = CreatePeerConnectionWithAudioVideo();
480 auto callee = CreatePeerConnection();
481 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
482 auto answer = callee->CreateAnswer();
483
484 const auto* audio_content =
485 cricket::GetFirstAudioContent(answer->description());
486 ASSERT_TRUE(audio_content);
487 EXPECT_FALSE(audio_content->rejected);
488
489 const auto* video_content =
490 cricket::GetFirstVideoContent(answer->description());
491 ASSERT_TRUE(video_content);
492 EXPECT_FALSE(video_content->rejected);
493}
494
495class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800496 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700497 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800498 std::tuple<SdpSemantics,
499 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700500 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800501 PeerConnectionMediaOfferDirectionTest()
502 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
503 auto param = std::get<1>(GetParam());
504 send_media_ = std::get<0>(param);
505 offer_to_receive_ = std::get<1>(param);
506 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700507 }
508
509 bool send_media_;
510 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800511 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700512};
513
514// Tests that the correct direction is set on the media description according
515// to the presence of a local media track and the offer_to_receive setting.
516TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
517 auto caller = CreatePeerConnection();
518 if (send_media_) {
519 caller->AddAudioTrack("a");
520 }
521
522 RTCOfferAnswerOptions options;
523 options.offer_to_receive_audio = offer_to_receive_;
524 auto offer = caller->CreateOffer(options);
525
Steve Antonad7bffc2018-01-22 10:21:56 -0800526 auto* content = cricket::GetFirstMediaContent(offer->description(),
527 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800528 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800529 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700530 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800531 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700532 }
533}
534
535// Note that in these tests, MD_INACTIVE indicates that no media section is
536// included in the offer, not that the media direction is inactive.
Steve Anton4e70a722017-11-28 14:57:10 -0800537INSTANTIATE_TEST_CASE_P(
538 PeerConnectionMediaTest,
539 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800540 Combine(
541 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
542 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
543 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
544 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
545 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
546 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
547 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700548
549class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800550 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700551 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800552 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700553 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800554 PeerConnectionMediaAnswerDirectionTest()
555 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
556 offer_direction_ = std::get<1>(GetParam());
557 send_media_ = std::get<2>(GetParam());
558 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700559 }
560
Steve Anton4e70a722017-11-28 14:57:10 -0800561 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700562 bool send_media_;
563 int offer_to_receive_;
564};
565
566// Tests that the direction in an answer is correct according to direction sent
567// in the offer, the presence of a local media track on the receive side and the
568// offer_to_receive setting.
569TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800570 if (IsUnifiedPlan() &&
571 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
572 // offer_to_receive_ is not implemented when creating answers with Unified
573 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800574 return;
575 }
Steve Anton22da89f2018-01-25 13:58:07 -0800576
Steve Anton8d3444d2017-10-20 15:30:51 -0700577 auto caller = CreatePeerConnection();
578 caller->AddAudioTrack("a");
579
580 // Create the offer with an audio section and set its direction.
581 auto offer = caller->CreateOffer();
582 cricket::GetFirstAudioContentDescription(offer->description())
583 ->set_direction(offer_direction_);
584
585 auto callee = CreatePeerConnection();
586 if (send_media_) {
587 callee->AddAudioTrack("a");
588 }
589 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
590
591 // Create the answer according to the test parameters.
592 RTCOfferAnswerOptions options;
593 options.offer_to_receive_audio = offer_to_receive_;
594 auto answer = callee->CreateAnswer(options);
595
596 // The expected direction in the answer is the intersection of each side's
597 // capability to send/recv media.
598 // For the offerer, the direction is given in the offer (offer_direction_).
599 // For the answerer, the direction has two components:
600 // 1. Send if the answerer has a local track to send.
601 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
602 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800603 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
604 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700605
606 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800607 bool negotiate_send = (send_media_ && offer_recv);
608 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700609
610 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800611 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700612 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800613 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700614}
615
616// Tests that the media section is rejected if and only if the callee has no
617// local media track and has set offer_to_receive to 0, no matter which
618// direction the caller indicated in the offer.
619TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800620 if (IsUnifiedPlan() &&
621 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
622 // offer_to_receive_ is not implemented when creating answers with Unified
623 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800624 return;
625 }
Steve Anton22da89f2018-01-25 13:58:07 -0800626
Steve Anton8d3444d2017-10-20 15:30:51 -0700627 auto caller = CreatePeerConnection();
628 caller->AddAudioTrack("a");
629
630 // Create the offer with an audio section and set its direction.
631 auto offer = caller->CreateOffer();
632 cricket::GetFirstAudioContentDescription(offer->description())
633 ->set_direction(offer_direction_);
634
635 auto callee = CreatePeerConnection();
636 if (send_media_) {
637 callee->AddAudioTrack("a");
638 }
639 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
640
641 // Create the answer according to the test parameters.
642 RTCOfferAnswerOptions options;
643 options.offer_to_receive_audio = offer_to_receive_;
644 auto answer = callee->CreateAnswer(options);
645
646 // The media section is rejected if and only if offer_to_receive is explicitly
647 // set to 0 and there is no media to send.
648 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
649 ASSERT_TRUE(audio_content);
650 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
651}
652
653INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
654 PeerConnectionMediaAnswerDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800655 Combine(Values(SdpSemantics::kPlanB,
656 SdpSemantics::kUnifiedPlan),
657 Values(RtpTransceiverDirection::kInactive,
Steve Anton4e70a722017-11-28 14:57:10 -0800658 RtpTransceiverDirection::kSendOnly,
659 RtpTransceiverDirection::kRecvOnly,
660 RtpTransceiverDirection::kSendRecv),
Steve Anton8d3444d2017-10-20 15:30:51 -0700661 Bool(),
662 Values(-1, 0, 1)));
663
Steve Antonad7bffc2018-01-22 10:21:56 -0800664TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700665 auto caller = CreatePeerConnection();
666 caller->AddVideoTrack("v");
667
668 RTCOfferAnswerOptions options;
669 options.offer_to_receive_audio = 1;
670 options.offer_to_receive_video = 0;
671 auto offer = caller->CreateOffer(options);
672
Steve Anton4e70a722017-11-28 14:57:10 -0800673 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800674 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800675 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800676 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700677}
678
Steve Antonad7bffc2018-01-22 10:21:56 -0800679TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800680 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800681 // offer_to_receive_ is not implemented when creating answers with Unified
682 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800683 return;
684 }
685
Steve Anton8d3444d2017-10-20 15:30:51 -0700686 auto caller = CreatePeerConnectionWithAudioVideo();
687 auto callee = CreatePeerConnection();
688 callee->AddVideoTrack("v");
689
690 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
691
692 RTCOfferAnswerOptions options;
693 options.offer_to_receive_audio = 1;
694 options.offer_to_receive_video = 0;
695 auto answer = callee->CreateAnswer(options);
696
Steve Anton4e70a722017-11-28 14:57:10 -0800697 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800698 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800699 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800700 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700701}
702
703void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
704 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
705 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
706
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100707 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700708 codecs.push_back(kComfortNoiseCodec8k);
709 codecs.push_back(kComfortNoiseCodec16k);
710 media_engine->SetAudioCodecs(codecs);
711}
712
713bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
714 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
715 for (const auto& codec : audio_desc->codecs()) {
716 if (codec.name == "CN") {
717 return true;
718 }
719 }
720 return false;
721}
722
Steve Antonad7bffc2018-01-22 10:21:56 -0800723TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700724 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
725 auto caller = CreatePeerConnectionWithAudioVideo();
726 AddComfortNoiseCodecsToSend(caller->media_engine());
727
728 RTCOfferAnswerOptions options;
729 options.voice_activity_detection = false;
730 auto offer = caller->CreateOffer(options);
731
732 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
733}
734
Steve Antonad7bffc2018-01-22 10:21:56 -0800735TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700736 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
737 auto caller = CreatePeerConnectionWithAudioVideo();
738 AddComfortNoiseCodecsToSend(caller->media_engine());
739 auto callee = CreatePeerConnectionWithAudioVideo();
740 AddComfortNoiseCodecsToSend(callee->media_engine());
741
742 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
743
744 RTCOfferAnswerOptions options;
745 options.voice_activity_detection = false;
746 auto answer = callee->CreateAnswer(options);
747
748 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
749}
750
751// The following test group verifies that we reject answers with invalid media
752// sections as per RFC 3264.
753
754class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800755 : public PeerConnectionMediaBaseTest,
756 public ::testing::WithParamInterface<std::tuple<
757 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700758 std::tuple<std::string,
759 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800760 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700761 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800762 PeerConnectionMediaInvalidMediaTest()
763 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
764 auto param = std::get<1>(GetParam());
765 mutator_ = std::get<1>(param);
766 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700767 }
768
769 std::function<void(cricket::SessionDescription*)> mutator_;
770 std::string expected_error_;
771};
772
773TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
774 auto caller = CreatePeerConnectionWithAudioVideo();
775 auto callee = CreatePeerConnectionWithAudioVideo();
776
777 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
778
779 auto answer = callee->CreateAnswer();
780 mutator_(answer->description());
781
782 std::string error;
783 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
784 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
785}
786
787TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
788 auto caller = CreatePeerConnectionWithAudioVideo();
789 auto callee = CreatePeerConnectionWithAudioVideo();
790
791 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
792
793 auto answer = callee->CreateAnswer();
794 mutator_(answer->description());
795
796 std::string error;
797 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
798 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
799}
800
801void RemoveVideoContent(cricket::SessionDescription* desc) {
802 auto content_name = cricket::GetFirstVideoContent(desc)->name;
803 desc->RemoveContentByName(content_name);
804 desc->RemoveTransportInfoByName(content_name);
805}
806
807void RenameVideoContent(cricket::SessionDescription* desc) {
808 auto* video_content = cricket::GetFirstVideoContent(desc);
809 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
810 video_content->name = "video_renamed";
811 transport_info->content_name = video_content->name;
812}
813
814void ReverseMediaContent(cricket::SessionDescription* desc) {
815 std::reverse(desc->contents().begin(), desc->contents().end());
816 std::reverse(desc->transport_infos().begin(), desc->transport_infos().end());
817}
818
819void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800820 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
821 desc->RemoveContentByName(audio_mid);
822 auto* video_content = cricket::GetFirstVideoContent(desc);
823 desc->AddContent(audio_mid, video_content->type,
Steve Antonb1c1de12017-12-21 15:14:30 -0800824 video_content->media_description()->Copy());
Steve Anton8d3444d2017-10-20 15:30:51 -0700825}
826
827constexpr char kMLinesOutOfOrder[] =
828 "The order of m-lines in answer doesn't match order in offer. Rejecting "
829 "answer.";
830
831INSTANTIATE_TEST_CASE_P(
832 PeerConnectionMediaTest,
833 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800834 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
835 Values(std::make_tuple("remove video",
836 RemoveVideoContent,
837 kMLinesOutOfOrder),
838 std::make_tuple("rename video",
839 RenameVideoContent,
840 kMLinesOutOfOrder),
841 std::make_tuple("reverse media sections",
842 ReverseMediaContent,
843 kMLinesOutOfOrder),
844 std::make_tuple("change audio type to video type",
845 ChangeMediaTypeAudioToVideo,
846 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700847
848// Test that the correct media engine send/recv streams are created when doing
849// a series of offer/answers where audio/video are both sent, then audio is
850// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800851TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800852 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800853 // offer_to_receive_ is not implemented when creating answers with Unified
854 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800855 return;
856 }
857
Steve Anton8d3444d2017-10-20 15:30:51 -0700858 RTCOfferAnswerOptions options_reject_video;
859 options_reject_video.offer_to_receive_audio =
860 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
861 options_reject_video.offer_to_receive_video = 0;
862
863 auto caller = CreatePeerConnection();
864 caller->AddAudioTrack("a");
865 caller->AddVideoTrack("v");
866 auto callee = CreatePeerConnection();
867
868 // Caller initially offers to send/recv audio and video.
869 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
870 // Callee accepts the audio as recv only but rejects the video.
871 ASSERT_TRUE(caller->SetRemoteDescription(
872 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
873
874 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
875 ASSERT_TRUE(caller_voice);
876 EXPECT_EQ(0u, caller_voice->recv_streams().size());
877 EXPECT_EQ(1u, caller_voice->send_streams().size());
878 auto caller_video = caller->media_engine()->GetVideoChannel(0);
879 EXPECT_FALSE(caller_video);
880
881 // Callee adds its own audio/video stream and offers to receive audio/video
882 // too.
883 callee->AddAudioTrack("a");
884 auto callee_video_track = callee->AddVideoTrack("v");
885 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
886 ASSERT_TRUE(
887 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
888
889 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
890 ASSERT_TRUE(callee_voice);
891 EXPECT_EQ(1u, callee_voice->recv_streams().size());
892 EXPECT_EQ(1u, callee_voice->send_streams().size());
893 auto callee_video = callee->media_engine()->GetVideoChannel(0);
894 ASSERT_TRUE(callee_video);
895 EXPECT_EQ(1u, callee_video->recv_streams().size());
896 EXPECT_EQ(1u, callee_video->send_streams().size());
897
898 // Callee removes video but keeps audio and rejects the video once again.
899 callee->pc()->RemoveTrack(callee_video_track);
900 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
901 ASSERT_TRUE(
902 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
903
904 callee_voice = callee->media_engine()->GetVoiceChannel(0);
905 ASSERT_TRUE(callee_voice);
906 EXPECT_EQ(1u, callee_voice->recv_streams().size());
907 EXPECT_EQ(1u, callee_voice->send_streams().size());
908 callee_video = callee->media_engine()->GetVideoChannel(0);
909 EXPECT_FALSE(callee_video);
910}
911
912// Test that the correct media engine send/recv streams are created when doing
913// a series of offer/answers where audio/video are both sent, then video is
914// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800915TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800916 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800917 // offer_to_receive_ is not implemented when creating answers with Unified
918 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800919 return;
920 }
921
Steve Anton8d3444d2017-10-20 15:30:51 -0700922 // Disable the bundling here. If the media is bundled on audio
923 // transport, then we can't reject the audio because switching the bundled
924 // transport is not currently supported.
925 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
926 RTCOfferAnswerOptions options_no_bundle;
927 options_no_bundle.use_rtp_mux = false;
928 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
929 options_reject_audio.offer_to_receive_audio = 0;
930 options_reject_audio.offer_to_receive_video =
931 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
932
933 auto caller = CreatePeerConnection();
934 caller->AddAudioTrack("a");
935 caller->AddVideoTrack("v");
936 auto callee = CreatePeerConnection();
937
938 // Caller initially offers to send/recv audio and video.
939 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
940 // Callee accepts the video as recv only but rejects the audio.
941 ASSERT_TRUE(caller->SetRemoteDescription(
942 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
943
944 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
945 EXPECT_FALSE(caller_voice);
946 auto caller_video = caller->media_engine()->GetVideoChannel(0);
947 ASSERT_TRUE(caller_video);
948 EXPECT_EQ(0u, caller_video->recv_streams().size());
949 EXPECT_EQ(1u, caller_video->send_streams().size());
950
951 // Callee adds its own audio/video stream and offers to receive audio/video
952 // too.
953 auto callee_audio_track = callee->AddAudioTrack("a");
954 callee->AddVideoTrack("v");
955 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
956 ASSERT_TRUE(caller->SetRemoteDescription(
957 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
958
959 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
960 ASSERT_TRUE(callee_voice);
961 EXPECT_EQ(1u, callee_voice->recv_streams().size());
962 EXPECT_EQ(1u, callee_voice->send_streams().size());
963 auto callee_video = callee->media_engine()->GetVideoChannel(0);
964 ASSERT_TRUE(callee_video);
965 EXPECT_EQ(1u, callee_video->recv_streams().size());
966 EXPECT_EQ(1u, callee_video->send_streams().size());
967
968 // Callee removes audio but keeps video and rejects the audio once again.
969 callee->pc()->RemoveTrack(callee_audio_track);
970 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
971 ASSERT_TRUE(
972 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
973
974 callee_voice = callee->media_engine()->GetVoiceChannel(0);
975 EXPECT_FALSE(callee_voice);
976 callee_video = callee->media_engine()->GetVideoChannel(0);
977 ASSERT_TRUE(callee_video);
978 EXPECT_EQ(1u, callee_video->recv_streams().size());
979 EXPECT_EQ(1u, callee_video->send_streams().size());
980}
981
982// Tests that if the underlying video encoder fails to be initialized (signaled
983// by failing to set send codecs), the PeerConnection signals the error to the
984// client.
Steve Antonad7bffc2018-01-22 10:21:56 -0800985TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700986 auto caller = CreatePeerConnectionWithAudioVideo();
987 auto callee = CreatePeerConnectionWithAudioVideo();
988
989 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
990
991 auto video_channel = caller->media_engine()->GetVideoChannel(0);
992 video_channel->set_fail_set_send_codecs(true);
993
994 std::string error;
995 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
996 &error));
997 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -0800998 "Failed to set remote answer sdp: Failed to set remote video description "
999 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -07001000 error);
1001}
1002
1003// Tests that if the underlying video encoder fails once then subsequent
1004// attempts at setting the local/remote description will also fail, even if
1005// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001006TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001007 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1008 auto caller = CreatePeerConnectionWithAudioVideo();
1009 auto callee = CreatePeerConnectionWithAudioVideo();
1010
1011 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1012
1013 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1014 video_channel->set_fail_set_send_codecs(true);
1015
1016 EXPECT_FALSE(
1017 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1018
1019 video_channel->set_fail_set_send_codecs(false);
1020
1021 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1022 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1023}
1024
1025void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001026 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001027 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001028 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001029 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001030 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001031 content->name = new_name;
1032 auto* transport = desc->GetTransportInfoByName(old_name);
1033 RTC_DCHECK(transport);
1034 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001035
1036 // Rename the content name in the BUNDLE group.
1037 cricket::ContentGroup new_bundle_group =
1038 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1039 new_bundle_group.RemoveContentName(old_name);
1040 new_bundle_group.AddContentName(new_name);
1041 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1042 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001043}
1044
1045// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001046TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001047 const std::string kAudioMid = "notdefault1";
1048 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001049
1050 auto caller = CreatePeerConnectionWithAudioVideo();
1051 auto callee = CreatePeerConnectionWithAudioVideo();
1052
1053 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001054 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1055 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001056 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1057
1058 auto answer = callee->CreateAnswer();
1059 EXPECT_EQ(kAudioMid,
1060 cricket::GetFirstAudioContent(answer->description())->name);
1061 EXPECT_EQ(kVideoMid,
1062 cricket::GetFirstVideoContent(answer->description())->name);
1063}
1064
1065// Test that if the callee creates a re-offer, the MIDs are the same as the
1066// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001067TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001068 const std::string kAudioMid = "notdefault1";
1069 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001070
1071 auto caller = CreatePeerConnectionWithAudioVideo();
1072 auto callee = CreatePeerConnectionWithAudioVideo();
1073
1074 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001075 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1076 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001077 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1078 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1079
1080 auto reoffer = callee->CreateOffer();
1081 EXPECT_EQ(kAudioMid,
1082 cricket::GetFirstAudioContent(reoffer->description())->name);
1083 EXPECT_EQ(kVideoMid,
1084 cricket::GetFirstVideoContent(reoffer->description())->name);
1085}
1086
Steve Antonad7bffc2018-01-22 10:21:56 -08001087TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001088 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1089 RTCConfiguration config;
1090 config.combined_audio_video_bwe.emplace(true);
1091 auto caller = CreatePeerConnectionWithAudioVideo(config);
1092
1093 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1094
1095 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1096 ASSERT_TRUE(caller_voice);
1097 const cricket::AudioOptions& audio_options = caller_voice->options();
1098 EXPECT_EQ(config.combined_audio_video_bwe,
1099 audio_options.combined_audio_video_bwe);
1100}
1101
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001102TEST_P(PeerConnectionMediaTest, MediaTransportPropagatedToVoiceEngine) {
1103 RTCConfiguration config;
1104
1105 // Setup PeerConnection to use media transport.
1106 config.use_media_transport = true;
1107
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001108 // Force SDES.
1109 config.enable_dtls_srtp = false;
1110
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001111 auto caller = CreatePeerConnectionWithAudio(config);
1112 auto callee = CreatePeerConnectionWithAudio(config);
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001113
1114 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1115 auto answer = callee->CreateAnswer();
1116 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1117
1118 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1119 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1120 ASSERT_TRUE(caller_voice);
1121 ASSERT_TRUE(callee_voice);
1122
1123 // Make sure media transport is propagated to voice channel.
1124 FakeMediaTransport* caller_voice_media_transport =
1125 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1126 FakeMediaTransport* callee_voice_media_transport =
1127 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1128 ASSERT_NE(nullptr, caller_voice_media_transport);
1129 ASSERT_NE(nullptr, callee_voice_media_transport);
1130
1131 // Make sure media transport is created with correct is_caller.
1132 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1133 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1134
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001135 // TODO(sukhanov): Propagate media transport to video channel.
1136 // This test does NOT set up video channels, because currently it causes
1137 // us to create two media transports.
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001138}
1139
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001140TEST_P(PeerConnectionMediaTest, MediaTransportOnlyForDataChannels) {
1141 RTCConfiguration config;
1142
1143 // Setup PeerConnection to use media transport for data channels.
1144 config.use_media_transport_for_data_channels = true;
1145
1146 // Force SDES.
1147 config.enable_dtls_srtp = false;
1148
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001149 auto caller = CreatePeerConnectionWithAudio(config);
1150 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001151
1152 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1153 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1154
1155 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1156 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1157 ASSERT_TRUE(caller_voice);
1158 ASSERT_TRUE(callee_voice);
1159
1160 // Make sure media transport is not propagated to voice channel.
1161 EXPECT_EQ(nullptr, caller_voice->media_transport());
1162 EXPECT_EQ(nullptr, callee_voice->media_transport());
1163}
1164
1165TEST_P(PeerConnectionMediaTest, MediaTransportForMediaAndDataChannels) {
1166 RTCConfiguration config;
1167
1168 // Setup PeerConnection to use media transport for both media and data
1169 // channels.
1170 config.use_media_transport = true;
1171 config.use_media_transport_for_data_channels = true;
1172
1173 // Force SDES.
1174 config.enable_dtls_srtp = false;
1175
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001176 auto caller = CreatePeerConnectionWithAudio(config);
1177 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001178
1179 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1180 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1181
1182 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1183 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1184 ASSERT_TRUE(caller_voice);
1185 ASSERT_TRUE(callee_voice);
1186
1187 // Make sure media transport is propagated to voice channel.
1188 FakeMediaTransport* caller_voice_media_transport =
1189 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1190 FakeMediaTransport* callee_voice_media_transport =
1191 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1192 ASSERT_NE(nullptr, caller_voice_media_transport);
1193 ASSERT_NE(nullptr, callee_voice_media_transport);
1194
1195 // Make sure media transport is created with correct is_caller.
1196 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1197 EXPECT_FALSE(callee_voice_media_transport->is_caller());
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001198}
1199
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001200TEST_P(PeerConnectionMediaTest, MediaTransportNotPropagatedToVoiceEngine) {
1201 auto caller = CreatePeerConnectionWithAudioVideo();
1202 auto callee = CreatePeerConnectionWithAudioVideo();
1203
1204 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1205 auto answer = callee->CreateAnswer();
1206 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1207
1208 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1209 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1210 ASSERT_TRUE(caller_voice);
1211 ASSERT_TRUE(callee_voice);
1212
1213 // Since we did not setup PeerConnection to use media transport, media
1214 // transport should not be created / propagated to the voice engine.
1215 ASSERT_EQ(nullptr, caller_voice->media_transport());
1216 ASSERT_EQ(nullptr, callee_voice->media_transport());
1217
1218 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1219 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1220 ASSERT_EQ(nullptr, caller_video->media_transport());
1221 ASSERT_EQ(nullptr, callee_video->media_transport());
1222}
1223
Steve Antonad7bffc2018-01-22 10:21:56 -08001224INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
1225 PeerConnectionMediaTest,
1226 Values(SdpSemantics::kPlanB,
1227 SdpSemantics::kUnifiedPlan));
1228
Steve Anton8d3444d2017-10-20 15:30:51 -07001229} // namespace webrtc