blob: 4cd379915a826514a951c96405feb447551a8532 [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 Anton1bc97162018-06-25 14:04:01 -0700262
Steve Anton69470252018-02-09 11:43:08 -0800263 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800264 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
265 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[0]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700266 EXPECT_EQ(0u, transceivers[0]->sender()->stream_ids().size());
267
Steve Anton69470252018-02-09 11:43:08 -0800268 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800269 EXPECT_EQ(caller_video->mid(), transceivers[1]->mid());
270 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly, transceivers[1]->direction());
Steve Anton1bc97162018-06-25 14:04:01 -0700271 EXPECT_EQ(0u, transceivers[1]->sender()->stream_ids().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800272}
273
274// Test that setting a remote offer with an audio track will reuse the
275// transceiver created for a local audio track added by AddTrack.
276// This is specified in JSEP section 5.10 (Applying a Remote Description). The
277// intent is to preserve backwards compatibility with clients who only use the
278// AddTrack API.
279TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiverFromAddTrack) {
280 auto caller = CreatePeerConnection();
281 caller->AddAudioTrack("a");
282 auto caller_audio = caller->pc()->GetTransceivers()[0];
283 auto callee = CreatePeerConnection();
284 callee->AddAudioTrack("a");
285
286 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
287
288 auto transceivers = callee->pc()->GetTransceivers();
289 ASSERT_EQ(1u, transceivers.size());
290 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
291 transceivers[0]->receiver()->track()->kind());
292 EXPECT_EQ(caller_audio->mid(), transceivers[0]->mid());
293}
294
295// Test that setting a remote offer with an audio track marked sendonly will not
296// reuse a transceiver created by AddTrack. JSEP only allows the transceiver to
297// be reused if the offer direction is sendrecv or recvonly.
298TEST_F(PeerConnectionJsepTest,
299 SetRemoteOfferDoesNotReuseTransceiverIfDirectionSendOnly) {
300 auto caller = CreatePeerConnection();
301 caller->AddAudioTrack("a");
302 auto caller_audio = caller->pc()->GetTransceivers()[0];
303 caller_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
304 auto callee = CreatePeerConnection();
305 callee->AddAudioTrack("a");
306
307 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
308
309 auto transceivers = callee->pc()->GetTransceivers();
310 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200311 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800312 EXPECT_EQ(caller_audio->mid(), transceivers[1]->mid());
313}
314
315// Test that setting a remote offer with an audio track will not reuse a
316// transceiver added by AddTransceiver. The logic for reusing a transceiver is
317// specific to those added by AddTrack and is tested above.
318TEST_F(PeerConnectionJsepTest,
319 SetRemoteOfferDoesNotReuseTransceiverFromAddTransceiver) {
320 auto caller = CreatePeerConnection();
321 caller->AddAudioTrack("a");
322 auto callee = CreatePeerConnection();
323 auto transceiver = callee->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
324
325 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
326
327 auto transceivers = callee->pc()->GetTransceivers();
328 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200329 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800330 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
331 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
332 transceivers[1]->receiver()->track()->kind());
333}
334
335// Test that setting a remote offer with an audio track will not reuse a
336// transceiver created for a local video track added by AddTrack.
337TEST_F(PeerConnectionJsepTest,
338 SetRemoteOfferDoesNotReuseTransceiverOfWrongType) {
339 auto caller = CreatePeerConnection();
340 caller->AddAudioTrack("a");
341 auto callee = CreatePeerConnection();
342 auto video_sender = callee->AddVideoTrack("v");
343
344 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
345
346 auto transceivers = callee->pc()->GetTransceivers();
347 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200348 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800349 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
350 EXPECT_EQ(MediaStreamTrackInterface::kAudioKind,
351 transceivers[1]->receiver()->track()->kind());
352}
353
354// Test that setting a remote offer with an audio track will not reuse a
355// stopped transceiver.
356TEST_F(PeerConnectionJsepTest, SetRemoteOfferDoesNotReuseStoppedTransceiver) {
357 auto caller = CreatePeerConnection();
358 caller->AddAudioTrack("a");
359 auto callee = CreatePeerConnection();
360 callee->AddAudioTrack("a");
361 callee->pc()->GetTransceivers()[0]->Stop();
362
363 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
364
365 auto transceivers = callee->pc()->GetTransceivers();
366 ASSERT_EQ(2u, transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200367 EXPECT_EQ(absl::nullopt, transceivers[0]->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800368 EXPECT_TRUE(transceivers[0]->stopped());
369 EXPECT_EQ(caller->pc()->GetTransceivers()[0]->mid(), transceivers[1]->mid());
370 EXPECT_FALSE(transceivers[1]->stopped());
371}
372
373// Test that audio and video transceivers created on the remote side with
374// AddTrack will all be reused if there is the same number of audio/video tracks
375// in the remote offer. Additionally, this tests that transceivers are
376// successfully matched even if they are in a different order on the remote
377// side.
378TEST_F(PeerConnectionJsepTest, SetRemoteOfferReusesTransceiversOfBothTypes) {
379 auto caller = CreatePeerConnection();
380 caller->AddVideoTrack("v");
381 caller->AddAudioTrack("a");
382 auto callee = CreatePeerConnection();
383 callee->AddAudioTrack("a");
384 callee->AddVideoTrack("v");
385
386 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
387
388 auto caller_transceivers = caller->pc()->GetTransceivers();
389 auto callee_transceivers = callee->pc()->GetTransceivers();
390 ASSERT_EQ(2u, callee_transceivers.size());
391 EXPECT_EQ(caller_transceivers[0]->mid(), callee_transceivers[1]->mid());
392 EXPECT_EQ(caller_transceivers[1]->mid(), callee_transceivers[0]->mid());
393}
394
395// Tests for JSEP initial CreateAnswer.
396
397// Test that the answer to a remote offer creates media sections for each
398// offered media in the same order and with the same mids.
399TEST_F(PeerConnectionJsepTest, CreateAnswerHasSameMidsAsOffer) {
400 auto caller = CreatePeerConnection();
401 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
402 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
403 auto third_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
Steve Antonfa2260d2017-12-28 16:38:23 -0800404 caller->CreateDataChannel("dc");
Steve Antondcc3c022017-12-22 16:02:54 -0800405 auto callee = CreatePeerConnection();
406
Steve Antonfa2260d2017-12-28 16:38:23 -0800407 auto offer = caller->CreateOffer();
408 const auto* offer_data = cricket::GetFirstDataContent(offer->description());
409 ASSERT_TRUE(
410 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
411 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antondcc3c022017-12-22 16:02:54 -0800412
413 auto answer = callee->CreateAnswer();
414 auto contents = answer->description()->contents();
Steve Antonfa2260d2017-12-28 16:38:23 -0800415 ASSERT_EQ(4u, contents.size());
Steve Antondcc3c022017-12-22 16:02:54 -0800416 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[0].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800417 EXPECT_EQ(first_transceiver->mid(), contents[0].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800418 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800419 EXPECT_EQ(second_transceiver->mid(), contents[1].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800420 EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, contents[2].media_description()->type());
Steve Antonfa2260d2017-12-28 16:38:23 -0800421 EXPECT_EQ(third_transceiver->mid(), contents[2].name);
422 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[3].media_description()->type());
423 EXPECT_EQ(offer_data->name, contents[3].name);
Steve Antondcc3c022017-12-22 16:02:54 -0800424}
425
426// Test that an answering media section is marked as rejected if the underlying
427// transceiver has been stopped.
428TEST_F(PeerConnectionJsepTest, CreateAnswerRejectsStoppedTransceiver) {
429 auto caller = CreatePeerConnection();
430 caller->AddAudioTrack("a");
431 auto callee = CreatePeerConnection();
432
433 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
434
435 callee->pc()->GetTransceivers()[0]->Stop();
436
437 auto answer = callee->CreateAnswer();
438 auto contents = answer->description()->contents();
439 ASSERT_EQ(1u, contents.size());
440 EXPECT_TRUE(contents[0].rejected);
441}
442
443// Test that CreateAnswer will generate media sections which will only send or
444// receive if the offer indicates it can do the reciprocating direction.
445// The full matrix is tested more extensively in MediaSession.
446TEST_F(PeerConnectionJsepTest, CreateAnswerNegotiatesDirection) {
447 auto caller = CreatePeerConnection();
448 RtpTransceiverInit init;
449 init.direction = RtpTransceiverDirection::kSendOnly;
450 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init);
451 auto callee = CreatePeerConnection();
452 callee->AddAudioTrack("a");
453
454 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
455
456 auto answer = callee->CreateAnswer();
457 auto contents = answer->description()->contents();
458 ASSERT_EQ(1u, contents.size());
459 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
460 contents[0].media_description()->direction());
461}
462
463// Tests for JSEP SetLocalDescription with a local answer.
464// Note that these test only the additional behaviors not covered by
465// SetLocalDescription with a local offer.
466
467// Test that SetLocalDescription with an answer sets the current_direction
468// property of the transceivers mentioned in the session description.
469TEST_F(PeerConnectionJsepTest, SetLocalAnswerUpdatesCurrentDirection) {
470 auto caller = CreatePeerConnection();
471 auto caller_audio = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
472 caller_audio->SetDirection(RtpTransceiverDirection::kRecvOnly);
473 auto callee = CreatePeerConnection();
474 callee->AddAudioTrack("a");
475
476 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
477 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
478
479 auto transceivers = callee->pc()->GetTransceivers();
480 ASSERT_EQ(1u, transceivers.size());
481 // Since the offer was recvonly and the transceiver direction is sendrecv,
482 // the negotiated direction will be sendonly.
483 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
484 transceivers[0]->current_direction());
485}
486
487// Tests for JSEP SetRemoteDescription with a remote answer.
488// Note that these test only the additional behaviors not covered by
489// SetRemoteDescription with a remote offer.
490
491TEST_F(PeerConnectionJsepTest, SetRemoteAnswerUpdatesCurrentDirection) {
492 auto caller = CreatePeerConnection();
493 caller->AddAudioTrack("a");
494 auto callee = CreatePeerConnection();
495 callee->AddAudioTrack("a");
496 auto callee_audio = callee->pc()->GetTransceivers()[0];
497 callee_audio->SetDirection(RtpTransceiverDirection::kSendOnly);
498
499 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
500 ASSERT_TRUE(
501 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
502
503 auto transceivers = caller->pc()->GetTransceivers();
504 ASSERT_EQ(1u, transceivers.size());
505 // Since the remote transceiver was set to sendonly, the negotiated direction
506 // in the answer would be sendonly which we apply as recvonly to the local
507 // transceiver.
508 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
509 transceivers[0]->current_direction());
510}
511
512// Tests for multiple round trips.
513
514// Test that setting a transceiver with the inactive direction does not stop it
515// on either the caller or the callee.
516TEST_F(PeerConnectionJsepTest, SettingTransceiverInactiveDoesNotStopIt) {
517 auto caller = CreatePeerConnection();
518 caller->AddAudioTrack("a");
519 auto callee = CreatePeerConnection();
520 callee->AddAudioTrack("a");
521 callee->pc()->GetTransceivers()[0]->SetDirection(
522 RtpTransceiverDirection::kInactive);
523
524 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
525 ASSERT_TRUE(
526 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
527
528 EXPECT_FALSE(caller->pc()->GetTransceivers()[0]->stopped());
529 EXPECT_FALSE(callee->pc()->GetTransceivers()[0]->stopped());
530}
531
532// Test that if a transceiver had been associated and later stopped, then a
533// media section is still generated for it and the media section is marked as
534// rejected.
535TEST_F(PeerConnectionJsepTest,
536 ReOfferMediaSectionForAssociatedStoppedTransceiverIsRejected) {
537 auto caller = CreatePeerConnection();
538 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
539 auto callee = CreatePeerConnection();
540
541 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
542 ASSERT_TRUE(
543 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
544
545 ASSERT_TRUE(transceiver->mid());
546 transceiver->Stop();
547
548 auto reoffer = caller->CreateOffer();
549 auto contents = reoffer->description()->contents();
550 ASSERT_EQ(1u, contents.size());
551 EXPECT_TRUE(contents[0].rejected);
552}
553
554// Test that stopping an associated transceiver on the caller side will stop the
555// corresponding transceiver on the remote side when the remote offer is
556// applied.
557TEST_F(PeerConnectionJsepTest,
558 StoppingTransceiverInOfferStopsTransceiverOnRemoteSide) {
559 auto caller = CreatePeerConnection();
560 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
561 auto callee = CreatePeerConnection();
562
563 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
564 ASSERT_TRUE(
565 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
566
567 transceiver->Stop();
568
569 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
570
571 auto transceivers = callee->pc()->GetTransceivers();
572 EXPECT_TRUE(transceivers[0]->stopped());
573 EXPECT_TRUE(transceivers[0]->mid());
574}
575
576// Test that CreateOffer will only generate a recycled media section if the
577// transceiver to be recycled has been seen stopped by the other side first.
578TEST_F(PeerConnectionJsepTest,
579 CreateOfferDoesNotRecycleMediaSectionIfFirstStopped) {
580 auto caller = CreatePeerConnection();
581 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
582 auto callee = CreatePeerConnection();
583
584 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
585 ASSERT_TRUE(
586 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
587
588 auto second_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
589 first_transceiver->Stop();
590
591 auto reoffer = caller->CreateOffer();
592 auto contents = reoffer->description()->contents();
593 ASSERT_EQ(2u, contents.size());
594 EXPECT_TRUE(contents[0].rejected);
595 EXPECT_FALSE(contents[1].rejected);
596}
597
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800598// Test that the offer/answer and the transceivers are correctly generated and
599// updated when the media section is recycled after the callee stops a
600// transceiver and sends an answer with a 0 port.
601TEST_F(PeerConnectionJsepTest,
602 RecycleMediaSectionWhenStoppingTransceiverOnAnswerer) {
603 auto caller = CreatePeerConnection();
604 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
605 auto callee = CreatePeerConnection();
606
607 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
608 callee->pc()->GetTransceivers()[0]->Stop();
609 ASSERT_TRUE(
610 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
611 EXPECT_TRUE(first_transceiver->stopped());
612 // First transceivers aren't dissociated yet.
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200613 ASSERT_NE(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800614 std::string first_mid = *first_transceiver->mid();
615 EXPECT_EQ(first_mid, callee->pc()->GetTransceivers()[0]->mid());
616
617 // New offer exchange with new transceivers that recycles the m section
618 // correctly.
619 caller->AddAudioTrack("audio2");
620 callee->AddAudioTrack("audio2");
621 auto offer = caller->CreateOffer();
622 auto offer_contents = offer->description()->contents();
623 std::string second_mid = offer_contents[0].name;
624 ASSERT_EQ(1u, offer_contents.size());
625 EXPECT_FALSE(offer_contents[0].rejected);
626 EXPECT_NE(first_mid, second_mid);
627
628 // Setting the offer on each side will dissociate the first transceivers and
629 // associate the new transceivers.
630 ASSERT_TRUE(
631 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200632 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800633 EXPECT_EQ(second_mid, caller->pc()->GetTransceivers()[1]->mid());
634 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200635 EXPECT_EQ(absl::nullopt, callee->pc()->GetTransceivers()[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800636 EXPECT_EQ(second_mid, callee->pc()->GetTransceivers()[1]->mid());
637
638 // The new answer should also recycle the m section correctly.
639 auto answer = callee->CreateAnswer();
640 auto answer_contents = answer->description()->contents();
641 ASSERT_EQ(1u, answer_contents.size());
642 EXPECT_FALSE(answer_contents[0].rejected);
643 EXPECT_EQ(second_mid, answer_contents[0].name);
644
645 // Finishing the negotiation shouldn't add or dissociate any transceivers.
646 ASSERT_TRUE(
647 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
648 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
649 auto caller_transceivers = caller->pc()->GetTransceivers();
650 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200651 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800652 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
653 auto callee_transceivers = callee->pc()->GetTransceivers();
654 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200655 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800656 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
657}
658
659// Test that creating/setting a local offer that recycles an m= section is
660// idempotent.
661TEST_F(PeerConnectionJsepTest, CreateOfferRecyclesWhenOfferingTwice) {
662 // Do a negotiation with a port 0 for the media section.
663 auto caller = CreatePeerConnection();
664 auto first_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
665 auto callee = CreatePeerConnection();
666 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
667 first_transceiver->Stop();
668 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
669 caller->AddAudioTrack("audio2");
670
671 // Create a new offer that recycles the media section and set it as a local
672 // description.
673 auto offer = caller->CreateOffer();
674 auto offer_contents = offer->description()->contents();
675 ASSERT_EQ(1u, offer_contents.size());
676 EXPECT_FALSE(offer_contents[0].rejected);
677 ASSERT_TRUE(caller->SetLocalDescription(std::move(offer)));
678 EXPECT_FALSE(caller->pc()->GetTransceivers()[1]->stopped());
679 std::string second_mid = offer_contents[0].name;
680
681 // Create another new offer and set the local description again without the
682 // rest of any negotation ocurring.
683 auto second_offer = caller->CreateOffer();
684 auto second_offer_contents = second_offer->description()->contents();
685 ASSERT_EQ(1u, second_offer_contents.size());
686 EXPECT_FALSE(second_offer_contents[0].rejected);
687 // The mid shouldn't change.
688 EXPECT_EQ(second_mid, second_offer_contents[0].name);
689
690 ASSERT_TRUE(caller->SetLocalDescription(std::move(second_offer)));
691 // Make sure that the caller's transceivers are associated correctly.
692 auto caller_transceivers = caller->pc()->GetTransceivers();
693 ASSERT_EQ(2u, caller_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200694 EXPECT_EQ(absl::nullopt, caller_transceivers[0]->mid());
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800695 EXPECT_EQ(second_mid, caller_transceivers[1]->mid());
696 EXPECT_FALSE(caller_transceivers[1]->stopped());
697}
698
Steve Antondcc3c022017-12-22 16:02:54 -0800699// Test that the offer/answer and transceivers for both the caller and callee
700// side are generated/updated correctly when recycling an audio/video media
701// section as a media section of either the same or opposite type.
702class RecycleMediaSectionTest
703 : public PeerConnectionJsepTest,
704 public testing::WithParamInterface<
705 std::tuple<cricket::MediaType, cricket::MediaType>> {
706 protected:
707 RecycleMediaSectionTest() {
708 first_type_ = std::get<0>(GetParam());
709 second_type_ = std::get<1>(GetParam());
710 }
711
712 cricket::MediaType first_type_;
713 cricket::MediaType second_type_;
714};
715
716TEST_P(RecycleMediaSectionTest, VerifyOfferAnswerAndTransceivers) {
717 auto caller = CreatePeerConnection();
718 auto first_transceiver = caller->AddTransceiver(first_type_);
719 auto callee = CreatePeerConnection();
720
721 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
722
723 std::string first_mid = *first_transceiver->mid();
724 first_transceiver->Stop();
725
726 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
727
728 auto second_transceiver = caller->AddTransceiver(second_type_);
729
730 // The offer should reuse the previous media section but allocate a new MID
731 // and change the media type.
732 auto offer = caller->CreateOffer();
733 auto offer_contents = offer->description()->contents();
734 ASSERT_EQ(1u, offer_contents.size());
735 EXPECT_FALSE(offer_contents[0].rejected);
736 EXPECT_EQ(second_type_, offer_contents[0].media_description()->type());
737 std::string second_mid = offer_contents[0].name;
738 EXPECT_NE(first_mid, second_mid);
739
740 // Setting the local offer will dissociate the previous transceiver and set
741 // the MID for the new transceiver.
742 ASSERT_TRUE(
743 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200744 EXPECT_EQ(absl::nullopt, first_transceiver->mid());
Steve Antondcc3c022017-12-22 16:02:54 -0800745 EXPECT_EQ(second_mid, second_transceiver->mid());
746
747 // Setting the remote offer will dissociate the previous transceiver and
748 // create a new transceiver for the media section.
749 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
750 auto callee_transceivers = callee->pc()->GetTransceivers();
751 ASSERT_EQ(2u, callee_transceivers.size());
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200752 EXPECT_EQ(absl::nullopt, callee_transceivers[0]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800753 EXPECT_EQ(first_type_, callee_transceivers[0]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800754 EXPECT_EQ(second_mid, callee_transceivers[1]->mid());
Steve Anton69470252018-02-09 11:43:08 -0800755 EXPECT_EQ(second_type_, callee_transceivers[1]->media_type());
Steve Antondcc3c022017-12-22 16:02:54 -0800756
757 // The answer should have only one media section for the new transceiver.
758 auto answer = callee->CreateAnswer();
759 auto answer_contents = answer->description()->contents();
760 ASSERT_EQ(1u, answer_contents.size());
761 EXPECT_FALSE(answer_contents[0].rejected);
762 EXPECT_EQ(second_mid, answer_contents[0].name);
763 EXPECT_EQ(second_type_, answer_contents[0].media_description()->type());
764
765 // Setting the local answer should succeed.
766 ASSERT_TRUE(
767 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
768
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800769 // Setting the remote answer should succeed and not create any new
770 // transceivers.
Steve Antondcc3c022017-12-22 16:02:54 -0800771 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
Seth Hampsonae8a90a2018-02-13 15:33:48 -0800772 ASSERT_EQ(2u, caller->pc()->GetTransceivers().size());
773 ASSERT_EQ(2u, callee->pc()->GetTransceivers().size());
Steve Antondcc3c022017-12-22 16:02:54 -0800774}
775
776// Test all combinations of audio and video as the first and second media type
777// for the media section. This is needed for full test coverage because
778// MediaSession has separate functions for processing audio and video media
779// sections.
780INSTANTIATE_TEST_CASE_P(
781 PeerConnectionJsepTest,
782 RecycleMediaSectionTest,
783 Combine(Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO),
784 Values(cricket::MEDIA_TYPE_AUDIO, cricket::MEDIA_TYPE_VIDEO)));
785
Steve Antonfa2260d2017-12-28 16:38:23 -0800786// Test that a new data channel section will not reuse a recycleable audio or
787// video media section. Additionally, tests that the new section is added to the
788// end of the session description.
789TEST_F(PeerConnectionJsepTest, DataChannelDoesNotRecycleMediaSection) {
790 auto caller = CreatePeerConnection();
791 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
792 auto callee = CreatePeerConnection();
793
794 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
795
796 transceiver->Stop();
797
798 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
799
800 caller->CreateDataChannel("dc");
801
802 auto offer = caller->CreateOffer();
803 auto offer_contents = offer->description()->contents();
804 ASSERT_EQ(2u, offer_contents.size());
805 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
806 offer_contents[0].media_description()->type());
807 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
808 offer_contents[1].media_description()->type());
809
810 ASSERT_TRUE(
811 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
812 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
813
814 auto answer = callee->CreateAnswer();
815 auto answer_contents = answer->description()->contents();
816 ASSERT_EQ(2u, answer_contents.size());
817 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO,
818 answer_contents[0].media_description()->type());
819 EXPECT_EQ(cricket::MEDIA_TYPE_DATA,
820 answer_contents[1].media_description()->type());
821}
822
823// Test that if a new track is added to an existing session that has a data,
824// the new section comes at the end of the new offer, after the existing data
825// section.
826TEST_F(PeerConnectionJsepTest, AudioTrackAddedAfterDataSectionInReoffer) {
827 auto caller = CreatePeerConnection();
828 caller->CreateDataChannel("dc");
829 auto callee = CreatePeerConnection();
830
831 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
832
833 caller->AddAudioTrack("a");
834
835 auto offer = caller->CreateOffer();
836 auto contents = offer->description()->contents();
837 ASSERT_EQ(2u, contents.size());
838 EXPECT_EQ(cricket::MEDIA_TYPE_DATA, contents[0].media_description()->type());
839 EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, contents[1].media_description()->type());
840}
841
Steve Antondcc3c022017-12-22 16:02:54 -0800842// Tests for MID properties.
843
844static void RenameSection(size_t mline_index,
845 const std::string& new_mid,
846 SessionDescriptionInterface* sdesc) {
847 cricket::SessionDescription* desc = sdesc->description();
848 std::string old_mid = desc->contents()[mline_index].name;
849 desc->contents()[mline_index].name = new_mid;
850 desc->transport_infos()[mline_index].content_name = new_mid;
851 const cricket::ContentGroup* bundle =
852 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
853 if (bundle) {
854 cricket::ContentGroup new_bundle = *bundle;
855 if (new_bundle.RemoveContentName(old_mid)) {
856 new_bundle.AddContentName(new_mid);
857 }
858 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
859 desc->AddGroup(new_bundle);
860 }
861}
862
863// Test that two PeerConnections can have a successful offer/answer exchange if
864// the MIDs are changed from the defaults.
865TEST_F(PeerConnectionJsepTest, OfferAnswerWithChangedMids) {
866 constexpr char kFirstMid[] = "nondefaultmid";
867 constexpr char kSecondMid[] = "randommid";
868
869 auto caller = CreatePeerConnection();
870 caller->AddAudioTrack("a");
871 caller->AddAudioTrack("b");
872 auto callee = CreatePeerConnection();
873
874 auto offer = caller->CreateOffer();
875 RenameSection(0, kFirstMid, offer.get());
876 RenameSection(1, kSecondMid, offer.get());
877
878 ASSERT_TRUE(
879 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
880 auto caller_transceivers = caller->pc()->GetTransceivers();
881 EXPECT_EQ(kFirstMid, caller_transceivers[0]->mid());
882 EXPECT_EQ(kSecondMid, caller_transceivers[1]->mid());
883
884 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
885 auto callee_transceivers = callee->pc()->GetTransceivers();
886 EXPECT_EQ(kFirstMid, callee_transceivers[0]->mid());
887 EXPECT_EQ(kSecondMid, callee_transceivers[1]->mid());
888
889 auto answer = callee->CreateAnswer();
890 auto answer_contents = answer->description()->contents();
891 EXPECT_EQ(kFirstMid, answer_contents[0].name);
892 EXPECT_EQ(kSecondMid, answer_contents[1].name);
893
894 ASSERT_TRUE(
895 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
896 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
897}
898
899// Test that CreateOffer will generate a MID that is not already used if the
900// default it would have picked is already taken. This is tested by using a
901// third PeerConnection to determine what the default would be for the second
902// media section then setting that as the first media section's MID.
903TEST_F(PeerConnectionJsepTest, CreateOfferGeneratesUniqueMidIfAlreadyTaken) {
904 // First, find what the default MID is for the second media section.
905 auto pc = CreatePeerConnection();
906 pc->AddAudioTrack("a");
907 pc->AddAudioTrack("b");
908 auto default_offer = pc->CreateOffer();
909 std::string default_second_mid =
910 default_offer->description()->contents()[1].name;
911
912 // Now, do an offer/answer with one track which has the MID set to the default
913 // second MID.
914 auto caller = CreatePeerConnection();
915 caller->AddAudioTrack("a");
916 auto callee = CreatePeerConnection();
917
918 auto offer = caller->CreateOffer();
919 RenameSection(0, default_second_mid, offer.get());
920
921 ASSERT_TRUE(
922 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
923 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
924 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
925
926 // Add a second track and ensure that the MID is different.
927 caller->AddAudioTrack("b");
928
929 auto reoffer = caller->CreateOffer();
930 auto reoffer_contents = reoffer->description()->contents();
931 EXPECT_EQ(default_second_mid, reoffer_contents[0].name);
932 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
933}
934
Steve Antonfa2260d2017-12-28 16:38:23 -0800935// Test that if an audio or video section has the default data section MID, then
936// CreateOffer will generate a unique MID for the newly added data section.
937TEST_F(PeerConnectionJsepTest,
938 CreateOfferGeneratesUniqueMidForDataSectionIfAlreadyTaken) {
939 // First, find what the default MID is for the data channel.
940 auto pc = CreatePeerConnection();
941 pc->CreateDataChannel("dc");
942 auto default_offer = pc->CreateOffer();
943 std::string default_data_mid =
944 default_offer->description()->contents()[0].name;
945
946 // Now do an offer/answer with one audio track which has a MID set to the
947 // default data MID.
948 auto caller = CreatePeerConnection();
949 caller->AddAudioTrack("a");
950 auto callee = CreatePeerConnection();
951
952 auto offer = caller->CreateOffer();
953 RenameSection(0, default_data_mid, offer.get());
954
955 ASSERT_TRUE(
956 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
957 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
958 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
959
960 // Add a data channel and ensure that the MID is different.
961 caller->CreateDataChannel("dc");
962
963 auto reoffer = caller->CreateOffer();
964 auto reoffer_contents = reoffer->description()->contents();
965 EXPECT_EQ(default_data_mid, reoffer_contents[0].name);
966 EXPECT_NE(reoffer_contents[0].name, reoffer_contents[1].name);
967}
968
Steve Antondcc3c022017-12-22 16:02:54 -0800969// Test that a reoffer initiated by the callee adds a new track to the caller.
970TEST_F(PeerConnectionJsepTest, CalleeDoesReoffer) {
971 auto caller = CreatePeerConnection();
972 caller->AddAudioTrack("a");
973 auto callee = CreatePeerConnection();
974 callee->AddAudioTrack("a");
975 callee->AddVideoTrack("v");
976
977 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
978
979 EXPECT_EQ(1u, caller->pc()->GetTransceivers().size());
980 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
981
982 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
983
984 EXPECT_EQ(2u, caller->pc()->GetTransceivers().size());
985 EXPECT_EQ(2u, callee->pc()->GetTransceivers().size());
986}
987
Steve Anton02ee47c2018-01-10 16:26:06 -0800988// Tests for MSID properties.
989
990// Test that adding a track with AddTrack results in an offer that signals the
991// track's ID.
992TEST_F(PeerConnectionJsepTest, AddingTrackWithAddTrackSpecifiesTrackId) {
993 const std::string kTrackId = "audio_track";
994
995 auto caller = CreatePeerConnection();
996 caller->AddAudioTrack(kTrackId);
997
998 auto offer = caller->CreateOffer();
999 auto contents = offer->description()->contents();
1000 ASSERT_EQ(1u, contents.size());
1001 auto streams = contents[0].media_description()->streams();
1002 ASSERT_EQ(1u, streams.size());
1003 EXPECT_EQ(kTrackId, streams[0].id);
1004}
1005
1006// Test that adding a track by calling AddTransceiver then SetTrack results in
1007// an offer that does not signal the track's ID and signals a random ID.
1008TEST_F(PeerConnectionJsepTest,
1009 AddingTrackWithAddTransceiverSpecifiesRandomTrackId) {
1010 const std::string kTrackId = "audio_track";
1011
1012 auto caller = CreatePeerConnection();
1013 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1014 transceiver->sender()->SetTrack(caller->CreateAudioTrack(kTrackId));
1015
1016 auto offer = caller->CreateOffer();
1017 auto contents = offer->description()->contents();
1018 ASSERT_EQ(1u, contents.size());
1019 auto streams = contents[0].media_description()->streams();
1020 ASSERT_EQ(1u, streams.size());
1021 EXPECT_NE(kTrackId, streams[0].id);
1022}
1023
Steve Anton5f94aa22018-02-01 10:58:30 -08001024// Test that if the transceiver is recvonly or inactive, then no MSID
1025// information is included in the offer.
1026TEST_F(PeerConnectionJsepTest, NoMsidInOfferIfTransceiverDirectionHasNoSend) {
1027 auto caller = CreatePeerConnection();
1028
1029 RtpTransceiverInit init_recvonly;
1030 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1031 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly));
1032
1033 RtpTransceiverInit init_inactive;
1034 init_inactive.direction = RtpTransceiverDirection::kInactive;
1035 ASSERT_TRUE(caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_inactive));
1036
1037 auto offer = caller->CreateOffer();
1038 auto contents = offer->description()->contents();
1039 ASSERT_EQ(2u, contents.size());
1040 // MSID is specified in the first stream, so no streams means no MSID.
1041 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1042 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1043}
1044
1045// Test that if an answer negotiates transceiver directions of recvonly or
1046// inactive, then no MSID information is included in the answer.
1047TEST_F(PeerConnectionJsepTest, NoMsidInAnswerIfNoRespondingTracks) {
1048 auto caller = CreatePeerConnection();
1049 auto callee = CreatePeerConnection();
1050
1051 // recvonly transceiver will get negotiated to inactive since the callee has
1052 // no tracks to send in response.
1053 RtpTransceiverInit init_recvonly;
1054 init_recvonly.direction = RtpTransceiverDirection::kRecvOnly;
1055 caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO, init_recvonly);
1056
1057 // sendrecv transceiver will get negotiated to recvonly since the callee has
1058 // no tracks to send in response.
1059 RtpTransceiverInit init_sendrecv;
1060 init_sendrecv.direction = RtpTransceiverDirection::kSendRecv;
1061 caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO, init_sendrecv);
1062
1063 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1064
1065 auto answer = callee->CreateAnswer();
1066 auto contents = answer->description()->contents();
1067 ASSERT_EQ(2u, contents.size());
1068 // MSID is specified in the first stream, so no streams means no MSID.
1069 EXPECT_EQ(0u, contents[0].media_description()->streams().size());
1070 EXPECT_EQ(0u, contents[1].media_description()->streams().size());
1071}
1072
1073// Test that the MSID is included even if the transceiver direction has changed
1074// to inactive if the transceiver had previously sent media.
1075TEST_F(PeerConnectionJsepTest, IncludeMsidEvenIfDirectionHasChanged) {
1076 auto caller = CreatePeerConnection();
1077 caller->AddAudioTrack("audio");
1078 auto callee = CreatePeerConnection();
1079 callee->AddAudioTrack("audio");
1080
1081 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1082
1083 caller->pc()->GetTransceivers()[0]->SetDirection(
1084 RtpTransceiverDirection::kInactive);
1085
1086 // The transceiver direction on both sides will turn to inactive.
1087 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1088
1089 auto* offer = callee->pc()->remote_description();
1090 auto offer_contents = offer->description()->contents();
1091 ASSERT_EQ(1u, offer_contents.size());
1092 // MSID is specified in the first stream. If it is present, assume that MSID
1093 // is there.
1094 EXPECT_EQ(1u, offer_contents[0].media_description()->streams().size());
1095
1096 auto* answer = caller->pc()->remote_description();
1097 auto answer_contents = answer->description()->contents();
1098 ASSERT_EQ(1u, answer_contents.size());
1099 EXPECT_EQ(1u, answer_contents[0].media_description()->streams().size());
1100}
1101
1102// Test that stopping a RtpTransceiver will cause future offers to not include
1103// any MSID information for that section.
1104TEST_F(PeerConnectionJsepTest, RemoveMsidIfTransceiverStopped) {
1105 auto caller = CreatePeerConnection();
1106 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1107 auto callee = CreatePeerConnection();
1108
1109 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1110
1111 transceiver->Stop();
1112
1113 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1114
1115 auto* offer = callee->pc()->remote_description();
1116 auto offer_contents = offer->description()->contents();
1117 ASSERT_EQ(1u, offer_contents.size());
1118 // MSID is specified in the first stream, so no streams means no MSID.
1119 EXPECT_EQ(0u, offer_contents[0].media_description()->streams().size());
1120}
1121
Steve Anton02ee47c2018-01-10 16:26:06 -08001122// Test that the callee RtpReceiver created by a call to SetRemoteDescription
1123// has its ID set to the signaled track ID.
1124TEST_F(PeerConnectionJsepTest,
1125 RtpReceiverCreatedBySetRemoteDescriptionHasSignaledTrackId) {
1126 const std::string kTrackId = "audio_track";
1127
1128 auto caller = CreatePeerConnection();
1129 auto callee = CreatePeerConnection();
1130 caller->AddAudioTrack(kTrackId);
1131
1132 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1133
1134 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1135 auto receiver = callee->pc()->GetReceivers()[0];
1136 EXPECT_EQ(kTrackId, receiver->id());
1137}
1138
1139// Test that if the callee RtpReceiver is reused by a call to
1140// SetRemoteDescription, its ID does not change.
1141TEST_F(PeerConnectionJsepTest,
1142 RtpReceiverCreatedBeforeSetRemoteDescriptionKeepsId) {
1143 const std::string kTrackId = "audio_track";
1144
1145 auto caller = CreatePeerConnection();
1146 auto callee = CreatePeerConnection();
1147 caller->AddAudioTrack(kTrackId);
1148 callee->AddAudioTrack("dummy_track");
1149
1150 ASSERT_EQ(1u, callee->pc()->GetReceivers().size());
1151 auto receiver = callee->pc()->GetReceivers()[0];
1152 std::string receiver_id = receiver->id();
1153
1154 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1155
1156 EXPECT_EQ(receiver_id, receiver->id());
1157}
1158
Steve Antonef65ef12018-01-10 17:15:20 -08001159// Test that setting a remote offer with one track that has no streams fires off
1160// the correct OnAddTrack event.
1161TEST_F(PeerConnectionJsepTest,
1162 SetRemoteOfferWithOneTrackNoStreamFiresOnAddTrack) {
1163 const std::string kTrackLabel = "audio_track";
1164
1165 auto caller = CreatePeerConnection();
1166 auto callee = CreatePeerConnection();
1167 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel));
1168
1169 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1170
Seth Hampson5b4f0752018-04-02 16:31:36 -07001171 const auto& track_events = callee->observer()->add_track_events_;
1172 ASSERT_EQ(1u, track_events.size());
1173 const auto& event = track_events[0];
1174 EXPECT_EQ(kTrackLabel, event.receiver->track()->id());
1175 EXPECT_EQ(0u, event.streams.size());
Steve Antonef65ef12018-01-10 17:15:20 -08001176}
1177
1178// Test that setting a remote offer with one track that has one stream fires off
1179// the correct OnAddTrack event.
1180TEST_F(PeerConnectionJsepTest,
1181 SetRemoteOfferWithOneTrackOneStreamFiresOnAddTrack) {
1182 const std::string kTrackLabel = "audio_track";
Seth Hampson845e8782018-03-02 11:34:10 -08001183 const std::string kStreamId = "audio_stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001184
1185 auto caller = CreatePeerConnection();
1186 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001187 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001188
1189 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1190
1191 const auto& track_events = callee->observer()->add_track_events_;
1192 ASSERT_EQ(1u, track_events.size());
1193 const auto& event = track_events[0];
1194 ASSERT_EQ(1u, event.streams.size());
1195 auto stream = event.streams[0];
Seth Hampson13b8bad2018-03-13 16:05:28 -07001196 EXPECT_EQ(kStreamId, stream->id());
Steve Antonef65ef12018-01-10 17:15:20 -08001197 EXPECT_THAT(track_events[0].snapshotted_stream_tracks.at(stream),
1198 ElementsAre(event.receiver->track()));
1199 EXPECT_EQ(event.receiver->streams(), track_events[0].streams);
1200}
1201
1202// Test that setting a remote offer with two tracks that share the same stream
1203// fires off two OnAddTrack events, both with the same stream that has both
1204// tracks present at the time of firing. This is to ensure that track events are
1205// not fired until SetRemoteDescription has finished processing all the media
1206// sections.
1207TEST_F(PeerConnectionJsepTest,
1208 SetRemoteOfferWithTwoTracksSameStreamFiresOnAddTrack) {
1209 const std::string kTrack1Label = "audio_track1";
1210 const std::string kTrack2Label = "audio_track2";
Seth Hampson845e8782018-03-02 11:34:10 -08001211 const std::string kSharedStreamId = "stream";
Steve Antonef65ef12018-01-10 17:15:20 -08001212
1213 auto caller = CreatePeerConnection();
1214 auto callee = CreatePeerConnection();
Seth Hampson845e8782018-03-02 11:34:10 -08001215 ASSERT_TRUE(caller->AddAudioTrack(kTrack1Label, {kSharedStreamId}));
1216 ASSERT_TRUE(caller->AddAudioTrack(kTrack2Label, {kSharedStreamId}));
Steve Antonef65ef12018-01-10 17:15:20 -08001217
1218 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1219
1220 const auto& track_events = callee->observer()->add_track_events_;
1221 ASSERT_EQ(2u, track_events.size());
1222 const auto& event1 = track_events[0];
1223 const auto& event2 = track_events[1];
1224 ASSERT_EQ(1u, event1.streams.size());
1225 auto stream = event1.streams[0];
1226 ASSERT_THAT(event2.streams, ElementsAre(stream));
1227 auto track1 = event1.receiver->track();
1228 auto track2 = event2.receiver->track();
1229 EXPECT_THAT(event1.snapshotted_stream_tracks.at(stream),
1230 UnorderedElementsAre(track1, track2));
1231 EXPECT_THAT(event2.snapshotted_stream_tracks.at(stream),
1232 UnorderedElementsAre(track1, track2));
1233}
1234
Seth Hampson5b4f0752018-04-02 16:31:36 -07001235// Test that setting a remote offer with one track that has two streams fires
1236// off the correct OnAddTrack event.
1237TEST_F(PeerConnectionJsepTest,
1238 SetRemoteOfferWithOneTrackTwoStreamFiresOnAddTrack) {
1239 const std::string kTrackLabel = "audio_track";
1240 const std::string kStreamId1 = "audio_stream1";
1241 const std::string kStreamId2 = "audio_stream2";
1242
1243 auto caller = CreatePeerConnection();
1244 auto callee = CreatePeerConnection();
1245 ASSERT_TRUE(caller->AddAudioTrack(kTrackLabel, {kStreamId1, kStreamId2}));
1246
1247 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1248
1249 const auto& track_events = callee->observer()->add_track_events_;
1250 ASSERT_EQ(1u, track_events.size());
1251 const auto& event = track_events[0];
1252 ASSERT_EQ(2u, event.streams.size());
1253 EXPECT_EQ(kStreamId1, event.streams[0]->id());
1254 EXPECT_EQ(kStreamId2, event.streams[1]->id());
1255}
Steve Antonef65ef12018-01-10 17:15:20 -08001256
Steve Anton54b84072018-02-20 15:19:52 -08001257// Test that if an RtpTransceiver with a current_direction set is stopped, then
1258// current_direction is changed to null.
1259TEST_F(PeerConnectionJsepTest, CurrentDirectionResetWhenRtpTransceiverStopped) {
1260 auto caller = CreatePeerConnection();
1261 auto callee = CreatePeerConnection();
1262
1263 auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
1264
1265 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1266
1267 ASSERT_TRUE(transceiver->current_direction());
1268 transceiver->Stop();
1269 EXPECT_FALSE(transceiver->current_direction());
1270}
1271
Steve Antonba42e992018-04-09 14:10:01 -07001272// Test that you can't set an answer on a PeerConnection before setting the
1273// offer.
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001274TEST_F(PeerConnectionJsepTest, AnswerBeforeOfferFails) {
1275 auto caller = CreatePeerConnection();
1276 auto callee = CreatePeerConnection();
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001277 caller->AddAudioTrack("audio");
Steve Antonba42e992018-04-09 14:10:01 -07001278
1279 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
1280
1281 RTCError error;
1282 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer(), &error));
1283 EXPECT_EQ(RTCErrorType::INVALID_STATE, error.type());
1284}
1285
1286// Test that a Unified Plan PeerConnection fails to set a Plan B offer if it has
1287// two video tracks.
1288TEST_F(PeerConnectionJsepTest, TwoVideoPlanBToUnifiedPlanFails) {
1289 RTCConfiguration config_planb;
1290 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1291 auto caller = CreatePeerConnection(config_planb);
1292 auto callee = CreatePeerConnection();
1293 caller->AddVideoTrack("video1");
1294 caller->AddVideoTrack("video2");
1295
1296 RTCError error;
1297 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
1298 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
1299}
1300
1301// Test that a Unified Plan PeerConnection fails to set a Plan B answer if it
1302// has two video tracks.
1303TEST_F(PeerConnectionJsepTest, OneVideoUnifiedPlanToTwoVideoPlanBFails) {
1304 auto caller = CreatePeerConnection();
1305 RTCConfiguration config_planb;
1306 config_planb.sdp_semantics = SdpSemantics::kPlanB;
1307 auto callee = CreatePeerConnection(config_planb);
1308 caller->AddVideoTrack("video");
1309 callee->AddVideoTrack("video1");
1310 callee->AddVideoTrack("video2");
1311
1312 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1313
1314 RTCError error;
1315 ASSERT_FALSE(caller->SetRemoteDescription(caller->CreateAnswer(), &error));
1316 EXPECT_EQ(RTCErrorType::INVALID_PARAMETER, error.type());
Harald Alvestrand5081c0c2018-03-09 15:18:03 +01001317}
1318
Steve Antondcc3c022017-12-22 16:02:54 -08001319} // namespace webrtc