blob: 3058238a6a0d4d186bce1376186eff24b2d1bad7 [file] [log] [blame]
Steve Antondcc3c022017-12-22 16:02:54 -08001/*
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#include "api/audio_codecs/builtin_audio_decoder_factory.h"
12#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Anders Carlssonb3306882018-05-14 10:11:42 +020013#include "api/video_codecs/builtin_video_decoder_factory.h"
14#include "api/video_codecs/builtin_video_encoder_factory.h"
Steve Antonfa2260d2017-12-28 16:38:23 -080015#include "media/engine/webrtcmediaengine.h"
16#include "modules/audio_processing/include/audio_processing.h"
Steve Antondcc3c022017-12-22 16:02:54 -080017#include "pc/mediasession.h"
Steve Antonfa2260d2017-12-28 16:38:23 -080018#include "pc/peerconnectionfactory.h"
Steve Antondcc3c022017-12-22 16:02:54 -080019#include "pc/peerconnectionwrapper.h"
20#include "pc/sdputils.h"
21#ifdef WEBRTC_ANDROID
22#include "pc/test/androidtestinitializer.h"
23#endif
24#include "pc/test/fakeaudiocapturemodule.h"
Steve Antonfa2260d2017-12-28 16:38:23 -080025#include "pc/test/fakesctptransport.h"
Steve Antondcc3c022017-12-22 16:02:54 -080026#include "rtc_base/gunit.h"
27#include "rtc_base/ptr_util.h"
28#include "rtc_base/virtualsocketserver.h"
29#include "test/gmock.h"
30
31// This file contains tests that ensure the PeerConnection's implementation of
32// CreateOffer/CreateAnswer/SetLocalDescription/SetRemoteDescription conform
33// to the JavaScript Session Establishment Protocol (JSEP).
34// For now these semantics are only available when configuring the
35// PeerConnection with Unified Plan, but eventually that will be the default.
36
37namespace webrtc {
38
39using cricket::MediaContentDescription;
40using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
41using ::testing::Values;
42using ::testing::Combine;
43using ::testing::ElementsAre;
Steve Antonef65ef12018-01-10 17:15:20 -080044using ::testing::UnorderedElementsAre;
Steve Antondcc3c022017-12-22 16:02:54 -080045
Steve Antonfa2260d2017-12-28 16:38:23 -080046class PeerConnectionFactoryForJsepTest : public PeerConnectionFactory {
47 public:
48 PeerConnectionFactoryForJsepTest()
Anders Carlssonb3306882018-05-14 10:11:42 +020049 : PeerConnectionFactory(rtc::Thread::Current(),
50 rtc::Thread::Current(),
51 rtc::Thread::Current(),
52 cricket::WebRtcMediaEngineFactory::Create(
53 rtc::scoped_refptr<AudioDeviceModule>(
54 FakeAudioCaptureModule::Create()),
55 CreateBuiltinAudioEncoderFactory(),
56 CreateBuiltinAudioDecoderFactory(),
57 CreateBuiltinVideoEncoderFactory(),
58 CreateBuiltinVideoDecoderFactory(),
59 nullptr,
60 AudioProcessingBuilder().Create()),
61 CreateCallFactory(),
62 nullptr) {}
Steve Antonfa2260d2017-12-28 16:38:23 -080063
64 std::unique_ptr<cricket::SctpTransportInternalFactory>
65 CreateSctpTransportInternalFactory() {
66 return rtc::MakeUnique<FakeSctpTransportFactory>();
67 }
68};
69
Steve Antondcc3c022017-12-22 16:02:54 -080070class PeerConnectionJsepTest : public ::testing::Test {
71 protected:
72 typedef std::unique_ptr<PeerConnectionWrapper> WrapperPtr;
73
74 PeerConnectionJsepTest()
75 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
76#ifdef WEBRTC_ANDROID
77 InitializeAndroidObjects();
78#endif
Steve Antondcc3c022017-12-22 16:02:54 -080079 }
80
81 WrapperPtr CreatePeerConnection() {
82 RTCConfiguration config;
83 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
84 return CreatePeerConnection(config);
85 }
86
87 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Steve Antonfa2260d2017-12-28 16:38:23 -080088 rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
89 new rtc::RefCountedObject<PeerConnectionFactoryForJsepTest>());
90 RTC_CHECK(pc_factory->Initialize());
Steve Antondcc3c022017-12-22 16:02:54 -080091 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
Steve Antonfa2260d2017-12-28 16:38:23 -080092 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
93 observer.get());
Steve Antondcc3c022017-12-22 16:02:54 -080094 if (!pc) {
95 return nullptr;
96 }
97
Steve Antonfa2260d2017-12-28 16:38:23 -080098 return rtc::MakeUnique<PeerConnectionWrapper>(pc_factory, pc,
Steve Antondcc3c022017-12-22 16:02:54 -080099 std::move(observer));
100 }
101
102 std::unique_ptr<rtc::VirtualSocketServer> vss_;
103 rtc::AutoSocketServerThread main_;
Steve Antondcc3c022017-12-22 16:02:54 -0800104};
105
106// Tests for JSEP initial offer generation.
107
108// Test that an offer created by a PeerConnection with no transceivers generates
109// no media sections.
110TEST_F(PeerConnectionJsepTest, EmptyInitialOffer) {
111 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800112
Steve Antondcc3c022017-12-22 16:02:54 -0800113 auto offer = caller->CreateOffer();
Steve Antonfa2260d2017-12-28 16:38:23 -0800114 ASSERT_EQ(0u, offer->description()->contents().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800115}
116
117// Test that an initial offer with one audio track generates one audio media
118// section.
119TEST_F(PeerConnectionJsepTest, AudioOnlyInitialOffer) {
120 auto caller = CreatePeerConnection();
121 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antondcc3c022017-12-22 16:02:54 -0800122
Steve Antonfa2260d2017-12-28 16:38:23 -0800123 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800124 auto contents = offer->description()->contents();
125 ASSERT_EQ(1u, contents.size());
126 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[0].media_description()->type());
127}
128
129// Test than an initial offer with one video track generates one video media
130// section
131TEST_F(PeerConnectionJsepTest, VideoOnlyInitialOffer) {
132 auto caller = CreatePeerConnection();
133 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antondcc3c022017-12-22 16:02:54 -0800134
Steve Antonfa2260d2017-12-28 16:38:23 -0800135 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800136 auto contents = offer->description()->contents();
137 ASSERT_EQ(1u, contents.size());
138 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
139}
140
Steve Antonfa2260d2017-12-28 16:38:23 -0800141// Test that an initial offer with one data channel generates one data media
142// section.
143TEST_F(PeerConnectionJsepTest, DataOnlyInitialOffer) {
144 auto caller = CreatePeerConnection();
145 caller->CreateDataChannel("dc");
146
147 auto offer = caller->CreateOffer();
148 auto contents = offer->description()->contents();
149 ASSERT_EQ(1u, contents.size());
150 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
151}
152
153// Test that creating multiple data channels only results in one data section
154// generated in the offer.
155TEST_F(PeerConnectionJsepTest, MultipleDataChannelsCreateOnlyOneDataSection) {
156 auto caller = CreatePeerConnection();
157 caller->CreateDataChannel("first");
158 caller->CreateDataChannel("second");
159 caller->CreateDataChannel("third");
160
161 auto offer = caller->CreateOffer();
162 ASSERT_EQ(1u, offer->description()->contents().size());
163}
164
Steve Antondcc3c022017-12-22 16:02:54 -0800165// Test that multiple media sections in the initial offer are ordered in the
166// order the transceivers were added to the PeerConnection. This is required by
167// JSEP section 5.2.1.
168TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferOrderedCorrectly) {
169 auto caller = CreatePeerConnection();
170 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
171 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
172 RtpTransceiverInit init;
173 init.direction = RtpTransceiverDirection::kSendOnly;
174 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init);
Steve Antondcc3c022017-12-22 16:02:54 -0800175
Steve Antonfa2260d2017-12-28 16:38:23 -0800176 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800177 auto contents = offer->description()->contents();
178 ASSERT_EQ(3u, contents.size());
179
180 const MediaContentDescription* media_description1 =
181 contents[0].media_description();
182 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description1->type());
183 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
184 media_description1->direction());
185
186 const MediaContentDescription* media_description2 =
187 contents[1].media_description();
188 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, media_description2->type());
189 EXPECT_EQ(RtpTransceiverDirection::kSendRecv,
190 media_description2->direction());
191
192 const MediaContentDescription* media_description3 =
193 contents[2].media_description();
194 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, media_description3->type());
195 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
196 media_description3->direction());
197}
198
199// Test that media sections in the initial offer have different mids.
200TEST_F(PeerConnectionJsepTest, MediaSectionsInInitialOfferHaveDifferentMids) {
201 auto caller = CreatePeerConnection();
202 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
203 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800204
Steve Antondcc3c022017-12-22 16:02:54 -0800205 auto offer = caller->CreateOffer();
Steve Antondcc3c022017-12-22 16:02:54 -0800206 auto contents = offer->description()->contents();
207 ASSERT_EQ(2u, contents.size());
208 EXPECT_NE(contents[0].name, contents[1].name);
209}
210
211TEST_F(PeerConnectionJsepTest,
212 StoppedTransceiverHasNoMediaSectionInInitialOffer) {
213 auto caller = CreatePeerConnection();
214 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
215 transceiver->Stop();
216
217 auto offer = caller->CreateOffer();
218 EXPECT_EQ(0u, offer->description()->contents().size());
219}
220
221// Tests for JSEP SetLocalDescription with a local offer.
222
223TEST_F(PeerConnectionJsepTest, SetLocalEmptyOfferCreatesNoTransceivers) {
224 auto caller = CreatePeerConnection();
Steve Antonfa2260d2017-12-28 16:38:23 -0800225
Steve Antondcc3c022017-12-22 16:02:54 -0800226 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
227
228 EXPECT_THAT(caller->pc()->GetTransceivers(), ElementsAre());
229 EXPECT_THAT(caller->pc()->GetSenders(), ElementsAre());
230 EXPECT_THAT(caller->pc()->GetReceivers(), ElementsAre());
231}
232
233TEST_F(PeerConnectionJsepTest, SetLocalOfferSetsTransceiverMid) {
234 auto caller = CreatePeerConnection();
235 auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
236 auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
237
238 auto offer = caller->CreateOffer();
239 std::string audio_mid = offer->description()->contents()[0].name;
240 std::string video_mid = offer->description()->contents()[1].name;
241
242 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
243
244 EXPECT_EQ(audio_mid, audio_transceiver->mid());
245 EXPECT_EQ(video_mid, video_transceiver->mid());
246}
247
248// Tests for JSEP SetRemoteDescription with a remote offer.
249
250// Test that setting a remote offer with sendrecv audio and video creates two
251// transceivers, one for receiving audio and one for receiving video.
252TEST_F(PeerConnectionJsepTest, SetRemoteOfferCreatesTransceivers) {
253 auto caller = CreatePeerConnection();
254 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
255 auto caller_video = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
256 auto callee = CreatePeerConnection();
257
258 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
259
260 auto transceivers = callee->pc()->GetTransceivers();
261 ASSERT_EQ(2u, transceivers.size());
Steve Anton69470252018-02-09 11:43:08 -0800262 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800263 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
264 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton69470252018-02-09 11:43:08 -0800265 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800266 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
267 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
268}
269
270// Test that setting a remote offer with an audio track will reuse the
271// transceiver created for a local audio track added by AddTrack.
272// This is specified in JSEP section 5.10 (Applying a Remote Description). The
273// intent is to preserve backwards compatibility with clients who only use the
274// AddTrack API.
275TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
276 auto caller = CreatePeerConnection();
277 caller->AddAudioTrack("a");
278 auto caller_audio = caller->pc()->GetTransceivers()[0];
279 auto callee = CreatePeerConnection();
280 callee->AddAudioTrack("a");
281
282 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
283
284 auto transceivers = callee->pc()->GetTransceivers();
285 ASSERT_EQ(1u, transceivers.size());
286 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
287 transceivers[0]->receiver()->track()->kind());
288 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
289}
290
291// Test that setting a remote offer with an audio track marked sendonly will not
292// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
293// be reused if the offer direction is sendrecv or recvonly.
294TEST_F(PeerConnectionJsepTest,
295 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
296 auto caller = CreatePeerConnection();
297 caller->AddAudioTrack("a");
298 auto caller_audio = caller->pc()->GetTransceivers()[0];
299 caller_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
300 auto callee = CreatePeerConnection();
301 callee->AddAudioTrack("a");
302
303 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
304
305 auto transceivers = callee->pc()->GetTransceivers();
306 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200307 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800308 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
309}
310
311// Test that setting a remote offer with an audio track will not reuse a
312// transceiver added by AddTransceiver. The logic for reusing a transceiver is
313// specific to those added by AddTrack and is tested above.
314TEST_F(PeerConnectionJsepTest,
315 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
316 auto caller = CreatePeerConnection();
317 caller->AddAudioTrack("a");
318 auto callee = CreatePeerConnection();
319 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
320
321 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
322
323 auto transceivers = callee->pc()->GetTransceivers();
324 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200325 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800326 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
327 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
328 transceivers[1]->receiver()->track()->kind());
329}
330
331// Test that setting a remote offer with an audio track will not reuse a
332// transceiver created for a local video track added by AddTrack.
333TEST_F(PeerConnectionJsepTest,
334 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
335 auto caller = CreatePeerConnection();
336 caller->AddAudioTrack("a");
337 auto callee = CreatePeerConnection();
338 auto video_sender = callee->AddVideoTrack("v");
339
340 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
341
342 auto transceivers = callee->pc()->GetTransceivers();
343 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200344 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800345 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
346 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
347 transceivers[1]->receiver()->track()->kind());
348}
349
350// Test that setting a remote offer with an audio track will not reuse a
351// stopped transceiver.
352TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
353 auto caller = CreatePeerConnection();
354 caller->AddAudioTrack("a");
355 auto callee = CreatePeerConnection();
356 callee->AddAudioTrack("a");
357 callee->pc()->GetTransceivers()[0]->Stop();
358
359 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
360
361 auto transceivers = callee->pc()->GetTransceivers();
362 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200363 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800364 EXPECT_TRUE(transceivers[0]->stopped());
365 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
366 EXPECT_FALSE(transceivers[1]->stopped());
367}
368
369// Test that audio and video transceivers created on the remote side with
370// AddTrack will all be reused if there is the same number of audio/video tracks
371// in the remote offer. Additionally, this tests that transceivers are
372// successfully matched even if they are in a different order on the remote
373// side.
374TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
375 auto caller = CreatePeerConnection();
376 caller->AddVideoTrack("v");
377 caller->AddAudioTrack("a");
378 auto callee = CreatePeerConnection();
379 callee->AddAudioTrack("a");
380 callee->AddVideoTrack("v");
381
382 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
383
384 auto caller_transceivers = caller->pc()->GetTransceivers();
385 auto callee_transceivers = callee->pc()->GetTransceivers();
386 ASSERT_EQ(2u, callee_transceivers.size());
387 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
388 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
389}
390
391// Tests for JSEP initial CreateAnswer.
392
393// Test that the answer to a remote offer creates media sections for each
394// offered media in the same order and with the same mids.
395TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
396 auto caller = CreatePeerConnection();
397 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
398 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
399 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800400 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800401 auto callee = CreatePeerConnection();
402
Steve Antonfa2260d2017-12-28 16:38:23 -0800403 auto offer = caller->CreateOffer();
404 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
405 ASSERT_TRUE(
406 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
407 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800408
409 auto answer = callee->CreateAnswer();
410 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800411 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800412 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800413 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800414 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800415 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800417 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
418 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
419 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800420}
421
422// Test that an answering media section is marked as rejected if the underlying
423// transceiver has been stopped.
424TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
425 auto caller = CreatePeerConnection();
426 caller->AddAudioTrack("a");
427 auto callee = CreatePeerConnection();
428
429 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
430
431 callee->pc()->GetTransceivers()[0]->Stop();
432
433 auto answer = callee->CreateAnswer();
434 auto contents = answer->description()->contents();
435 ASSERT_EQ(1u, contents.size());
436 EXPECT_TRUE(contents[0].rejected);
437}
438
439// Test that CreateAnswer will generate media sections which will only send or
440// receive if the offer indicates it can do the reciprocating direction.
441// The full matrix is tested more extensively in MediaSession.
442TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
443 auto caller = CreatePeerConnection();
444 RtpTransceiverInit init;
445 init.direction = RtpTransceiverDirection::kSendOnly;
446 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
447 auto callee = CreatePeerConnection();
448 callee->AddAudioTrack("a");
449
450 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
451
452 auto answer = callee->CreateAnswer();
453 auto contents = answer->description()->contents();
454 ASSERT_EQ(1u, contents.size());
455 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
456 contents[0].media_description()->direction());
457}
458
459// Tests for JSEP SetLocalDescription with a local answer.
460// Note that these test only the additional behaviors not covered by
461// SetLocalDescription with a local offer.
462
463// Test that SetLocalDescription with an answer sets the current_direction
464// property of the transceivers mentioned in the session description.
465TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
466 auto caller = CreatePeerConnection();
467 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
468 caller_audio->SetDirection(RtpTransceiverDirection::kRecvOnly);
469 auto callee = CreatePeerConnection();
470 callee->AddAudioTrack("a");
471
472 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
473 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
474
475 auto transceivers = callee->pc()->GetTransceivers();
476 ASSERT_EQ(1u, transceivers.size());
477 // Since the offer was recvonly and the transceiver direction is sendrecv,
478 // the negotiated direction will be sendonly.
479 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
480 transceivers[0]->current_direction());
481}
482
483// Tests for JSEP SetRemoteDescription with a remote answer.
484// Note that these test only the additional behaviors not covered by
485// SetRemoteDescription with a remote offer.
486
487TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
488 auto caller = CreatePeerConnection();
489 caller->AddAudioTrack("a");
490 auto callee = CreatePeerConnection();
491 callee->AddAudioTrack("a");
492 auto callee_audio = callee->pc()->GetTransceivers()[0];
493 callee_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
494
495 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
496 ASSERT_TRUE(
497 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
498
499 auto transceivers = caller->pc()->GetTransceivers();
500 ASSERT_EQ(1u, transceivers.size());
501 // Since the remote transceiver was set to sendonly, the negotiated direction
502 // in the answer would be sendonly which we apply as recvonly to the local
503 // transceiver.
504 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
505 transceivers[0]->current_direction());
506}
507
508// Tests for multiple round trips.
509
510// Test that setting a transceiver with the inactive direction does not stop it
511// on either the caller or the callee.
512TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
513 auto caller = CreatePeerConnection();
514 caller->AddAudioTrack("a");
515 auto callee = CreatePeerConnection();
516 callee->AddAudioTrack("a");
517 callee->pc()->GetTransceivers()[0]->SetDirection(
518 RtpTransceiverDirection::kInactive);
519
520 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
521 ASSERT_TRUE(
522 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
523
524 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
525 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
526}
527
528// Test that if a transceiver had been associated and later stopped, then a
529// media section is still generated for it and the media section is marked as
530// rejected.
531TEST_F(PeerConnectionJsepTest,
532 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
533 auto caller = CreatePeerConnection();
534 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
535 auto callee = CreatePeerConnection();
536
537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
538 ASSERT_TRUE(
539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
540
541 ASSERT_TRUE(transceiver->mid());
542 transceiver->Stop();
543
544 auto reoffer = caller->CreateOffer();
545 auto contents = reoffer->description()->contents();
546 ASSERT_EQ(1u, contents.size());
547 EXPECT_TRUE(contents[0].rejected);
548}
549
550// Test that stopping an associated transceiver on the caller side will stop the
551// corresponding transceiver on the remote side when the remote offer is
552// applied.
553TEST_F(PeerConnectionJsepTest,
554 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
555 auto caller = CreatePeerConnection();
556 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
557 auto callee = CreatePeerConnection();
558
559 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
560 ASSERT_TRUE(
561 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
562
563 transceiver->Stop();
564
565 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
566
567 auto transceivers = callee->pc()->GetTransceivers();
568 EXPECT_TRUE(transceivers[0]->stopped());
569 EXPECT_TRUE(transceivers[0]->mid());
570}
571
572// Test that CreateOffer will only generate a recycled media section if the
573// transceiver to be recycled has been seen stopped by the other side first.
574TEST_F(PeerConnectionJsepTest,
575 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
576 auto caller = CreatePeerConnection();
577 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
578 auto callee = CreatePeerConnection();
579
580 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
581 ASSERT_TRUE(
582 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
583
584 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
585 first_transceiver->Stop();
586
587 auto reoffer = caller->CreateOffer();
588 auto contents = reoffer->description()->contents();
589 ASSERT_EQ(2u, contents.size());
590 EXPECT_TRUE(contents[0].rejected);
591 EXPECT_FALSE(contents[1].rejected);
592}
593
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800594// Test that the offer/answer and the transceivers are correctly generated and
595// updated when the media section is recycled after the callee stops a
596// transceiver and sends an answer with a 0 port.
597TEST_F(PeerConnectionJsepTest,
598 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
599 auto caller = CreatePeerConnection();
600 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
601 auto callee = CreatePeerConnection();
602
603 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
604 callee->pc()->GetTransceivers()[0]->Stop();
605 ASSERT_TRUE(
606 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
607 EXPECT_TRUE(first_transceiver->stopped());
608 // First transceivers aren't dissociated yet.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200609 ASSERT_NE(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800610 std::string first_mid = *first_transceiver->mid();
611 EXPECT_EQ(first_mid, callee->pc()->GetTransceivers()[0]->mid());
612
613 // New offer exchange with new transceivers that recycles the m section
614 // correctly.
615 caller->AddAudioTrack("audio2");
616 callee->AddAudioTrack("audio2");
617 auto offer = caller->CreateOffer();
618 auto offer_contents = offer->description()->contents();
619 std::string second_mid = offer_contents[0].name;
620 ASSERT_EQ(1u, offer_contents.size());
621 EXPECT_FALSE(offer_contents[0].rejected);
622 EXPECT_NE(first_mid, second_mid);
623
624 // Setting the offer on each side will dissociate the first transceivers and
625 // associate the new transceivers.
626 ASSERT_TRUE(
627 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200628 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800629 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[1]->mid());
630 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200631 EXPECT_EQ(absl::nullopt, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800632 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[1]->mid());
633
634 // The new answer should also recycle the m section correctly.
635 auto answer = callee->CreateAnswer();
636 auto answer_contents = answer->description()->contents();
637 ASSERT_EQ(1u, answer_contents.size());
638 EXPECT_FALSE(answer_contents[0].rejected);
639 EXPECT_EQ(second_mid, answer_contents[0].name);
640
641 // Finishing the negotiation shouldn't add or dissociate any transceivers.
642 ASSERT_TRUE(
643 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
644 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
645 auto caller_transceivers = caller->pc()->GetTransceivers();
646 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200647 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800648 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
649 auto callee_transceivers = callee->pc()->GetTransceivers();
650 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200651 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800652 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
653}
654
655// Test that creating/setting a local offer that recycles an m= section is
656// idempotent.
657TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
658 // Do a negotiation with a port 0 for the media section.
659 auto caller = CreatePeerConnection();
660 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
661 auto callee = CreatePeerConnection();
662 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
663 first_transceiver->Stop();
664 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
665 caller->AddAudioTrack("audio2");
666
667 // Create a new offer that recycles the media section and set it as a local
668 // description.
669 auto offer = caller->CreateOffer();
670 auto offer_contents = offer->description()->contents();
671 ASSERT_EQ(1u, offer_contents.size());
672 EXPECT_FALSE(offer_contents[0].rejected);
673 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
674 EXPECT_FALSE(caller->pc()->GetTransceivers()[1]->stopped());
675 std::string second_mid = offer_contents[0].name;
676
677 // Create another new offer and set the local description again without the
678 // rest of any negotation ocurring.
679 auto second_offer = caller->CreateOffer();
680 auto second_offer_contents = second_offer->description()->contents();
681 ASSERT_EQ(1u, second_offer_contents.size());
682 EXPECT_FALSE(second_offer_contents[0].rejected);
683 // The mid shouldn't change.
684 EXPECT_EQ(second_mid, second_offer_contents[0].name);
685
686 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
687 // Make sure that the caller's transceivers are associated correctly.
688 auto caller_transceivers = caller->pc()->GetTransceivers();
689 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200690 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800691 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
692 EXPECT_FALSE(caller_transceivers[1]->stopped());
693}
694
Steve Antondcc3c022017-12-22 16:02:54 -0800695// Test that the offer/answer and transceivers for both the caller and callee
696// side are generated/updated correctly when recycling an audio/video media
697// section as a media section of either the same or opposite type.
698class RecycleMediaSectionTest
699 : public PeerConnectionJsepTest,
700 public testing::WithParamInterface<
701 std::tuple<cricket::MediaType, cricket::MediaType>> {
702 protected:
703 RecycleMediaSectionTest() {
704 first_type_ = std::get<0>(GetParam());
705 second_type_ = std::get<1>(GetParam());
706 }
707
708 cricket::MediaType first_type_;
709 cricket::MediaType second_type_;
710};
711
712TEST_P(RecycleMediaSectionTest, VerifyOfferAnswerAndTransceivers) {
713 auto caller = CreatePeerConnection();
714 auto first_transceiver = caller->AddTransceiver(first_type_);
715 auto callee = CreatePeerConnection();
716
717 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
718
719 std::string first_mid = *first_transceiver->mid();
720 first_transceiver->Stop();
721
722 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
723
724 auto second_transceiver = caller->AddTransceiver(second_type_);
725
726 // The offer should reuse the previous media section but allocate a new MID
727 // and change the media type.
728 auto offer = caller->CreateOffer();
729 auto offer_contents = offer->description()->contents();
730 ASSERT_EQ(1u, offer_contents.size());
731 EXPECT_FALSE(offer_contents[0].rejected);
732 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
733 std::string second_mid = offer_contents[0].name;
734 EXPECT_NE(first_mid, second_mid);
735
736 // Setting the local offer will dissociate the previous transceiver and set
737 // the MID for the new transceiver.
738 ASSERT_TRUE(
739 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200740 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800741 EXPECT_EQ(second_mid, second_transceiver->mid());
742
743 // Setting the remote offer will dissociate the previous transceiver and
744 // create a new transceiver for the media section.
745 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
746 auto callee_transceivers = callee->pc()->GetTransceivers();
747 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200748 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800749 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800750 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800751 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800752
753 // The answer should have only one media section for the new transceiver.
754 auto answer = callee->CreateAnswer();
755 auto answer_contents = answer->description()->contents();
756 ASSERT_EQ(1u, answer_contents.size());
757 EXPECT_FALSE(answer_contents[0].rejected);
758 EXPECT_EQ(second_mid, answer_contents[0].name);
759 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
760
761 // Setting the local answer should succeed.
762 ASSERT_TRUE(
763 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
764
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800765 // Setting the remote answer should succeed and not create any new
766 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800767 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800768 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
769 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800770}
771
772// Test all combinations of audio and video as the first and second media type
773// for the media section. This is needed for full test coverage because
774// MediaSession has separate functions for processing audio and video media
775// sections.
776INSTANTIATE_TEST_CASE_P(
777 PeerConnectionJsepTest,
778 RecycleMediaSectionTest,
779 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
780 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
781
Steve Antonfa2260d2017-12-28 16:38:23 -0800782// Test that a new data channel section will not reuse a recycleable audio or
783// video media section. Additionally, tests that the new section is added to the
784// end of the session description.
785TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
786 auto caller = CreatePeerConnection();
787 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
788 auto callee = CreatePeerConnection();
789
790 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
791
792 transceiver->Stop();
793
794 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
795
796 caller->CreateDataChannel("dc");
797
798 auto offer = caller->CreateOffer();
799 auto offer_contents = offer->description()->contents();
800 ASSERT_EQ(2u, offer_contents.size());
801 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
802 offer_contents[0].media_description()->type());
803 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
804 offer_contents[1].media_description()->type());
805
806 ASSERT_TRUE(
807 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
808 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
809
810 auto answer = callee->CreateAnswer();
811 auto answer_contents = answer->description()->contents();
812 ASSERT_EQ(2u, answer_contents.size());
813 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
814 answer_contents[0].media_description()->type());
815 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
816 answer_contents[1].media_description()->type());
817}
818
819// Test that if a new track is added to an existing session that has a data,
820// the new section comes at the end of the new offer, after the existing data
821// section.
822TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
823 auto caller = CreatePeerConnection();
824 caller->CreateDataChannel("dc");
825 auto callee = CreatePeerConnection();
826
827 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
828
829 caller->AddAudioTrack("a");
830
831 auto offer = caller->CreateOffer();
832 auto contents = offer->description()->contents();
833 ASSERT_EQ(2u, contents.size());
834 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
835 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
836}
837
Steve Antondcc3c022017-12-22 16:02:54 -0800838// Tests for MID properties.
839
840static void RenameSection(size_t mline_index,
841 const std::string& new_mid,
842 SessionDescriptionInterface* sdesc) {
843 cricket::SessionDescription* desc = sdesc->description();
844 std::string old_mid = desc->contents()[mline_index].name;
845 desc->contents()[mline_index].name = new_mid;
846 desc->transport_infos()[mline_index].content_name = new_mid;
847 const cricket::ContentGroup* bundle =
848 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
849 if (bundle) {
850 cricket::ContentGroup new_bundle = *bundle;
851 if (new_bundle.RemoveContentName(old_mid)) {
852 new_bundle.AddContentName(new_mid);
853 }
854 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
855 desc->AddGroup(new_bundle);
856 }
857}
858
859// Test that two PeerConnections can have a successful offer/answer exchange if
860// the MIDs are changed from the defaults.
861TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
862 constexpr char kFirstMid[] = "nondefaultmid";
863 constexpr char kSecondMid[] = "randommid";
864
865 auto caller = CreatePeerConnection();
866 caller->AddAudioTrack("a");
867 caller->AddAudioTrack("b");
868 auto callee = CreatePeerConnection();
869
870 auto offer = caller->CreateOffer();
871 RenameSection(0, kFirstMid, offer.get());
872 RenameSection(1, kSecondMid, offer.get());
873
874 ASSERT_TRUE(
875 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
876 auto caller_transceivers = caller->pc()->GetTransceivers();
877 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
878 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
879
880 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
881 auto callee_transceivers = callee->pc()->GetTransceivers();
882 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
883 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
884
885 auto answer = callee->CreateAnswer();
886 auto answer_contents = answer->description()->contents();
887 EXPECT_EQ(kFirstMid, answer_contents[0].name);
888 EXPECT_EQ(kSecondMid, answer_contents[1].name);
889
890 ASSERT_TRUE(
891 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
892 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
893}
894
895// Test that CreateOffer will generate a MID that is not already used if the
896// default it would have picked is already taken. This is tested by using a
897// third PeerConnection to determine what the default would be for the second
898// media section then setting that as the first media section's MID.
899TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
900 // First, find what the default MID is for the second media section.
901 auto pc = CreatePeerConnection();
902 pc->AddAudioTrack("a");
903 pc->AddAudioTrack("b");
904 auto default_offer = pc->CreateOffer();
905 std::string default_second_mid =
906 default_offer->description()->contents()[1].name;
907
908 // Now, do an offer/answer with one track which has the MID set to the default
909 // second MID.
910 auto caller = CreatePeerConnection();
911 caller->AddAudioTrack("a");
912 auto callee = CreatePeerConnection();
913
914 auto offer = caller->CreateOffer();
915 RenameSection(0, default_second_mid, offer.get());
916
917 ASSERT_TRUE(
918 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
919 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
920 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
921
922 // Add a second track and ensure that the MID is different.
923 caller->AddAudioTrack("b");
924
925 auto reoffer = caller->CreateOffer();
926 auto reoffer_contents = reoffer->description()->contents();
927 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
928 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
929}
930
Steve Antonfa2260d2017-12-28 16:38:23 -0800931// Test that if an audio or video section has the default data section MID, then
932// CreateOffer will generate a unique MID for the newly added data section.
933TEST_F(PeerConnectionJsepTest,
934 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
935 // First, find what the default MID is for the data channel.
936 auto pc = CreatePeerConnection();
937 pc->CreateDataChannel("dc");
938 auto default_offer = pc->CreateOffer();
939 std::string default_data_mid =
940 default_offer->description()->contents()[0].name;
941
942 // Now do an offer/answer with one audio track which has a MID set to the
943 // default data MID.
944 auto caller = CreatePeerConnection();
945 caller->AddAudioTrack("a");
946 auto callee = CreatePeerConnection();
947
948 auto offer = caller->CreateOffer();
949 RenameSection(0, default_data_mid, offer.get());
950
951 ASSERT_TRUE(
952 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
953 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
954 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
955
956 // Add a data channel and ensure that the MID is different.
957 caller->CreateDataChannel("dc");
958
959 auto reoffer = caller->CreateOffer();
960 auto reoffer_contents = reoffer->description()->contents();
961 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
962 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
963}
964
Steve Antondcc3c022017-12-22 16:02:54 -0800965// Test that a reoffer initiated by the callee adds a new track to the caller.
966TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
967 auto caller = CreatePeerConnection();
968 caller->AddAudioTrack("a");
969 auto callee = CreatePeerConnection();
970 callee->AddAudioTrack("a");
971 callee->AddVideoTrack("v");
972
973 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
974
975 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
976 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
977
978 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
979
980 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
981 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
982}
983
Steve Anton02ee47c2018-01-10 16:26:06 -0800984// Tests for MSID properties.
985
986// Test that adding a track with AddTrack results in an offer that signals the
987// track's ID.
988TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
989 const std::string kTrackId = "audio_track";
990
991 auto caller = CreatePeerConnection();
992 caller->AddAudioTrack(kTrackId);
993
994 auto offer = caller->CreateOffer();
995 auto contents = offer->description()->contents();
996 ASSERT_EQ(1u, contents.size());
997 auto streams = contents[0].media_description()->streams();
998 ASSERT_EQ(1u, streams.size());
999 EXPECT_EQ(kTrackId, streams[0].id);
1000}
1001
1002// Test that adding a track by calling AddTransceiver then SetTrack results in
1003// an offer that does not signal the track's ID and signals a random ID.
1004TEST_F(PeerConnectionJsepTest,
1005 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1006 const std::string kTrackId = "audio_track";
1007
1008 auto caller = CreatePeerConnection();
1009 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1010 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1011
1012 auto offer = caller->CreateOffer();
1013 auto contents = offer->description()->contents();
1014 ASSERT_EQ(1u, contents.size());
1015 auto streams = contents[0].media_description()->streams();
1016 ASSERT_EQ(1u, streams.size());
1017 EXPECT_NE(kTrackId, streams[0].id);
1018}
1019
Steve Anton5f94aa22018-02-01 10:58:30 -08001020// Test that if the transceiver is recvonly or inactive, then no MSID
1021// information is included in the offer.
1022TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1023 auto caller = CreatePeerConnection();
1024
1025 RtpTransceiverInit init_recvonly;
1026 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1027 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1028
1029 RtpTransceiverInit init_inactive;
1030 init_inactive.direction = RtpTransceiverDirection::kInactive;
1031 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1032
1033 auto offer = caller->CreateOffer();
1034 auto contents = offer->description()->contents();
1035 ASSERT_EQ(2u, contents.size());
1036 // MSID is specified in the first stream, so no streams means no MSID.
1037 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1038 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1039}
1040
1041// Test that if an answer negotiates transceiver directions of recvonly or
1042// inactive, then no MSID information is included in the answer.
1043TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1044 auto caller = CreatePeerConnection();
1045 auto callee = CreatePeerConnection();
1046
1047 // recvonly transceiver will get negotiated to inactive since the callee has
1048 // no tracks to send in response.
1049 RtpTransceiverInit init_recvonly;
1050 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1051 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1052
1053 // sendrecv transceiver will get negotiated to recvonly since the callee has
1054 // no tracks to send in response.
1055 RtpTransceiverInit init_sendrecv;
1056 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1057 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1058
1059 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1060
1061 auto answer = callee->CreateAnswer();
1062 auto contents = answer->description()->contents();
1063 ASSERT_EQ(2u, contents.size());
1064 // MSID is specified in the first stream, so no streams means no MSID.
1065 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1066 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1067}
1068
1069// Test that the MSID is included even if the transceiver direction has changed
1070// to inactive if the transceiver had previously sent media.
1071TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1072 auto caller = CreatePeerConnection();
1073 caller->AddAudioTrack("audio");
1074 auto callee = CreatePeerConnection();
1075 callee->AddAudioTrack("audio");
1076
1077 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1078
1079 caller->pc()->GetTransceivers()[0]->SetDirection(
1080 RtpTransceiverDirection::kInactive);
1081
1082 // The transceiver direction on both sides will turn to inactive.
1083 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1084
1085 auto* offer = callee->pc()->remote_description();
1086 auto offer_contents = offer->description()->contents();
1087 ASSERT_EQ(1u, offer_contents.size());
1088 // MSID is specified in the first stream. If it is present, assume that MSID
1089 // is there.
1090 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1091
1092 auto* answer = caller->pc()->remote_description();
1093 auto answer_contents = answer->description()->contents();
1094 ASSERT_EQ(1u, answer_contents.size());
1095 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1096}
1097
1098// Test that stopping a RtpTransceiver will cause future offers to not include
1099// any MSID information for that section.
1100TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1101 auto caller = CreatePeerConnection();
1102 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1103 auto callee = CreatePeerConnection();
1104
1105 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1106
1107 transceiver->Stop();
1108
1109 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1110
1111 auto* offer = callee->pc()->remote_description();
1112 auto offer_contents = offer->description()->contents();
1113 ASSERT_EQ(1u, offer_contents.size());
1114 // MSID is specified in the first stream, so no streams means no MSID.
1115 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1116}
1117
Steve Anton02ee47c2018-01-10 16:26:06 -08001118// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1119// has its ID set to the signaled track ID.
1120TEST_F(PeerConnectionJsepTest,
1121 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1122 const std::string kTrackId = "audio_track";
1123
1124 auto caller = CreatePeerConnection();
1125 auto callee = CreatePeerConnection();
1126 caller->AddAudioTrack(kTrackId);
1127
1128 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1129
1130 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1131 auto receiver = callee->pc()->GetReceivers()[0];
1132 EXPECT_EQ(kTrackId, receiver->id());
1133}
1134
1135// Test that if the callee RtpReceiver is reused by a call to
1136// SetRemoteDescription, its ID does not change.
1137TEST_F(PeerConnectionJsepTest,
1138 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1139 const std::string kTrackId = "audio_track";
1140
1141 auto caller = CreatePeerConnection();
1142 auto callee = CreatePeerConnection();
1143 caller->AddAudioTrack(kTrackId);
1144 callee->AddAudioTrack("dummy_track");
1145
1146 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1147 auto receiver = callee->pc()->GetReceivers()[0];
1148 std::string receiver_id = receiver->id();
1149
1150 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1151
1152 EXPECT_EQ(receiver_id, receiver->id());
1153}
1154
Steve Antonef65ef12018-01-10 17:15:20 -08001155// Test that setting a remote offer with one track that has no streams fires off
1156// the correct OnAddTrack event.
1157TEST_F(PeerConnectionJsepTest,
1158 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1159 const std::string kTrackLabel = "audio_track";
1160
1161 auto caller = CreatePeerConnection();
1162 auto callee = CreatePeerConnection();
1163 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1164
1165 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1166
Seth Hampson5b4f0752018-04-02 16:31:36 -07001167 const auto& track_events = callee->observer()->add_track_events_;
1168 ASSERT_EQ(1u, track_events.size());
1169 const auto& event = track_events[0];
1170 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1171 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001172}
1173
1174// Test that setting a remote offer with one track that has one stream fires off
1175// the correct OnAddTrack event.
1176TEST_F(PeerConnectionJsepTest,
1177 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1178 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001179 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001180
1181 auto caller = CreatePeerConnection();
1182 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001183 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001184
1185 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1186
1187 const auto& track_events = callee->observer()->add_track_events_;
1188 ASSERT_EQ(1u, track_events.size());
1189 const auto& event = track_events[0];
1190 ASSERT_EQ(1u, event.streams.size());
1191 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001192 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001193 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1194 ElementsAre(event.receiver->track()));
1195 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1196}
1197
1198// Test that setting a remote offer with two tracks that share the same stream
1199// fires off two OnAddTrack events, both with the same stream that has both
1200// tracks present at the time of firing. This is to ensure that track events are
1201// not fired until SetRemoteDescription has finished processing all the media
1202// sections.
1203TEST_F(PeerConnectionJsepTest,
1204 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1205 const std::string kTrack1Label = "audio_track1";
1206 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001207 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001208
1209 auto caller = CreatePeerConnection();
1210 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001211 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1212 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001213
1214 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1215
1216 const auto& track_events = callee->observer()->add_track_events_;
1217 ASSERT_EQ(2u, track_events.size());
1218 const auto& event1 = track_events[0];
1219 const auto& event2 = track_events[1];
1220 ASSERT_EQ(1u, event1.streams.size());
1221 auto stream = event1.streams[0];
1222 ASSERT_THAT(event2.streams, ElementsAre(stream));
1223 auto track1 = event1.receiver->track();
1224 auto track2 = event2.receiver->track();
1225 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1226 UnorderedElementsAre(track1, track2));
1227 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1228 UnorderedElementsAre(track1, track2));
1229}
1230
Seth Hampson5b4f0752018-04-02 16:31:36 -07001231// Test that setting a remote offer with one track that has two streams fires
1232// off the correct OnAddTrack event.
1233TEST_F(PeerConnectionJsepTest,
1234 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1235 const std::string kTrackLabel = "audio_track";
1236 const std::string kStreamId1 = "audio_stream1";
1237 const std::string kStreamId2 = "audio_stream2";
1238
1239 auto caller = CreatePeerConnection();
1240 auto callee = CreatePeerConnection();
1241 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1242
1243 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1244
1245 const auto& track_events = callee->observer()->add_track_events_;
1246 ASSERT_EQ(1u, track_events.size());
1247 const auto& event = track_events[0];
1248 ASSERT_EQ(2u, event.streams.size());
1249 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1250 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1251}
Steve Antonef65ef12018-01-10 17:15:20 -08001252
Steve Anton54b84072018-02-20 15:19:52 -08001253// Test that if an RtpTransceiver with a current_direction set is stopped, then
1254// current_direction is changed to null.
1255TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1256 auto caller = CreatePeerConnection();
1257 auto callee = CreatePeerConnection();
1258
1259 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1260
1261 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1262
1263 ASSERT_TRUE(transceiver->current_direction());
1264 transceiver->Stop();
1265 EXPECT_FALSE(transceiver->current_direction());
1266}
1267
Steve Antonba42e992018-04-09 14:10:01 -07001268// Test that you can't set an answer on a PeerConnection before setting the
1269// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001270TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1271 auto caller = CreatePeerConnection();
1272 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001273 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001274
1275 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1276
1277 RTCError error;
1278 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1279 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1280}
1281
1282// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1283// two video tracks.
1284TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1285 RTCConfiguration config_planb;
1286 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1287 auto caller = CreatePeerConnection(config_planb);
1288 auto callee = CreatePeerConnection();
1289 caller->AddVideoTrack("video1");
1290 caller->AddVideoTrack("video2");
1291
1292 RTCError error;
1293 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1294 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1295}
1296
1297// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1298// has two video tracks.
1299TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1300 auto caller = CreatePeerConnection();
1301 RTCConfiguration config_planb;
1302 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1303 auto callee = CreatePeerConnection(config_planb);
1304 caller->AddVideoTrack("video");
1305 callee->AddVideoTrack("video1");
1306 callee->AddVideoTrack("video2");
1307
1308 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1309
1310 RTCError error;
1311 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1312 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001313}
1314
Steve Antondcc3c022017-12-22 16:02:54 -08001315} // namespace webrtc