blob: 3c069aea7a391446e7469866bc819c31bd9c9a04 [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
116 // and video tracks.
117 template <typename... Args>
118 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
119 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
120 if (!wrapper) {
121 return nullptr;
122 }
123 wrapper->AddAudioTrack("a");
124 wrapper->AddVideoTrack("v");
125 return wrapper;
126 }
127
Steve Anton4e70a722017-11-28 14:57:10 -0800128 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700129 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800130 cricket::MediaType media_type) {
131 auto* content =
132 cricket::GetFirstMediaContent(sdesc->description(), media_type);
133 RTC_DCHECK(content);
134 return content->media_description()->direction();
135 }
136
137 bool IsUnifiedPlan() const {
138 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700139 }
140
141 std::unique_ptr<rtc::VirtualSocketServer> vss_;
142 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800143 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700144};
145
Steve Antonad7bffc2018-01-22 10:21:56 -0800146class PeerConnectionMediaTest
147 : public PeerConnectionMediaBaseTest,
148 public ::testing::WithParamInterface<SdpSemantics> {
149 protected:
150 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
151};
152
153class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
154 protected:
155 PeerConnectionMediaTestUnifiedPlan()
156 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
157};
158
159class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
160 protected:
161 PeerConnectionMediaTestPlanB()
162 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
163};
164
165TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700166 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
167 auto caller = CreatePeerConnectionWithAudioVideo();
168 auto callee = CreatePeerConnectionWithAudioVideo();
169 callee->media_engine()->set_fail_create_channel(true);
170
171 std::string error;
172 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800173 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
174 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700175}
176
Steve Antonad7bffc2018-01-22 10:21:56 -0800177TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700178 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
179 auto caller = CreatePeerConnectionWithAudioVideo();
180 caller->media_engine()->set_fail_create_channel(true);
181
182 std::string error;
183 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800184 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
185 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700186}
187
188std::vector<std::string> GetIds(
189 const std::vector<cricket::StreamParams>& streams) {
190 std::vector<std::string> ids;
191 for (const auto& stream : streams) {
192 ids.push_back(stream.id);
193 }
194 return ids;
195}
196
197// Test that exchanging an offer and answer with each side having an audio and
198// video stream creates the appropriate send/recv streams in the underlying
199// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800200TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700201 const std::string kCallerAudioId = "caller_a";
202 const std::string kCallerVideoId = "caller_v";
203 const std::string kCalleeAudioId = "callee_a";
204 const std::string kCalleeVideoId = "callee_v";
205
206 auto caller = CreatePeerConnection();
207 caller->AddAudioTrack(kCallerAudioId);
208 caller->AddVideoTrack(kCallerVideoId);
209
210 auto callee = CreatePeerConnection();
211 callee->AddAudioTrack(kCalleeAudioId);
212 callee->AddVideoTrack(kCalleeVideoId);
213
214 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
215 ASSERT_TRUE(
216 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
217
218 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
219 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
220 ElementsAre(kCalleeAudioId));
221 EXPECT_THAT(GetIds(caller_voice->send_streams()),
222 ElementsAre(kCallerAudioId));
223
224 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
225 EXPECT_THAT(GetIds(caller_video->recv_streams()),
226 ElementsAre(kCalleeVideoId));
227 EXPECT_THAT(GetIds(caller_video->send_streams()),
228 ElementsAre(kCallerVideoId));
229
230 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
231 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
232 ElementsAre(kCallerAudioId));
233 EXPECT_THAT(GetIds(callee_voice->send_streams()),
234 ElementsAre(kCalleeAudioId));
235
236 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
237 EXPECT_THAT(GetIds(callee_video->recv_streams()),
238 ElementsAre(kCallerVideoId));
239 EXPECT_THAT(GetIds(callee_video->send_streams()),
240 ElementsAre(kCalleeVideoId));
241}
242
Steve Antonad7bffc2018-01-22 10:21:56 -0800243// Test that stopping the caller transceivers causes the media channels on the
244// callee to be destroyed after calling SetRemoteDescription on the generated
245// offer.
246// See next test for equivalent behavior with Plan B semantics.
247TEST_F(PeerConnectionMediaTestUnifiedPlan,
248 StoppedRemoteTransceiversRemovesMediaChannels) {
249 auto caller = CreatePeerConnectionWithAudioVideo();
250 auto callee = CreatePeerConnection();
251
252 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
253
254 // Stop both audio and video transceivers on the caller.
255 auto transceivers = caller->pc()->GetTransceivers();
256 ASSERT_EQ(2u, transceivers.size());
257 transceivers[0]->Stop();
258 transceivers[1]->Stop();
259
260 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
261
262 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
263 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
264}
265
Steve Anton8d3444d2017-10-20 15:30:51 -0700266// Test that removing streams from a subsequent offer causes the receive streams
267// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800268// See previous test for equivalent behavior with Unified Plan semantics.
269TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700270 auto caller = CreatePeerConnection();
271 auto caller_audio_track = caller->AddAudioTrack("a");
272 auto caller_video_track = caller->AddVideoTrack("v");
273 auto callee = CreatePeerConnectionWithAudioVideo();
274
Steve Antonad7bffc2018-01-22 10:21:56 -0800275 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700276
277 // Remove both tracks from caller.
278 caller->pc()->RemoveTrack(caller_audio_track);
279 caller->pc()->RemoveTrack(caller_video_track);
280
Steve Antonad7bffc2018-01-22 10:21:56 -0800281 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700282
283 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800284 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700285 EXPECT_EQ(1u, callee_voice->send_streams().size());
286 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700287 EXPECT_EQ(1u, callee_video->send_streams().size());
288 EXPECT_EQ(0u, callee_video->recv_streams().size());
289}
290
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200291// Test enabling of simulcast with Plan B semantics.
292// This test creating an offer.
293TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
294 auto caller = CreatePeerConnection();
295 auto caller_video_track = caller->AddVideoTrack("v");
296 RTCOfferAnswerOptions options;
297 options.num_simulcast_layers = 3;
298 auto offer = caller->CreateOffer(options);
299 auto* description = cricket::GetFirstMediaContent(
300 offer->description(),
301 cricket::MEDIA_TYPE_VIDEO)->media_description();
302 ASSERT_EQ(1u, description->streams().size());
303 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
304 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
305
306 // Check that it actually creates simulcast aswell.
307 caller->SetLocalDescription(std::move(offer));
308 auto senders = caller->pc()->GetSenders();
309 ASSERT_EQ(1u, senders.size());
310 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
311 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
312}
313
314// Test enabling of simulcast with Plan B semantics.
315// This test creating an answer.
316TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
317 auto caller = CreatePeerConnection();
318 caller->AddVideoTrack("v0");
319 auto offer = caller->CreateOffer();
320 auto callee = CreatePeerConnection();
321 auto callee_video_track = callee->AddVideoTrack("v1");
322 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
323 RTCOfferAnswerOptions options;
324 options.num_simulcast_layers = 3;
325 auto answer = callee->CreateAnswer(options);
326 auto* description = cricket::GetFirstMediaContent(
327 answer->description(),
328 cricket::MEDIA_TYPE_VIDEO)->media_description();
329 ASSERT_EQ(1u, description->streams().size());
330 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
331 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
332
333 // Check that it actually creates simulcast aswell.
334 callee->SetLocalDescription(std::move(answer));
335 auto senders = callee->pc()->GetSenders();
336 ASSERT_EQ(1u, senders.size());
337 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
338 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
339}
340
Steve Antonad7bffc2018-01-22 10:21:56 -0800341// Test that stopping the callee transceivers causes the media channels to be
342// destroyed on the callee after calling SetLocalDescription on the local
343// answer.
344// See next test for equivalent behavior with Plan B semantics.
345TEST_F(PeerConnectionMediaTestUnifiedPlan,
346 StoppedLocalTransceiversRemovesMediaChannels) {
347 auto caller = CreatePeerConnectionWithAudioVideo();
348 auto callee = CreatePeerConnectionWithAudioVideo();
349
350 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
351
352 // Stop both audio and video transceivers on the callee.
353 auto transceivers = callee->pc()->GetTransceivers();
354 ASSERT_EQ(2u, transceivers.size());
355 transceivers[0]->Stop();
356 transceivers[1]->Stop();
357
358 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
359
360 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
361 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
362}
363
Steve Anton8d3444d2017-10-20 15:30:51 -0700364// Test that removing streams from a subsequent answer causes the send streams
365// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800366// See previous test for equivalent behavior with Unified Plan semantics.
367TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700368 auto caller = CreatePeerConnectionWithAudioVideo();
369 auto callee = CreatePeerConnection();
370 auto callee_audio_track = callee->AddAudioTrack("a");
371 auto callee_video_track = callee->AddVideoTrack("v");
372
Steve Antonad7bffc2018-01-22 10:21:56 -0800373 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700374
375 // Remove both tracks from callee.
376 callee->pc()->RemoveTrack(callee_audio_track);
377 callee->pc()->RemoveTrack(callee_video_track);
378
Steve Antonad7bffc2018-01-22 10:21:56 -0800379 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700380
381 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800382 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700383 EXPECT_EQ(0u, callee_voice->send_streams().size());
384 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700385 EXPECT_EQ(0u, callee_video->send_streams().size());
386 EXPECT_EQ(1u, callee_video->recv_streams().size());
387}
388
389// Test that a new stream in a subsequent offer causes a new receive stream to
390// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800391TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700392 auto caller = CreatePeerConnectionWithAudioVideo();
393 auto callee = CreatePeerConnection();
394
Steve Antonad7bffc2018-01-22 10:21:56 -0800395 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700396
397 // Add second set of tracks to the caller.
398 caller->AddAudioTrack("a2");
399 caller->AddVideoTrack("v2");
400
Steve Antonad7bffc2018-01-22 10:21:56 -0800401 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700402
Steve Antonad7bffc2018-01-22 10:21:56 -0800403 auto a1 = callee->media_engine()->GetVoiceChannel(0);
404 auto a2 = callee->media_engine()->GetVoiceChannel(1);
405 auto v1 = callee->media_engine()->GetVideoChannel(0);
406 auto v2 = callee->media_engine()->GetVideoChannel(1);
407 if (IsUnifiedPlan()) {
408 ASSERT_TRUE(a1);
409 EXPECT_EQ(1u, a1->recv_streams().size());
410 ASSERT_TRUE(a2);
411 EXPECT_EQ(1u, a2->recv_streams().size());
412 ASSERT_TRUE(v1);
413 EXPECT_EQ(1u, v1->recv_streams().size());
414 ASSERT_TRUE(v2);
415 EXPECT_EQ(1u, v2->recv_streams().size());
416 } else {
417 ASSERT_TRUE(a1);
418 EXPECT_EQ(2u, a1->recv_streams().size());
419 ASSERT_FALSE(a2);
420 ASSERT_TRUE(v1);
421 EXPECT_EQ(2u, v1->recv_streams().size());
422 ASSERT_FALSE(v2);
423 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700424}
425
426// Test that a new stream in a subsequent answer causes a new send stream to be
427// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800428TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700429 auto caller = CreatePeerConnection();
430 auto callee = CreatePeerConnectionWithAudioVideo();
431
Steve Anton22da89f2018-01-25 13:58:07 -0800432 RTCOfferAnswerOptions offer_options;
433 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700434 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800435 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700436 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800437 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700438
Steve Anton22da89f2018-01-25 13:58:07 -0800439 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
440 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700441
442 // Add second set of tracks to the callee.
443 callee->AddAudioTrack("a2");
444 callee->AddVideoTrack("v2");
445
Steve Anton22da89f2018-01-25 13:58:07 -0800446 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
447 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700448
449 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800450 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700451 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800452 ASSERT_TRUE(callee_video);
453
454 if (IsUnifiedPlan()) {
455 EXPECT_EQ(1u, callee_voice->send_streams().size());
456 EXPECT_EQ(1u, callee_video->send_streams().size());
457 } else {
458 EXPECT_EQ(2u, callee_voice->send_streams().size());
459 EXPECT_EQ(2u, callee_video->send_streams().size());
460 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700461}
462
463// A PeerConnection with no local streams and no explicit answer constraints
464// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800465TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700466 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
467 auto caller = CreatePeerConnectionWithAudioVideo();
468 auto callee = CreatePeerConnection();
469 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
470 auto answer = callee->CreateAnswer();
471
472 const auto* audio_content =
473 cricket::GetFirstAudioContent(answer->description());
474 ASSERT_TRUE(audio_content);
475 EXPECT_FALSE(audio_content->rejected);
476
477 const auto* video_content =
478 cricket::GetFirstVideoContent(answer->description());
479 ASSERT_TRUE(video_content);
480 EXPECT_FALSE(video_content->rejected);
481}
482
483class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800484 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700485 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800486 std::tuple<SdpSemantics,
487 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700488 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800489 PeerConnectionMediaOfferDirectionTest()
490 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
491 auto param = std::get<1>(GetParam());
492 send_media_ = std::get<0>(param);
493 offer_to_receive_ = std::get<1>(param);
494 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700495 }
496
497 bool send_media_;
498 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800499 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700500};
501
502// Tests that the correct direction is set on the media description according
503// to the presence of a local media track and the offer_to_receive setting.
504TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
505 auto caller = CreatePeerConnection();
506 if (send_media_) {
507 caller->AddAudioTrack("a");
508 }
509
510 RTCOfferAnswerOptions options;
511 options.offer_to_receive_audio = offer_to_receive_;
512 auto offer = caller->CreateOffer(options);
513
Steve Antonad7bffc2018-01-22 10:21:56 -0800514 auto* content = cricket::GetFirstMediaContent(offer->description(),
515 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800516 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800517 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700518 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800519 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700520 }
521}
522
523// Note that in these tests, MD_INACTIVE indicates that no media section is
524// included in the offer, not that the media direction is inactive.
Steve Anton4e70a722017-11-28 14:57:10 -0800525INSTANTIATE_TEST_CASE_P(
526 PeerConnectionMediaTest,
527 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800528 Combine(
529 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
530 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
531 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
532 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
533 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
534 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
535 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700536
537class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800538 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700539 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800540 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700541 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800542 PeerConnectionMediaAnswerDirectionTest()
543 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
544 offer_direction_ = std::get<1>(GetParam());
545 send_media_ = std::get<2>(GetParam());
546 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700547 }
548
Steve Anton4e70a722017-11-28 14:57:10 -0800549 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700550 bool send_media_;
551 int offer_to_receive_;
552};
553
554// Tests that the direction in an answer is correct according to direction sent
555// in the offer, the presence of a local media track on the receive side and the
556// offer_to_receive setting.
557TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800558 if (IsUnifiedPlan() &&
559 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
560 // offer_to_receive_ is not implemented when creating answers with Unified
561 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800562 return;
563 }
Steve Anton22da89f2018-01-25 13:58:07 -0800564
Steve Anton8d3444d2017-10-20 15:30:51 -0700565 auto caller = CreatePeerConnection();
566 caller->AddAudioTrack("a");
567
568 // Create the offer with an audio section and set its direction.
569 auto offer = caller->CreateOffer();
570 cricket::GetFirstAudioContentDescription(offer->description())
571 ->set_direction(offer_direction_);
572
573 auto callee = CreatePeerConnection();
574 if (send_media_) {
575 callee->AddAudioTrack("a");
576 }
577 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
578
579 // Create the answer according to the test parameters.
580 RTCOfferAnswerOptions options;
581 options.offer_to_receive_audio = offer_to_receive_;
582 auto answer = callee->CreateAnswer(options);
583
584 // The expected direction in the answer is the intersection of each side's
585 // capability to send/recv media.
586 // For the offerer, the direction is given in the offer (offer_direction_).
587 // For the answerer, the direction has two components:
588 // 1. Send if the answerer has a local track to send.
589 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
590 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800591 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
592 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700593
594 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800595 bool negotiate_send = (send_media_ && offer_recv);
596 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700597
598 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800599 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700600 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800601 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700602}
603
604// Tests that the media section is rejected if and only if the callee has no
605// local media track and has set offer_to_receive to 0, no matter which
606// direction the caller indicated in the offer.
607TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800608 if (IsUnifiedPlan() &&
609 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
610 // offer_to_receive_ is not implemented when creating answers with Unified
611 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800612 return;
613 }
Steve Anton22da89f2018-01-25 13:58:07 -0800614
Steve Anton8d3444d2017-10-20 15:30:51 -0700615 auto caller = CreatePeerConnection();
616 caller->AddAudioTrack("a");
617
618 // Create the offer with an audio section and set its direction.
619 auto offer = caller->CreateOffer();
620 cricket::GetFirstAudioContentDescription(offer->description())
621 ->set_direction(offer_direction_);
622
623 auto callee = CreatePeerConnection();
624 if (send_media_) {
625 callee->AddAudioTrack("a");
626 }
627 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
628
629 // Create the answer according to the test parameters.
630 RTCOfferAnswerOptions options;
631 options.offer_to_receive_audio = offer_to_receive_;
632 auto answer = callee->CreateAnswer(options);
633
634 // The media section is rejected if and only if offer_to_receive is explicitly
635 // set to 0 and there is no media to send.
636 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
637 ASSERT_TRUE(audio_content);
638 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
639}
640
641INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
642 PeerConnectionMediaAnswerDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800643 Combine(Values(SdpSemantics::kPlanB,
644 SdpSemantics::kUnifiedPlan),
645 Values(RtpTransceiverDirection::kInactive,
Steve Anton4e70a722017-11-28 14:57:10 -0800646 RtpTransceiverDirection::kSendOnly,
647 RtpTransceiverDirection::kRecvOnly,
648 RtpTransceiverDirection::kSendRecv),
Steve Anton8d3444d2017-10-20 15:30:51 -0700649 Bool(),
650 Values(-1, 0, 1)));
651
Steve Antonad7bffc2018-01-22 10:21:56 -0800652TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700653 auto caller = CreatePeerConnection();
654 caller->AddVideoTrack("v");
655
656 RTCOfferAnswerOptions options;
657 options.offer_to_receive_audio = 1;
658 options.offer_to_receive_video = 0;
659 auto offer = caller->CreateOffer(options);
660
Steve Anton4e70a722017-11-28 14:57:10 -0800661 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800662 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800663 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800664 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700665}
666
Steve Antonad7bffc2018-01-22 10:21:56 -0800667TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800668 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800669 // offer_to_receive_ is not implemented when creating answers with Unified
670 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800671 return;
672 }
673
Steve Anton8d3444d2017-10-20 15:30:51 -0700674 auto caller = CreatePeerConnectionWithAudioVideo();
675 auto callee = CreatePeerConnection();
676 callee->AddVideoTrack("v");
677
678 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
679
680 RTCOfferAnswerOptions options;
681 options.offer_to_receive_audio = 1;
682 options.offer_to_receive_video = 0;
683 auto answer = callee->CreateAnswer(options);
684
Steve Anton4e70a722017-11-28 14:57:10 -0800685 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800686 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800687 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800688 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700689}
690
691void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
692 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
693 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
694
695 auto codecs = media_engine->audio_send_codecs();
696 codecs.push_back(kComfortNoiseCodec8k);
697 codecs.push_back(kComfortNoiseCodec16k);
698 media_engine->SetAudioCodecs(codecs);
699}
700
701bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
702 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
703 for (const auto& codec : audio_desc->codecs()) {
704 if (codec.name == "CN") {
705 return true;
706 }
707 }
708 return false;
709}
710
Steve Antonad7bffc2018-01-22 10:21:56 -0800711TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700712 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
713 auto caller = CreatePeerConnectionWithAudioVideo();
714 AddComfortNoiseCodecsToSend(caller->media_engine());
715
716 RTCOfferAnswerOptions options;
717 options.voice_activity_detection = false;
718 auto offer = caller->CreateOffer(options);
719
720 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
721}
722
Steve Antonad7bffc2018-01-22 10:21:56 -0800723TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700724 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
725 auto caller = CreatePeerConnectionWithAudioVideo();
726 AddComfortNoiseCodecsToSend(caller->media_engine());
727 auto callee = CreatePeerConnectionWithAudioVideo();
728 AddComfortNoiseCodecsToSend(callee->media_engine());
729
730 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
731
732 RTCOfferAnswerOptions options;
733 options.voice_activity_detection = false;
734 auto answer = callee->CreateAnswer(options);
735
736 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
737}
738
739// The following test group verifies that we reject answers with invalid media
740// sections as per RFC 3264.
741
742class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800743 : public PeerConnectionMediaBaseTest,
744 public ::testing::WithParamInterface<std::tuple<
745 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700746 std::tuple<std::string,
747 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800748 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700749 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800750 PeerConnectionMediaInvalidMediaTest()
751 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
752 auto param = std::get<1>(GetParam());
753 mutator_ = std::get<1>(param);
754 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700755 }
756
757 std::function<void(cricket::SessionDescription*)> mutator_;
758 std::string expected_error_;
759};
760
761TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
762 auto caller = CreatePeerConnectionWithAudioVideo();
763 auto callee = CreatePeerConnectionWithAudioVideo();
764
765 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
766
767 auto answer = callee->CreateAnswer();
768 mutator_(answer->description());
769
770 std::string error;
771 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
772 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
773}
774
775TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
776 auto caller = CreatePeerConnectionWithAudioVideo();
777 auto callee = CreatePeerConnectionWithAudioVideo();
778
779 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
780
781 auto answer = callee->CreateAnswer();
782 mutator_(answer->description());
783
784 std::string error;
785 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
786 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
787}
788
789void RemoveVideoContent(cricket::SessionDescription* desc) {
790 auto content_name = cricket::GetFirstVideoContent(desc)->name;
791 desc->RemoveContentByName(content_name);
792 desc->RemoveTransportInfoByName(content_name);
793}
794
795void RenameVideoContent(cricket::SessionDescription* desc) {
796 auto* video_content = cricket::GetFirstVideoContent(desc);
797 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
798 video_content->name = "video_renamed";
799 transport_info->content_name = video_content->name;
800}
801
802void ReverseMediaContent(cricket::SessionDescription* desc) {
803 std::reverse(desc->contents().begin(), desc->contents().end());
804 std::reverse(desc->transport_infos().begin(), desc->transport_infos().end());
805}
806
807void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800808 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
809 desc->RemoveContentByName(audio_mid);
810 auto* video_content = cricket::GetFirstVideoContent(desc);
811 desc->AddContent(audio_mid, video_content->type,
Steve Antonb1c1de12017-12-21 15:14:30 -0800812 video_content->media_description()->Copy());
Steve Anton8d3444d2017-10-20 15:30:51 -0700813}
814
815constexpr char kMLinesOutOfOrder[] =
816 "The order of m-lines in answer doesn't match order in offer. Rejecting "
817 "answer.";
818
819INSTANTIATE_TEST_CASE_P(
820 PeerConnectionMediaTest,
821 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800822 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
823 Values(std::make_tuple("remove video",
824 RemoveVideoContent,
825 kMLinesOutOfOrder),
826 std::make_tuple("rename video",
827 RenameVideoContent,
828 kMLinesOutOfOrder),
829 std::make_tuple("reverse media sections",
830 ReverseMediaContent,
831 kMLinesOutOfOrder),
832 std::make_tuple("change audio type to video type",
833 ChangeMediaTypeAudioToVideo,
834 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700835
836// Test that the correct media engine send/recv streams are created when doing
837// a series of offer/answers where audio/video are both sent, then audio is
838// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800839TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800840 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800841 // offer_to_receive_ is not implemented when creating answers with Unified
842 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800843 return;
844 }
845
Steve Anton8d3444d2017-10-20 15:30:51 -0700846 RTCOfferAnswerOptions options_reject_video;
847 options_reject_video.offer_to_receive_audio =
848 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
849 options_reject_video.offer_to_receive_video = 0;
850
851 auto caller = CreatePeerConnection();
852 caller->AddAudioTrack("a");
853 caller->AddVideoTrack("v");
854 auto callee = CreatePeerConnection();
855
856 // Caller initially offers to send/recv audio and video.
857 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
858 // Callee accepts the audio as recv only but rejects the video.
859 ASSERT_TRUE(caller->SetRemoteDescription(
860 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
861
862 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
863 ASSERT_TRUE(caller_voice);
864 EXPECT_EQ(0u, caller_voice->recv_streams().size());
865 EXPECT_EQ(1u, caller_voice->send_streams().size());
866 auto caller_video = caller->media_engine()->GetVideoChannel(0);
867 EXPECT_FALSE(caller_video);
868
869 // Callee adds its own audio/video stream and offers to receive audio/video
870 // too.
871 callee->AddAudioTrack("a");
872 auto callee_video_track = callee->AddVideoTrack("v");
873 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
874 ASSERT_TRUE(
875 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
876
877 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
878 ASSERT_TRUE(callee_voice);
879 EXPECT_EQ(1u, callee_voice->recv_streams().size());
880 EXPECT_EQ(1u, callee_voice->send_streams().size());
881 auto callee_video = callee->media_engine()->GetVideoChannel(0);
882 ASSERT_TRUE(callee_video);
883 EXPECT_EQ(1u, callee_video->recv_streams().size());
884 EXPECT_EQ(1u, callee_video->send_streams().size());
885
886 // Callee removes video but keeps audio and rejects the video once again.
887 callee->pc()->RemoveTrack(callee_video_track);
888 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
889 ASSERT_TRUE(
890 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
891
892 callee_voice = callee->media_engine()->GetVoiceChannel(0);
893 ASSERT_TRUE(callee_voice);
894 EXPECT_EQ(1u, callee_voice->recv_streams().size());
895 EXPECT_EQ(1u, callee_voice->send_streams().size());
896 callee_video = callee->media_engine()->GetVideoChannel(0);
897 EXPECT_FALSE(callee_video);
898}
899
900// Test that the correct media engine send/recv streams are created when doing
901// a series of offer/answers where audio/video are both sent, then video is
902// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800903TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800904 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800905 // offer_to_receive_ is not implemented when creating answers with Unified
906 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800907 return;
908 }
909
Steve Anton8d3444d2017-10-20 15:30:51 -0700910 // Disable the bundling here. If the media is bundled on audio
911 // transport, then we can't reject the audio because switching the bundled
912 // transport is not currently supported.
913 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
914 RTCOfferAnswerOptions options_no_bundle;
915 options_no_bundle.use_rtp_mux = false;
916 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
917 options_reject_audio.offer_to_receive_audio = 0;
918 options_reject_audio.offer_to_receive_video =
919 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
920
921 auto caller = CreatePeerConnection();
922 caller->AddAudioTrack("a");
923 caller->AddVideoTrack("v");
924 auto callee = CreatePeerConnection();
925
926 // Caller initially offers to send/recv audio and video.
927 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
928 // Callee accepts the video as recv only but rejects the audio.
929 ASSERT_TRUE(caller->SetRemoteDescription(
930 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
931
932 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
933 EXPECT_FALSE(caller_voice);
934 auto caller_video = caller->media_engine()->GetVideoChannel(0);
935 ASSERT_TRUE(caller_video);
936 EXPECT_EQ(0u, caller_video->recv_streams().size());
937 EXPECT_EQ(1u, caller_video->send_streams().size());
938
939 // Callee adds its own audio/video stream and offers to receive audio/video
940 // too.
941 auto callee_audio_track = callee->AddAudioTrack("a");
942 callee->AddVideoTrack("v");
943 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
944 ASSERT_TRUE(caller->SetRemoteDescription(
945 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
946
947 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
948 ASSERT_TRUE(callee_voice);
949 EXPECT_EQ(1u, callee_voice->recv_streams().size());
950 EXPECT_EQ(1u, callee_voice->send_streams().size());
951 auto callee_video = callee->media_engine()->GetVideoChannel(0);
952 ASSERT_TRUE(callee_video);
953 EXPECT_EQ(1u, callee_video->recv_streams().size());
954 EXPECT_EQ(1u, callee_video->send_streams().size());
955
956 // Callee removes audio but keeps video and rejects the audio once again.
957 callee->pc()->RemoveTrack(callee_audio_track);
958 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
959 ASSERT_TRUE(
960 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
961
962 callee_voice = callee->media_engine()->GetVoiceChannel(0);
963 EXPECT_FALSE(callee_voice);
964 callee_video = callee->media_engine()->GetVideoChannel(0);
965 ASSERT_TRUE(callee_video);
966 EXPECT_EQ(1u, callee_video->recv_streams().size());
967 EXPECT_EQ(1u, callee_video->send_streams().size());
968}
969
970// Tests that if the underlying video encoder fails to be initialized (signaled
971// by failing to set send codecs), the PeerConnection signals the error to the
972// client.
Steve Antonad7bffc2018-01-22 10:21:56 -0800973TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700974 auto caller = CreatePeerConnectionWithAudioVideo();
975 auto callee = CreatePeerConnectionWithAudioVideo();
976
977 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
978
979 auto video_channel = caller->media_engine()->GetVideoChannel(0);
980 video_channel->set_fail_set_send_codecs(true);
981
982 std::string error;
983 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
984 &error));
985 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -0800986 "Failed to set remote answer sdp: Failed to set remote video description "
987 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -0700988 error);
989}
990
991// Tests that if the underlying video encoder fails once then subsequent
992// attempts at setting the local/remote description will also fail, even if
993// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -0800994TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700995 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
996 auto caller = CreatePeerConnectionWithAudioVideo();
997 auto callee = CreatePeerConnectionWithAudioVideo();
998
999 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1000
1001 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1002 video_channel->set_fail_set_send_codecs(true);
1003
1004 EXPECT_FALSE(
1005 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1006
1007 video_channel->set_fail_set_send_codecs(false);
1008
1009 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1010 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1011}
1012
1013void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001014 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001015 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001016 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001017 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001018 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001019 content->name = new_name;
1020 auto* transport = desc->GetTransportInfoByName(old_name);
1021 RTC_DCHECK(transport);
1022 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001023
1024 // Rename the content name in the BUNDLE group.
1025 cricket::ContentGroup new_bundle_group =
1026 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1027 new_bundle_group.RemoveContentName(old_name);
1028 new_bundle_group.AddContentName(new_name);
1029 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1030 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001031}
1032
1033// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001034TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001035 const std::string kAudioMid = "notdefault1";
1036 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001037
1038 auto caller = CreatePeerConnectionWithAudioVideo();
1039 auto callee = CreatePeerConnectionWithAudioVideo();
1040
1041 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001042 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1043 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001044 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1045
1046 auto answer = callee->CreateAnswer();
1047 EXPECT_EQ(kAudioMid,
1048 cricket::GetFirstAudioContent(answer->description())->name);
1049 EXPECT_EQ(kVideoMid,
1050 cricket::GetFirstVideoContent(answer->description())->name);
1051}
1052
1053// Test that if the callee creates a re-offer, the MIDs are the same as the
1054// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001055TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001056 const std::string kAudioMid = "notdefault1";
1057 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001058
1059 auto caller = CreatePeerConnectionWithAudioVideo();
1060 auto callee = CreatePeerConnectionWithAudioVideo();
1061
1062 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001063 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1064 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001065 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1066 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1067
1068 auto reoffer = callee->CreateOffer();
1069 EXPECT_EQ(kAudioMid,
1070 cricket::GetFirstAudioContent(reoffer->description())->name);
1071 EXPECT_EQ(kVideoMid,
1072 cricket::GetFirstVideoContent(reoffer->description())->name);
1073}
1074
Steve Antonad7bffc2018-01-22 10:21:56 -08001075TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001076 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1077 RTCConfiguration config;
1078 config.combined_audio_video_bwe.emplace(true);
1079 auto caller = CreatePeerConnectionWithAudioVideo(config);
1080
1081 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1082
1083 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1084 ASSERT_TRUE(caller_voice);
1085 const cricket::AudioOptions& audio_options = caller_voice->options();
1086 EXPECT_EQ(config.combined_audio_video_bwe,
1087 audio_options.combined_audio_video_bwe);
1088}
1089
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001090TEST_P(PeerConnectionMediaTest, MediaTransportPropagatedToVoiceEngine) {
1091 RTCConfiguration config;
1092
1093 // Setup PeerConnection to use media transport.
1094 config.use_media_transport = true;
1095
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001096 // Force SDES.
1097 config.enable_dtls_srtp = false;
1098
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001099 auto caller = CreatePeerConnectionWithAudioVideo(config);
1100 auto callee = CreatePeerConnectionWithAudioVideo(config);
1101
1102 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1103 auto answer = callee->CreateAnswer();
1104 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1105
1106 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1107 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1108 ASSERT_TRUE(caller_voice);
1109 ASSERT_TRUE(callee_voice);
1110
1111 // Make sure media transport is propagated to voice channel.
1112 FakeMediaTransport* caller_voice_media_transport =
1113 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1114 FakeMediaTransport* callee_voice_media_transport =
1115 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1116 ASSERT_NE(nullptr, caller_voice_media_transport);
1117 ASSERT_NE(nullptr, callee_voice_media_transport);
1118
1119 // Make sure media transport is created with correct is_caller.
1120 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1121 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1122
1123 // TODO(sukhanov): Propagate media transport to video channel. This test
1124 // will fail once media transport is propagated to video channel and it will
1125 // serve as a reminder to add a test for video channel propagation.
1126 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1127 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1128 ASSERT_EQ(nullptr, caller_video->media_transport());
1129 ASSERT_EQ(nullptr, callee_video->media_transport());
1130}
1131
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001132TEST_P(PeerConnectionMediaTest, MediaTransportOnlyForDataChannels) {
1133 RTCConfiguration config;
1134
1135 // Setup PeerConnection to use media transport for data channels.
1136 config.use_media_transport_for_data_channels = true;
1137
1138 // Force SDES.
1139 config.enable_dtls_srtp = false;
1140
1141 auto caller = CreatePeerConnectionWithAudioVideo(config);
1142 auto callee = CreatePeerConnectionWithAudioVideo(config);
1143
1144 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1145 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1146
1147 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1148 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1149 ASSERT_TRUE(caller_voice);
1150 ASSERT_TRUE(callee_voice);
1151
1152 // Make sure media transport is not propagated to voice channel.
1153 EXPECT_EQ(nullptr, caller_voice->media_transport());
1154 EXPECT_EQ(nullptr, callee_voice->media_transport());
1155}
1156
1157TEST_P(PeerConnectionMediaTest, MediaTransportForMediaAndDataChannels) {
1158 RTCConfiguration config;
1159
1160 // Setup PeerConnection to use media transport for both media and data
1161 // channels.
1162 config.use_media_transport = true;
1163 config.use_media_transport_for_data_channels = true;
1164
1165 // Force SDES.
1166 config.enable_dtls_srtp = false;
1167
1168 auto caller = CreatePeerConnectionWithAudioVideo(config);
1169 auto callee = CreatePeerConnectionWithAudioVideo(config);
1170
1171 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1172 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1173
1174 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1175 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1176 ASSERT_TRUE(caller_voice);
1177 ASSERT_TRUE(callee_voice);
1178
1179 // Make sure media transport is propagated to voice channel.
1180 FakeMediaTransport* caller_voice_media_transport =
1181 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1182 FakeMediaTransport* callee_voice_media_transport =
1183 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1184 ASSERT_NE(nullptr, caller_voice_media_transport);
1185 ASSERT_NE(nullptr, callee_voice_media_transport);
1186
1187 // Make sure media transport is created with correct is_caller.
1188 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1189 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1190
1191 // TODO(sukhanov): Propagate media transport to video channel. This test
1192 // will fail once media transport is propagated to video channel and it will
1193 // serve as a reminder to add a test for video channel propagation.
1194 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1195 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1196 ASSERT_EQ(nullptr, caller_video->media_transport());
1197 ASSERT_EQ(nullptr, callee_video->media_transport());
1198}
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