blob: c81d5111b72b458cdbef8fcde327e893fa492fda [file] [log] [blame]
Steve Anton8d3444d2017-10-20 15:30:51 -07001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11// This file contains tests that check the interaction between the
12// PeerConnection and the underlying media engine, as well as tests that check
13// the media-related aspects of SDP.
14
15#include <tuple>
16
Steve Anton64b626b2019-01-28 17:25:26 -080017#include "absl/algorithm/container.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "api/call/call_factory_interface.h"
Anton Sukhanov98a462c2018-10-17 13:15:42 -070019#include "api/test/fake_media_transport.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070020#include "logging/rtc_event_log/rtc_event_log_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "media/base/fake_media_engine.h"
22#include "p2p/base/fake_port_allocator.h"
23#include "pc/media_session.h"
24#include "pc/peer_connection_wrapper.h"
25#include "pc/rtp_media_utils.h"
26#include "pc/sdp_utils.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070027#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070029#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020030#include "absl/memory/memory.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070032#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070034#include "test/gmock.h"
35
36namespace webrtc {
37
38using cricket::FakeMediaEngine;
39using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
40using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
41using ::testing::Bool;
42using ::testing::Combine;
43using ::testing::Values;
44using ::testing::ElementsAre;
45
46class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
47 public:
48 using PeerConnectionWrapper::PeerConnectionWrapper;
49
50 FakeMediaEngine* media_engine() { return media_engine_; }
51 void set_media_engine(FakeMediaEngine* media_engine) {
52 media_engine_ = media_engine;
53 }
54
55 private:
56 FakeMediaEngine* media_engine_;
57};
58
Steve Antonad7bffc2018-01-22 10:21:56 -080059class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070060 protected:
61 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
62
Steve Antonad7bffc2018-01-22 10:21:56 -080063 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
64 : vss_(new rtc::VirtualSocketServer()),
65 main_(vss_.get()),
66 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -070067#ifdef WEBRTC_ANDROID
68 InitializeAndroidObjects();
69#endif
70 }
71
72 WrapperPtr CreatePeerConnection() {
73 return CreatePeerConnection(RTCConfiguration());
74 }
75
Anton Sukhanov98a462c2018-10-17 13:15:42 -070076 // Creates PeerConnectionFactory and PeerConnection for given configuration.
77 // Note that PeerConnectionFactory is created with MediaTransportFactory,
78 // because some tests pass config.use_media_transport = true.
Steve Anton8d3444d2017-10-20 15:30:51 -070079 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Karl Wiberg918f50c2018-07-05 11:40:33 +020080 auto media_engine = absl::make_unique<FakeMediaEngine>();
Steve Anton8d3444d2017-10-20 15:30:51 -070081 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 13:15:42 -070082
83 PeerConnectionFactoryDependencies factory_dependencies;
84
85 factory_dependencies.network_thread = rtc::Thread::Current();
86 factory_dependencies.worker_thread = rtc::Thread::Current();
87 factory_dependencies.signaling_thread = rtc::Thread::Current();
88 factory_dependencies.media_engine = std::move(media_engine);
89 factory_dependencies.call_factory = CreateCallFactory();
90 factory_dependencies.event_log_factory = CreateRtcEventLogFactory();
91 factory_dependencies.media_transport_factory =
92 absl::make_unique<FakeMediaTransportFactory>();
93
94 auto pc_factory =
95 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -070096
Karl Wiberg918f50c2018-07-05 11:40:33 +020097 auto fake_port_allocator = absl::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -070098 rtc::Thread::Current(), nullptr);
Karl Wiberg918f50c2018-07-05 11:40:33 +020099 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 10:21:56 -0800100 auto modified_config = config;
101 modified_config.sdp_semantics = sdp_semantics_;
102 auto pc = pc_factory->CreatePeerConnection(modified_config,
103 std::move(fake_port_allocator),
104 nullptr, observer.get());
Steve Anton8d3444d2017-10-20 15:30:51 -0700105 if (!pc) {
106 return nullptr;
107 }
108
Yves Gerey4e933292018-10-31 15:36:05 +0100109 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200110 auto wrapper = absl::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700111 pc_factory, pc, std::move(observer));
112 wrapper->set_media_engine(media_engine_ptr);
113 return wrapper;
114 }
115
116 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800117 // track (but no video).
118 template <typename... Args>
119 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
120 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
121 if (!wrapper) {
122 return nullptr;
123 }
124 wrapper->AddAudioTrack("a");
125 return wrapper;
126 }
127
128 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 15:30:51 -0700129 // and video tracks.
130 template <typename... Args>
131 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
132 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
133 if (!wrapper) {
134 return nullptr;
135 }
136 wrapper->AddAudioTrack("a");
137 wrapper->AddVideoTrack("v");
138 return wrapper;
139 }
140
Steve Anton4e70a722017-11-28 14:57:10 -0800141 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700142 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800143 cricket::MediaType media_type) {
144 auto* content =
145 cricket::GetFirstMediaContent(sdesc->description(), media_type);
146 RTC_DCHECK(content);
147 return content->media_description()->direction();
148 }
149
150 bool IsUnifiedPlan() const {
151 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700152 }
153
154 std::unique_ptr<rtc::VirtualSocketServer> vss_;
155 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800156 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700157};
158
Steve Antonad7bffc2018-01-22 10:21:56 -0800159class PeerConnectionMediaTest
160 : public PeerConnectionMediaBaseTest,
161 public ::testing::WithParamInterface<SdpSemantics> {
162 protected:
163 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
164};
165
166class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
167 protected:
168 PeerConnectionMediaTestUnifiedPlan()
169 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
170};
171
172class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
173 protected:
174 PeerConnectionMediaTestPlanB()
175 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
176};
177
178TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700179 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
180 auto caller = CreatePeerConnectionWithAudioVideo();
181 auto callee = CreatePeerConnectionWithAudioVideo();
182 callee->media_engine()->set_fail_create_channel(true);
183
184 std::string error;
185 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800186 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
187 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700188}
189
Steve Antonad7bffc2018-01-22 10:21:56 -0800190TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700191 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
192 auto caller = CreatePeerConnectionWithAudioVideo();
193 caller->media_engine()->set_fail_create_channel(true);
194
195 std::string error;
196 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800197 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
198 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700199}
200
201std::vector<std::string> GetIds(
202 const std::vector<cricket::StreamParams>& streams) {
203 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100204 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700205 for (const auto& stream : streams) {
206 ids.push_back(stream.id);
207 }
208 return ids;
209}
210
211// Test that exchanging an offer and answer with each side having an audio and
212// video stream creates the appropriate send/recv streams in the underlying
213// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800214TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700215 const std::string kCallerAudioId = "caller_a";
216 const std::string kCallerVideoId = "caller_v";
217 const std::string kCalleeAudioId = "callee_a";
218 const std::string kCalleeVideoId = "callee_v";
219
220 auto caller = CreatePeerConnection();
221 caller->AddAudioTrack(kCallerAudioId);
222 caller->AddVideoTrack(kCallerVideoId);
223
224 auto callee = CreatePeerConnection();
225 callee->AddAudioTrack(kCalleeAudioId);
226 callee->AddVideoTrack(kCalleeVideoId);
227
228 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
229 ASSERT_TRUE(
230 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
231
232 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
233 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
234 ElementsAre(kCalleeAudioId));
235 EXPECT_THAT(GetIds(caller_voice->send_streams()),
236 ElementsAre(kCallerAudioId));
237
238 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
239 EXPECT_THAT(GetIds(caller_video->recv_streams()),
240 ElementsAre(kCalleeVideoId));
241 EXPECT_THAT(GetIds(caller_video->send_streams()),
242 ElementsAre(kCallerVideoId));
243
244 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
245 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
246 ElementsAre(kCallerAudioId));
247 EXPECT_THAT(GetIds(callee_voice->send_streams()),
248 ElementsAre(kCalleeAudioId));
249
250 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
251 EXPECT_THAT(GetIds(callee_video->recv_streams()),
252 ElementsAre(kCallerVideoId));
253 EXPECT_THAT(GetIds(callee_video->send_streams()),
254 ElementsAre(kCalleeVideoId));
255}
256
Steve Antonad7bffc2018-01-22 10:21:56 -0800257// Test that stopping the caller transceivers causes the media channels on the
258// callee to be destroyed after calling SetRemoteDescription on the generated
259// offer.
260// See next test for equivalent behavior with Plan B semantics.
261TEST_F(PeerConnectionMediaTestUnifiedPlan,
262 StoppedRemoteTransceiversRemovesMediaChannels) {
263 auto caller = CreatePeerConnectionWithAudioVideo();
264 auto callee = CreatePeerConnection();
265
266 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
267
268 // Stop both audio and video transceivers on the caller.
269 auto transceivers = caller->pc()->GetTransceivers();
270 ASSERT_EQ(2u, transceivers.size());
271 transceivers[0]->Stop();
272 transceivers[1]->Stop();
273
274 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
275
276 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
277 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
278}
279
Steve Anton8d3444d2017-10-20 15:30:51 -0700280// Test that removing streams from a subsequent offer causes the receive streams
281// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800282// See previous test for equivalent behavior with Unified Plan semantics.
283TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700284 auto caller = CreatePeerConnection();
285 auto caller_audio_track = caller->AddAudioTrack("a");
286 auto caller_video_track = caller->AddVideoTrack("v");
287 auto callee = CreatePeerConnectionWithAudioVideo();
288
Steve Antonad7bffc2018-01-22 10:21:56 -0800289 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700290
291 // Remove both tracks from caller.
292 caller->pc()->RemoveTrack(caller_audio_track);
293 caller->pc()->RemoveTrack(caller_video_track);
294
Steve Antonad7bffc2018-01-22 10:21:56 -0800295 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700296
297 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800298 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700299 EXPECT_EQ(1u, callee_voice->send_streams().size());
300 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700301 EXPECT_EQ(1u, callee_video->send_streams().size());
302 EXPECT_EQ(0u, callee_video->recv_streams().size());
303}
304
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200305// Test enabling of simulcast with Plan B semantics.
306// This test creating an offer.
307TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
308 auto caller = CreatePeerConnection();
309 auto caller_video_track = caller->AddVideoTrack("v");
310 RTCOfferAnswerOptions options;
311 options.num_simulcast_layers = 3;
312 auto offer = caller->CreateOffer(options);
313 auto* description = cricket::GetFirstMediaContent(
314 offer->description(),
315 cricket::MEDIA_TYPE_VIDEO)->media_description();
316 ASSERT_EQ(1u, description->streams().size());
317 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
318 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
319
320 // Check that it actually creates simulcast aswell.
321 caller->SetLocalDescription(std::move(offer));
322 auto senders = caller->pc()->GetSenders();
323 ASSERT_EQ(1u, senders.size());
324 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
325 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
326}
327
328// Test enabling of simulcast with Plan B semantics.
329// This test creating an answer.
330TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
331 auto caller = CreatePeerConnection();
332 caller->AddVideoTrack("v0");
333 auto offer = caller->CreateOffer();
334 auto callee = CreatePeerConnection();
335 auto callee_video_track = callee->AddVideoTrack("v1");
336 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
337 RTCOfferAnswerOptions options;
338 options.num_simulcast_layers = 3;
339 auto answer = callee->CreateAnswer(options);
340 auto* description = cricket::GetFirstMediaContent(
341 answer->description(),
342 cricket::MEDIA_TYPE_VIDEO)->media_description();
343 ASSERT_EQ(1u, description->streams().size());
344 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
345 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
346
347 // Check that it actually creates simulcast aswell.
348 callee->SetLocalDescription(std::move(answer));
349 auto senders = callee->pc()->GetSenders();
350 ASSERT_EQ(1u, senders.size());
351 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
352 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
353}
354
Steve Antonad7bffc2018-01-22 10:21:56 -0800355// Test that stopping the callee transceivers causes the media channels to be
356// destroyed on the callee after calling SetLocalDescription on the local
357// answer.
358// See next test for equivalent behavior with Plan B semantics.
359TEST_F(PeerConnectionMediaTestUnifiedPlan,
360 StoppedLocalTransceiversRemovesMediaChannels) {
361 auto caller = CreatePeerConnectionWithAudioVideo();
362 auto callee = CreatePeerConnectionWithAudioVideo();
363
364 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
365
366 // Stop both audio and video transceivers on the callee.
367 auto transceivers = callee->pc()->GetTransceivers();
368 ASSERT_EQ(2u, transceivers.size());
369 transceivers[0]->Stop();
370 transceivers[1]->Stop();
371
372 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
373
374 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
375 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
376}
377
Steve Anton8d3444d2017-10-20 15:30:51 -0700378// Test that removing streams from a subsequent answer causes the send streams
379// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800380// See previous test for equivalent behavior with Unified Plan semantics.
381TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700382 auto caller = CreatePeerConnectionWithAudioVideo();
383 auto callee = CreatePeerConnection();
384 auto callee_audio_track = callee->AddAudioTrack("a");
385 auto callee_video_track = callee->AddVideoTrack("v");
386
Steve Antonad7bffc2018-01-22 10:21:56 -0800387 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700388
389 // Remove both tracks from callee.
390 callee->pc()->RemoveTrack(callee_audio_track);
391 callee->pc()->RemoveTrack(callee_video_track);
392
Steve Antonad7bffc2018-01-22 10:21:56 -0800393 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700394
395 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800396 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700397 EXPECT_EQ(0u, callee_voice->send_streams().size());
398 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700399 EXPECT_EQ(0u, callee_video->send_streams().size());
400 EXPECT_EQ(1u, callee_video->recv_streams().size());
401}
402
403// Test that a new stream in a subsequent offer causes a new receive stream to
404// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800405TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700406 auto caller = CreatePeerConnectionWithAudioVideo();
407 auto callee = CreatePeerConnection();
408
Steve Antonad7bffc2018-01-22 10:21:56 -0800409 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700410
411 // Add second set of tracks to the caller.
412 caller->AddAudioTrack("a2");
413 caller->AddVideoTrack("v2");
414
Steve Antonad7bffc2018-01-22 10:21:56 -0800415 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700416
Steve Antonad7bffc2018-01-22 10:21:56 -0800417 auto a1 = callee->media_engine()->GetVoiceChannel(0);
418 auto a2 = callee->media_engine()->GetVoiceChannel(1);
419 auto v1 = callee->media_engine()->GetVideoChannel(0);
420 auto v2 = callee->media_engine()->GetVideoChannel(1);
421 if (IsUnifiedPlan()) {
422 ASSERT_TRUE(a1);
423 EXPECT_EQ(1u, a1->recv_streams().size());
424 ASSERT_TRUE(a2);
425 EXPECT_EQ(1u, a2->recv_streams().size());
426 ASSERT_TRUE(v1);
427 EXPECT_EQ(1u, v1->recv_streams().size());
428 ASSERT_TRUE(v2);
429 EXPECT_EQ(1u, v2->recv_streams().size());
430 } else {
431 ASSERT_TRUE(a1);
432 EXPECT_EQ(2u, a1->recv_streams().size());
433 ASSERT_FALSE(a2);
434 ASSERT_TRUE(v1);
435 EXPECT_EQ(2u, v1->recv_streams().size());
436 ASSERT_FALSE(v2);
437 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700438}
439
440// Test that a new stream in a subsequent answer causes a new send stream to be
441// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800442TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700443 auto caller = CreatePeerConnection();
444 auto callee = CreatePeerConnectionWithAudioVideo();
445
Steve Anton22da89f2018-01-25 13:58:07 -0800446 RTCOfferAnswerOptions offer_options;
447 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700448 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800449 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700450 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800451 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700452
Steve Anton22da89f2018-01-25 13:58:07 -0800453 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
454 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700455
456 // Add second set of tracks to the callee.
457 callee->AddAudioTrack("a2");
458 callee->AddVideoTrack("v2");
459
Steve Anton22da89f2018-01-25 13:58:07 -0800460 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
461 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700462
463 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800464 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700465 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800466 ASSERT_TRUE(callee_video);
467
468 if (IsUnifiedPlan()) {
469 EXPECT_EQ(1u, callee_voice->send_streams().size());
470 EXPECT_EQ(1u, callee_video->send_streams().size());
471 } else {
472 EXPECT_EQ(2u, callee_voice->send_streams().size());
473 EXPECT_EQ(2u, callee_video->send_streams().size());
474 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700475}
476
477// A PeerConnection with no local streams and no explicit answer constraints
478// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800479TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700480 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
481 auto caller = CreatePeerConnectionWithAudioVideo();
482 auto callee = CreatePeerConnection();
483 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
484 auto answer = callee->CreateAnswer();
485
486 const auto* audio_content =
487 cricket::GetFirstAudioContent(answer->description());
488 ASSERT_TRUE(audio_content);
489 EXPECT_FALSE(audio_content->rejected);
490
491 const auto* video_content =
492 cricket::GetFirstVideoContent(answer->description());
493 ASSERT_TRUE(video_content);
494 EXPECT_FALSE(video_content->rejected);
495}
496
497class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800498 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700499 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800500 std::tuple<SdpSemantics,
501 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700502 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800503 PeerConnectionMediaOfferDirectionTest()
504 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
505 auto param = std::get<1>(GetParam());
506 send_media_ = std::get<0>(param);
507 offer_to_receive_ = std::get<1>(param);
508 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700509 }
510
511 bool send_media_;
512 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800513 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700514};
515
516// Tests that the correct direction is set on the media description according
517// to the presence of a local media track and the offer_to_receive setting.
518TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
519 auto caller = CreatePeerConnection();
520 if (send_media_) {
521 caller->AddAudioTrack("a");
522 }
523
524 RTCOfferAnswerOptions options;
525 options.offer_to_receive_audio = offer_to_receive_;
526 auto offer = caller->CreateOffer(options);
527
Steve Antonad7bffc2018-01-22 10:21:56 -0800528 auto* content = cricket::GetFirstMediaContent(offer->description(),
529 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800530 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800531 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700532 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800533 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700534 }
535}
536
537// Note that in these tests, MD_INACTIVE indicates that no media section is
538// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100539INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 14:57:10 -0800540 PeerConnectionMediaTest,
541 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800542 Combine(
543 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
544 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
545 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
546 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
547 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
548 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
549 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700550
551class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800552 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700553 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800554 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700555 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800556 PeerConnectionMediaAnswerDirectionTest()
557 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
558 offer_direction_ = std::get<1>(GetParam());
559 send_media_ = std::get<2>(GetParam());
560 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700561 }
562
Steve Anton4e70a722017-11-28 14:57:10 -0800563 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700564 bool send_media_;
565 int offer_to_receive_;
566};
567
568// Tests that the direction in an answer is correct according to direction sent
569// in the offer, the presence of a local media track on the receive side and the
570// offer_to_receive setting.
571TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800572 if (IsUnifiedPlan() &&
573 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
574 // offer_to_receive_ is not implemented when creating answers with Unified
575 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800576 return;
577 }
Steve Anton22da89f2018-01-25 13:58:07 -0800578
Steve Anton8d3444d2017-10-20 15:30:51 -0700579 auto caller = CreatePeerConnection();
580 caller->AddAudioTrack("a");
581
582 // Create the offer with an audio section and set its direction.
583 auto offer = caller->CreateOffer();
584 cricket::GetFirstAudioContentDescription(offer->description())
585 ->set_direction(offer_direction_);
586
587 auto callee = CreatePeerConnection();
588 if (send_media_) {
589 callee->AddAudioTrack("a");
590 }
591 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
592
593 // Create the answer according to the test parameters.
594 RTCOfferAnswerOptions options;
595 options.offer_to_receive_audio = offer_to_receive_;
596 auto answer = callee->CreateAnswer(options);
597
598 // The expected direction in the answer is the intersection of each side's
599 // capability to send/recv media.
600 // For the offerer, the direction is given in the offer (offer_direction_).
601 // For the answerer, the direction has two components:
602 // 1. Send if the answerer has a local track to send.
603 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
604 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800605 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
606 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700607
608 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800609 bool negotiate_send = (send_media_ && offer_recv);
610 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700611
612 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800613 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700614 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800615 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700616}
617
618// Tests that the media section is rejected if and only if the callee has no
619// local media track and has set offer_to_receive to 0, no matter which
620// direction the caller indicated in the offer.
621TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800622 if (IsUnifiedPlan() &&
623 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
624 // offer_to_receive_ is not implemented when creating answers with Unified
625 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800626 return;
627 }
Steve Anton22da89f2018-01-25 13:58:07 -0800628
Steve Anton8d3444d2017-10-20 15:30:51 -0700629 auto caller = CreatePeerConnection();
630 caller->AddAudioTrack("a");
631
632 // Create the offer with an audio section and set its direction.
633 auto offer = caller->CreateOffer();
634 cricket::GetFirstAudioContentDescription(offer->description())
635 ->set_direction(offer_direction_);
636
637 auto callee = CreatePeerConnection();
638 if (send_media_) {
639 callee->AddAudioTrack("a");
640 }
641 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
642
643 // Create the answer according to the test parameters.
644 RTCOfferAnswerOptions options;
645 options.offer_to_receive_audio = offer_to_receive_;
646 auto answer = callee->CreateAnswer(options);
647
648 // The media section is rejected if and only if offer_to_receive is explicitly
649 // set to 0 and there is no media to send.
650 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
651 ASSERT_TRUE(audio_content);
652 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
653}
654
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100655INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
656 PeerConnectionMediaAnswerDirectionTest,
657 Combine(Values(SdpSemantics::kPlanB,
658 SdpSemantics::kUnifiedPlan),
659 Values(RtpTransceiverDirection::kInactive,
660 RtpTransceiverDirection::kSendOnly,
661 RtpTransceiverDirection::kRecvOnly,
662 RtpTransceiverDirection::kSendRecv),
663 Bool(),
664 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 15:30:51 -0700665
Steve Antonad7bffc2018-01-22 10:21:56 -0800666TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700667 auto caller = CreatePeerConnection();
668 caller->AddVideoTrack("v");
669
670 RTCOfferAnswerOptions options;
671 options.offer_to_receive_audio = 1;
672 options.offer_to_receive_video = 0;
673 auto offer = caller->CreateOffer(options);
674
Steve Anton4e70a722017-11-28 14:57:10 -0800675 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800676 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800677 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800678 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700679}
680
Steve Antonad7bffc2018-01-22 10:21:56 -0800681TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800682 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800683 // offer_to_receive_ is not implemented when creating answers with Unified
684 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800685 return;
686 }
687
Steve Anton8d3444d2017-10-20 15:30:51 -0700688 auto caller = CreatePeerConnectionWithAudioVideo();
689 auto callee = CreatePeerConnection();
690 callee->AddVideoTrack("v");
691
692 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
693
694 RTCOfferAnswerOptions options;
695 options.offer_to_receive_audio = 1;
696 options.offer_to_receive_video = 0;
697 auto answer = callee->CreateAnswer(options);
698
Steve Anton4e70a722017-11-28 14:57:10 -0800699 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800700 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800701 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800702 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700703}
704
705void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
706 const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
707 const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
708
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100709 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700710 codecs.push_back(kComfortNoiseCodec8k);
711 codecs.push_back(kComfortNoiseCodec16k);
712 media_engine->SetAudioCodecs(codecs);
713}
714
715bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
716 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
717 for (const auto& codec : audio_desc->codecs()) {
718 if (codec.name == "CN") {
719 return true;
720 }
721 }
722 return false;
723}
724
Steve Antonad7bffc2018-01-22 10:21:56 -0800725TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700726 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
727 auto caller = CreatePeerConnectionWithAudioVideo();
728 AddComfortNoiseCodecsToSend(caller->media_engine());
729
730 RTCOfferAnswerOptions options;
731 options.voice_activity_detection = false;
732 auto offer = caller->CreateOffer(options);
733
734 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
735}
736
Steve Antonad7bffc2018-01-22 10:21:56 -0800737TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700738 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
739 auto caller = CreatePeerConnectionWithAudioVideo();
740 AddComfortNoiseCodecsToSend(caller->media_engine());
741 auto callee = CreatePeerConnectionWithAudioVideo();
742 AddComfortNoiseCodecsToSend(callee->media_engine());
743
744 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
745
746 RTCOfferAnswerOptions options;
747 options.voice_activity_detection = false;
748 auto answer = callee->CreateAnswer(options);
749
750 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
751}
752
753// The following test group verifies that we reject answers with invalid media
754// sections as per RFC 3264.
755
756class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800757 : public PeerConnectionMediaBaseTest,
758 public ::testing::WithParamInterface<std::tuple<
759 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700760 std::tuple<std::string,
761 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800762 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700763 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800764 PeerConnectionMediaInvalidMediaTest()
765 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
766 auto param = std::get<1>(GetParam());
767 mutator_ = std::get<1>(param);
768 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700769 }
770
771 std::function<void(cricket::SessionDescription*)> mutator_;
772 std::string expected_error_;
773};
774
775TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
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(caller->SetRemoteDescription(std::move(answer), &error));
786 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
787}
788
789TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
790 auto caller = CreatePeerConnectionWithAudioVideo();
791 auto callee = CreatePeerConnectionWithAudioVideo();
792
793 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
794
795 auto answer = callee->CreateAnswer();
796 mutator_(answer->description());
797
798 std::string error;
799 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
800 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
801}
802
803void RemoveVideoContent(cricket::SessionDescription* desc) {
804 auto content_name = cricket::GetFirstVideoContent(desc)->name;
805 desc->RemoveContentByName(content_name);
806 desc->RemoveTransportInfoByName(content_name);
807}
808
809void RenameVideoContent(cricket::SessionDescription* desc) {
810 auto* video_content = cricket::GetFirstVideoContent(desc);
811 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
812 video_content->name = "video_renamed";
813 transport_info->content_name = video_content->name;
814}
815
816void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -0800817 absl::c_reverse(desc->contents());
818 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -0700819}
820
821void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800822 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
823 desc->RemoveContentByName(audio_mid);
824 auto* video_content = cricket::GetFirstVideoContent(desc);
825 desc->AddContent(audio_mid, video_content->type,
Steve Antonb1c1de12017-12-21 15:14:30 -0800826 video_content->media_description()->Copy());
Steve Anton8d3444d2017-10-20 15:30:51 -0700827}
828
829constexpr char kMLinesOutOfOrder[] =
830 "The order of m-lines in answer doesn't match order in offer. Rejecting "
831 "answer.";
832
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100833INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -0700834 PeerConnectionMediaTest,
835 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800836 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
837 Values(std::make_tuple("remove video",
838 RemoveVideoContent,
839 kMLinesOutOfOrder),
840 std::make_tuple("rename video",
841 RenameVideoContent,
842 kMLinesOutOfOrder),
843 std::make_tuple("reverse media sections",
844 ReverseMediaContent,
845 kMLinesOutOfOrder),
846 std::make_tuple("change audio type to video type",
847 ChangeMediaTypeAudioToVideo,
848 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700849
850// Test that the correct media engine send/recv streams are created when doing
851// a series of offer/answers where audio/video are both sent, then audio is
852// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800853TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800854 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800855 // offer_to_receive_ is not implemented when creating answers with Unified
856 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800857 return;
858 }
859
Steve Anton8d3444d2017-10-20 15:30:51 -0700860 RTCOfferAnswerOptions options_reject_video;
861 options_reject_video.offer_to_receive_audio =
862 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
863 options_reject_video.offer_to_receive_video = 0;
864
865 auto caller = CreatePeerConnection();
866 caller->AddAudioTrack("a");
867 caller->AddVideoTrack("v");
868 auto callee = CreatePeerConnection();
869
870 // Caller initially offers to send/recv audio and video.
871 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
872 // Callee accepts the audio as recv only but rejects the video.
873 ASSERT_TRUE(caller->SetRemoteDescription(
874 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
875
876 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
877 ASSERT_TRUE(caller_voice);
878 EXPECT_EQ(0u, caller_voice->recv_streams().size());
879 EXPECT_EQ(1u, caller_voice->send_streams().size());
880 auto caller_video = caller->media_engine()->GetVideoChannel(0);
881 EXPECT_FALSE(caller_video);
882
883 // Callee adds its own audio/video stream and offers to receive audio/video
884 // too.
885 callee->AddAudioTrack("a");
886 auto callee_video_track = callee->AddVideoTrack("v");
887 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
888 ASSERT_TRUE(
889 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
890
891 auto 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 auto callee_video = callee->media_engine()->GetVideoChannel(0);
896 ASSERT_TRUE(callee_video);
897 EXPECT_EQ(1u, callee_video->recv_streams().size());
898 EXPECT_EQ(1u, callee_video->send_streams().size());
899
900 // Callee removes video but keeps audio and rejects the video once again.
901 callee->pc()->RemoveTrack(callee_video_track);
902 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
903 ASSERT_TRUE(
904 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
905
906 callee_voice = callee->media_engine()->GetVoiceChannel(0);
907 ASSERT_TRUE(callee_voice);
908 EXPECT_EQ(1u, callee_voice->recv_streams().size());
909 EXPECT_EQ(1u, callee_voice->send_streams().size());
910 callee_video = callee->media_engine()->GetVideoChannel(0);
911 EXPECT_FALSE(callee_video);
912}
913
914// Test that the correct media engine send/recv streams are created when doing
915// a series of offer/answers where audio/video are both sent, then video is
916// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -0800917TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800918 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800919 // offer_to_receive_ is not implemented when creating answers with Unified
920 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800921 return;
922 }
923
Steve Anton8d3444d2017-10-20 15:30:51 -0700924 // Disable the bundling here. If the media is bundled on audio
925 // transport, then we can't reject the audio because switching the bundled
926 // transport is not currently supported.
927 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
928 RTCOfferAnswerOptions options_no_bundle;
929 options_no_bundle.use_rtp_mux = false;
930 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
931 options_reject_audio.offer_to_receive_audio = 0;
932 options_reject_audio.offer_to_receive_video =
933 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
934
935 auto caller = CreatePeerConnection();
936 caller->AddAudioTrack("a");
937 caller->AddVideoTrack("v");
938 auto callee = CreatePeerConnection();
939
940 // Caller initially offers to send/recv audio and video.
941 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
942 // Callee accepts the video as recv only but rejects the audio.
943 ASSERT_TRUE(caller->SetRemoteDescription(
944 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
945
946 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
947 EXPECT_FALSE(caller_voice);
948 auto caller_video = caller->media_engine()->GetVideoChannel(0);
949 ASSERT_TRUE(caller_video);
950 EXPECT_EQ(0u, caller_video->recv_streams().size());
951 EXPECT_EQ(1u, caller_video->send_streams().size());
952
953 // Callee adds its own audio/video stream and offers to receive audio/video
954 // too.
955 auto callee_audio_track = callee->AddAudioTrack("a");
956 callee->AddVideoTrack("v");
957 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
958 ASSERT_TRUE(caller->SetRemoteDescription(
959 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
960
961 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
962 ASSERT_TRUE(callee_voice);
963 EXPECT_EQ(1u, callee_voice->recv_streams().size());
964 EXPECT_EQ(1u, callee_voice->send_streams().size());
965 auto callee_video = callee->media_engine()->GetVideoChannel(0);
966 ASSERT_TRUE(callee_video);
967 EXPECT_EQ(1u, callee_video->recv_streams().size());
968 EXPECT_EQ(1u, callee_video->send_streams().size());
969
970 // Callee removes audio but keeps video and rejects the audio once again.
971 callee->pc()->RemoveTrack(callee_audio_track);
972 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
973 ASSERT_TRUE(
974 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
975
976 callee_voice = callee->media_engine()->GetVoiceChannel(0);
977 EXPECT_FALSE(callee_voice);
978 callee_video = callee->media_engine()->GetVideoChannel(0);
979 ASSERT_TRUE(callee_video);
980 EXPECT_EQ(1u, callee_video->recv_streams().size());
981 EXPECT_EQ(1u, callee_video->send_streams().size());
982}
983
984// Tests that if the underlying video encoder fails to be initialized (signaled
985// by failing to set send codecs), the PeerConnection signals the error to the
986// client.
Steve Antonad7bffc2018-01-22 10:21:56 -0800987TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700988 auto caller = CreatePeerConnectionWithAudioVideo();
989 auto callee = CreatePeerConnectionWithAudioVideo();
990
991 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
992
993 auto video_channel = caller->media_engine()->GetVideoChannel(0);
994 video_channel->set_fail_set_send_codecs(true);
995
996 std::string error;
997 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
998 &error));
999 EXPECT_EQ(
Steve Anton80dd7b52018-02-16 17:08:42 -08001000 "Failed to set remote answer sdp: Failed to set remote video description "
1001 "send parameters.",
Steve Anton8d3444d2017-10-20 15:30:51 -07001002 error);
1003}
1004
1005// Tests that if the underlying video encoder fails once then subsequent
1006// attempts at setting the local/remote description will also fail, even if
1007// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001008TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001009 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1010 auto caller = CreatePeerConnectionWithAudioVideo();
1011 auto callee = CreatePeerConnectionWithAudioVideo();
1012
1013 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1014
1015 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1016 video_channel->set_fail_set_send_codecs(true);
1017
1018 EXPECT_FALSE(
1019 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1020
1021 video_channel->set_fail_set_send_codecs(false);
1022
1023 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1024 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1025}
1026
1027void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001028 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001029 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001030 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001031 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001032 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001033 content->name = new_name;
1034 auto* transport = desc->GetTransportInfoByName(old_name);
1035 RTC_DCHECK(transport);
1036 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001037
1038 // Rename the content name in the BUNDLE group.
1039 cricket::ContentGroup new_bundle_group =
1040 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1041 new_bundle_group.RemoveContentName(old_name);
1042 new_bundle_group.AddContentName(new_name);
1043 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1044 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001045}
1046
1047// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001048TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001049 const std::string kAudioMid = "notdefault1";
1050 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001051
1052 auto caller = CreatePeerConnectionWithAudioVideo();
1053 auto callee = CreatePeerConnectionWithAudioVideo();
1054
1055 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001056 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1057 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001058 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1059
1060 auto answer = callee->CreateAnswer();
1061 EXPECT_EQ(kAudioMid,
1062 cricket::GetFirstAudioContent(answer->description())->name);
1063 EXPECT_EQ(kVideoMid,
1064 cricket::GetFirstVideoContent(answer->description())->name);
1065}
1066
1067// Test that if the callee creates a re-offer, the MIDs are the same as the
1068// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001069TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001070 const std::string kAudioMid = "notdefault1";
1071 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001072
1073 auto caller = CreatePeerConnectionWithAudioVideo();
1074 auto callee = CreatePeerConnectionWithAudioVideo();
1075
1076 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001077 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1078 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001079 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1080 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1081
1082 auto reoffer = callee->CreateOffer();
1083 EXPECT_EQ(kAudioMid,
1084 cricket::GetFirstAudioContent(reoffer->description())->name);
1085 EXPECT_EQ(kVideoMid,
1086 cricket::GetFirstVideoContent(reoffer->description())->name);
1087}
1088
Steve Anton06817cd2018-12-18 15:55:30 -08001089// Test that SetRemoteDescription returns an error if there are two m= sections
1090// with the same MID value.
1091TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1092 auto caller = CreatePeerConnectionWithAudioVideo();
1093 auto callee = CreatePeerConnectionWithAudioVideo();
1094
1095 auto offer = caller->CreateOffer();
1096 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1097 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1098
1099 std::string error;
1100 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1101 EXPECT_EQ(error,
1102 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1103}
1104
Steve Antonad7bffc2018-01-22 10:21:56 -08001105TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001106 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1107 RTCConfiguration config;
1108 config.combined_audio_video_bwe.emplace(true);
1109 auto caller = CreatePeerConnectionWithAudioVideo(config);
1110
1111 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1112
1113 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1114 ASSERT_TRUE(caller_voice);
1115 const cricket::AudioOptions& audio_options = caller_voice->options();
1116 EXPECT_EQ(config.combined_audio_video_bwe,
1117 audio_options.combined_audio_video_bwe);
1118}
1119
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001120TEST_P(PeerConnectionMediaTest, MediaTransportPropagatedToVoiceEngine) {
1121 RTCConfiguration config;
1122
1123 // Setup PeerConnection to use media transport.
1124 config.use_media_transport = true;
1125
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001126 // Force SDES.
1127 config.enable_dtls_srtp = false;
1128
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001129 auto caller = CreatePeerConnectionWithAudio(config);
1130 auto callee = CreatePeerConnectionWithAudio(config);
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001131
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 // Make sure media transport is propagated to voice channel.
1142 FakeMediaTransport* caller_voice_media_transport =
1143 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1144 FakeMediaTransport* callee_voice_media_transport =
1145 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1146 ASSERT_NE(nullptr, caller_voice_media_transport);
1147 ASSERT_NE(nullptr, callee_voice_media_transport);
1148
1149 // Make sure media transport is created with correct is_caller.
1150 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1151 EXPECT_FALSE(callee_voice_media_transport->is_caller());
1152
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001153 // TODO(sukhanov): Propagate media transport to video channel.
1154 // This test does NOT set up video channels, because currently it causes
1155 // us to create two media transports.
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001156}
1157
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001158TEST_P(PeerConnectionMediaTest, MediaTransportOnlyForDataChannels) {
1159 RTCConfiguration config;
1160
1161 // Setup PeerConnection to use media transport for data channels.
1162 config.use_media_transport_for_data_channels = true;
1163
1164 // Force SDES.
1165 config.enable_dtls_srtp = false;
1166
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001167 auto caller = CreatePeerConnectionWithAudio(config);
1168 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001169
1170 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1171 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1172
1173 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1174 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1175 ASSERT_TRUE(caller_voice);
1176 ASSERT_TRUE(callee_voice);
1177
1178 // Make sure media transport is not propagated to voice channel.
1179 EXPECT_EQ(nullptr, caller_voice->media_transport());
1180 EXPECT_EQ(nullptr, callee_voice->media_transport());
1181}
1182
1183TEST_P(PeerConnectionMediaTest, MediaTransportForMediaAndDataChannels) {
1184 RTCConfiguration config;
1185
1186 // Setup PeerConnection to use media transport for both media and data
1187 // channels.
1188 config.use_media_transport = true;
1189 config.use_media_transport_for_data_channels = true;
1190
1191 // Force SDES.
1192 config.enable_dtls_srtp = false;
1193
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -08001194 auto caller = CreatePeerConnectionWithAudio(config);
1195 auto callee = CreatePeerConnectionWithAudio(config);
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001196
1197 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1198 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1199
1200 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1201 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1202 ASSERT_TRUE(caller_voice);
1203 ASSERT_TRUE(callee_voice);
1204
1205 // Make sure media transport is propagated to voice channel.
1206 FakeMediaTransport* caller_voice_media_transport =
1207 static_cast<FakeMediaTransport*>(caller_voice->media_transport());
1208 FakeMediaTransport* callee_voice_media_transport =
1209 static_cast<FakeMediaTransport*>(callee_voice->media_transport());
1210 ASSERT_NE(nullptr, caller_voice_media_transport);
1211 ASSERT_NE(nullptr, callee_voice_media_transport);
1212
1213 // Make sure media transport is created with correct is_caller.
1214 EXPECT_TRUE(caller_voice_media_transport->is_caller());
1215 EXPECT_FALSE(callee_voice_media_transport->is_caller());
Bjorn Mellema9bbd862018-11-02 09:07:48 -07001216}
1217
Anton Sukhanov98a462c2018-10-17 13:15:42 -07001218TEST_P(PeerConnectionMediaTest, MediaTransportNotPropagatedToVoiceEngine) {
1219 auto caller = CreatePeerConnectionWithAudioVideo();
1220 auto callee = CreatePeerConnectionWithAudioVideo();
1221
1222 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1223 auto answer = callee->CreateAnswer();
1224 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
1225
1226 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1227 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1228 ASSERT_TRUE(caller_voice);
1229 ASSERT_TRUE(callee_voice);
1230
1231 // Since we did not setup PeerConnection to use media transport, media
1232 // transport should not be created / propagated to the voice engine.
1233 ASSERT_EQ(nullptr, caller_voice->media_transport());
1234 ASSERT_EQ(nullptr, callee_voice->media_transport());
1235
1236 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1237 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1238 ASSERT_EQ(nullptr, caller_video->media_transport());
1239 ASSERT_EQ(nullptr, callee_video->media_transport());
1240}
1241
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001242INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
1243 PeerConnectionMediaTest,
1244 Values(SdpSemantics::kPlanB,
1245 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08001246
Steve Anton8d3444d2017-10-20 15:30:51 -07001247} // namespace webrtc