blob: 6b500915f046bd5d3c30b0569295784447e9e477 [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
Karl Wiberg918f50c2018-07-05 11:40:33 +0200108 auto wrapper = absl::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700109 pc_factory, pc, std::move(observer));
110 wrapper->set_media_engine(media_engine_ptr);
111 return wrapper;
112 }
113
114 // Accepts the same arguments as CreatePeerConnection and adds default audio
115 // and video tracks.
116 template <typename... Args>
117 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
118 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
119 if (!wrapper) {
120 return nullptr;
121 }
122 wrapper->AddAudioTrack("a");
123 wrapper->AddVideoTrack("v");
124 return wrapper;
125 }
126
Steve Anton4e70a722017-11-28 14:57:10 -0800127 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700128 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800129 cricket::MediaType media_type) {
130 auto* content =
131 cricket::GetFirstMediaContent(sdesc->description(), media_type);
132 RTC_DCHECK(content);
133 return content->media_description()->direction();
134 }
135
136 bool IsUnifiedPlan() const {
137 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700138 }
139
140 std::unique_ptr<rtc::VirtualSocketServer> vss_;
141 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800142 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700143};
144
Steve Antonad7bffc2018-01-22 10:21:56 -0800145class PeerConnectionMediaTest
146 : public PeerConnectionMediaBaseTest,
147 public ::testing::WithParamInterface<SdpSemantics> {
148 protected:
149 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
150};
151
152class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
153 protected:
154 PeerConnectionMediaTestUnifiedPlan()
155 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
156};
157
158class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
159 protected:
160 PeerConnectionMediaTestPlanB()
161 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
162};
163
164TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700165 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
166 auto caller = CreatePeerConnectionWithAudioVideo();
167 auto callee = CreatePeerConnectionWithAudioVideo();
168 callee->media_engine()->set_fail_create_channel(true);
169
170 std::string error;
171 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800172 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
173 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700174}
175
Steve Antonad7bffc2018-01-22 10:21:56 -0800176TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700177 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
178 auto caller = CreatePeerConnectionWithAudioVideo();
179 caller->media_engine()->set_fail_create_channel(true);
180
181 std::string error;
182 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800183 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
184 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700185}
186
187std::vector<std::string> GetIds(
188 const std::vector<cricket::StreamParams>& streams) {
189 std::vector<std::string> ids;
190 for (const auto& stream : streams) {
191 ids.push_back(stream.id);
192 }
193 return ids;
194}
195
196// Test that exchanging an offer and answer with each side having an audio and
197// video stream creates the appropriate send/recv streams in the underlying
198// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800199TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700200 const std::string kCallerAudioId = "caller_a";
201 const std::string kCallerVideoId = "caller_v";
202 const std::string kCalleeAudioId = "callee_a";
203 const std::string kCalleeVideoId = "callee_v";
204
205 auto caller = CreatePeerConnection();
206 caller->AddAudioTrack(kCallerAudioId);
207 caller->AddVideoTrack(kCallerVideoId);
208
209 auto callee = CreatePeerConnection();
210 callee->AddAudioTrack(kCalleeAudioId);
211 callee->AddVideoTrack(kCalleeVideoId);
212
213 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
214 ASSERT_TRUE(
215 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
216
217 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
218 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
219 ElementsAre(kCalleeAudioId));
220 EXPECT_THAT(GetIds(caller_voice->send_streams()),
221 ElementsAre(kCallerAudioId));
222
223 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
224 EXPECT_THAT(GetIds(caller_video->recv_streams()),
225 ElementsAre(kCalleeVideoId));
226 EXPECT_THAT(GetIds(caller_video->send_streams()),
227 ElementsAre(kCallerVideoId));
228
229 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
230 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
231 ElementsAre(kCallerAudioId));
232 EXPECT_THAT(GetIds(callee_voice->send_streams()),
233 ElementsAre(kCalleeAudioId));
234
235 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
236 EXPECT_THAT(GetIds(callee_video->recv_streams()),
237 ElementsAre(kCallerVideoId));
238 EXPECT_THAT(GetIds(callee_video->send_streams()),
239 ElementsAre(kCalleeVideoId));
240}
241
Steve Antonad7bffc2018-01-22 10:21:56 -0800242// Test that stopping the caller transceivers causes the media channels on the
243// callee to be destroyed after calling SetRemoteDescription on the generated
244// offer.
245// See next test for equivalent behavior with Plan B semantics.
246TEST_F(PeerConnectionMediaTestUnifiedPlan,
247 StoppedRemoteTransceiversRemovesMediaChannels) {
248 auto caller = CreatePeerConnectionWithAudioVideo();
249 auto callee = CreatePeerConnection();
250
251 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
252
253 // Stop both audio and video transceivers on the caller.
254 auto transceivers = caller->pc()->GetTransceivers();
255 ASSERT_EQ(2u, transceivers.size());
256 transceivers[0]->Stop();
257 transceivers[1]->Stop();
258
259 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
260
261 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
262 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
263}
264
Steve Anton8d3444d2017-10-20 15:30:51 -0700265// Test that removing streams from a subsequent offer causes the receive streams
266// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800267// See previous test for equivalent behavior with Unified Plan semantics.
268TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700269 auto caller = CreatePeerConnection();
270 auto caller_audio_track = caller->AddAudioTrack("a");
271 auto caller_video_track = caller->AddVideoTrack("v");
272 auto callee = CreatePeerConnectionWithAudioVideo();
273
Steve Antonad7bffc2018-01-22 10:21:56 -0800274 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700275
276 // Remove both tracks from caller.
277 caller->pc()->RemoveTrack(caller_audio_track);
278 caller->pc()->RemoveTrack(caller_video_track);
279
Steve Antonad7bffc2018-01-22 10:21:56 -0800280 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700281
282 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800283 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700284 EXPECT_EQ(1u, callee_voice->send_streams().size());
285 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700286 EXPECT_EQ(1u, callee_video->send_streams().size());
287 EXPECT_EQ(0u, callee_video->recv_streams().size());
288}
289
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200290// Test enabling of simulcast with Plan B semantics.
291// This test creating an offer.
292TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
293 auto caller = CreatePeerConnection();
294 auto caller_video_track = caller->AddVideoTrack("v");
295 RTCOfferAnswerOptions options;
296 options.num_simulcast_layers = 3;
297 auto offer = caller->CreateOffer(options);
298 auto* description = cricket::GetFirstMediaContent(
299 offer->description(),
300 cricket::MEDIA_TYPE_VIDEO)->media_description();
301 ASSERT_EQ(1u, description->streams().size());
302 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
303 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
304
305 // Check that it actually creates simulcast aswell.
306 caller->SetLocalDescription(std::move(offer));
307 auto senders = caller->pc()->GetSenders();
308 ASSERT_EQ(1u, senders.size());
309 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
310 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
311}
312
313// Test enabling of simulcast with Plan B semantics.
314// This test creating an answer.
315TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
316 auto caller = CreatePeerConnection();
317 caller->AddVideoTrack("v0");
318 auto offer = caller->CreateOffer();
319 auto callee = CreatePeerConnection();
320 auto callee_video_track = callee->AddVideoTrack("v1");
321 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
322 RTCOfferAnswerOptions options;
323 options.num_simulcast_layers = 3;
324 auto answer = callee->CreateAnswer(options);
325 auto* description = cricket::GetFirstMediaContent(
326 answer->description(),
327 cricket::MEDIA_TYPE_VIDEO)->media_description();
328 ASSERT_EQ(1u, description->streams().size());
329 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
330 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
331
332 // Check that it actually creates simulcast aswell.
333 callee->SetLocalDescription(std::move(answer));
334 auto senders = callee->pc()->GetSenders();
335 ASSERT_EQ(1u, senders.size());
336 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
337 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
338}
339
Steve Antonad7bffc2018-01-22 10:21:56 -0800340// Test that stopping the callee transceivers causes the media channels to be
341// destroyed on the callee after calling SetLocalDescription on the local
342// answer.
343// See next test for equivalent behavior with Plan B semantics.
344TEST_F(PeerConnectionMediaTestUnifiedPlan,
345 StoppedLocalTransceiversRemovesMediaChannels) {
346 auto caller = CreatePeerConnectionWithAudioVideo();
347 auto callee = CreatePeerConnectionWithAudioVideo();
348
349 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
350
351 // Stop both audio and video transceivers on the callee.
352 auto transceivers = callee->pc()->GetTransceivers();
353 ASSERT_EQ(2u, transceivers.size());
354 transceivers[0]->Stop();
355 transceivers[1]->Stop();
356
357 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
358
359 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
360 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
361}
362
Steve Anton8d3444d2017-10-20 15:30:51 -0700363// Test that removing streams from a subsequent answer causes the send streams
364// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800365// See previous test for equivalent behavior with Unified Plan semantics.
366TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700367 auto caller = CreatePeerConnectionWithAudioVideo();
368 auto callee = CreatePeerConnection();
369 auto callee_audio_track = callee->AddAudioTrack("a");
370 auto callee_video_track = callee->AddVideoTrack("v");
371
Steve Antonad7bffc2018-01-22 10:21:56 -0800372 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700373
374 // Remove both tracks from callee.
375 callee->pc()->RemoveTrack(callee_audio_track);
376 callee->pc()->RemoveTrack(callee_video_track);
377
Steve Antonad7bffc2018-01-22 10:21:56 -0800378 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700379
380 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800381 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700382 EXPECT_EQ(0u, callee_voice->send_streams().size());
383 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700384 EXPECT_EQ(0u, callee_video->send_streams().size());
385 EXPECT_EQ(1u, callee_video->recv_streams().size());
386}
387
388// Test that a new stream in a subsequent offer causes a new receive stream to
389// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800390TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700391 auto caller = CreatePeerConnectionWithAudioVideo();
392 auto callee = CreatePeerConnection();
393
Steve Antonad7bffc2018-01-22 10:21:56 -0800394 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700395
396 // Add second set of tracks to the caller.
397 caller->AddAudioTrack("a2");
398 caller->AddVideoTrack("v2");
399
Steve Antonad7bffc2018-01-22 10:21:56 -0800400 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700401
Steve Antonad7bffc2018-01-22 10:21:56 -0800402 auto a1 = callee->media_engine()->GetVoiceChannel(0);
403 auto a2 = callee->media_engine()->GetVoiceChannel(1);
404 auto v1 = callee->media_engine()->GetVideoChannel(0);
405 auto v2 = callee->media_engine()->GetVideoChannel(1);
406 if (IsUnifiedPlan()) {
407 ASSERT_TRUE(a1);
408 EXPECT_EQ(1u, a1->recv_streams().size());
409 ASSERT_TRUE(a2);
410 EXPECT_EQ(1u, a2->recv_streams().size());
411 ASSERT_TRUE(v1);
412 EXPECT_EQ(1u, v1->recv_streams().size());
413 ASSERT_TRUE(v2);
414 EXPECT_EQ(1u, v2->recv_streams().size());
415 } else {
416 ASSERT_TRUE(a1);
417 EXPECT_EQ(2u, a1->recv_streams().size());
418 ASSERT_FALSE(a2);
419 ASSERT_TRUE(v1);
420 EXPECT_EQ(2u, v1->recv_streams().size());
421 ASSERT_FALSE(v2);
422 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700423}
424
425// Test that a new stream in a subsequent answer causes a new send stream to be
426// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800427TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700428 auto caller = CreatePeerConnection();
429 auto callee = CreatePeerConnectionWithAudioVideo();
430
Steve Anton22da89f2018-01-25 13:58:07 -0800431 RTCOfferAnswerOptions offer_options;
432 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700433 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800434 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700435 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800436 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700437
Steve Anton22da89f2018-01-25 13:58:07 -0800438 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
439 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700440
441 // Add second set of tracks to the callee.
442 callee->AddAudioTrack("a2");
443 callee->AddVideoTrack("v2");
444
Steve Anton22da89f2018-01-25 13:58:07 -0800445 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
446 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700447
448 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800449 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700450 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800451 ASSERT_TRUE(callee_video);
452
453 if (IsUnifiedPlan()) {
454 EXPECT_EQ(1u, callee_voice->send_streams().size());
455 EXPECT_EQ(1u, callee_video->send_streams().size());
456 } else {
457 EXPECT_EQ(2u, callee_voice->send_streams().size());
458 EXPECT_EQ(2u, callee_video->send_streams().size());
459 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700460}
461
462// A PeerConnection with no local streams and no explicit answer constraints
463// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800464TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700465 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
466 auto caller = CreatePeerConnectionWithAudioVideo();
467 auto callee = CreatePeerConnection();
468 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
469 auto answer = callee->CreateAnswer();
470
471 const auto* audio_content =
472 cricket::GetFirstAudioContent(answer->description());
473 ASSERT_TRUE(audio_content);
474 EXPECT_FALSE(audio_content->rejected);
475
476 const auto* video_content =
477 cricket::GetFirstVideoContent(answer->description());
478 ASSERT_TRUE(video_content);
479 EXPECT_FALSE(video_content->rejected);
480}
481
482class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800483 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700484 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800485 std::tuple<SdpSemantics,
486 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700487 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800488 PeerConnectionMediaOfferDirectionTest()
489 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
490 auto param = std::get<1>(GetParam());
491 send_media_ = std::get<0>(param);
492 offer_to_receive_ = std::get<1>(param);
493 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700494 }
495
496 bool send_media_;
497 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800498 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700499};
500
501// Tests that the correct direction is set on the media description according
502// to the presence of a local media track and the offer_to_receive setting.
503TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
504 auto caller = CreatePeerConnection();
505 if (send_media_) {
506 caller->AddAudioTrack("a");
507 }
508
509 RTCOfferAnswerOptions options;
510 options.offer_to_receive_audio = offer_to_receive_;
511 auto offer = caller->CreateOffer(options);
512
Steve Antonad7bffc2018-01-22 10:21:56 -0800513 auto* content = cricket::GetFirstMediaContent(offer->description(),
514 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800515 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800516 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700517 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800518 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700519 }
520}
521
522// Note that in these tests, MD_INACTIVE indicates that no media section is
523// included in the offer, not that the media direction is inactive.
Steve Anton4e70a722017-11-28 14:57:10 -0800524INSTANTIATE_TEST_CASE_P(
525 PeerConnectionMediaTest,
526 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800527 Combine(
528 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
529 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
530 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
531 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
532 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
533 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
534 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700535
536class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800537 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700538 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800539 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700540 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800541 PeerConnectionMediaAnswerDirectionTest()
542 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
543 offer_direction_ = std::get<1>(GetParam());
544 send_media_ = std::get<2>(GetParam());
545 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700546 }
547
Steve Anton4e70a722017-11-28 14:57:10 -0800548 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700549 bool send_media_;
550 int offer_to_receive_;
551};
552
553// Tests that the direction in an answer is correct according to direction sent
554// in the offer, the presence of a local media track on the receive side and the
555// offer_to_receive setting.
556TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800557 if (IsUnifiedPlan() &&
558 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
559 // offer_to_receive_ is not implemented when creating answers with Unified
560 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800561 return;
562 }
Steve Anton22da89f2018-01-25 13:58:07 -0800563
Steve Anton8d3444d2017-10-20 15:30:51 -0700564 auto caller = CreatePeerConnection();
565 caller->AddAudioTrack("a");
566
567 // Create the offer with an audio section and set its direction.
568 auto offer = caller->CreateOffer();
569 cricket::GetFirstAudioContentDescription(offer->description())
570 ->set_direction(offer_direction_);
571
572 auto callee = CreatePeerConnection();
573 if (send_media_) {
574 callee->AddAudioTrack("a");
575 }
576 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
577
578 // Create the answer according to the test parameters.
579 RTCOfferAnswerOptions options;
580 options.offer_to_receive_audio = offer_to_receive_;
581 auto answer = callee->CreateAnswer(options);
582
583 // The expected direction in the answer is the intersection of each side's
584 // capability to send/recv media.
585 // For the offerer, the direction is given in the offer (offer_direction_).
586 // For the answerer, the direction has two components:
587 // 1. Send if the answerer has a local track to send.
588 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
589 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800590 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
591 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700592
593 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800594 bool negotiate_send = (send_media_ && offer_recv);
595 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700596
597 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800598 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700599 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800600 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700601}
602
603// Tests that the media section is rejected if and only if the callee has no
604// local media track and has set offer_to_receive to 0, no matter which
605// direction the caller indicated in the offer.
606TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800607 if (IsUnifiedPlan() &&
608 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
609 // offer_to_receive_ is not implemented when creating answers with Unified
610 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800611 return;
612 }
Steve Anton22da89f2018-01-25 13:58:07 -0800613
Steve Anton8d3444d2017-10-20 15:30:51 -0700614 auto caller = CreatePeerConnection();
615 caller->AddAudioTrack("a");
616
617 // Create the offer with an audio section and set its direction.
618 auto offer = caller->CreateOffer();
619 cricket::GetFirstAudioContentDescription(offer->description())
620 ->set_direction(offer_direction_);
621
622 auto callee = CreatePeerConnection();
623 if (send_media_) {
624 callee->AddAudioTrack("a");
625 }
626 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
627
628 // Create the answer according to the test parameters.
629 RTCOfferAnswerOptions options;
630 options.offer_to_receive_audio = offer_to_receive_;
631 auto answer = callee->CreateAnswer(options);
632
633 // The media section is rejected if and only if offer_to_receive is explicitly
634 // set to 0 and there is no media to send.
635 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
636 ASSERT_TRUE(audio_content);
637 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
638}
639
640INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
641 PeerConnectionMediaAnswerDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800642 Combine(Values(SdpSemantics::kPlanB,
643 SdpSemantics::kUnifiedPlan),
644 Values(RtpTransceiverDirection::kInactive,
Steve Anton4e70a722017-11-28 14:57:10 -0800645 RtpTransceiverDirection::kSendOnly,
646 RtpTransceiverDirection::kRecvOnly,
647 RtpTransceiverDirection::kSendRecv),
Steve Anton8d3444d2017-10-20 15:30:51 -0700648 Bool(),
649 Values(-1, 0, 1)));
650
Steve Antonad7bffc2018-01-22 10:21:56 -0800651TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700652 auto caller = CreatePeerConnection();
653 caller->AddVideoTrack("v");
654
655 RTCOfferAnswerOptions options;
656 options.offer_to_receive_audio = 1;
657 options.offer_to_receive_video = 0;
658 auto offer = caller->CreateOffer(options);
659
Steve Anton4e70a722017-11-28 14:57:10 -0800660 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800661 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800662 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800663 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700664}
665
Steve Antonad7bffc2018-01-22 10:21:56 -0800666TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800667 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800668 // offer_to_receive_ is not implemented when creating answers with Unified
669 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800670 return;
671 }
672
Steve Anton8d3444d2017-10-20 15:30:51 -0700673 auto caller = CreatePeerConnectionWithAudioVideo();
674 auto callee = CreatePeerConnection();
675 callee->AddVideoTrack("v");
676
677 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
678
679 RTCOfferAnswerOptions options;
680 options.offer_to_receive_audio = 1;
681 options.offer_to_receive_video = 0;
682 auto answer = callee->CreateAnswer(options);
683
Steve Anton4e70a722017-11-28 14:57:10 -0800684 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800685 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800686 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800687 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700688}
689
690void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
691 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
692 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
693
694 auto codecs = media_engine->audio_send_codecs();
695 codecs.push_back(kComfortNoiseCodec8k);
696 codecs.push_back(kComfortNoiseCodec16k);
697 media_engine->SetAudioCodecs(codecs);
698}
699
700bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
701 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
702 for (const auto& codec : audio_desc->codecs()) {
703 if (codec.name == "CN") {
704 return true;
705 }
706 }
707 return false;
708}
709
Steve Antonad7bffc2018-01-22 10:21:56 -0800710TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700711 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
712 auto caller = CreatePeerConnectionWithAudioVideo();
713 AddComfortNoiseCodecsToSend(caller->media_engine());
714
715 RTCOfferAnswerOptions options;
716 options.voice_activity_detection = false;
717 auto offer = caller->CreateOffer(options);
718
719 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
720}
721
Steve Antonad7bffc2018-01-22 10:21:56 -0800722TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700723 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
724 auto caller = CreatePeerConnectionWithAudioVideo();
725 AddComfortNoiseCodecsToSend(caller->media_engine());
726 auto callee = CreatePeerConnectionWithAudioVideo();
727 AddComfortNoiseCodecsToSend(callee->media_engine());
728
729 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
730
731 RTCOfferAnswerOptions options;
732 options.voice_activity_detection = false;
733 auto answer = callee->CreateAnswer(options);
734
735 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
736}
737
738// The following test group verifies that we reject answers with invalid media
739// sections as per RFC 3264.
740
741class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800742 : public PeerConnectionMediaBaseTest,
743 public ::testing::WithParamInterface<std::tuple<
744 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700745 std::tuple<std::string,
746 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800747 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700748 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800749 PeerConnectionMediaInvalidMediaTest()
750 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
751 auto param = std::get<1>(GetParam());
752 mutator_ = std::get<1>(param);
753 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700754 }
755
756 std::function<void(cricket::SessionDescription*)> mutator_;
757 std::string expected_error_;
758};
759
760TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
761 auto caller = CreatePeerConnectionWithAudioVideo();
762 auto callee = CreatePeerConnectionWithAudioVideo();
763
764 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
765
766 auto answer = callee->CreateAnswer();
767 mutator_(answer->description());
768
769 std::string error;
770 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
771 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
772}
773
774TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
775 auto caller = CreatePeerConnectionWithAudioVideo();
776 auto callee = CreatePeerConnectionWithAudioVideo();
777
778 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
779
780 auto answer = callee->CreateAnswer();
781 mutator_(answer->description());
782
783 std::string error;
784 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
785 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
786}
787
788void RemoveVideoContent(cricket::SessionDescription* desc) {
789 auto content_name = cricket::GetFirstVideoContent(desc)->name;
790 desc->RemoveContentByName(content_name);
791 desc->RemoveTransportInfoByName(content_name);
792}
793
794void RenameVideoContent(cricket::SessionDescription* desc) {
795 auto* video_content = cricket::GetFirstVideoContent(desc);
796 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
797 video_content->name = "video_renamed";
798 transport_info->content_name = video_content->name;
799}
800
801void ReverseMediaContent(cricket::SessionDescription* desc) {
802 std::reverse(desc->contents().begin(), desc->contents().end());
803 std::reverse(desc->transport_infos().begin(), desc->transport_infos().end());
804}
805
806void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800807 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
808 desc->RemoveContentByName(audio_mid);
809 auto* video_content = cricket::GetFirstVideoContent(desc);
810 desc->AddContent(audio_mid, video_content->type,
Steve Antonb1c1de12017-12-21 15:14:30 -0800811 video_content->media_description()->Copy());
Steve Anton8d3444d2017-10-20 15:30:51 -0700812}
813
814constexpr char kMLinesOutOfOrder[] =
815 "The order of m-lines in answer doesn't match order in offer. Rejecting "
816 "answer.";
817
818INSTANTIATE_TEST_CASE_P(
819 PeerConnectionMediaTest,
820 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800821 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
822 Values(std::make_tuple("remove video",
823 RemoveVideoContent,
824 kMLinesOutOfOrder),
825 std::make_tuple("rename video",
826 RenameVideoContent,
827 kMLinesOutOfOrder),
828 std::make_tuple("reverse media sections",
829 ReverseMediaContent,
830 kMLinesOutOfOrder),
831 std::make_tuple("change audio type to video type",
832 ChangeMediaTypeAudioToVideo,
833 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700834
835// Test that the correct media engine send/recv streams are created when doing
836// a series of offer/answers where audio/video are both sent, then audio is
837// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800838TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800839 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800840 // offer_to_receive_ is not implemented when creating answers with Unified
841 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800842 return;
843 }
844
Steve Anton8d3444d2017-10-20 15:30:51 -0700845 RTCOfferAnswerOptions options_reject_video;
846 options_reject_video.offer_to_receive_audio =
847 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
848 options_reject_video.offer_to_receive_video = 0;
849
850 auto caller = CreatePeerConnection();
851 caller->AddAudioTrack("a");
852 caller->AddVideoTrack("v");
853 auto callee = CreatePeerConnection();
854
855 // Caller initially offers to send/recv audio and video.
856 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
857 // Callee accepts the audio as recv only but rejects the video.
858 ASSERT_TRUE(caller->SetRemoteDescription(
859 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
860
861 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
862 ASSERT_TRUE(caller_voice);
863 EXPECT_EQ(0u, caller_voice->recv_streams().size());
864 EXPECT_EQ(1u, caller_voice->send_streams().size());
865 auto caller_video = caller->media_engine()->GetVideoChannel(0);
866 EXPECT_FALSE(caller_video);
867
868 // Callee adds its own audio/video stream and offers to receive audio/video
869 // too.
870 callee->AddAudioTrack("a");
871 auto callee_video_track = callee->AddVideoTrack("v");
872 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
873 ASSERT_TRUE(
874 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
875
876 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
877 ASSERT_TRUE(callee_voice);
878 EXPECT_EQ(1u, callee_voice->recv_streams().size());
879 EXPECT_EQ(1u, callee_voice->send_streams().size());
880 auto callee_video = callee->media_engine()->GetVideoChannel(0);
881 ASSERT_TRUE(callee_video);
882 EXPECT_EQ(1u, callee_video->recv_streams().size());
883 EXPECT_EQ(1u, callee_video->send_streams().size());
884
885 // Callee removes video but keeps audio and rejects the video once again.
886 callee->pc()->RemoveTrack(callee_video_track);
887 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
888 ASSERT_TRUE(
889 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
890
891 callee_voice = callee->media_engine()->GetVoiceChannel(0);
892 ASSERT_TRUE(callee_voice);
893 EXPECT_EQ(1u, callee_voice->recv_streams().size());
894 EXPECT_EQ(1u, callee_voice->send_streams().size());
895 callee_video = callee->media_engine()->GetVideoChannel(0);
896 EXPECT_FALSE(callee_video);
897}
898
899// Test that the correct media engine send/recv streams are created when doing
900// a series of offer/answers where audio/video are both sent, then video is
901// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800902TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800903 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800904 // offer_to_receive_ is not implemented when creating answers with Unified
905 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800906 return;
907 }
908
Steve Anton8d3444d2017-10-20 15:30:51 -0700909 // Disable the bundling here. If the media is bundled on audio
910 // transport, then we can't reject the audio because switching the bundled
911 // transport is not currently supported.
912 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
913 RTCOfferAnswerOptions options_no_bundle;
914 options_no_bundle.use_rtp_mux = false;
915 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
916 options_reject_audio.offer_to_receive_audio = 0;
917 options_reject_audio.offer_to_receive_video =
918 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
919
920 auto caller = CreatePeerConnection();
921 caller->AddAudioTrack("a");
922 caller->AddVideoTrack("v");
923 auto callee = CreatePeerConnection();
924
925 // Caller initially offers to send/recv audio and video.
926 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
927 // Callee accepts the video as recv only but rejects the audio.
928 ASSERT_TRUE(caller->SetRemoteDescription(
929 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
930
931 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
932 EXPECT_FALSE(caller_voice);
933 auto caller_video = caller->media_engine()->GetVideoChannel(0);
934 ASSERT_TRUE(caller_video);
935 EXPECT_EQ(0u, caller_video->recv_streams().size());
936 EXPECT_EQ(1u, caller_video->send_streams().size());
937
938 // Callee adds its own audio/video stream and offers to receive audio/video
939 // too.
940 auto callee_audio_track = callee->AddAudioTrack("a");
941 callee->AddVideoTrack("v");
942 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
943 ASSERT_TRUE(caller->SetRemoteDescription(
944 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
945
946 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
947 ASSERT_TRUE(callee_voice);
948 EXPECT_EQ(1u, callee_voice->recv_streams().size());
949 EXPECT_EQ(1u, callee_voice->send_streams().size());
950 auto callee_video = callee->media_engine()->GetVideoChannel(0);
951 ASSERT_TRUE(callee_video);
952 EXPECT_EQ(1u, callee_video->recv_streams().size());
953 EXPECT_EQ(1u, callee_video->send_streams().size());
954
955 // Callee removes audio but keeps video and rejects the audio once again.
956 callee->pc()->RemoveTrack(callee_audio_track);
957 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
958 ASSERT_TRUE(
959 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
960
961 callee_voice = callee->media_engine()->GetVoiceChannel(0);
962 EXPECT_FALSE(callee_voice);
963 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
969// Tests that if the underlying video encoder fails to be initialized (signaled
970// by failing to set send codecs), the PeerConnection signals the error to the
971// client.
Steve Antonad7bffc2018-01-22 10:21:56 -0800972TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700973 auto caller = CreatePeerConnectionWithAudioVideo();
974 auto callee = CreatePeerConnectionWithAudioVideo();
975
976 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
977
978 auto video_channel = caller->media_engine()->GetVideoChannel(0);
979 video_channel->set_fail_set_send_codecs(true);
980
981 std::string error;
982 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
983 &error));
984 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -0800985 "Failed to set remote answer sdp: Failed to set remote video description "
986 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -0700987 error);
988}
989
990// Tests that if the underlying video encoder fails once then subsequent
991// attempts at setting the local/remote description will also fail, even if
992// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -0800993TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700994 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
995 auto caller = CreatePeerConnectionWithAudioVideo();
996 auto callee = CreatePeerConnectionWithAudioVideo();
997
998 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
999
1000 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1001 video_channel->set_fail_set_send_codecs(true);
1002
1003 EXPECT_FALSE(
1004 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1005
1006 video_channel->set_fail_set_send_codecs(false);
1007
1008 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1009 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1010}
1011
1012void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001013 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001014 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001015 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001016 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001017 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001018 content->name = new_name;
1019 auto* transport = desc->GetTransportInfoByName(old_name);
1020 RTC_DCHECK(transport);
1021 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001022
1023 // Rename the content name in the BUNDLE group.
1024 cricket::ContentGroup new_bundle_group =
1025 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1026 new_bundle_group.RemoveContentName(old_name);
1027 new_bundle_group.AddContentName(new_name);
1028 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1029 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001030}
1031
1032// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001033TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001034 const std::string kAudioMid = "notdefault1";
1035 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001036
1037 auto caller = CreatePeerConnectionWithAudioVideo();
1038 auto callee = CreatePeerConnectionWithAudioVideo();
1039
1040 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001041 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1042 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001043 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1044
1045 auto answer = callee->CreateAnswer();
1046 EXPECT_EQ(kAudioMid,
1047 cricket::GetFirstAudioContent(answer->description())->name);
1048 EXPECT_EQ(kVideoMid,
1049 cricket::GetFirstVideoContent(answer->description())->name);
1050}
1051
1052// Test that if the callee creates a re-offer, the MIDs are the same as the
1053// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001054TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001055 const std::string kAudioMid = "notdefault1";
1056 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001057
1058 auto caller = CreatePeerConnectionWithAudioVideo();
1059 auto callee = CreatePeerConnectionWithAudioVideo();
1060
1061 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001062 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1063 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001064 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1065 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1066
1067 auto reoffer = callee->CreateOffer();
1068 EXPECT_EQ(kAudioMid,
1069 cricket::GetFirstAudioContent(reoffer->description())->name);
1070 EXPECT_EQ(kVideoMid,
1071 cricket::GetFirstVideoContent(reoffer->description())->name);
1072}
1073
Steve Antonad7bffc2018-01-22 10:21:56 -08001074TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001075 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1076 RTCConfiguration config;
1077 config.combined_audio_video_bwe.emplace(true);
1078 auto caller = CreatePeerConnectionWithAudioVideo(config);
1079
1080 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1081
1082 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1083 ASSERT_TRUE(caller_voice);
1084 const cricket::AudioOptions& audio_options = caller_voice->options();
1085 EXPECT_EQ(config.combined_audio_video_bwe,
1086 audio_options.combined_audio_video_bwe);
1087}
1088
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001089TEST_P(PeerConnectionMediaTest, MediaTransportPropagatedToVoiceEngine) {
1090 RTCConfiguration config;
1091
1092 // Setup PeerConnection to use media transport.
1093 config.use_media_transport = true;
1094
1095 auto caller = CreatePeerConnectionWithAudioVideo(config);
1096 auto callee = CreatePeerConnectionWithAudioVideo(config);
1097
1098 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1099 auto answer = callee->CreateAnswer();
1100 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1101
1102 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1103 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1104 ASSERT_TRUE(caller_voice);
1105 ASSERT_TRUE(callee_voice);
1106
1107 // Make sure media transport is propagated to voice channel.
1108 FakeMediaTransport* caller_voice_media_transport =
1109 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1110 FakeMediaTransport* callee_voice_media_transport =
1111 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1112 ASSERT_NE(nullptr, caller_voice_media_transport);
1113 ASSERT_NE(nullptr, callee_voice_media_transport);
1114
1115 // Make sure media transport is created with correct is_caller.
1116 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1117 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1118
1119 // TODO(sukhanov): Propagate media transport to video channel. This test
1120 // will fail once media transport is propagated to video channel and it will
1121 // serve as a reminder to add a test for video channel propagation.
1122 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1123 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1124 ASSERT_EQ(nullptr, caller_video->media_transport());
1125 ASSERT_EQ(nullptr, callee_video->media_transport());
1126}
1127
1128TEST_P(PeerConnectionMediaTest, MediaTransportNotPropagatedToVoiceEngine) {
1129 auto caller = CreatePeerConnectionWithAudioVideo();
1130 auto callee = CreatePeerConnectionWithAudioVideo();
1131
1132 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1133 auto answer = callee->CreateAnswer();
1134 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1135
1136 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1137 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1138 ASSERT_TRUE(caller_voice);
1139 ASSERT_TRUE(callee_voice);
1140
1141 // Since we did not setup PeerConnection to use media transport, media
1142 // transport should not be created / propagated to the voice engine.
1143 ASSERT_EQ(nullptr, caller_voice->media_transport());
1144 ASSERT_EQ(nullptr, callee_voice->media_transport());
1145
1146 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1147 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1148 ASSERT_EQ(nullptr, caller_video->media_transport());
1149 ASSERT_EQ(nullptr, callee_video->media_transport());
1150}
1151
Steve Antonad7bffc2018-01-22 10:21:56 -08001152INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
1153 PeerConnectionMediaTest,
1154 Values(SdpSemantics::kPlanB,
1155 SdpSemantics::kUnifiedPlan));
1156
Steve Anton8d3444d2017-10-20 15:30:51 -07001157} // namespace webrtc